From d0bd919ff47a930840730c0f163b00139403b8ed Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Mon, 11 May 2026 12:53:17 +0200 Subject: [PATCH] refactor: migrate models to freezed + json_serializable --- .github/workflows/ci.yml | 9 + build.yaml | 15 + lib/media/library_query.dart | 130 +- lib/media/library_query.freezed.dart | 1167 ++++++++ lib/media/media_sort.dart | 31 +- lib/media/media_sort.freezed.dart | 280 ++ lib/media/media_sort.g.dart | 15 +- lib/media/play_queue.dart | 151 +- lib/media/play_queue.freezed.dart | 377 +++ .../companion_remote/remote_command.dart | 40 +- .../remote_command.freezed.dart | 282 ++ .../companion_remote/remote_command.g.dart | 21 + .../companion_remote/remote_session.dart | 107 +- .../remote_session.freezed.dart | 570 ++++ .../companion_remote/remote_session.g.dart | 75 - lib/models/download_models.dart | 112 +- lib/models/download_models.freezed.dart | 552 ++++ lib/models/plex/plex_home.g.dart | 2 +- lib/models/shader_preset.dart | 90 +- lib/models/shader_preset.freezed.dart | 793 ++++++ lib/models/shader_preset.g.dart | 78 + lib/models/trackers/device_code.dart | 65 +- lib/models/trackers/device_code.freezed.dart | 718 +++++ lib/models/trackers/fribb_mapping_row.dart | 47 +- lib/models/trackers/fribb_mapping_row.g.dart | 20 + lib/models/trakt/trakt_scrobble_request.dart | 110 +- .../trakt/trakt_scrobble_request.freezed.dart | 345 +++ lib/models/trakt/trakt_user.dart | 7 +- lib/models/trakt/trakt_user.g.dart | 12 + lib/mpv/models.dart | 208 +- lib/mpv/models.freezed.dart | 2416 +++++++++++++++++ lib/mpv/player/player_base.dart | 6 +- lib/profiles/profile.dart | 231 +- lib/profiles/profile.freezed.dart | 380 +++ lib/profiles/profile_connection.dart | 56 +- lib/profiles/profile_connection.freezed.dart | 283 ++ lib/providers/companion_remote_provider.dart | 31 +- .../profile/add_local_profile_screen.dart | 3 +- .../profile/profile_detail_screen.dart | 8 +- lib/screens/settings/add_jellyfin_screen.dart | 3 +- .../companion_remote_peer_service.dart | 14 +- lib/utils/json_converters.dart | 21 + lib/watch_together/models/watch_session.dart | 143 +- .../models/watch_session.freezed.dart | 552 ++++ .../providers/watch_together_provider.dart | 4 +- scripts/ci_checks.sh | 22 +- scripts/codegen.sh | 4 + test/media/media_sort_test.dart | 10 +- test/profiles/active_profile_binder_test.dart | 16 +- .../active_profile_provider_test.dart | 44 +- test/profiles/profile_registry_test.dart | 34 +- test/profiles/profile_test.dart | 14 +- test/profiles/profiles_view_test.dart | 10 +- .../companion_remote_provider_test.dart | 2 +- .../providers/user_profile_provider_test.dart | 14 +- test/screens/auth_screen_test.dart | 14 +- .../profile/profile_detail_screen_test.dart | 7 +- .../profile/profile_switch_screen_test.dart | 7 +- .../settings/add_jellyfin_screen_test.dart | 9 +- 59 files changed, 9551 insertions(+), 1236 deletions(-) create mode 100644 build.yaml create mode 100644 lib/media/library_query.freezed.dart create mode 100644 lib/media/media_sort.freezed.dart create mode 100644 lib/media/play_queue.freezed.dart create mode 100644 lib/models/companion_remote/remote_command.freezed.dart create mode 100644 lib/models/companion_remote/remote_command.g.dart create mode 100644 lib/models/companion_remote/remote_session.freezed.dart delete mode 100644 lib/models/companion_remote/remote_session.g.dart create mode 100644 lib/models/download_models.freezed.dart create mode 100644 lib/models/shader_preset.freezed.dart create mode 100644 lib/models/shader_preset.g.dart create mode 100644 lib/models/trackers/device_code.freezed.dart create mode 100644 lib/models/trackers/fribb_mapping_row.g.dart create mode 100644 lib/models/trakt/trakt_scrobble_request.freezed.dart create mode 100644 lib/models/trakt/trakt_user.g.dart create mode 100644 lib/mpv/models.freezed.dart create mode 100644 lib/profiles/profile.freezed.dart create mode 100644 lib/profiles/profile_connection.freezed.dart create mode 100644 lib/utils/json_converters.dart create mode 100644 lib/watch_together/models/watch_session.freezed.dart create mode 100755 scripts/codegen.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30cc2e89..bff31c02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,15 @@ jobs: flutter pub get + - name: Verify generated files committed + run: | + dart run build_runner build --delete-conflicting-outputs + if ! git diff --exit-code lib/; then + echo "::error::Generated files (.g.dart / .freezed.dart) are out of date." + echo "Run 'scripts/codegen.sh' and commit the result." + exit 1 + fi + - name: Verify formatting run: | # Find all Dart files excluding generated files diff --git a/build.yaml b/build.yaml new file mode 100644 index 00000000..e3837c51 --- /dev/null +++ b/build.yaml @@ -0,0 +1,15 @@ +targets: + $default: + builders: + json_serializable: + options: + create_to_json: true + explicit_to_json: true + field_rename: none + include_if_null: true + checked: false + freezed: + options: + copy_with: true + equal: true + to_string: true diff --git a/lib/media/library_query.dart b/lib/media/library_query.dart index cc634870..c8b9a685 100644 --- a/lib/media/library_query.dart +++ b/lib/media/library_query.dart @@ -1,114 +1,74 @@ +// ignore_for_file: invalid_annotation_target +import 'package:freezed_annotation/freezed_annotation.dart'; + import 'media_kind.dart'; +part 'library_query.freezed.dart'; + /// Sort order applied to a library query. enum LibrarySortDirection { ascending, descending } -class LibrarySort { +@freezed +sealed class LibrarySort with _$LibrarySort { /// Backend-neutral sort field. Common values: `addedAt`, `originallyAvailableAt`, /// `lastViewedAt`, `title`, `rating`, `viewCount`, `random`. - final String field; - final LibrarySortDirection direction; - - const LibrarySort({required this.field, this.direction = LibrarySortDirection.descending}); + const factory LibrarySort({ + required String field, + @Default(LibrarySortDirection.descending) LibrarySortDirection direction, + }) = _LibrarySort; } /// A single filter clause. The semantics of `field` and `value` are /// backend-translated — the neutral query just carries the intent. -class LibraryFilter { - final String field; - final String op; // "=", "!=", "contains", ">=", etc. - final List values; - - const LibraryFilter({required this.field, this.op = '=', required this.values}); +@freezed +sealed class LibraryFilter with _$LibraryFilter { + const factory LibraryFilter({required String field, @Default('=') String op, required List values}) = + _LibraryFilter; } /// Backend-neutral library content query. Each backend's adapter translates /// these into its own query DSL (Plex `/library/sections/{id}/all?type=...` /// or Jellyfin `/Items?ParentId=...&Filters=...`). -class LibraryQuery { - /// Restrict to a single kind (e.g. `MediaKind.movie`). Null = library default. - final MediaKind? kind; - - /// Pagination — zero-based offset. - final int offset; - final int limit; - - final LibrarySort? sort; - final List filters; - - /// Free-text search restricted to this library. Distinct from the global - /// search endpoint. - final String? search; - - /// Whether to include items the active user has already watched. - final bool includeWatched; - - /// Restrict the result to items whose sort name starts with this string — - /// the alpha-jump bar's filter UX. The literal `#` is a sentinel for - /// "non-alphabetic" and translates to a `NameLessThan=A` query for backends - /// that support it. - final String? nameStartsWith; - - /// Genre filter — used by the per-library filter sheet. Backends that - /// take multiple values (Jellyfin) AND/intersect; those that take one - /// (Plex's existing flow) consult `filters` instead. - final List? genres; - final List? officialRatings; - final List? years; - final List? tags; - - const LibraryQuery({ - this.kind, - this.offset = 0, - this.limit = 50, - this.sort, - this.filters = const [], - this.search, - this.includeWatched = true, - this.nameStartsWith, - this.genres, - this.officialRatings, - this.years, - this.tags, - }); - - LibraryQuery copyWith({ +@freezed +sealed class LibraryQuery with _$LibraryQuery { + const factory LibraryQuery({ + /// Restrict to a single kind (e.g. `MediaKind.movie`). Null = library default. MediaKind? kind, - int? offset, - int? limit, + + /// Pagination — zero-based offset. + @Default(0) int offset, + @Default(50) int limit, + LibrarySort? sort, - List? filters, + @Default([]) List filters, + + /// Free-text search restricted to this library. Distinct from the global + /// search endpoint. String? search, - bool? includeWatched, + + /// Whether to include items the active user has already watched. + @Default(true) bool includeWatched, + + /// Restrict the result to items whose sort name starts with this string — + /// the alpha-jump bar's filter UX. The literal `#` is a sentinel for + /// "non-alphabetic" and translates to a `NameLessThan=A` query for backends + /// that support it. String? nameStartsWith, + + /// Genre filter — used by the per-library filter sheet. Backends that + /// take multiple values (Jellyfin) AND/intersect; those that take one + /// (Plex's existing flow) consult `filters` instead. List? genres, List? officialRatings, List? years, List? tags, - }) { - return LibraryQuery( - kind: kind ?? this.kind, - offset: offset ?? this.offset, - limit: limit ?? this.limit, - sort: sort ?? this.sort, - filters: filters ?? this.filters, - search: search ?? this.search, - includeWatched: includeWatched ?? this.includeWatched, - nameStartsWith: nameStartsWith ?? this.nameStartsWith, - genres: genres ?? this.genres, - officialRatings: officialRatings ?? this.officialRatings, - years: years ?? this.years, - tags: tags ?? this.tags, - ); - } + }) = _LibraryQuery; } /// Page of items returned by [MediaServerClient.getLibraryContent]. /// Carries the total count so the UI can render correct pagination affordances. -class LibraryPage { - final List items; - final int totalCount; - final int offset; - - const LibraryPage({required this.items, required this.totalCount, this.offset = 0}); +@freezed +sealed class LibraryPage with _$LibraryPage { + const factory LibraryPage({required List items, required int totalCount, @Default(0) int offset}) = + _LibraryPage; } diff --git a/lib/media/library_query.freezed.dart b/lib/media/library_query.freezed.dart new file mode 100644 index 00000000..c9219275 --- /dev/null +++ b/lib/media/library_query.freezed.dart @@ -0,0 +1,1167 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'library_query.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$LibrarySort { + + String get field; LibrarySortDirection get direction; +/// Create a copy of LibrarySort +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LibrarySortCopyWith get copyWith => _$LibrarySortCopyWithImpl(this as LibrarySort, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LibrarySort&&(identical(other.field, field) || other.field == field)&&(identical(other.direction, direction) || other.direction == direction)); +} + + +@override +int get hashCode => Object.hash(runtimeType,field,direction); + +@override +String toString() { + return 'LibrarySort(field: $field, direction: $direction)'; +} + + +} + +/// @nodoc +abstract mixin class $LibrarySortCopyWith<$Res> { + factory $LibrarySortCopyWith(LibrarySort value, $Res Function(LibrarySort) _then) = _$LibrarySortCopyWithImpl; +@useResult +$Res call({ + String field, LibrarySortDirection direction +}); + + + + +} +/// @nodoc +class _$LibrarySortCopyWithImpl<$Res> + implements $LibrarySortCopyWith<$Res> { + _$LibrarySortCopyWithImpl(this._self, this._then); + + final LibrarySort _self; + final $Res Function(LibrarySort) _then; + +/// Create a copy of LibrarySort +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? field = null,Object? direction = null,}) { + return _then(_self.copyWith( +field: null == field ? _self.field : field // ignore: cast_nullable_to_non_nullable +as String,direction: null == direction ? _self.direction : direction // ignore: cast_nullable_to_non_nullable +as LibrarySortDirection, + )); +} + +} + + +/// Adds pattern-matching-related methods to [LibrarySort]. +extension LibrarySortPatterns on LibrarySort { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LibrarySort value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LibrarySort() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LibrarySort value) $default,){ +final _that = this; +switch (_that) { +case _LibrarySort(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LibrarySort value)? $default,){ +final _that = this; +switch (_that) { +case _LibrarySort() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String field, LibrarySortDirection direction)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LibrarySort() when $default != null: +return $default(_that.field,_that.direction);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String field, LibrarySortDirection direction) $default,) {final _that = this; +switch (_that) { +case _LibrarySort(): +return $default(_that.field,_that.direction);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String field, LibrarySortDirection direction)? $default,) {final _that = this; +switch (_that) { +case _LibrarySort() when $default != null: +return $default(_that.field,_that.direction);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _LibrarySort implements LibrarySort { + const _LibrarySort({required this.field, this.direction = LibrarySortDirection.descending}); + + +@override final String field; +@override@JsonKey() final LibrarySortDirection direction; + +/// Create a copy of LibrarySort +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LibrarySortCopyWith<_LibrarySort> get copyWith => __$LibrarySortCopyWithImpl<_LibrarySort>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LibrarySort&&(identical(other.field, field) || other.field == field)&&(identical(other.direction, direction) || other.direction == direction)); +} + + +@override +int get hashCode => Object.hash(runtimeType,field,direction); + +@override +String toString() { + return 'LibrarySort(field: $field, direction: $direction)'; +} + + +} + +/// @nodoc +abstract mixin class _$LibrarySortCopyWith<$Res> implements $LibrarySortCopyWith<$Res> { + factory _$LibrarySortCopyWith(_LibrarySort value, $Res Function(_LibrarySort) _then) = __$LibrarySortCopyWithImpl; +@override @useResult +$Res call({ + String field, LibrarySortDirection direction +}); + + + + +} +/// @nodoc +class __$LibrarySortCopyWithImpl<$Res> + implements _$LibrarySortCopyWith<$Res> { + __$LibrarySortCopyWithImpl(this._self, this._then); + + final _LibrarySort _self; + final $Res Function(_LibrarySort) _then; + +/// Create a copy of LibrarySort +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? field = null,Object? direction = null,}) { + return _then(_LibrarySort( +field: null == field ? _self.field : field // ignore: cast_nullable_to_non_nullable +as String,direction: null == direction ? _self.direction : direction // ignore: cast_nullable_to_non_nullable +as LibrarySortDirection, + )); +} + + +} + +/// @nodoc +mixin _$LibraryFilter { + + String get field; String get op; List get values; +/// Create a copy of LibraryFilter +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LibraryFilterCopyWith get copyWith => _$LibraryFilterCopyWithImpl(this as LibraryFilter, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LibraryFilter&&(identical(other.field, field) || other.field == field)&&(identical(other.op, op) || other.op == op)&&const DeepCollectionEquality().equals(other.values, values)); +} + + +@override +int get hashCode => Object.hash(runtimeType,field,op,const DeepCollectionEquality().hash(values)); + +@override +String toString() { + return 'LibraryFilter(field: $field, op: $op, values: $values)'; +} + + +} + +/// @nodoc +abstract mixin class $LibraryFilterCopyWith<$Res> { + factory $LibraryFilterCopyWith(LibraryFilter value, $Res Function(LibraryFilter) _then) = _$LibraryFilterCopyWithImpl; +@useResult +$Res call({ + String field, String op, List values +}); + + + + +} +/// @nodoc +class _$LibraryFilterCopyWithImpl<$Res> + implements $LibraryFilterCopyWith<$Res> { + _$LibraryFilterCopyWithImpl(this._self, this._then); + + final LibraryFilter _self; + final $Res Function(LibraryFilter) _then; + +/// Create a copy of LibraryFilter +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? field = null,Object? op = null,Object? values = null,}) { + return _then(_self.copyWith( +field: null == field ? _self.field : field // ignore: cast_nullable_to_non_nullable +as String,op: null == op ? _self.op : op // ignore: cast_nullable_to_non_nullable +as String,values: null == values ? _self.values : values // ignore: cast_nullable_to_non_nullable +as List, + )); +} + +} + + +/// Adds pattern-matching-related methods to [LibraryFilter]. +extension LibraryFilterPatterns on LibraryFilter { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LibraryFilter value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LibraryFilter() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LibraryFilter value) $default,){ +final _that = this; +switch (_that) { +case _LibraryFilter(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LibraryFilter value)? $default,){ +final _that = this; +switch (_that) { +case _LibraryFilter() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String field, String op, List values)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LibraryFilter() when $default != null: +return $default(_that.field,_that.op,_that.values);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String field, String op, List values) $default,) {final _that = this; +switch (_that) { +case _LibraryFilter(): +return $default(_that.field,_that.op,_that.values);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String field, String op, List values)? $default,) {final _that = this; +switch (_that) { +case _LibraryFilter() when $default != null: +return $default(_that.field,_that.op,_that.values);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _LibraryFilter implements LibraryFilter { + const _LibraryFilter({required this.field, this.op = '=', required final List values}): _values = values; + + +@override final String field; +@override@JsonKey() final String op; + final List _values; +@override List get values { + if (_values is EqualUnmodifiableListView) return _values; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_values); +} + + +/// Create a copy of LibraryFilter +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LibraryFilterCopyWith<_LibraryFilter> get copyWith => __$LibraryFilterCopyWithImpl<_LibraryFilter>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LibraryFilter&&(identical(other.field, field) || other.field == field)&&(identical(other.op, op) || other.op == op)&&const DeepCollectionEquality().equals(other._values, _values)); +} + + +@override +int get hashCode => Object.hash(runtimeType,field,op,const DeepCollectionEquality().hash(_values)); + +@override +String toString() { + return 'LibraryFilter(field: $field, op: $op, values: $values)'; +} + + +} + +/// @nodoc +abstract mixin class _$LibraryFilterCopyWith<$Res> implements $LibraryFilterCopyWith<$Res> { + factory _$LibraryFilterCopyWith(_LibraryFilter value, $Res Function(_LibraryFilter) _then) = __$LibraryFilterCopyWithImpl; +@override @useResult +$Res call({ + String field, String op, List values +}); + + + + +} +/// @nodoc +class __$LibraryFilterCopyWithImpl<$Res> + implements _$LibraryFilterCopyWith<$Res> { + __$LibraryFilterCopyWithImpl(this._self, this._then); + + final _LibraryFilter _self; + final $Res Function(_LibraryFilter) _then; + +/// Create a copy of LibraryFilter +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? field = null,Object? op = null,Object? values = null,}) { + return _then(_LibraryFilter( +field: null == field ? _self.field : field // ignore: cast_nullable_to_non_nullable +as String,op: null == op ? _self.op : op // ignore: cast_nullable_to_non_nullable +as String,values: null == values ? _self._values : values // ignore: cast_nullable_to_non_nullable +as List, + )); +} + + +} + +/// @nodoc +mixin _$LibraryQuery { + +/// Restrict to a single kind (e.g. `MediaKind.movie`). Null = library default. + MediaKind? get kind;/// Pagination — zero-based offset. + int get offset; int get limit; LibrarySort? get sort; List get filters;/// Free-text search restricted to this library. Distinct from the global +/// search endpoint. + String? get search;/// Whether to include items the active user has already watched. + bool get includeWatched;/// Restrict the result to items whose sort name starts with this string — +/// the alpha-jump bar's filter UX. The literal `#` is a sentinel for +/// "non-alphabetic" and translates to a `NameLessThan=A` query for backends +/// that support it. + String? get nameStartsWith;/// Genre filter — used by the per-library filter sheet. Backends that +/// take multiple values (Jellyfin) AND/intersect; those that take one +/// (Plex's existing flow) consult `filters` instead. + List? get genres; List? get officialRatings; List? get years; List? get tags; +/// Create a copy of LibraryQuery +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LibraryQueryCopyWith get copyWith => _$LibraryQueryCopyWithImpl(this as LibraryQuery, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LibraryQuery&&(identical(other.kind, kind) || other.kind == kind)&&(identical(other.offset, offset) || other.offset == offset)&&(identical(other.limit, limit) || other.limit == limit)&&(identical(other.sort, sort) || other.sort == sort)&&const DeepCollectionEquality().equals(other.filters, filters)&&(identical(other.search, search) || other.search == search)&&(identical(other.includeWatched, includeWatched) || other.includeWatched == includeWatched)&&(identical(other.nameStartsWith, nameStartsWith) || other.nameStartsWith == nameStartsWith)&&const DeepCollectionEquality().equals(other.genres, genres)&&const DeepCollectionEquality().equals(other.officialRatings, officialRatings)&&const DeepCollectionEquality().equals(other.years, years)&&const DeepCollectionEquality().equals(other.tags, tags)); +} + + +@override +int get hashCode => Object.hash(runtimeType,kind,offset,limit,sort,const DeepCollectionEquality().hash(filters),search,includeWatched,nameStartsWith,const DeepCollectionEquality().hash(genres),const DeepCollectionEquality().hash(officialRatings),const DeepCollectionEquality().hash(years),const DeepCollectionEquality().hash(tags)); + +@override +String toString() { + return 'LibraryQuery(kind: $kind, offset: $offset, limit: $limit, sort: $sort, filters: $filters, search: $search, includeWatched: $includeWatched, nameStartsWith: $nameStartsWith, genres: $genres, officialRatings: $officialRatings, years: $years, tags: $tags)'; +} + + +} + +/// @nodoc +abstract mixin class $LibraryQueryCopyWith<$Res> { + factory $LibraryQueryCopyWith(LibraryQuery value, $Res Function(LibraryQuery) _then) = _$LibraryQueryCopyWithImpl; +@useResult +$Res call({ + MediaKind? kind, int offset, int limit, LibrarySort? sort, List filters, String? search, bool includeWatched, String? nameStartsWith, List? genres, List? officialRatings, List? years, List? tags +}); + + +$LibrarySortCopyWith<$Res>? get sort; + +} +/// @nodoc +class _$LibraryQueryCopyWithImpl<$Res> + implements $LibraryQueryCopyWith<$Res> { + _$LibraryQueryCopyWithImpl(this._self, this._then); + + final LibraryQuery _self; + final $Res Function(LibraryQuery) _then; + +/// Create a copy of LibraryQuery +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? kind = freezed,Object? offset = null,Object? limit = null,Object? sort = freezed,Object? filters = null,Object? search = freezed,Object? includeWatched = null,Object? nameStartsWith = freezed,Object? genres = freezed,Object? officialRatings = freezed,Object? years = freezed,Object? tags = freezed,}) { + return _then(_self.copyWith( +kind: freezed == kind ? _self.kind : kind // ignore: cast_nullable_to_non_nullable +as MediaKind?,offset: null == offset ? _self.offset : offset // ignore: cast_nullable_to_non_nullable +as int,limit: null == limit ? _self.limit : limit // ignore: cast_nullable_to_non_nullable +as int,sort: freezed == sort ? _self.sort : sort // ignore: cast_nullable_to_non_nullable +as LibrarySort?,filters: null == filters ? _self.filters : filters // ignore: cast_nullable_to_non_nullable +as List,search: freezed == search ? _self.search : search // ignore: cast_nullable_to_non_nullable +as String?,includeWatched: null == includeWatched ? _self.includeWatched : includeWatched // ignore: cast_nullable_to_non_nullable +as bool,nameStartsWith: freezed == nameStartsWith ? _self.nameStartsWith : nameStartsWith // ignore: cast_nullable_to_non_nullable +as String?,genres: freezed == genres ? _self.genres : genres // ignore: cast_nullable_to_non_nullable +as List?,officialRatings: freezed == officialRatings ? _self.officialRatings : officialRatings // ignore: cast_nullable_to_non_nullable +as List?,years: freezed == years ? _self.years : years // ignore: cast_nullable_to_non_nullable +as List?,tags: freezed == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable +as List?, + )); +} +/// Create a copy of LibraryQuery +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$LibrarySortCopyWith<$Res>? get sort { + if (_self.sort == null) { + return null; + } + + return $LibrarySortCopyWith<$Res>(_self.sort!, (value) { + return _then(_self.copyWith(sort: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [LibraryQuery]. +extension LibraryQueryPatterns on LibraryQuery { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LibraryQuery value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LibraryQuery() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LibraryQuery value) $default,){ +final _that = this; +switch (_that) { +case _LibraryQuery(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LibraryQuery value)? $default,){ +final _that = this; +switch (_that) { +case _LibraryQuery() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( MediaKind? kind, int offset, int limit, LibrarySort? sort, List filters, String? search, bool includeWatched, String? nameStartsWith, List? genres, List? officialRatings, List? years, List? tags)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LibraryQuery() when $default != null: +return $default(_that.kind,_that.offset,_that.limit,_that.sort,_that.filters,_that.search,_that.includeWatched,_that.nameStartsWith,_that.genres,_that.officialRatings,_that.years,_that.tags);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( MediaKind? kind, int offset, int limit, LibrarySort? sort, List filters, String? search, bool includeWatched, String? nameStartsWith, List? genres, List? officialRatings, List? years, List? tags) $default,) {final _that = this; +switch (_that) { +case _LibraryQuery(): +return $default(_that.kind,_that.offset,_that.limit,_that.sort,_that.filters,_that.search,_that.includeWatched,_that.nameStartsWith,_that.genres,_that.officialRatings,_that.years,_that.tags);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( MediaKind? kind, int offset, int limit, LibrarySort? sort, List filters, String? search, bool includeWatched, String? nameStartsWith, List? genres, List? officialRatings, List? years, List? tags)? $default,) {final _that = this; +switch (_that) { +case _LibraryQuery() when $default != null: +return $default(_that.kind,_that.offset,_that.limit,_that.sort,_that.filters,_that.search,_that.includeWatched,_that.nameStartsWith,_that.genres,_that.officialRatings,_that.years,_that.tags);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _LibraryQuery implements LibraryQuery { + const _LibraryQuery({this.kind, this.offset = 0, this.limit = 50, this.sort, final List filters = const [], this.search, this.includeWatched = true, this.nameStartsWith, final List? genres, final List? officialRatings, final List? years, final List? tags}): _filters = filters,_genres = genres,_officialRatings = officialRatings,_years = years,_tags = tags; + + +/// Restrict to a single kind (e.g. `MediaKind.movie`). Null = library default. +@override final MediaKind? kind; +/// Pagination — zero-based offset. +@override@JsonKey() final int offset; +@override@JsonKey() final int limit; +@override final LibrarySort? sort; + final List _filters; +@override@JsonKey() List get filters { + if (_filters is EqualUnmodifiableListView) return _filters; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_filters); +} + +/// Free-text search restricted to this library. Distinct from the global +/// search endpoint. +@override final String? search; +/// Whether to include items the active user has already watched. +@override@JsonKey() final bool includeWatched; +/// Restrict the result to items whose sort name starts with this string — +/// the alpha-jump bar's filter UX. The literal `#` is a sentinel for +/// "non-alphabetic" and translates to a `NameLessThan=A` query for backends +/// that support it. +@override final String? nameStartsWith; +/// Genre filter — used by the per-library filter sheet. Backends that +/// take multiple values (Jellyfin) AND/intersect; those that take one +/// (Plex's existing flow) consult `filters` instead. + final List? _genres; +/// Genre filter — used by the per-library filter sheet. Backends that +/// take multiple values (Jellyfin) AND/intersect; those that take one +/// (Plex's existing flow) consult `filters` instead. +@override List? get genres { + final value = _genres; + if (value == null) return null; + if (_genres is EqualUnmodifiableListView) return _genres; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + final List? _officialRatings; +@override List? get officialRatings { + final value = _officialRatings; + if (value == null) return null; + if (_officialRatings is EqualUnmodifiableListView) return _officialRatings; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + final List? _years; +@override List? get years { + final value = _years; + if (value == null) return null; + if (_years is EqualUnmodifiableListView) return _years; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + final List? _tags; +@override List? get tags { + final value = _tags; + if (value == null) return null; + if (_tags is EqualUnmodifiableListView) return _tags; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + +/// Create a copy of LibraryQuery +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LibraryQueryCopyWith<_LibraryQuery> get copyWith => __$LibraryQueryCopyWithImpl<_LibraryQuery>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LibraryQuery&&(identical(other.kind, kind) || other.kind == kind)&&(identical(other.offset, offset) || other.offset == offset)&&(identical(other.limit, limit) || other.limit == limit)&&(identical(other.sort, sort) || other.sort == sort)&&const DeepCollectionEquality().equals(other._filters, _filters)&&(identical(other.search, search) || other.search == search)&&(identical(other.includeWatched, includeWatched) || other.includeWatched == includeWatched)&&(identical(other.nameStartsWith, nameStartsWith) || other.nameStartsWith == nameStartsWith)&&const DeepCollectionEquality().equals(other._genres, _genres)&&const DeepCollectionEquality().equals(other._officialRatings, _officialRatings)&&const DeepCollectionEquality().equals(other._years, _years)&&const DeepCollectionEquality().equals(other._tags, _tags)); +} + + +@override +int get hashCode => Object.hash(runtimeType,kind,offset,limit,sort,const DeepCollectionEquality().hash(_filters),search,includeWatched,nameStartsWith,const DeepCollectionEquality().hash(_genres),const DeepCollectionEquality().hash(_officialRatings),const DeepCollectionEquality().hash(_years),const DeepCollectionEquality().hash(_tags)); + +@override +String toString() { + return 'LibraryQuery(kind: $kind, offset: $offset, limit: $limit, sort: $sort, filters: $filters, search: $search, includeWatched: $includeWatched, nameStartsWith: $nameStartsWith, genres: $genres, officialRatings: $officialRatings, years: $years, tags: $tags)'; +} + + +} + +/// @nodoc +abstract mixin class _$LibraryQueryCopyWith<$Res> implements $LibraryQueryCopyWith<$Res> { + factory _$LibraryQueryCopyWith(_LibraryQuery value, $Res Function(_LibraryQuery) _then) = __$LibraryQueryCopyWithImpl; +@override @useResult +$Res call({ + MediaKind? kind, int offset, int limit, LibrarySort? sort, List filters, String? search, bool includeWatched, String? nameStartsWith, List? genres, List? officialRatings, List? years, List? tags +}); + + +@override $LibrarySortCopyWith<$Res>? get sort; + +} +/// @nodoc +class __$LibraryQueryCopyWithImpl<$Res> + implements _$LibraryQueryCopyWith<$Res> { + __$LibraryQueryCopyWithImpl(this._self, this._then); + + final _LibraryQuery _self; + final $Res Function(_LibraryQuery) _then; + +/// Create a copy of LibraryQuery +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? kind = freezed,Object? offset = null,Object? limit = null,Object? sort = freezed,Object? filters = null,Object? search = freezed,Object? includeWatched = null,Object? nameStartsWith = freezed,Object? genres = freezed,Object? officialRatings = freezed,Object? years = freezed,Object? tags = freezed,}) { + return _then(_LibraryQuery( +kind: freezed == kind ? _self.kind : kind // ignore: cast_nullable_to_non_nullable +as MediaKind?,offset: null == offset ? _self.offset : offset // ignore: cast_nullable_to_non_nullable +as int,limit: null == limit ? _self.limit : limit // ignore: cast_nullable_to_non_nullable +as int,sort: freezed == sort ? _self.sort : sort // ignore: cast_nullable_to_non_nullable +as LibrarySort?,filters: null == filters ? _self._filters : filters // ignore: cast_nullable_to_non_nullable +as List,search: freezed == search ? _self.search : search // ignore: cast_nullable_to_non_nullable +as String?,includeWatched: null == includeWatched ? _self.includeWatched : includeWatched // ignore: cast_nullable_to_non_nullable +as bool,nameStartsWith: freezed == nameStartsWith ? _self.nameStartsWith : nameStartsWith // ignore: cast_nullable_to_non_nullable +as String?,genres: freezed == genres ? _self._genres : genres // ignore: cast_nullable_to_non_nullable +as List?,officialRatings: freezed == officialRatings ? _self._officialRatings : officialRatings // ignore: cast_nullable_to_non_nullable +as List?,years: freezed == years ? _self._years : years // ignore: cast_nullable_to_non_nullable +as List?,tags: freezed == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable +as List?, + )); +} + +/// Create a copy of LibraryQuery +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$LibrarySortCopyWith<$Res>? get sort { + if (_self.sort == null) { + return null; + } + + return $LibrarySortCopyWith<$Res>(_self.sort!, (value) { + return _then(_self.copyWith(sort: value)); + }); +} +} + +/// @nodoc +mixin _$LibraryPage { + + List get items; int get totalCount; int get offset; +/// Create a copy of LibraryPage +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LibraryPageCopyWith> get copyWith => _$LibraryPageCopyWithImpl>(this as LibraryPage, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LibraryPage&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.totalCount, totalCount) || other.totalCount == totalCount)&&(identical(other.offset, offset) || other.offset == offset)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(items),totalCount,offset); + +@override +String toString() { + return 'LibraryPage<$T>(items: $items, totalCount: $totalCount, offset: $offset)'; +} + + +} + +/// @nodoc +abstract mixin class $LibraryPageCopyWith { + factory $LibraryPageCopyWith(LibraryPage value, $Res Function(LibraryPage) _then) = _$LibraryPageCopyWithImpl; +@useResult +$Res call({ + List items, int totalCount, int offset +}); + + + + +} +/// @nodoc +class _$LibraryPageCopyWithImpl + implements $LibraryPageCopyWith { + _$LibraryPageCopyWithImpl(this._self, this._then); + + final LibraryPage _self; + final $Res Function(LibraryPage) _then; + +/// Create a copy of LibraryPage +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? items = null,Object? totalCount = null,Object? offset = null,}) { + return _then(_self.copyWith( +items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable +as List,totalCount: null == totalCount ? _self.totalCount : totalCount // ignore: cast_nullable_to_non_nullable +as int,offset: null == offset ? _self.offset : offset // ignore: cast_nullable_to_non_nullable +as int, + )); +} + +} + + +/// Adds pattern-matching-related methods to [LibraryPage]. +extension LibraryPagePatterns on LibraryPage { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LibraryPage value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LibraryPage() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LibraryPage value) $default,){ +final _that = this; +switch (_that) { +case _LibraryPage(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LibraryPage value)? $default,){ +final _that = this; +switch (_that) { +case _LibraryPage() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( List items, int totalCount, int offset)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LibraryPage() when $default != null: +return $default(_that.items,_that.totalCount,_that.offset);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( List items, int totalCount, int offset) $default,) {final _that = this; +switch (_that) { +case _LibraryPage(): +return $default(_that.items,_that.totalCount,_that.offset);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( List items, int totalCount, int offset)? $default,) {final _that = this; +switch (_that) { +case _LibraryPage() when $default != null: +return $default(_that.items,_that.totalCount,_that.offset);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _LibraryPage implements LibraryPage { + const _LibraryPage({required final List items, required this.totalCount, this.offset = 0}): _items = items; + + + final List _items; +@override List get items { + if (_items is EqualUnmodifiableListView) return _items; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_items); +} + +@override final int totalCount; +@override@JsonKey() final int offset; + +/// Create a copy of LibraryPage +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LibraryPageCopyWith> get copyWith => __$LibraryPageCopyWithImpl>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LibraryPage&&const DeepCollectionEquality().equals(other._items, _items)&&(identical(other.totalCount, totalCount) || other.totalCount == totalCount)&&(identical(other.offset, offset) || other.offset == offset)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_items),totalCount,offset); + +@override +String toString() { + return 'LibraryPage<$T>(items: $items, totalCount: $totalCount, offset: $offset)'; +} + + +} + +/// @nodoc +abstract mixin class _$LibraryPageCopyWith implements $LibraryPageCopyWith { + factory _$LibraryPageCopyWith(_LibraryPage value, $Res Function(_LibraryPage) _then) = __$LibraryPageCopyWithImpl; +@override @useResult +$Res call({ + List items, int totalCount, int offset +}); + + + + +} +/// @nodoc +class __$LibraryPageCopyWithImpl + implements _$LibraryPageCopyWith { + __$LibraryPageCopyWithImpl(this._self, this._then); + + final _LibraryPage _self; + final $Res Function(_LibraryPage) _then; + +/// Create a copy of LibraryPage +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? items = null,Object? totalCount = null,Object? offset = null,}) { + return _then(_LibraryPage( +items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable +as List,totalCount: null == totalCount ? _self.totalCount : totalCount // ignore: cast_nullable_to_non_nullable +as int,offset: null == offset ? _self.offset : offset // ignore: cast_nullable_to_non_nullable +as int, + )); +} + + +} + +// dart format on diff --git a/lib/media/media_sort.dart b/lib/media/media_sort.dart index 168c9d8c..4025317b 100644 --- a/lib/media/media_sort.dart +++ b/lib/media/media_sort.dart @@ -1,20 +1,17 @@ -import 'package:json_annotation/json_annotation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'media_sort.freezed.dart'; part 'media_sort.g.dart'; -@JsonSerializable() -class MediaSort { - final String key; - final String? descKey; - final String title; - final String? defaultDirection; +@freezed +sealed class MediaSort with _$MediaSort { + const MediaSort._(); - MediaSort({required this.key, this.descKey, required this.title, this.defaultDirection}); + const factory MediaSort({required String key, String? descKey, required String title, String? defaultDirection}) = + _MediaSort; factory MediaSort.fromJson(Map json) => _$MediaSortFromJson(json); - Map toJson() => _$MediaSortToJson(this); - String getSortKey({bool descending = false}) { if (!descending) { return key; @@ -26,18 +23,4 @@ class MediaSort { bool get isDefaultDescending { return defaultDirection?.toLowerCase() == 'desc'; } - - @override - String toString() { - return 'MediaSort(key: $key, title: $title, defaultDirection: $defaultDirection)'; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is MediaSort && other.key == key; - } - - @override - int get hashCode => key.hashCode; } diff --git a/lib/media/media_sort.freezed.dart b/lib/media/media_sort.freezed.dart new file mode 100644 index 00000000..aa585214 --- /dev/null +++ b/lib/media/media_sort.freezed.dart @@ -0,0 +1,280 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'media_sort.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$MediaSort { + + String get key; String? get descKey; String get title; String? get defaultDirection; +/// Create a copy of MediaSort +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$MediaSortCopyWith get copyWith => _$MediaSortCopyWithImpl(this as MediaSort, _$identity); + + /// Serializes this MediaSort to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is MediaSort&&(identical(other.key, key) || other.key == key)&&(identical(other.descKey, descKey) || other.descKey == descKey)&&(identical(other.title, title) || other.title == title)&&(identical(other.defaultDirection, defaultDirection) || other.defaultDirection == defaultDirection)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,key,descKey,title,defaultDirection); + +@override +String toString() { + return 'MediaSort(key: $key, descKey: $descKey, title: $title, defaultDirection: $defaultDirection)'; +} + + +} + +/// @nodoc +abstract mixin class $MediaSortCopyWith<$Res> { + factory $MediaSortCopyWith(MediaSort value, $Res Function(MediaSort) _then) = _$MediaSortCopyWithImpl; +@useResult +$Res call({ + String key, String? descKey, String title, String? defaultDirection +}); + + + + +} +/// @nodoc +class _$MediaSortCopyWithImpl<$Res> + implements $MediaSortCopyWith<$Res> { + _$MediaSortCopyWithImpl(this._self, this._then); + + final MediaSort _self; + final $Res Function(MediaSort) _then; + +/// Create a copy of MediaSort +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? key = null,Object? descKey = freezed,Object? title = null,Object? defaultDirection = freezed,}) { + return _then(_self.copyWith( +key: null == key ? _self.key : key // ignore: cast_nullable_to_non_nullable +as String,descKey: freezed == descKey ? _self.descKey : descKey // ignore: cast_nullable_to_non_nullable +as String?,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable +as String,defaultDirection: freezed == defaultDirection ? _self.defaultDirection : defaultDirection // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [MediaSort]. +extension MediaSortPatterns on MediaSort { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _MediaSort value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _MediaSort() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _MediaSort value) $default,){ +final _that = this; +switch (_that) { +case _MediaSort(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _MediaSort value)? $default,){ +final _that = this; +switch (_that) { +case _MediaSort() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String key, String? descKey, String title, String? defaultDirection)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _MediaSort() when $default != null: +return $default(_that.key,_that.descKey,_that.title,_that.defaultDirection);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String key, String? descKey, String title, String? defaultDirection) $default,) {final _that = this; +switch (_that) { +case _MediaSort(): +return $default(_that.key,_that.descKey,_that.title,_that.defaultDirection);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String key, String? descKey, String title, String? defaultDirection)? $default,) {final _that = this; +switch (_that) { +case _MediaSort() when $default != null: +return $default(_that.key,_that.descKey,_that.title,_that.defaultDirection);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _MediaSort extends MediaSort { + const _MediaSort({required this.key, this.descKey, required this.title, this.defaultDirection}): super._(); + factory _MediaSort.fromJson(Map json) => _$MediaSortFromJson(json); + +@override final String key; +@override final String? descKey; +@override final String title; +@override final String? defaultDirection; + +/// Create a copy of MediaSort +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$MediaSortCopyWith<_MediaSort> get copyWith => __$MediaSortCopyWithImpl<_MediaSort>(this, _$identity); + +@override +Map toJson() { + return _$MediaSortToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _MediaSort&&(identical(other.key, key) || other.key == key)&&(identical(other.descKey, descKey) || other.descKey == descKey)&&(identical(other.title, title) || other.title == title)&&(identical(other.defaultDirection, defaultDirection) || other.defaultDirection == defaultDirection)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,key,descKey,title,defaultDirection); + +@override +String toString() { + return 'MediaSort(key: $key, descKey: $descKey, title: $title, defaultDirection: $defaultDirection)'; +} + + +} + +/// @nodoc +abstract mixin class _$MediaSortCopyWith<$Res> implements $MediaSortCopyWith<$Res> { + factory _$MediaSortCopyWith(_MediaSort value, $Res Function(_MediaSort) _then) = __$MediaSortCopyWithImpl; +@override @useResult +$Res call({ + String key, String? descKey, String title, String? defaultDirection +}); + + + + +} +/// @nodoc +class __$MediaSortCopyWithImpl<$Res> + implements _$MediaSortCopyWith<$Res> { + __$MediaSortCopyWithImpl(this._self, this._then); + + final _MediaSort _self; + final $Res Function(_MediaSort) _then; + +/// Create a copy of MediaSort +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? key = null,Object? descKey = freezed,Object? title = null,Object? defaultDirection = freezed,}) { + return _then(_MediaSort( +key: null == key ? _self.key : key // ignore: cast_nullable_to_non_nullable +as String,descKey: freezed == descKey ? _self.descKey : descKey // ignore: cast_nullable_to_non_nullable +as String?,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable +as String,defaultDirection: freezed == defaultDirection ? _self.defaultDirection : defaultDirection // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/lib/media/media_sort.g.dart b/lib/media/media_sort.g.dart index 0e127209..d207c1df 100644 --- a/lib/media/media_sort.g.dart +++ b/lib/media/media_sort.g.dart @@ -6,16 +6,17 @@ part of 'media_sort.dart'; // JsonSerializableGenerator // ************************************************************************** -MediaSort _$MediaSortFromJson(Map json) => MediaSort( +_MediaSort _$MediaSortFromJson(Map json) => _MediaSort( key: json['key'] as String, descKey: json['descKey'] as String?, title: json['title'] as String, defaultDirection: json['defaultDirection'] as String?, ); -Map _$MediaSortToJson(MediaSort instance) => { - 'key': instance.key, - 'descKey': instance.descKey, - 'title': instance.title, - 'defaultDirection': instance.defaultDirection, -}; +Map _$MediaSortToJson(_MediaSort instance) => + { + 'key': instance.key, + 'descKey': instance.descKey, + 'title': instance.title, + 'defaultDirection': instance.defaultDirection, + }; diff --git a/lib/media/play_queue.dart b/lib/media/play_queue.dart index 97698352..f6dd71a1 100644 --- a/lib/media/play_queue.dart +++ b/lib/media/play_queue.dart @@ -1,122 +1,61 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + import 'media_item.dart'; +part 'play_queue.freezed.dart'; + /// Backend-neutral play queue — a flat ordered list of items with a current /// cursor. Implementations differ in whether the queue is server-resourced /// (Plex) or client-only (Jellyfin). -sealed class PlayQueue { - /// Items in playback order. - List get items; +@freezed +sealed class PlayQueue with _$PlayQueue { + const PlayQueue._(); - /// Index of the currently-playing item, or `null` if the queue has not - /// started. - int? get currentIndex; - - /// Whether the queue has been shuffled. - bool get shuffled; - - /// Backend that minted this queue. - String get backendId; - - MediaItem? get current => - currentIndex != null && currentIndex! >= 0 && currentIndex! < items.length ? items[currentIndex!] : null; - - bool get hasNext => currentIndex != null && currentIndex! + 1 < items.length; - bool get hasPrevious => currentIndex != null && currentIndex! > 0; -} - -/// Plex play queue — coordinated server-side via `/playQueues` so multiple -/// devices can view/control the same queue. -class PlexServerPlayQueue extends PlayQueue { - /// Plex `playQueueID` — addresses the queue for subsequent fetches. - final int playQueueId; - - @override - final List items; - - @override - final int? currentIndex; - - @override - final bool shuffled; - - /// Plex `playQueueSelectedItemID` of the active item. - final int? selectedItemId; - - /// Plex `playQueueVersion` — server-side optimistic concurrency token. - final int? version; - - /// Plex `playQueueSourceURI` — used for "Up Next" derivation. - final String? sourceUri; - - PlexServerPlayQueue({ - required this.playQueueId, - required this.items, - this.currentIndex, - this.shuffled = false, - this.selectedItemId, - this.version, - this.sourceUri, - }); - - @override - String get backendId => 'plex'; - - PlexServerPlayQueue copyWith({ - int? playQueueId, - List? items, + /// Plex play queue — coordinated server-side via `/playQueues` so multiple + /// devices can view/control the same queue. + const factory PlayQueue.plex({ + /// Plex `playQueueID` — addresses the queue for subsequent fetches. + required int playQueueId, + required List items, int? currentIndex, - bool? shuffled, + @Default(false) bool shuffled, + + /// Plex `playQueueSelectedItemID` of the active item. int? selectedItemId, + + /// Plex `playQueueVersion` — server-side optimistic concurrency token. int? version, + + /// Plex `playQueueSourceURI` — used for "Up Next" derivation. String? sourceUri, - }) { - return PlexServerPlayQueue( - playQueueId: playQueueId ?? this.playQueueId, - items: items ?? this.items, - currentIndex: currentIndex ?? this.currentIndex, - shuffled: shuffled ?? this.shuffled, - selectedItemId: selectedItemId ?? this.selectedItemId, - version: version ?? this.version, - sourceUri: sourceUri ?? this.sourceUri, - ); - } -} + }) = PlexServerPlayQueue; -/// Client-only play queue used by Jellyfin and any backend without a -/// server-side queue concept. Each [LocalPlayQueue] is anchored by a -/// client-generated UUID so callers can address it like a Plex queue. -class LocalPlayQueue extends PlayQueue { - /// Client-generated UUID identifying this queue for the session. - final String id; + /// Client-only play queue used by Jellyfin and any backend without a + /// server-side queue concept. Each [LocalPlayQueue] is anchored by a + /// client-generated UUID so callers can address it like a Plex queue. + const factory PlayQueue.local({ + /// Client-generated UUID identifying this queue for the session. + required String id, + required List items, - @override - final List items; + /// Server kind that owns this queue's items (typically `"jellyfin"`). + required String backendId, + int? currentIndex, + @Default(false) bool shuffled, + }) = LocalPlayQueue; - @override - final int? currentIndex; + MediaItem? get current => switch (this) { + PlexServerPlayQueue(:final items, :final currentIndex) || LocalPlayQueue(:final items, :final currentIndex) => + currentIndex != null && currentIndex >= 0 && currentIndex < items.length ? items[currentIndex] : null, + }; - @override - final bool shuffled; + bool get hasNext => switch (this) { + PlexServerPlayQueue(:final items, :final currentIndex) || + LocalPlayQueue(:final items, :final currentIndex) => currentIndex != null && currentIndex + 1 < items.length, + }; - /// Server kind that owns this queue's items (typically `"jellyfin"`). - @override - final String backendId; - - LocalPlayQueue({ - required this.id, - required this.items, - required this.backendId, - this.currentIndex, - this.shuffled = false, - }); - - LocalPlayQueue copyWith({String? id, List? items, int? currentIndex, bool? shuffled, String? backendId}) { - return LocalPlayQueue( - id: id ?? this.id, - items: items ?? this.items, - currentIndex: currentIndex ?? this.currentIndex, - shuffled: shuffled ?? this.shuffled, - backendId: backendId ?? this.backendId, - ); - } + bool get hasPrevious => switch (this) { + PlexServerPlayQueue(:final currentIndex) || + LocalPlayQueue(:final currentIndex) => currentIndex != null && currentIndex > 0, + }; } diff --git a/lib/media/play_queue.freezed.dart b/lib/media/play_queue.freezed.dart new file mode 100644 index 00000000..3c969669 --- /dev/null +++ b/lib/media/play_queue.freezed.dart @@ -0,0 +1,377 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'play_queue.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$PlayQueue { + + List get items; int? get currentIndex; bool get shuffled; +/// Create a copy of PlayQueue +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$PlayQueueCopyWith get copyWith => _$PlayQueueCopyWithImpl(this as PlayQueue, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is PlayQueue&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&(identical(other.shuffled, shuffled) || other.shuffled == shuffled)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(items),currentIndex,shuffled); + +@override +String toString() { + return 'PlayQueue(items: $items, currentIndex: $currentIndex, shuffled: $shuffled)'; +} + + +} + +/// @nodoc +abstract mixin class $PlayQueueCopyWith<$Res> { + factory $PlayQueueCopyWith(PlayQueue value, $Res Function(PlayQueue) _then) = _$PlayQueueCopyWithImpl; +@useResult +$Res call({ + List items, int? currentIndex, bool shuffled +}); + + + + +} +/// @nodoc +class _$PlayQueueCopyWithImpl<$Res> + implements $PlayQueueCopyWith<$Res> { + _$PlayQueueCopyWithImpl(this._self, this._then); + + final PlayQueue _self; + final $Res Function(PlayQueue) _then; + +/// Create a copy of PlayQueue +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? items = null,Object? currentIndex = freezed,Object? shuffled = null,}) { + return _then(_self.copyWith( +items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable +as List,currentIndex: freezed == currentIndex ? _self.currentIndex : currentIndex // ignore: cast_nullable_to_non_nullable +as int?,shuffled: null == shuffled ? _self.shuffled : shuffled // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + +} + + +/// Adds pattern-matching-related methods to [PlayQueue]. +extension PlayQueuePatterns on PlayQueue { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap({TResult Function( PlexServerPlayQueue value)? plex,TResult Function( LocalPlayQueue value)? local,required TResult orElse(),}){ +final _that = this; +switch (_that) { +case PlexServerPlayQueue() when plex != null: +return plex(_that);case LocalPlayQueue() when local != null: +return local(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map({required TResult Function( PlexServerPlayQueue value) plex,required TResult Function( LocalPlayQueue value) local,}){ +final _that = this; +switch (_that) { +case PlexServerPlayQueue(): +return plex(_that);case LocalPlayQueue(): +return local(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull({TResult? Function( PlexServerPlayQueue value)? plex,TResult? Function( LocalPlayQueue value)? local,}){ +final _that = this; +switch (_that) { +case PlexServerPlayQueue() when plex != null: +return plex(_that);case LocalPlayQueue() when local != null: +return local(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen({TResult Function( int playQueueId, List items, int? currentIndex, bool shuffled, int? selectedItemId, int? version, String? sourceUri)? plex,TResult Function( String id, List items, String backendId, int? currentIndex, bool shuffled)? local,required TResult orElse(),}) {final _that = this; +switch (_that) { +case PlexServerPlayQueue() when plex != null: +return plex(_that.playQueueId,_that.items,_that.currentIndex,_that.shuffled,_that.selectedItemId,_that.version,_that.sourceUri);case LocalPlayQueue() when local != null: +return local(_that.id,_that.items,_that.backendId,_that.currentIndex,_that.shuffled);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when({required TResult Function( int playQueueId, List items, int? currentIndex, bool shuffled, int? selectedItemId, int? version, String? sourceUri) plex,required TResult Function( String id, List items, String backendId, int? currentIndex, bool shuffled) local,}) {final _that = this; +switch (_that) { +case PlexServerPlayQueue(): +return plex(_that.playQueueId,_that.items,_that.currentIndex,_that.shuffled,_that.selectedItemId,_that.version,_that.sourceUri);case LocalPlayQueue(): +return local(_that.id,_that.items,_that.backendId,_that.currentIndex,_that.shuffled);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull({TResult? Function( int playQueueId, List items, int? currentIndex, bool shuffled, int? selectedItemId, int? version, String? sourceUri)? plex,TResult? Function( String id, List items, String backendId, int? currentIndex, bool shuffled)? local,}) {final _that = this; +switch (_that) { +case PlexServerPlayQueue() when plex != null: +return plex(_that.playQueueId,_that.items,_that.currentIndex,_that.shuffled,_that.selectedItemId,_that.version,_that.sourceUri);case LocalPlayQueue() when local != null: +return local(_that.id,_that.items,_that.backendId,_that.currentIndex,_that.shuffled);case _: + return null; + +} +} + +} + +/// @nodoc + + +class PlexServerPlayQueue extends PlayQueue { + const PlexServerPlayQueue({required this.playQueueId, required final List items, this.currentIndex, this.shuffled = false, this.selectedItemId, this.version, this.sourceUri}): _items = items,super._(); + + +/// Plex `playQueueID` — addresses the queue for subsequent fetches. + final int playQueueId; + final List _items; +@override List get items { + if (_items is EqualUnmodifiableListView) return _items; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_items); +} + +@override final int? currentIndex; +@override@JsonKey() final bool shuffled; +/// Plex `playQueueSelectedItemID` of the active item. + final int? selectedItemId; +/// Plex `playQueueVersion` — server-side optimistic concurrency token. + final int? version; +/// Plex `playQueueSourceURI` — used for "Up Next" derivation. + final String? sourceUri; + +/// Create a copy of PlayQueue +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$PlexServerPlayQueueCopyWith get copyWith => _$PlexServerPlayQueueCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is PlexServerPlayQueue&&(identical(other.playQueueId, playQueueId) || other.playQueueId == playQueueId)&&const DeepCollectionEquality().equals(other._items, _items)&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&(identical(other.shuffled, shuffled) || other.shuffled == shuffled)&&(identical(other.selectedItemId, selectedItemId) || other.selectedItemId == selectedItemId)&&(identical(other.version, version) || other.version == version)&&(identical(other.sourceUri, sourceUri) || other.sourceUri == sourceUri)); +} + + +@override +int get hashCode => Object.hash(runtimeType,playQueueId,const DeepCollectionEquality().hash(_items),currentIndex,shuffled,selectedItemId,version,sourceUri); + +@override +String toString() { + return 'PlayQueue.plex(playQueueId: $playQueueId, items: $items, currentIndex: $currentIndex, shuffled: $shuffled, selectedItemId: $selectedItemId, version: $version, sourceUri: $sourceUri)'; +} + + +} + +/// @nodoc +abstract mixin class $PlexServerPlayQueueCopyWith<$Res> implements $PlayQueueCopyWith<$Res> { + factory $PlexServerPlayQueueCopyWith(PlexServerPlayQueue value, $Res Function(PlexServerPlayQueue) _then) = _$PlexServerPlayQueueCopyWithImpl; +@override @useResult +$Res call({ + int playQueueId, List items, int? currentIndex, bool shuffled, int? selectedItemId, int? version, String? sourceUri +}); + + + + +} +/// @nodoc +class _$PlexServerPlayQueueCopyWithImpl<$Res> + implements $PlexServerPlayQueueCopyWith<$Res> { + _$PlexServerPlayQueueCopyWithImpl(this._self, this._then); + + final PlexServerPlayQueue _self; + final $Res Function(PlexServerPlayQueue) _then; + +/// Create a copy of PlayQueue +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? playQueueId = null,Object? items = null,Object? currentIndex = freezed,Object? shuffled = null,Object? selectedItemId = freezed,Object? version = freezed,Object? sourceUri = freezed,}) { + return _then(PlexServerPlayQueue( +playQueueId: null == playQueueId ? _self.playQueueId : playQueueId // ignore: cast_nullable_to_non_nullable +as int,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable +as List,currentIndex: freezed == currentIndex ? _self.currentIndex : currentIndex // ignore: cast_nullable_to_non_nullable +as int?,shuffled: null == shuffled ? _self.shuffled : shuffled // ignore: cast_nullable_to_non_nullable +as bool,selectedItemId: freezed == selectedItemId ? _self.selectedItemId : selectedItemId // ignore: cast_nullable_to_non_nullable +as int?,version: freezed == version ? _self.version : version // ignore: cast_nullable_to_non_nullable +as int?,sourceUri: freezed == sourceUri ? _self.sourceUri : sourceUri // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +/// @nodoc + + +class LocalPlayQueue extends PlayQueue { + const LocalPlayQueue({required this.id, required final List items, required this.backendId, this.currentIndex, this.shuffled = false}): _items = items,super._(); + + +/// Client-generated UUID identifying this queue for the session. + final String id; + final List _items; +@override List get items { + if (_items is EqualUnmodifiableListView) return _items; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_items); +} + +/// Server kind that owns this queue's items (typically `"jellyfin"`). + final String backendId; +@override final int? currentIndex; +@override@JsonKey() final bool shuffled; + +/// Create a copy of PlayQueue +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LocalPlayQueueCopyWith get copyWith => _$LocalPlayQueueCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LocalPlayQueue&&(identical(other.id, id) || other.id == id)&&const DeepCollectionEquality().equals(other._items, _items)&&(identical(other.backendId, backendId) || other.backendId == backendId)&&(identical(other.currentIndex, currentIndex) || other.currentIndex == currentIndex)&&(identical(other.shuffled, shuffled) || other.shuffled == shuffled)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,const DeepCollectionEquality().hash(_items),backendId,currentIndex,shuffled); + +@override +String toString() { + return 'PlayQueue.local(id: $id, items: $items, backendId: $backendId, currentIndex: $currentIndex, shuffled: $shuffled)'; +} + + +} + +/// @nodoc +abstract mixin class $LocalPlayQueueCopyWith<$Res> implements $PlayQueueCopyWith<$Res> { + factory $LocalPlayQueueCopyWith(LocalPlayQueue value, $Res Function(LocalPlayQueue) _then) = _$LocalPlayQueueCopyWithImpl; +@override @useResult +$Res call({ + String id, List items, String backendId, int? currentIndex, bool shuffled +}); + + + + +} +/// @nodoc +class _$LocalPlayQueueCopyWithImpl<$Res> + implements $LocalPlayQueueCopyWith<$Res> { + _$LocalPlayQueueCopyWithImpl(this._self, this._then); + + final LocalPlayQueue _self; + final $Res Function(LocalPlayQueue) _then; + +/// Create a copy of PlayQueue +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? items = null,Object? backendId = null,Object? currentIndex = freezed,Object? shuffled = null,}) { + return _then(LocalPlayQueue( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable +as List,backendId: null == backendId ? _self.backendId : backendId // ignore: cast_nullable_to_non_nullable +as String,currentIndex: freezed == currentIndex ? _self.currentIndex : currentIndex // ignore: cast_nullable_to_non_nullable +as int?,shuffled: null == shuffled ? _self.shuffled : shuffled // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + +// dart format on diff --git a/lib/models/companion_remote/remote_command.dart b/lib/models/companion_remote/remote_command.dart index cb1e8a0e..2ddd3bc7 100644 --- a/lib/models/companion_remote/remote_command.dart +++ b/lib/models/companion_remote/remote_command.dart @@ -1,3 +1,11 @@ +// ignore_for_file: invalid_annotation_target +import 'package:freezed_annotation/freezed_annotation.dart'; + +import '../../utils/json_converters.dart'; + +part 'remote_command.freezed.dart'; +part 'remote_command.g.dart'; + enum RemoteCommandType { dpadUp, dpadDown, @@ -46,24 +54,16 @@ enum RemoteCommandType { syncState, } -class RemoteCommand { - final RemoteCommandType type; - final Map? data; - - const RemoteCommand({required this.type, this.data}); - - factory RemoteCommand.fromJson(Map json) { - final index = json['t'] as int; - return RemoteCommand( - type: index < RemoteCommandType.values.length ? RemoteCommandType.values[index] : RemoteCommandType.ping, - data: json['d'] as Map?, - ); - } - - Map toJson() { - return {'t': type.index, if (data != null) 'd': data}; - } - - @override - String toString() => 'RemoteCommand(${type.name}, data: $data)'; +class _RemoteCommandTypeConverter extends IndexedEnumConverter { + const _RemoteCommandTypeConverter() : super(RemoteCommandType.values, RemoteCommandType.ping); +} + +@freezed +sealed class RemoteCommand with _$RemoteCommand { + const factory RemoteCommand({ + @JsonKey(name: 't') @_RemoteCommandTypeConverter() required RemoteCommandType type, + @JsonKey(name: 'd') Map? data, + }) = _RemoteCommand; + + factory RemoteCommand.fromJson(Map json) => _$RemoteCommandFromJson(json); } diff --git a/lib/models/companion_remote/remote_command.freezed.dart b/lib/models/companion_remote/remote_command.freezed.dart new file mode 100644 index 00000000..0cb4b0d7 --- /dev/null +++ b/lib/models/companion_remote/remote_command.freezed.dart @@ -0,0 +1,282 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'remote_command.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$RemoteCommand { + +@JsonKey(name: 't')@_RemoteCommandTypeConverter() RemoteCommandType get type;@JsonKey(name: 'd') Map? get data; +/// Create a copy of RemoteCommand +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RemoteCommandCopyWith get copyWith => _$RemoteCommandCopyWithImpl(this as RemoteCommand, _$identity); + + /// Serializes this RemoteCommand to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is RemoteCommand&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.data, data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,type,const DeepCollectionEquality().hash(data)); + +@override +String toString() { + return 'RemoteCommand(type: $type, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class $RemoteCommandCopyWith<$Res> { + factory $RemoteCommandCopyWith(RemoteCommand value, $Res Function(RemoteCommand) _then) = _$RemoteCommandCopyWithImpl; +@useResult +$Res call({ +@JsonKey(name: 't')@_RemoteCommandTypeConverter() RemoteCommandType type,@JsonKey(name: 'd') Map? data +}); + + + + +} +/// @nodoc +class _$RemoteCommandCopyWithImpl<$Res> + implements $RemoteCommandCopyWith<$Res> { + _$RemoteCommandCopyWithImpl(this._self, this._then); + + final RemoteCommand _self; + final $Res Function(RemoteCommand) _then; + +/// Create a copy of RemoteCommand +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? data = freezed,}) { + return _then(_self.copyWith( +type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as RemoteCommandType,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable +as Map?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [RemoteCommand]. +extension RemoteCommandPatterns on RemoteCommand { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _RemoteCommand value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _RemoteCommand() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _RemoteCommand value) $default,){ +final _that = this; +switch (_that) { +case _RemoteCommand(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _RemoteCommand value)? $default,){ +final _that = this; +switch (_that) { +case _RemoteCommand() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function(@JsonKey(name: 't')@_RemoteCommandTypeConverter() RemoteCommandType type, @JsonKey(name: 'd') Map? data)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _RemoteCommand() when $default != null: +return $default(_that.type,_that.data);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function(@JsonKey(name: 't')@_RemoteCommandTypeConverter() RemoteCommandType type, @JsonKey(name: 'd') Map? data) $default,) {final _that = this; +switch (_that) { +case _RemoteCommand(): +return $default(_that.type,_that.data);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function(@JsonKey(name: 't')@_RemoteCommandTypeConverter() RemoteCommandType type, @JsonKey(name: 'd') Map? data)? $default,) {final _that = this; +switch (_that) { +case _RemoteCommand() when $default != null: +return $default(_that.type,_that.data);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _RemoteCommand implements RemoteCommand { + const _RemoteCommand({@JsonKey(name: 't')@_RemoteCommandTypeConverter() required this.type, @JsonKey(name: 'd') final Map? data}): _data = data; + factory _RemoteCommand.fromJson(Map json) => _$RemoteCommandFromJson(json); + +@override@JsonKey(name: 't')@_RemoteCommandTypeConverter() final RemoteCommandType type; + final Map? _data; +@override@JsonKey(name: 'd') Map? get data { + final value = _data; + if (value == null) return null; + if (_data is EqualUnmodifiableMapView) return _data; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); +} + + +/// Create a copy of RemoteCommand +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RemoteCommandCopyWith<_RemoteCommand> get copyWith => __$RemoteCommandCopyWithImpl<_RemoteCommand>(this, _$identity); + +@override +Map toJson() { + return _$RemoteCommandToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RemoteCommand&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._data, _data)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,type,const DeepCollectionEquality().hash(_data)); + +@override +String toString() { + return 'RemoteCommand(type: $type, data: $data)'; +} + + +} + +/// @nodoc +abstract mixin class _$RemoteCommandCopyWith<$Res> implements $RemoteCommandCopyWith<$Res> { + factory _$RemoteCommandCopyWith(_RemoteCommand value, $Res Function(_RemoteCommand) _then) = __$RemoteCommandCopyWithImpl; +@override @useResult +$Res call({ +@JsonKey(name: 't')@_RemoteCommandTypeConverter() RemoteCommandType type,@JsonKey(name: 'd') Map? data +}); + + + + +} +/// @nodoc +class __$RemoteCommandCopyWithImpl<$Res> + implements _$RemoteCommandCopyWith<$Res> { + __$RemoteCommandCopyWithImpl(this._self, this._then); + + final _RemoteCommand _self; + final $Res Function(_RemoteCommand) _then; + +/// Create a copy of RemoteCommand +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? data = freezed,}) { + return _then(_RemoteCommand( +type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as RemoteCommandType,data: freezed == data ? _self._data : data // ignore: cast_nullable_to_non_nullable +as Map?, + )); +} + + +} + +// dart format on diff --git a/lib/models/companion_remote/remote_command.g.dart b/lib/models/companion_remote/remote_command.g.dart new file mode 100644 index 00000000..ed60d97e --- /dev/null +++ b/lib/models/companion_remote/remote_command.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'remote_command.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_RemoteCommand _$RemoteCommandFromJson(Map json) => + _RemoteCommand( + type: const _RemoteCommandTypeConverter().fromJson( + (json['t'] as num).toInt(), + ), + data: json['d'] as Map?, + ); + +Map _$RemoteCommandToJson(_RemoteCommand instance) => + { + 't': const _RemoteCommandTypeConverter().toJson(instance.type), + 'd': instance.data, + }; diff --git a/lib/models/companion_remote/remote_session.dart b/lib/models/companion_remote/remote_session.dart index 24f55452..173bf207 100644 --- a/lib/models/companion_remote/remote_session.dart +++ b/lib/models/companion_remote/remote_session.dart @@ -1,100 +1,35 @@ -import 'package:json_annotation/json_annotation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; -part 'remote_session.g.dart'; +part 'remote_session.freezed.dart'; enum RemoteSessionRole { host, remote } enum RemoteSessionStatus { disconnected, connecting, connected, reconnecting, error } -@JsonSerializable() -class RemoteDevice { - final String id; - final String name; - final String platform; - final DateTime connectedAt; - final Map capabilities; - - RemoteDevice({ - required this.id, - required this.name, - required this.platform, - DateTime? connectedAt, - Map? capabilities, - }) : connectedAt = connectedAt ?? DateTime.now(), - capabilities = capabilities ?? {}; - - factory RemoteDevice.fromJson(Map json) => _$RemoteDeviceFromJson(json); - - Map toJson() => _$RemoteDeviceToJson(this); - - RemoteDevice copyWith({ - String? id, - String? name, - String? platform, - DateTime? connectedAt, - Map? capabilities, - }) { - return RemoteDevice( - id: id ?? this.id, - name: name ?? this.name, - platform: platform ?? this.platform, - connectedAt: connectedAt ?? this.connectedAt, - capabilities: capabilities ?? this.capabilities, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is RemoteDevice && other.id == id; - } - - @override - int get hashCode => id.hashCode; +@freezed +sealed class RemoteDevice with _$RemoteDevice { + const factory RemoteDevice({ + required String id, + required String name, + required String platform, + required DateTime connectedAt, + @Default({}) Map capabilities, + }) = _RemoteDevice; } -@JsonSerializable() -class RemoteSession { - @JsonKey(unknownEnumValue: RemoteSessionRole.remote) - final RemoteSessionRole role; - @JsonKey(unknownEnumValue: RemoteSessionStatus.disconnected) - final RemoteSessionStatus status; - final RemoteDevice? connectedDevice; - final DateTime createdAt; - final String? errorMessage; +@freezed +sealed class RemoteSession with _$RemoteSession { + const RemoteSession._(); - RemoteSession({ - required this.role, - this.status = RemoteSessionStatus.disconnected, - this.connectedDevice, - DateTime? createdAt, - this.errorMessage, - }) : createdAt = createdAt ?? DateTime.now(); + const factory RemoteSession({ + required RemoteSessionRole role, + @Default(RemoteSessionStatus.disconnected) RemoteSessionStatus status, + RemoteDevice? connectedDevice, + required DateTime createdAt, + String? errorMessage, + }) = _RemoteSession; bool get isConnected => status == RemoteSessionStatus.connected; bool get isHost => role == RemoteSessionRole.host; bool get isRemote => role == RemoteSessionRole.remote; - - factory RemoteSession.fromJson(Map json) => _$RemoteSessionFromJson(json); - - Map toJson() => _$RemoteSessionToJson(this); - - RemoteSession copyWith({ - RemoteSessionRole? role, - RemoteSessionStatus? status, - RemoteDevice? connectedDevice, - bool clearConnectedDevice = false, - DateTime? createdAt, - String? errorMessage, - bool clearErrorMessage = false, - }) { - return RemoteSession( - role: role ?? this.role, - status: status ?? this.status, - connectedDevice: clearConnectedDevice ? null : (connectedDevice ?? this.connectedDevice), - createdAt: createdAt ?? this.createdAt, - errorMessage: clearErrorMessage ? null : (errorMessage ?? this.errorMessage), - ); - } } diff --git a/lib/models/companion_remote/remote_session.freezed.dart b/lib/models/companion_remote/remote_session.freezed.dart new file mode 100644 index 00000000..1da0a6cd --- /dev/null +++ b/lib/models/companion_remote/remote_session.freezed.dart @@ -0,0 +1,570 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'remote_session.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$RemoteDevice { + + String get id; String get name; String get platform; DateTime get connectedAt; Map get capabilities; +/// Create a copy of RemoteDevice +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RemoteDeviceCopyWith get copyWith => _$RemoteDeviceCopyWithImpl(this as RemoteDevice, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is RemoteDevice&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.connectedAt, connectedAt) || other.connectedAt == connectedAt)&&const DeepCollectionEquality().equals(other.capabilities, capabilities)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,name,platform,connectedAt,const DeepCollectionEquality().hash(capabilities)); + +@override +String toString() { + return 'RemoteDevice(id: $id, name: $name, platform: $platform, connectedAt: $connectedAt, capabilities: $capabilities)'; +} + + +} + +/// @nodoc +abstract mixin class $RemoteDeviceCopyWith<$Res> { + factory $RemoteDeviceCopyWith(RemoteDevice value, $Res Function(RemoteDevice) _then) = _$RemoteDeviceCopyWithImpl; +@useResult +$Res call({ + String id, String name, String platform, DateTime connectedAt, Map capabilities +}); + + + + +} +/// @nodoc +class _$RemoteDeviceCopyWithImpl<$Res> + implements $RemoteDeviceCopyWith<$Res> { + _$RemoteDeviceCopyWithImpl(this._self, this._then); + + final RemoteDevice _self; + final $Res Function(RemoteDevice) _then; + +/// Create a copy of RemoteDevice +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? platform = null,Object? connectedAt = null,Object? capabilities = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable +as String,connectedAt: null == connectedAt ? _self.connectedAt : connectedAt // ignore: cast_nullable_to_non_nullable +as DateTime,capabilities: null == capabilities ? _self.capabilities : capabilities // ignore: cast_nullable_to_non_nullable +as Map, + )); +} + +} + + +/// Adds pattern-matching-related methods to [RemoteDevice]. +extension RemoteDevicePatterns on RemoteDevice { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _RemoteDevice value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _RemoteDevice() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _RemoteDevice value) $default,){ +final _that = this; +switch (_that) { +case _RemoteDevice(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _RemoteDevice value)? $default,){ +final _that = this; +switch (_that) { +case _RemoteDevice() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String name, String platform, DateTime connectedAt, Map capabilities)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _RemoteDevice() when $default != null: +return $default(_that.id,_that.name,_that.platform,_that.connectedAt,_that.capabilities);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String id, String name, String platform, DateTime connectedAt, Map capabilities) $default,) {final _that = this; +switch (_that) { +case _RemoteDevice(): +return $default(_that.id,_that.name,_that.platform,_that.connectedAt,_that.capabilities);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String name, String platform, DateTime connectedAt, Map capabilities)? $default,) {final _that = this; +switch (_that) { +case _RemoteDevice() when $default != null: +return $default(_that.id,_that.name,_that.platform,_that.connectedAt,_that.capabilities);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _RemoteDevice implements RemoteDevice { + const _RemoteDevice({required this.id, required this.name, required this.platform, required this.connectedAt, final Map capabilities = const {}}): _capabilities = capabilities; + + +@override final String id; +@override final String name; +@override final String platform; +@override final DateTime connectedAt; + final Map _capabilities; +@override@JsonKey() Map get capabilities { + if (_capabilities is EqualUnmodifiableMapView) return _capabilities; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_capabilities); +} + + +/// Create a copy of RemoteDevice +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RemoteDeviceCopyWith<_RemoteDevice> get copyWith => __$RemoteDeviceCopyWithImpl<_RemoteDevice>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RemoteDevice&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.connectedAt, connectedAt) || other.connectedAt == connectedAt)&&const DeepCollectionEquality().equals(other._capabilities, _capabilities)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,name,platform,connectedAt,const DeepCollectionEquality().hash(_capabilities)); + +@override +String toString() { + return 'RemoteDevice(id: $id, name: $name, platform: $platform, connectedAt: $connectedAt, capabilities: $capabilities)'; +} + + +} + +/// @nodoc +abstract mixin class _$RemoteDeviceCopyWith<$Res> implements $RemoteDeviceCopyWith<$Res> { + factory _$RemoteDeviceCopyWith(_RemoteDevice value, $Res Function(_RemoteDevice) _then) = __$RemoteDeviceCopyWithImpl; +@override @useResult +$Res call({ + String id, String name, String platform, DateTime connectedAt, Map capabilities +}); + + + + +} +/// @nodoc +class __$RemoteDeviceCopyWithImpl<$Res> + implements _$RemoteDeviceCopyWith<$Res> { + __$RemoteDeviceCopyWithImpl(this._self, this._then); + + final _RemoteDevice _self; + final $Res Function(_RemoteDevice) _then; + +/// Create a copy of RemoteDevice +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? platform = null,Object? connectedAt = null,Object? capabilities = null,}) { + return _then(_RemoteDevice( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable +as String,connectedAt: null == connectedAt ? _self.connectedAt : connectedAt // ignore: cast_nullable_to_non_nullable +as DateTime,capabilities: null == capabilities ? _self._capabilities : capabilities // ignore: cast_nullable_to_non_nullable +as Map, + )); +} + + +} + +/// @nodoc +mixin _$RemoteSession { + + RemoteSessionRole get role; RemoteSessionStatus get status; RemoteDevice? get connectedDevice; DateTime get createdAt; String? get errorMessage; +/// Create a copy of RemoteSession +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RemoteSessionCopyWith get copyWith => _$RemoteSessionCopyWithImpl(this as RemoteSession, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is RemoteSession&&(identical(other.role, role) || other.role == role)&&(identical(other.status, status) || other.status == status)&&(identical(other.connectedDevice, connectedDevice) || other.connectedDevice == connectedDevice)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); +} + + +@override +int get hashCode => Object.hash(runtimeType,role,status,connectedDevice,createdAt,errorMessage); + +@override +String toString() { + return 'RemoteSession(role: $role, status: $status, connectedDevice: $connectedDevice, createdAt: $createdAt, errorMessage: $errorMessage)'; +} + + +} + +/// @nodoc +abstract mixin class $RemoteSessionCopyWith<$Res> { + factory $RemoteSessionCopyWith(RemoteSession value, $Res Function(RemoteSession) _then) = _$RemoteSessionCopyWithImpl; +@useResult +$Res call({ + RemoteSessionRole role, RemoteSessionStatus status, RemoteDevice? connectedDevice, DateTime createdAt, String? errorMessage +}); + + +$RemoteDeviceCopyWith<$Res>? get connectedDevice; + +} +/// @nodoc +class _$RemoteSessionCopyWithImpl<$Res> + implements $RemoteSessionCopyWith<$Res> { + _$RemoteSessionCopyWithImpl(this._self, this._then); + + final RemoteSession _self; + final $Res Function(RemoteSession) _then; + +/// Create a copy of RemoteSession +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? role = null,Object? status = null,Object? connectedDevice = freezed,Object? createdAt = null,Object? errorMessage = freezed,}) { + return _then(_self.copyWith( +role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as RemoteSessionRole,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable +as RemoteSessionStatus,connectedDevice: freezed == connectedDevice ? _self.connectedDevice : connectedDevice // ignore: cast_nullable_to_non_nullable +as RemoteDevice?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,errorMessage: freezed == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String?, + )); +} +/// Create a copy of RemoteSession +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RemoteDeviceCopyWith<$Res>? get connectedDevice { + if (_self.connectedDevice == null) { + return null; + } + + return $RemoteDeviceCopyWith<$Res>(_self.connectedDevice!, (value) { + return _then(_self.copyWith(connectedDevice: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [RemoteSession]. +extension RemoteSessionPatterns on RemoteSession { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _RemoteSession value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _RemoteSession() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _RemoteSession value) $default,){ +final _that = this; +switch (_that) { +case _RemoteSession(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _RemoteSession value)? $default,){ +final _that = this; +switch (_that) { +case _RemoteSession() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( RemoteSessionRole role, RemoteSessionStatus status, RemoteDevice? connectedDevice, DateTime createdAt, String? errorMessage)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _RemoteSession() when $default != null: +return $default(_that.role,_that.status,_that.connectedDevice,_that.createdAt,_that.errorMessage);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( RemoteSessionRole role, RemoteSessionStatus status, RemoteDevice? connectedDevice, DateTime createdAt, String? errorMessage) $default,) {final _that = this; +switch (_that) { +case _RemoteSession(): +return $default(_that.role,_that.status,_that.connectedDevice,_that.createdAt,_that.errorMessage);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( RemoteSessionRole role, RemoteSessionStatus status, RemoteDevice? connectedDevice, DateTime createdAt, String? errorMessage)? $default,) {final _that = this; +switch (_that) { +case _RemoteSession() when $default != null: +return $default(_that.role,_that.status,_that.connectedDevice,_that.createdAt,_that.errorMessage);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _RemoteSession extends RemoteSession { + const _RemoteSession({required this.role, this.status = RemoteSessionStatus.disconnected, this.connectedDevice, required this.createdAt, this.errorMessage}): super._(); + + +@override final RemoteSessionRole role; +@override@JsonKey() final RemoteSessionStatus status; +@override final RemoteDevice? connectedDevice; +@override final DateTime createdAt; +@override final String? errorMessage; + +/// Create a copy of RemoteSession +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RemoteSessionCopyWith<_RemoteSession> get copyWith => __$RemoteSessionCopyWithImpl<_RemoteSession>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RemoteSession&&(identical(other.role, role) || other.role == role)&&(identical(other.status, status) || other.status == status)&&(identical(other.connectedDevice, connectedDevice) || other.connectedDevice == connectedDevice)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); +} + + +@override +int get hashCode => Object.hash(runtimeType,role,status,connectedDevice,createdAt,errorMessage); + +@override +String toString() { + return 'RemoteSession(role: $role, status: $status, connectedDevice: $connectedDevice, createdAt: $createdAt, errorMessage: $errorMessage)'; +} + + +} + +/// @nodoc +abstract mixin class _$RemoteSessionCopyWith<$Res> implements $RemoteSessionCopyWith<$Res> { + factory _$RemoteSessionCopyWith(_RemoteSession value, $Res Function(_RemoteSession) _then) = __$RemoteSessionCopyWithImpl; +@override @useResult +$Res call({ + RemoteSessionRole role, RemoteSessionStatus status, RemoteDevice? connectedDevice, DateTime createdAt, String? errorMessage +}); + + +@override $RemoteDeviceCopyWith<$Res>? get connectedDevice; + +} +/// @nodoc +class __$RemoteSessionCopyWithImpl<$Res> + implements _$RemoteSessionCopyWith<$Res> { + __$RemoteSessionCopyWithImpl(this._self, this._then); + + final _RemoteSession _self; + final $Res Function(_RemoteSession) _then; + +/// Create a copy of RemoteSession +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? role = null,Object? status = null,Object? connectedDevice = freezed,Object? createdAt = null,Object? errorMessage = freezed,}) { + return _then(_RemoteSession( +role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as RemoteSessionRole,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable +as RemoteSessionStatus,connectedDevice: freezed == connectedDevice ? _self.connectedDevice : connectedDevice // ignore: cast_nullable_to_non_nullable +as RemoteDevice?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,errorMessage: freezed == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +/// Create a copy of RemoteSession +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RemoteDeviceCopyWith<$Res>? get connectedDevice { + if (_self.connectedDevice == null) { + return null; + } + + return $RemoteDeviceCopyWith<$Res>(_self.connectedDevice!, (value) { + return _then(_self.copyWith(connectedDevice: value)); + }); +} +} + +// dart format on diff --git a/lib/models/companion_remote/remote_session.g.dart b/lib/models/companion_remote/remote_session.g.dart deleted file mode 100644 index ee6f3c4e..00000000 --- a/lib/models/companion_remote/remote_session.g.dart +++ /dev/null @@ -1,75 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'remote_session.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -RemoteDevice _$RemoteDeviceFromJson(Map json) => RemoteDevice( - id: json['id'] as String, - name: json['name'] as String, - platform: json['platform'] as String, - connectedAt: json['connectedAt'] == null - ? null - : DateTime.parse(json['connectedAt'] as String), - capabilities: (json['capabilities'] as Map?)?.map( - (k, e) => MapEntry(k, e as bool), - ), -); - -Map _$RemoteDeviceToJson(RemoteDevice instance) => - { - 'id': instance.id, - 'name': instance.name, - 'platform': instance.platform, - 'connectedAt': instance.connectedAt.toIso8601String(), - 'capabilities': instance.capabilities, - }; - -RemoteSession _$RemoteSessionFromJson(Map json) => - RemoteSession( - role: $enumDecode( - _$RemoteSessionRoleEnumMap, - json['role'], - unknownValue: RemoteSessionRole.remote, - ), - status: - $enumDecodeNullable( - _$RemoteSessionStatusEnumMap, - json['status'], - unknownValue: RemoteSessionStatus.disconnected, - ) ?? - RemoteSessionStatus.disconnected, - connectedDevice: json['connectedDevice'] == null - ? null - : RemoteDevice.fromJson( - json['connectedDevice'] as Map, - ), - createdAt: json['createdAt'] == null - ? null - : DateTime.parse(json['createdAt'] as String), - errorMessage: json['errorMessage'] as String?, - ); - -Map _$RemoteSessionToJson(RemoteSession instance) => - { - 'role': _$RemoteSessionRoleEnumMap[instance.role]!, - 'status': _$RemoteSessionStatusEnumMap[instance.status]!, - 'connectedDevice': instance.connectedDevice, - 'createdAt': instance.createdAt.toIso8601String(), - 'errorMessage': instance.errorMessage, - }; - -const _$RemoteSessionRoleEnumMap = { - RemoteSessionRole.host: 'host', - RemoteSessionRole.remote: 'remote', -}; - -const _$RemoteSessionStatusEnumMap = { - RemoteSessionStatus.disconnected: 'disconnected', - RemoteSessionStatus.connecting: 'connecting', - RemoteSessionStatus.connected: 'connected', - RemoteSessionStatus.reconnecting: 'reconnecting', - RemoteSessionStatus.error: 'error', -}; diff --git a/lib/models/download_models.dart b/lib/models/download_models.dart index 90ab449c..50d8ce6c 100644 --- a/lib/models/download_models.dart +++ b/lib/models/download_models.dart @@ -1,5 +1,10 @@ +// ignore_for_file: invalid_annotation_target +import 'package:freezed_annotation/freezed_annotation.dart'; + import '../utils/formatters.dart'; +part 'download_models.freezed.dart'; + enum DownloadStatus { queued, downloading, @@ -10,30 +15,21 @@ enum DownloadStatus { partial, // Some episodes downloaded, but not all (for shows/seasons) } -class DownloadProgress { - final String globalKey; - final DownloadStatus status; - final int progress; // 0-100 - final int downloadedBytes; - final int totalBytes; - final double speed; // bytes per second - final String? errorMessage; - final String? currentFile; // What's being downloaded (video, subtitles, artwork) +@freezed +sealed class DownloadProgress with _$DownloadProgress { + const DownloadProgress._(); - // Thumbnail path (populated after artwork download completes) - final String? thumbPath; - - const DownloadProgress({ - required this.globalKey, - required this.status, - this.progress = 0, - this.downloadedBytes = 0, - this.totalBytes = 0, - this.speed = 0, - this.errorMessage, - this.currentFile, - this.thumbPath, - }); + const factory DownloadProgress({ + required String globalKey, + required DownloadStatus status, + @Default(0) int progress, + @Default(0) int downloadedBytes, + @Default(0) int totalBytes, + @Default(0.0) double speed, + String? errorMessage, + String? currentFile, + String? thumbPath, + }) = _DownloadProgress; double get progressPercent => progress / 100.0; @@ -42,73 +38,23 @@ class DownloadProgress { String get totalFormatted => ByteFormatter.formatBytes(totalBytes); bool get hasArtworkPaths => thumbPath != null; - - DownloadProgress copyWith({ - String? globalKey, - DownloadStatus? status, - int? progress, - int? downloadedBytes, - int? totalBytes, - double? speed, - String? errorMessage, - String? currentFile, - String? thumbPath, - }) { - return DownloadProgress( - globalKey: globalKey ?? this.globalKey, - status: status ?? this.status, - progress: progress ?? this.progress, - downloadedBytes: downloadedBytes ?? this.downloadedBytes, - totalBytes: totalBytes ?? this.totalBytes, - speed: speed ?? this.speed, - errorMessage: errorMessage ?? this.errorMessage, - currentFile: currentFile ?? this.currentFile, - thumbPath: thumbPath ?? this.thumbPath, - ); - } } -class DeletionProgress { - final String globalKey; - final String itemTitle; - final int currentItem; - final int totalItems; - final String? currentOperation; +@freezed +sealed class DeletionProgress with _$DeletionProgress { + const DeletionProgress._(); - const DeletionProgress({ - required this.globalKey, - required this.itemTitle, - required this.currentItem, - required this.totalItems, - this.currentOperation, - }); + const factory DeletionProgress({ + required String globalKey, + required String itemTitle, + required int currentItem, + required int totalItems, + String? currentOperation, + }) = _DeletionProgress; double get progressPercent => totalItems > 0 ? (currentItem / totalItems) : 0.0; int get progressPercentInt => (progressPercent * 100).round(); bool get isComplete => currentItem >= totalItems; - - DeletionProgress copyWith({ - String? globalKey, - String? itemTitle, - int? currentItem, - int? totalItems, - String? currentOperation, - }) { - return DeletionProgress( - globalKey: globalKey ?? this.globalKey, - itemTitle: itemTitle ?? this.itemTitle, - currentItem: currentItem ?? this.currentItem, - totalItems: totalItems ?? this.totalItems, - currentOperation: currentOperation ?? this.currentOperation, - ); - } - - @override - String toString() { - return 'DeletionProgress(globalKey: $globalKey, itemTitle: $itemTitle, ' - 'currentItem: $currentItem, totalItems: $totalItems, ' - 'progressPercent: $progressPercentInt%)'; - } } diff --git a/lib/models/download_models.freezed.dart b/lib/models/download_models.freezed.dart new file mode 100644 index 00000000..38dd240f --- /dev/null +++ b/lib/models/download_models.freezed.dart @@ -0,0 +1,552 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'download_models.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$DownloadProgress { + + String get globalKey; DownloadStatus get status; int get progress; int get downloadedBytes; int get totalBytes; double get speed; String? get errorMessage; String? get currentFile; String? get thumbPath; +/// Create a copy of DownloadProgress +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$DownloadProgressCopyWith get copyWith => _$DownloadProgressCopyWithImpl(this as DownloadProgress, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DownloadProgress&&(identical(other.globalKey, globalKey) || other.globalKey == globalKey)&&(identical(other.status, status) || other.status == status)&&(identical(other.progress, progress) || other.progress == progress)&&(identical(other.downloadedBytes, downloadedBytes) || other.downloadedBytes == downloadedBytes)&&(identical(other.totalBytes, totalBytes) || other.totalBytes == totalBytes)&&(identical(other.speed, speed) || other.speed == speed)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.currentFile, currentFile) || other.currentFile == currentFile)&&(identical(other.thumbPath, thumbPath) || other.thumbPath == thumbPath)); +} + + +@override +int get hashCode => Object.hash(runtimeType,globalKey,status,progress,downloadedBytes,totalBytes,speed,errorMessage,currentFile,thumbPath); + +@override +String toString() { + return 'DownloadProgress(globalKey: $globalKey, status: $status, progress: $progress, downloadedBytes: $downloadedBytes, totalBytes: $totalBytes, speed: $speed, errorMessage: $errorMessage, currentFile: $currentFile, thumbPath: $thumbPath)'; +} + + +} + +/// @nodoc +abstract mixin class $DownloadProgressCopyWith<$Res> { + factory $DownloadProgressCopyWith(DownloadProgress value, $Res Function(DownloadProgress) _then) = _$DownloadProgressCopyWithImpl; +@useResult +$Res call({ + String globalKey, DownloadStatus status, int progress, int downloadedBytes, int totalBytes, double speed, String? errorMessage, String? currentFile, String? thumbPath +}); + + + + +} +/// @nodoc +class _$DownloadProgressCopyWithImpl<$Res> + implements $DownloadProgressCopyWith<$Res> { + _$DownloadProgressCopyWithImpl(this._self, this._then); + + final DownloadProgress _self; + final $Res Function(DownloadProgress) _then; + +/// Create a copy of DownloadProgress +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? globalKey = null,Object? status = null,Object? progress = null,Object? downloadedBytes = null,Object? totalBytes = null,Object? speed = null,Object? errorMessage = freezed,Object? currentFile = freezed,Object? thumbPath = freezed,}) { + return _then(_self.copyWith( +globalKey: null == globalKey ? _self.globalKey : globalKey // ignore: cast_nullable_to_non_nullable +as String,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable +as DownloadStatus,progress: null == progress ? _self.progress : progress // ignore: cast_nullable_to_non_nullable +as int,downloadedBytes: null == downloadedBytes ? _self.downloadedBytes : downloadedBytes // ignore: cast_nullable_to_non_nullable +as int,totalBytes: null == totalBytes ? _self.totalBytes : totalBytes // ignore: cast_nullable_to_non_nullable +as int,speed: null == speed ? _self.speed : speed // ignore: cast_nullable_to_non_nullable +as double,errorMessage: freezed == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String?,currentFile: freezed == currentFile ? _self.currentFile : currentFile // ignore: cast_nullable_to_non_nullable +as String?,thumbPath: freezed == thumbPath ? _self.thumbPath : thumbPath // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [DownloadProgress]. +extension DownloadProgressPatterns on DownloadProgress { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _DownloadProgress value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _DownloadProgress() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _DownloadProgress value) $default,){ +final _that = this; +switch (_that) { +case _DownloadProgress(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _DownloadProgress value)? $default,){ +final _that = this; +switch (_that) { +case _DownloadProgress() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String globalKey, DownloadStatus status, int progress, int downloadedBytes, int totalBytes, double speed, String? errorMessage, String? currentFile, String? thumbPath)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _DownloadProgress() when $default != null: +return $default(_that.globalKey,_that.status,_that.progress,_that.downloadedBytes,_that.totalBytes,_that.speed,_that.errorMessage,_that.currentFile,_that.thumbPath);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String globalKey, DownloadStatus status, int progress, int downloadedBytes, int totalBytes, double speed, String? errorMessage, String? currentFile, String? thumbPath) $default,) {final _that = this; +switch (_that) { +case _DownloadProgress(): +return $default(_that.globalKey,_that.status,_that.progress,_that.downloadedBytes,_that.totalBytes,_that.speed,_that.errorMessage,_that.currentFile,_that.thumbPath);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String globalKey, DownloadStatus status, int progress, int downloadedBytes, int totalBytes, double speed, String? errorMessage, String? currentFile, String? thumbPath)? $default,) {final _that = this; +switch (_that) { +case _DownloadProgress() when $default != null: +return $default(_that.globalKey,_that.status,_that.progress,_that.downloadedBytes,_that.totalBytes,_that.speed,_that.errorMessage,_that.currentFile,_that.thumbPath);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _DownloadProgress extends DownloadProgress { + const _DownloadProgress({required this.globalKey, required this.status, this.progress = 0, this.downloadedBytes = 0, this.totalBytes = 0, this.speed = 0.0, this.errorMessage, this.currentFile, this.thumbPath}): super._(); + + +@override final String globalKey; +@override final DownloadStatus status; +@override@JsonKey() final int progress; +@override@JsonKey() final int downloadedBytes; +@override@JsonKey() final int totalBytes; +@override@JsonKey() final double speed; +@override final String? errorMessage; +@override final String? currentFile; +@override final String? thumbPath; + +/// Create a copy of DownloadProgress +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$DownloadProgressCopyWith<_DownloadProgress> get copyWith => __$DownloadProgressCopyWithImpl<_DownloadProgress>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _DownloadProgress&&(identical(other.globalKey, globalKey) || other.globalKey == globalKey)&&(identical(other.status, status) || other.status == status)&&(identical(other.progress, progress) || other.progress == progress)&&(identical(other.downloadedBytes, downloadedBytes) || other.downloadedBytes == downloadedBytes)&&(identical(other.totalBytes, totalBytes) || other.totalBytes == totalBytes)&&(identical(other.speed, speed) || other.speed == speed)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.currentFile, currentFile) || other.currentFile == currentFile)&&(identical(other.thumbPath, thumbPath) || other.thumbPath == thumbPath)); +} + + +@override +int get hashCode => Object.hash(runtimeType,globalKey,status,progress,downloadedBytes,totalBytes,speed,errorMessage,currentFile,thumbPath); + +@override +String toString() { + return 'DownloadProgress(globalKey: $globalKey, status: $status, progress: $progress, downloadedBytes: $downloadedBytes, totalBytes: $totalBytes, speed: $speed, errorMessage: $errorMessage, currentFile: $currentFile, thumbPath: $thumbPath)'; +} + + +} + +/// @nodoc +abstract mixin class _$DownloadProgressCopyWith<$Res> implements $DownloadProgressCopyWith<$Res> { + factory _$DownloadProgressCopyWith(_DownloadProgress value, $Res Function(_DownloadProgress) _then) = __$DownloadProgressCopyWithImpl; +@override @useResult +$Res call({ + String globalKey, DownloadStatus status, int progress, int downloadedBytes, int totalBytes, double speed, String? errorMessage, String? currentFile, String? thumbPath +}); + + + + +} +/// @nodoc +class __$DownloadProgressCopyWithImpl<$Res> + implements _$DownloadProgressCopyWith<$Res> { + __$DownloadProgressCopyWithImpl(this._self, this._then); + + final _DownloadProgress _self; + final $Res Function(_DownloadProgress) _then; + +/// Create a copy of DownloadProgress +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? globalKey = null,Object? status = null,Object? progress = null,Object? downloadedBytes = null,Object? totalBytes = null,Object? speed = null,Object? errorMessage = freezed,Object? currentFile = freezed,Object? thumbPath = freezed,}) { + return _then(_DownloadProgress( +globalKey: null == globalKey ? _self.globalKey : globalKey // ignore: cast_nullable_to_non_nullable +as String,status: null == status ? _self.status : status // ignore: cast_nullable_to_non_nullable +as DownloadStatus,progress: null == progress ? _self.progress : progress // ignore: cast_nullable_to_non_nullable +as int,downloadedBytes: null == downloadedBytes ? _self.downloadedBytes : downloadedBytes // ignore: cast_nullable_to_non_nullable +as int,totalBytes: null == totalBytes ? _self.totalBytes : totalBytes // ignore: cast_nullable_to_non_nullable +as int,speed: null == speed ? _self.speed : speed // ignore: cast_nullable_to_non_nullable +as double,errorMessage: freezed == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String?,currentFile: freezed == currentFile ? _self.currentFile : currentFile // ignore: cast_nullable_to_non_nullable +as String?,thumbPath: freezed == thumbPath ? _self.thumbPath : thumbPath // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +/// @nodoc +mixin _$DeletionProgress { + + String get globalKey; String get itemTitle; int get currentItem; int get totalItems; String? get currentOperation; +/// Create a copy of DeletionProgress +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$DeletionProgressCopyWith get copyWith => _$DeletionProgressCopyWithImpl(this as DeletionProgress, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DeletionProgress&&(identical(other.globalKey, globalKey) || other.globalKey == globalKey)&&(identical(other.itemTitle, itemTitle) || other.itemTitle == itemTitle)&&(identical(other.currentItem, currentItem) || other.currentItem == currentItem)&&(identical(other.totalItems, totalItems) || other.totalItems == totalItems)&&(identical(other.currentOperation, currentOperation) || other.currentOperation == currentOperation)); +} + + +@override +int get hashCode => Object.hash(runtimeType,globalKey,itemTitle,currentItem,totalItems,currentOperation); + +@override +String toString() { + return 'DeletionProgress(globalKey: $globalKey, itemTitle: $itemTitle, currentItem: $currentItem, totalItems: $totalItems, currentOperation: $currentOperation)'; +} + + +} + +/// @nodoc +abstract mixin class $DeletionProgressCopyWith<$Res> { + factory $DeletionProgressCopyWith(DeletionProgress value, $Res Function(DeletionProgress) _then) = _$DeletionProgressCopyWithImpl; +@useResult +$Res call({ + String globalKey, String itemTitle, int currentItem, int totalItems, String? currentOperation +}); + + + + +} +/// @nodoc +class _$DeletionProgressCopyWithImpl<$Res> + implements $DeletionProgressCopyWith<$Res> { + _$DeletionProgressCopyWithImpl(this._self, this._then); + + final DeletionProgress _self; + final $Res Function(DeletionProgress) _then; + +/// Create a copy of DeletionProgress +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? globalKey = null,Object? itemTitle = null,Object? currentItem = null,Object? totalItems = null,Object? currentOperation = freezed,}) { + return _then(_self.copyWith( +globalKey: null == globalKey ? _self.globalKey : globalKey // ignore: cast_nullable_to_non_nullable +as String,itemTitle: null == itemTitle ? _self.itemTitle : itemTitle // ignore: cast_nullable_to_non_nullable +as String,currentItem: null == currentItem ? _self.currentItem : currentItem // ignore: cast_nullable_to_non_nullable +as int,totalItems: null == totalItems ? _self.totalItems : totalItems // ignore: cast_nullable_to_non_nullable +as int,currentOperation: freezed == currentOperation ? _self.currentOperation : currentOperation // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [DeletionProgress]. +extension DeletionProgressPatterns on DeletionProgress { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _DeletionProgress value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _DeletionProgress() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _DeletionProgress value) $default,){ +final _that = this; +switch (_that) { +case _DeletionProgress(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _DeletionProgress value)? $default,){ +final _that = this; +switch (_that) { +case _DeletionProgress() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String globalKey, String itemTitle, int currentItem, int totalItems, String? currentOperation)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _DeletionProgress() when $default != null: +return $default(_that.globalKey,_that.itemTitle,_that.currentItem,_that.totalItems,_that.currentOperation);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String globalKey, String itemTitle, int currentItem, int totalItems, String? currentOperation) $default,) {final _that = this; +switch (_that) { +case _DeletionProgress(): +return $default(_that.globalKey,_that.itemTitle,_that.currentItem,_that.totalItems,_that.currentOperation);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String globalKey, String itemTitle, int currentItem, int totalItems, String? currentOperation)? $default,) {final _that = this; +switch (_that) { +case _DeletionProgress() when $default != null: +return $default(_that.globalKey,_that.itemTitle,_that.currentItem,_that.totalItems,_that.currentOperation);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _DeletionProgress extends DeletionProgress { + const _DeletionProgress({required this.globalKey, required this.itemTitle, required this.currentItem, required this.totalItems, this.currentOperation}): super._(); + + +@override final String globalKey; +@override final String itemTitle; +@override final int currentItem; +@override final int totalItems; +@override final String? currentOperation; + +/// Create a copy of DeletionProgress +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$DeletionProgressCopyWith<_DeletionProgress> get copyWith => __$DeletionProgressCopyWithImpl<_DeletionProgress>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _DeletionProgress&&(identical(other.globalKey, globalKey) || other.globalKey == globalKey)&&(identical(other.itemTitle, itemTitle) || other.itemTitle == itemTitle)&&(identical(other.currentItem, currentItem) || other.currentItem == currentItem)&&(identical(other.totalItems, totalItems) || other.totalItems == totalItems)&&(identical(other.currentOperation, currentOperation) || other.currentOperation == currentOperation)); +} + + +@override +int get hashCode => Object.hash(runtimeType,globalKey,itemTitle,currentItem,totalItems,currentOperation); + +@override +String toString() { + return 'DeletionProgress(globalKey: $globalKey, itemTitle: $itemTitle, currentItem: $currentItem, totalItems: $totalItems, currentOperation: $currentOperation)'; +} + + +} + +/// @nodoc +abstract mixin class _$DeletionProgressCopyWith<$Res> implements $DeletionProgressCopyWith<$Res> { + factory _$DeletionProgressCopyWith(_DeletionProgress value, $Res Function(_DeletionProgress) _then) = __$DeletionProgressCopyWithImpl; +@override @useResult +$Res call({ + String globalKey, String itemTitle, int currentItem, int totalItems, String? currentOperation +}); + + + + +} +/// @nodoc +class __$DeletionProgressCopyWithImpl<$Res> + implements _$DeletionProgressCopyWith<$Res> { + __$DeletionProgressCopyWithImpl(this._self, this._then); + + final _DeletionProgress _self; + final $Res Function(_DeletionProgress) _then; + +/// Create a copy of DeletionProgress +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? globalKey = null,Object? itemTitle = null,Object? currentItem = null,Object? totalItems = null,Object? currentOperation = freezed,}) { + return _then(_DeletionProgress( +globalKey: null == globalKey ? _self.globalKey : globalKey // ignore: cast_nullable_to_non_nullable +as String,itemTitle: null == itemTitle ? _self.itemTitle : itemTitle // ignore: cast_nullable_to_non_nullable +as String,currentItem: null == currentItem ? _self.currentItem : currentItem // ignore: cast_nullable_to_non_nullable +as int,totalItems: null == totalItems ? _self.totalItems : totalItems // ignore: cast_nullable_to_non_nullable +as int,currentOperation: freezed == currentOperation ? _self.currentOperation : currentOperation // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/lib/models/plex/plex_home.g.dart b/lib/models/plex/plex_home.g.dart index d9c51148..43d9690e 100644 --- a/lib/models/plex/plex_home.g.dart +++ b/lib/models/plex/plex_home.g.dart @@ -27,5 +27,5 @@ Map _$PlexHomeToJson(PlexHome instance) => { 'guestUserUUID': instance.guestUserUUID, 'guestEnabled': instance.guestEnabled, 'subscription': instance.subscription, - 'users': instance.users, + 'users': instance.users.map((e) => e.toJson()).toList(), }; diff --git a/lib/models/shader_preset.dart b/lib/models/shader_preset.dart index 5bb0b4a0..daa80132 100644 --- a/lib/models/shader_preset.dart +++ b/lib/models/shader_preset.dart @@ -1,3 +1,9 @@ +// ignore_for_file: invalid_annotation_target +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'shader_preset.freezed.dart'; +part 'shader_preset.g.dart'; + enum ShaderPresetType { none, nvscaler, artcnn, anime4k, custom } /// ArtCNN real-time model sizes. @@ -51,76 +57,34 @@ enum Anime4KMode { modeCA, } -class Anime4KConfig { - final Anime4KQuality quality; - final Anime4KMode mode; +@freezed +sealed class Anime4KConfig with _$Anime4KConfig { + const factory Anime4KConfig({ + @JsonKey(unknownEnumValue: Anime4KQuality.fast) required Anime4KQuality quality, + @JsonKey(unknownEnumValue: Anime4KMode.modeA) required Anime4KMode mode, + }) = _Anime4KConfig; - const Anime4KConfig({required this.quality, required this.mode}); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is Anime4KConfig && other.quality == quality && other.mode == mode; - } - - @override - int get hashCode => quality.hashCode ^ mode.hashCode; - - Map toJson() => {'quality': quality.name, 'mode': mode.name}; - - factory Anime4KConfig.fromJson(Map json) { - return Anime4KConfig( - quality: Anime4KQuality.values.asNameMap()[json['quality']] ?? Anime4KQuality.fast, - mode: Anime4KMode.values.asNameMap()[json['mode']] ?? Anime4KMode.modeA, - ); - } + factory Anime4KConfig.fromJson(Map json) => _$Anime4KConfigFromJson(json); } -class ArtCNNConfig { - final ArtCNNModel model; - final ArtCNNVariant variant; +@freezed +sealed class ArtCNNConfig with _$ArtCNNConfig { + const factory ArtCNNConfig({ + @JsonKey(unknownEnumValue: ArtCNNModel.c4f16) required ArtCNNModel model, + @JsonKey(unknownEnumValue: ArtCNNVariant.neutral) required ArtCNNVariant variant, + }) = _ArtCNNConfig; - const ArtCNNConfig({required this.model, required this.variant}); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is ArtCNNConfig && other.model == model && other.variant == variant; - } - - @override - int get hashCode => model.hashCode ^ variant.hashCode; - - Map toJson() => {'model': model.name, 'variant': variant.name}; - - factory ArtCNNConfig.fromJson(Map json) { - return ArtCNNConfig( - model: ArtCNNModel.values.asNameMap()[json['model']] ?? ArtCNNModel.c4f16, - variant: ArtCNNVariant.values.asNameMap()[json['variant']] ?? ArtCNNVariant.neutral, - ); - } + factory ArtCNNConfig.fromJson(Map json) => _$ArtCNNConfigFromJson(json); } -class NVScalerConfig { - /// Whether to automatically skip NVScaler on HDR content - final bool autoHdrSkip; +@freezed +sealed class NVScalerConfig with _$NVScalerConfig { + const factory NVScalerConfig({ + /// Whether to automatically skip NVScaler on HDR content + @Default(true) bool autoHdrSkip, + }) = _NVScalerConfig; - const NVScalerConfig({this.autoHdrSkip = true}); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is NVScalerConfig && other.autoHdrSkip == autoHdrSkip; - } - - @override - int get hashCode => autoHdrSkip.hashCode; - - Map toJson() => {'autoHdrSkip': autoHdrSkip}; - - factory NVScalerConfig.fromJson(Map json) { - return NVScalerConfig(autoHdrSkip: json['autoHdrSkip'] as bool? ?? true); - } + factory NVScalerConfig.fromJson(Map json) => _$NVScalerConfigFromJson(json); } class ShaderPreset { diff --git a/lib/models/shader_preset.freezed.dart b/lib/models/shader_preset.freezed.dart new file mode 100644 index 00000000..fcc557eb --- /dev/null +++ b/lib/models/shader_preset.freezed.dart @@ -0,0 +1,793 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'shader_preset.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$Anime4KConfig { + +@JsonKey(unknownEnumValue: Anime4KQuality.fast) Anime4KQuality get quality;@JsonKey(unknownEnumValue: Anime4KMode.modeA) Anime4KMode get mode; +/// Create a copy of Anime4KConfig +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$Anime4KConfigCopyWith get copyWith => _$Anime4KConfigCopyWithImpl(this as Anime4KConfig, _$identity); + + /// Serializes this Anime4KConfig to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Anime4KConfig&&(identical(other.quality, quality) || other.quality == quality)&&(identical(other.mode, mode) || other.mode == mode)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,quality,mode); + +@override +String toString() { + return 'Anime4KConfig(quality: $quality, mode: $mode)'; +} + + +} + +/// @nodoc +abstract mixin class $Anime4KConfigCopyWith<$Res> { + factory $Anime4KConfigCopyWith(Anime4KConfig value, $Res Function(Anime4KConfig) _then) = _$Anime4KConfigCopyWithImpl; +@useResult +$Res call({ +@JsonKey(unknownEnumValue: Anime4KQuality.fast) Anime4KQuality quality,@JsonKey(unknownEnumValue: Anime4KMode.modeA) Anime4KMode mode +}); + + + + +} +/// @nodoc +class _$Anime4KConfigCopyWithImpl<$Res> + implements $Anime4KConfigCopyWith<$Res> { + _$Anime4KConfigCopyWithImpl(this._self, this._then); + + final Anime4KConfig _self; + final $Res Function(Anime4KConfig) _then; + +/// Create a copy of Anime4KConfig +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? quality = null,Object? mode = null,}) { + return _then(_self.copyWith( +quality: null == quality ? _self.quality : quality // ignore: cast_nullable_to_non_nullable +as Anime4KQuality,mode: null == mode ? _self.mode : mode // ignore: cast_nullable_to_non_nullable +as Anime4KMode, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Anime4KConfig]. +extension Anime4KConfigPatterns on Anime4KConfig { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Anime4KConfig value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Anime4KConfig() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Anime4KConfig value) $default,){ +final _that = this; +switch (_that) { +case _Anime4KConfig(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Anime4KConfig value)? $default,){ +final _that = this; +switch (_that) { +case _Anime4KConfig() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function(@JsonKey(unknownEnumValue: Anime4KQuality.fast) Anime4KQuality quality, @JsonKey(unknownEnumValue: Anime4KMode.modeA) Anime4KMode mode)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Anime4KConfig() when $default != null: +return $default(_that.quality,_that.mode);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function(@JsonKey(unknownEnumValue: Anime4KQuality.fast) Anime4KQuality quality, @JsonKey(unknownEnumValue: Anime4KMode.modeA) Anime4KMode mode) $default,) {final _that = this; +switch (_that) { +case _Anime4KConfig(): +return $default(_that.quality,_that.mode);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function(@JsonKey(unknownEnumValue: Anime4KQuality.fast) Anime4KQuality quality, @JsonKey(unknownEnumValue: Anime4KMode.modeA) Anime4KMode mode)? $default,) {final _that = this; +switch (_that) { +case _Anime4KConfig() when $default != null: +return $default(_that.quality,_that.mode);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Anime4KConfig implements Anime4KConfig { + const _Anime4KConfig({@JsonKey(unknownEnumValue: Anime4KQuality.fast) required this.quality, @JsonKey(unknownEnumValue: Anime4KMode.modeA) required this.mode}); + factory _Anime4KConfig.fromJson(Map json) => _$Anime4KConfigFromJson(json); + +@override@JsonKey(unknownEnumValue: Anime4KQuality.fast) final Anime4KQuality quality; +@override@JsonKey(unknownEnumValue: Anime4KMode.modeA) final Anime4KMode mode; + +/// Create a copy of Anime4KConfig +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$Anime4KConfigCopyWith<_Anime4KConfig> get copyWith => __$Anime4KConfigCopyWithImpl<_Anime4KConfig>(this, _$identity); + +@override +Map toJson() { + return _$Anime4KConfigToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Anime4KConfig&&(identical(other.quality, quality) || other.quality == quality)&&(identical(other.mode, mode) || other.mode == mode)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,quality,mode); + +@override +String toString() { + return 'Anime4KConfig(quality: $quality, mode: $mode)'; +} + + +} + +/// @nodoc +abstract mixin class _$Anime4KConfigCopyWith<$Res> implements $Anime4KConfigCopyWith<$Res> { + factory _$Anime4KConfigCopyWith(_Anime4KConfig value, $Res Function(_Anime4KConfig) _then) = __$Anime4KConfigCopyWithImpl; +@override @useResult +$Res call({ +@JsonKey(unknownEnumValue: Anime4KQuality.fast) Anime4KQuality quality,@JsonKey(unknownEnumValue: Anime4KMode.modeA) Anime4KMode mode +}); + + + + +} +/// @nodoc +class __$Anime4KConfigCopyWithImpl<$Res> + implements _$Anime4KConfigCopyWith<$Res> { + __$Anime4KConfigCopyWithImpl(this._self, this._then); + + final _Anime4KConfig _self; + final $Res Function(_Anime4KConfig) _then; + +/// Create a copy of Anime4KConfig +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? quality = null,Object? mode = null,}) { + return _then(_Anime4KConfig( +quality: null == quality ? _self.quality : quality // ignore: cast_nullable_to_non_nullable +as Anime4KQuality,mode: null == mode ? _self.mode : mode // ignore: cast_nullable_to_non_nullable +as Anime4KMode, + )); +} + + +} + + +/// @nodoc +mixin _$ArtCNNConfig { + +@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) ArtCNNModel get model;@JsonKey(unknownEnumValue: ArtCNNVariant.neutral) ArtCNNVariant get variant; +/// Create a copy of ArtCNNConfig +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ArtCNNConfigCopyWith get copyWith => _$ArtCNNConfigCopyWithImpl(this as ArtCNNConfig, _$identity); + + /// Serializes this ArtCNNConfig to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ArtCNNConfig&&(identical(other.model, model) || other.model == model)&&(identical(other.variant, variant) || other.variant == variant)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,model,variant); + +@override +String toString() { + return 'ArtCNNConfig(model: $model, variant: $variant)'; +} + + +} + +/// @nodoc +abstract mixin class $ArtCNNConfigCopyWith<$Res> { + factory $ArtCNNConfigCopyWith(ArtCNNConfig value, $Res Function(ArtCNNConfig) _then) = _$ArtCNNConfigCopyWithImpl; +@useResult +$Res call({ +@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) ArtCNNModel model,@JsonKey(unknownEnumValue: ArtCNNVariant.neutral) ArtCNNVariant variant +}); + + + + +} +/// @nodoc +class _$ArtCNNConfigCopyWithImpl<$Res> + implements $ArtCNNConfigCopyWith<$Res> { + _$ArtCNNConfigCopyWithImpl(this._self, this._then); + + final ArtCNNConfig _self; + final $Res Function(ArtCNNConfig) _then; + +/// Create a copy of ArtCNNConfig +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? model = null,Object? variant = null,}) { + return _then(_self.copyWith( +model: null == model ? _self.model : model // ignore: cast_nullable_to_non_nullable +as ArtCNNModel,variant: null == variant ? _self.variant : variant // ignore: cast_nullable_to_non_nullable +as ArtCNNVariant, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ArtCNNConfig]. +extension ArtCNNConfigPatterns on ArtCNNConfig { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _ArtCNNConfig value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ArtCNNConfig() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _ArtCNNConfig value) $default,){ +final _that = this; +switch (_that) { +case _ArtCNNConfig(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _ArtCNNConfig value)? $default,){ +final _that = this; +switch (_that) { +case _ArtCNNConfig() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function(@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) ArtCNNModel model, @JsonKey(unknownEnumValue: ArtCNNVariant.neutral) ArtCNNVariant variant)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ArtCNNConfig() when $default != null: +return $default(_that.model,_that.variant);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function(@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) ArtCNNModel model, @JsonKey(unknownEnumValue: ArtCNNVariant.neutral) ArtCNNVariant variant) $default,) {final _that = this; +switch (_that) { +case _ArtCNNConfig(): +return $default(_that.model,_that.variant);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function(@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) ArtCNNModel model, @JsonKey(unknownEnumValue: ArtCNNVariant.neutral) ArtCNNVariant variant)? $default,) {final _that = this; +switch (_that) { +case _ArtCNNConfig() when $default != null: +return $default(_that.model,_that.variant);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _ArtCNNConfig implements ArtCNNConfig { + const _ArtCNNConfig({@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) required this.model, @JsonKey(unknownEnumValue: ArtCNNVariant.neutral) required this.variant}); + factory _ArtCNNConfig.fromJson(Map json) => _$ArtCNNConfigFromJson(json); + +@override@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) final ArtCNNModel model; +@override@JsonKey(unknownEnumValue: ArtCNNVariant.neutral) final ArtCNNVariant variant; + +/// Create a copy of ArtCNNConfig +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ArtCNNConfigCopyWith<_ArtCNNConfig> get copyWith => __$ArtCNNConfigCopyWithImpl<_ArtCNNConfig>(this, _$identity); + +@override +Map toJson() { + return _$ArtCNNConfigToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ArtCNNConfig&&(identical(other.model, model) || other.model == model)&&(identical(other.variant, variant) || other.variant == variant)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,model,variant); + +@override +String toString() { + return 'ArtCNNConfig(model: $model, variant: $variant)'; +} + + +} + +/// @nodoc +abstract mixin class _$ArtCNNConfigCopyWith<$Res> implements $ArtCNNConfigCopyWith<$Res> { + factory _$ArtCNNConfigCopyWith(_ArtCNNConfig value, $Res Function(_ArtCNNConfig) _then) = __$ArtCNNConfigCopyWithImpl; +@override @useResult +$Res call({ +@JsonKey(unknownEnumValue: ArtCNNModel.c4f16) ArtCNNModel model,@JsonKey(unknownEnumValue: ArtCNNVariant.neutral) ArtCNNVariant variant +}); + + + + +} +/// @nodoc +class __$ArtCNNConfigCopyWithImpl<$Res> + implements _$ArtCNNConfigCopyWith<$Res> { + __$ArtCNNConfigCopyWithImpl(this._self, this._then); + + final _ArtCNNConfig _self; + final $Res Function(_ArtCNNConfig) _then; + +/// Create a copy of ArtCNNConfig +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? model = null,Object? variant = null,}) { + return _then(_ArtCNNConfig( +model: null == model ? _self.model : model // ignore: cast_nullable_to_non_nullable +as ArtCNNModel,variant: null == variant ? _self.variant : variant // ignore: cast_nullable_to_non_nullable +as ArtCNNVariant, + )); +} + + +} + + +/// @nodoc +mixin _$NVScalerConfig { + +/// Whether to automatically skip NVScaler on HDR content + bool get autoHdrSkip; +/// Create a copy of NVScalerConfig +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$NVScalerConfigCopyWith get copyWith => _$NVScalerConfigCopyWithImpl(this as NVScalerConfig, _$identity); + + /// Serializes this NVScalerConfig to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is NVScalerConfig&&(identical(other.autoHdrSkip, autoHdrSkip) || other.autoHdrSkip == autoHdrSkip)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,autoHdrSkip); + +@override +String toString() { + return 'NVScalerConfig(autoHdrSkip: $autoHdrSkip)'; +} + + +} + +/// @nodoc +abstract mixin class $NVScalerConfigCopyWith<$Res> { + factory $NVScalerConfigCopyWith(NVScalerConfig value, $Res Function(NVScalerConfig) _then) = _$NVScalerConfigCopyWithImpl; +@useResult +$Res call({ + bool autoHdrSkip +}); + + + + +} +/// @nodoc +class _$NVScalerConfigCopyWithImpl<$Res> + implements $NVScalerConfigCopyWith<$Res> { + _$NVScalerConfigCopyWithImpl(this._self, this._then); + + final NVScalerConfig _self; + final $Res Function(NVScalerConfig) _then; + +/// Create a copy of NVScalerConfig +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? autoHdrSkip = null,}) { + return _then(_self.copyWith( +autoHdrSkip: null == autoHdrSkip ? _self.autoHdrSkip : autoHdrSkip // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + +} + + +/// Adds pattern-matching-related methods to [NVScalerConfig]. +extension NVScalerConfigPatterns on NVScalerConfig { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _NVScalerConfig value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _NVScalerConfig() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _NVScalerConfig value) $default,){ +final _that = this; +switch (_that) { +case _NVScalerConfig(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _NVScalerConfig value)? $default,){ +final _that = this; +switch (_that) { +case _NVScalerConfig() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( bool autoHdrSkip)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _NVScalerConfig() when $default != null: +return $default(_that.autoHdrSkip);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( bool autoHdrSkip) $default,) {final _that = this; +switch (_that) { +case _NVScalerConfig(): +return $default(_that.autoHdrSkip);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( bool autoHdrSkip)? $default,) {final _that = this; +switch (_that) { +case _NVScalerConfig() when $default != null: +return $default(_that.autoHdrSkip);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _NVScalerConfig implements NVScalerConfig { + const _NVScalerConfig({this.autoHdrSkip = true}); + factory _NVScalerConfig.fromJson(Map json) => _$NVScalerConfigFromJson(json); + +/// Whether to automatically skip NVScaler on HDR content +@override@JsonKey() final bool autoHdrSkip; + +/// Create a copy of NVScalerConfig +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$NVScalerConfigCopyWith<_NVScalerConfig> get copyWith => __$NVScalerConfigCopyWithImpl<_NVScalerConfig>(this, _$identity); + +@override +Map toJson() { + return _$NVScalerConfigToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _NVScalerConfig&&(identical(other.autoHdrSkip, autoHdrSkip) || other.autoHdrSkip == autoHdrSkip)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,autoHdrSkip); + +@override +String toString() { + return 'NVScalerConfig(autoHdrSkip: $autoHdrSkip)'; +} + + +} + +/// @nodoc +abstract mixin class _$NVScalerConfigCopyWith<$Res> implements $NVScalerConfigCopyWith<$Res> { + factory _$NVScalerConfigCopyWith(_NVScalerConfig value, $Res Function(_NVScalerConfig) _then) = __$NVScalerConfigCopyWithImpl; +@override @useResult +$Res call({ + bool autoHdrSkip +}); + + + + +} +/// @nodoc +class __$NVScalerConfigCopyWithImpl<$Res> + implements _$NVScalerConfigCopyWith<$Res> { + __$NVScalerConfigCopyWithImpl(this._self, this._then); + + final _NVScalerConfig _self; + final $Res Function(_NVScalerConfig) _then; + +/// Create a copy of NVScalerConfig +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? autoHdrSkip = null,}) { + return _then(_NVScalerConfig( +autoHdrSkip: null == autoHdrSkip ? _self.autoHdrSkip : autoHdrSkip // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + +// dart format on diff --git a/lib/models/shader_preset.g.dart b/lib/models/shader_preset.g.dart new file mode 100644 index 00000000..f9fb074e --- /dev/null +++ b/lib/models/shader_preset.g.dart @@ -0,0 +1,78 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'shader_preset.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_Anime4KConfig _$Anime4KConfigFromJson(Map json) => + _Anime4KConfig( + quality: $enumDecode( + _$Anime4KQualityEnumMap, + json['quality'], + unknownValue: Anime4KQuality.fast, + ), + mode: $enumDecode( + _$Anime4KModeEnumMap, + json['mode'], + unknownValue: Anime4KMode.modeA, + ), + ); + +Map _$Anime4KConfigToJson(_Anime4KConfig instance) => + { + 'quality': _$Anime4KQualityEnumMap[instance.quality]!, + 'mode': _$Anime4KModeEnumMap[instance.mode]!, + }; + +const _$Anime4KQualityEnumMap = { + Anime4KQuality.fast: 'fast', + Anime4KQuality.hq: 'hq', +}; + +const _$Anime4KModeEnumMap = { + Anime4KMode.modeA: 'modeA', + Anime4KMode.modeB: 'modeB', + Anime4KMode.modeC: 'modeC', + Anime4KMode.modeAA: 'modeAA', + Anime4KMode.modeBB: 'modeBB', + Anime4KMode.modeCA: 'modeCA', +}; + +_ArtCNNConfig _$ArtCNNConfigFromJson(Map json) => + _ArtCNNConfig( + model: $enumDecode( + _$ArtCNNModelEnumMap, + json['model'], + unknownValue: ArtCNNModel.c4f16, + ), + variant: $enumDecode( + _$ArtCNNVariantEnumMap, + json['variant'], + unknownValue: ArtCNNVariant.neutral, + ), + ); + +Map _$ArtCNNConfigToJson(_ArtCNNConfig instance) => + { + 'model': _$ArtCNNModelEnumMap[instance.model]!, + 'variant': _$ArtCNNVariantEnumMap[instance.variant]!, + }; + +const _$ArtCNNModelEnumMap = { + ArtCNNModel.c4f16: 'c4f16', + ArtCNNModel.c4f32: 'c4f32', +}; + +const _$ArtCNNVariantEnumMap = { + ArtCNNVariant.neutral: 'neutral', + ArtCNNVariant.denoise: 'denoise', + ArtCNNVariant.denoiseSharpen: 'denoiseSharpen', +}; + +_NVScalerConfig _$NVScalerConfigFromJson(Map json) => + _NVScalerConfig(autoHdrSkip: json['autoHdrSkip'] as bool? ?? true); + +Map _$NVScalerConfigToJson(_NVScalerConfig instance) => + {'autoHdrSkip': instance.autoHdrSkip}; diff --git a/lib/models/trackers/device_code.dart b/lib/models/trackers/device_code.dart index f3798678..4b1fe1ff 100644 --- a/lib/models/trackers/device_code.dart +++ b/lib/models/trackers/device_code.dart @@ -1,52 +1,33 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'device_code.freezed.dart'; + /// Result of requesting a device code from an RFC 8628 authorization server. /// /// The user enters [userCode] at [verificationUrl]; the app polls the token /// endpoint with [deviceCode] every [interval] seconds until [expiresIn] /// seconds elapse. -class DeviceCode { - final String deviceCode; - final String userCode; - final String verificationUrl; +@freezed +sealed class DeviceCode with _$DeviceCode { + const factory DeviceCode({ + required String deviceCode, + required String userCode, + required String verificationUrl, + required int expiresIn, + required int interval, - /// URL with the code pre-filled (e.g. `https://trakt.tv/activate/ABC12345`) - /// when the provider supports it. Nullable — Simkl doesn't. - final String? verificationUrlComplete; - - final int expiresIn; - final int interval; - - const DeviceCode({ - required this.deviceCode, - required this.userCode, - required this.verificationUrl, - required this.expiresIn, - required this.interval, - this.verificationUrlComplete, - }); + /// URL with the code pre-filled (e.g. `https://trakt.tv/activate/ABC12345`) + /// when the provider supports it. Nullable — Simkl doesn't. + String? verificationUrlComplete, + }) = _DeviceCode; } /// Discriminated event emitted by a device-code poll loop. -sealed class DevicePollEvent { - const DevicePollEvent(); -} - -class DevicePollPending extends DevicePollEvent { - const DevicePollPending(); -} - -class DevicePollSlowDown extends DevicePollEvent { - const DevicePollSlowDown(); -} - -class DevicePollDenied extends DevicePollEvent { - const DevicePollDenied(); -} - -class DevicePollExpired extends DevicePollEvent { - const DevicePollExpired(); -} - -class DevicePollSuccess extends DevicePollEvent { - final Map tokenResponse; - const DevicePollSuccess(this.tokenResponse); +@freezed +sealed class DevicePollEvent with _$DevicePollEvent { + const factory DevicePollEvent.pending() = DevicePollPending; + const factory DevicePollEvent.slowDown() = DevicePollSlowDown; + const factory DevicePollEvent.denied() = DevicePollDenied; + const factory DevicePollEvent.expired() = DevicePollExpired; + const factory DevicePollEvent.success(Map tokenResponse) = DevicePollSuccess; } diff --git a/lib/models/trackers/device_code.freezed.dart b/lib/models/trackers/device_code.freezed.dart new file mode 100644 index 00000000..f8683ecd --- /dev/null +++ b/lib/models/trackers/device_code.freezed.dart @@ -0,0 +1,718 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'device_code.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$DeviceCode { + + String get deviceCode; String get userCode; String get verificationUrl; int get expiresIn; int get interval;/// URL with the code pre-filled (e.g. `https://trakt.tv/activate/ABC12345`) +/// when the provider supports it. Nullable — Simkl doesn't. + String? get verificationUrlComplete; +/// Create a copy of DeviceCode +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$DeviceCodeCopyWith get copyWith => _$DeviceCodeCopyWithImpl(this as DeviceCode, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DeviceCode&&(identical(other.deviceCode, deviceCode) || other.deviceCode == deviceCode)&&(identical(other.userCode, userCode) || other.userCode == userCode)&&(identical(other.verificationUrl, verificationUrl) || other.verificationUrl == verificationUrl)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.interval, interval) || other.interval == interval)&&(identical(other.verificationUrlComplete, verificationUrlComplete) || other.verificationUrlComplete == verificationUrlComplete)); +} + + +@override +int get hashCode => Object.hash(runtimeType,deviceCode,userCode,verificationUrl,expiresIn,interval,verificationUrlComplete); + +@override +String toString() { + return 'DeviceCode(deviceCode: $deviceCode, userCode: $userCode, verificationUrl: $verificationUrl, expiresIn: $expiresIn, interval: $interval, verificationUrlComplete: $verificationUrlComplete)'; +} + + +} + +/// @nodoc +abstract mixin class $DeviceCodeCopyWith<$Res> { + factory $DeviceCodeCopyWith(DeviceCode value, $Res Function(DeviceCode) _then) = _$DeviceCodeCopyWithImpl; +@useResult +$Res call({ + String deviceCode, String userCode, String verificationUrl, int expiresIn, int interval, String? verificationUrlComplete +}); + + + + +} +/// @nodoc +class _$DeviceCodeCopyWithImpl<$Res> + implements $DeviceCodeCopyWith<$Res> { + _$DeviceCodeCopyWithImpl(this._self, this._then); + + final DeviceCode _self; + final $Res Function(DeviceCode) _then; + +/// Create a copy of DeviceCode +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? deviceCode = null,Object? userCode = null,Object? verificationUrl = null,Object? expiresIn = null,Object? interval = null,Object? verificationUrlComplete = freezed,}) { + return _then(_self.copyWith( +deviceCode: null == deviceCode ? _self.deviceCode : deviceCode // ignore: cast_nullable_to_non_nullable +as String,userCode: null == userCode ? _self.userCode : userCode // ignore: cast_nullable_to_non_nullable +as String,verificationUrl: null == verificationUrl ? _self.verificationUrl : verificationUrl // ignore: cast_nullable_to_non_nullable +as String,expiresIn: null == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable +as int,interval: null == interval ? _self.interval : interval // ignore: cast_nullable_to_non_nullable +as int,verificationUrlComplete: freezed == verificationUrlComplete ? _self.verificationUrlComplete : verificationUrlComplete // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [DeviceCode]. +extension DeviceCodePatterns on DeviceCode { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _DeviceCode value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _DeviceCode() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _DeviceCode value) $default,){ +final _that = this; +switch (_that) { +case _DeviceCode(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _DeviceCode value)? $default,){ +final _that = this; +switch (_that) { +case _DeviceCode() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String deviceCode, String userCode, String verificationUrl, int expiresIn, int interval, String? verificationUrlComplete)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _DeviceCode() when $default != null: +return $default(_that.deviceCode,_that.userCode,_that.verificationUrl,_that.expiresIn,_that.interval,_that.verificationUrlComplete);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String deviceCode, String userCode, String verificationUrl, int expiresIn, int interval, String? verificationUrlComplete) $default,) {final _that = this; +switch (_that) { +case _DeviceCode(): +return $default(_that.deviceCode,_that.userCode,_that.verificationUrl,_that.expiresIn,_that.interval,_that.verificationUrlComplete);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String deviceCode, String userCode, String verificationUrl, int expiresIn, int interval, String? verificationUrlComplete)? $default,) {final _that = this; +switch (_that) { +case _DeviceCode() when $default != null: +return $default(_that.deviceCode,_that.userCode,_that.verificationUrl,_that.expiresIn,_that.interval,_that.verificationUrlComplete);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _DeviceCode implements DeviceCode { + const _DeviceCode({required this.deviceCode, required this.userCode, required this.verificationUrl, required this.expiresIn, required this.interval, this.verificationUrlComplete}); + + +@override final String deviceCode; +@override final String userCode; +@override final String verificationUrl; +@override final int expiresIn; +@override final int interval; +/// URL with the code pre-filled (e.g. `https://trakt.tv/activate/ABC12345`) +/// when the provider supports it. Nullable — Simkl doesn't. +@override final String? verificationUrlComplete; + +/// Create a copy of DeviceCode +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$DeviceCodeCopyWith<_DeviceCode> get copyWith => __$DeviceCodeCopyWithImpl<_DeviceCode>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _DeviceCode&&(identical(other.deviceCode, deviceCode) || other.deviceCode == deviceCode)&&(identical(other.userCode, userCode) || other.userCode == userCode)&&(identical(other.verificationUrl, verificationUrl) || other.verificationUrl == verificationUrl)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.interval, interval) || other.interval == interval)&&(identical(other.verificationUrlComplete, verificationUrlComplete) || other.verificationUrlComplete == verificationUrlComplete)); +} + + +@override +int get hashCode => Object.hash(runtimeType,deviceCode,userCode,verificationUrl,expiresIn,interval,verificationUrlComplete); + +@override +String toString() { + return 'DeviceCode(deviceCode: $deviceCode, userCode: $userCode, verificationUrl: $verificationUrl, expiresIn: $expiresIn, interval: $interval, verificationUrlComplete: $verificationUrlComplete)'; +} + + +} + +/// @nodoc +abstract mixin class _$DeviceCodeCopyWith<$Res> implements $DeviceCodeCopyWith<$Res> { + factory _$DeviceCodeCopyWith(_DeviceCode value, $Res Function(_DeviceCode) _then) = __$DeviceCodeCopyWithImpl; +@override @useResult +$Res call({ + String deviceCode, String userCode, String verificationUrl, int expiresIn, int interval, String? verificationUrlComplete +}); + + + + +} +/// @nodoc +class __$DeviceCodeCopyWithImpl<$Res> + implements _$DeviceCodeCopyWith<$Res> { + __$DeviceCodeCopyWithImpl(this._self, this._then); + + final _DeviceCode _self; + final $Res Function(_DeviceCode) _then; + +/// Create a copy of DeviceCode +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? deviceCode = null,Object? userCode = null,Object? verificationUrl = null,Object? expiresIn = null,Object? interval = null,Object? verificationUrlComplete = freezed,}) { + return _then(_DeviceCode( +deviceCode: null == deviceCode ? _self.deviceCode : deviceCode // ignore: cast_nullable_to_non_nullable +as String,userCode: null == userCode ? _self.userCode : userCode // ignore: cast_nullable_to_non_nullable +as String,verificationUrl: null == verificationUrl ? _self.verificationUrl : verificationUrl // ignore: cast_nullable_to_non_nullable +as String,expiresIn: null == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable +as int,interval: null == interval ? _self.interval : interval // ignore: cast_nullable_to_non_nullable +as int,verificationUrlComplete: freezed == verificationUrlComplete ? _self.verificationUrlComplete : verificationUrlComplete // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +/// @nodoc +mixin _$DevicePollEvent { + + + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DevicePollEvent); +} + + +@override +int get hashCode => runtimeType.hashCode; + +@override +String toString() { + return 'DevicePollEvent()'; +} + + +} + +/// @nodoc +class $DevicePollEventCopyWith<$Res> { +$DevicePollEventCopyWith(DevicePollEvent _, $Res Function(DevicePollEvent) __); +} + + +/// Adds pattern-matching-related methods to [DevicePollEvent]. +extension DevicePollEventPatterns on DevicePollEvent { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap({TResult Function( DevicePollPending value)? pending,TResult Function( DevicePollSlowDown value)? slowDown,TResult Function( DevicePollDenied value)? denied,TResult Function( DevicePollExpired value)? expired,TResult Function( DevicePollSuccess value)? success,required TResult orElse(),}){ +final _that = this; +switch (_that) { +case DevicePollPending() when pending != null: +return pending(_that);case DevicePollSlowDown() when slowDown != null: +return slowDown(_that);case DevicePollDenied() when denied != null: +return denied(_that);case DevicePollExpired() when expired != null: +return expired(_that);case DevicePollSuccess() when success != null: +return success(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map({required TResult Function( DevicePollPending value) pending,required TResult Function( DevicePollSlowDown value) slowDown,required TResult Function( DevicePollDenied value) denied,required TResult Function( DevicePollExpired value) expired,required TResult Function( DevicePollSuccess value) success,}){ +final _that = this; +switch (_that) { +case DevicePollPending(): +return pending(_that);case DevicePollSlowDown(): +return slowDown(_that);case DevicePollDenied(): +return denied(_that);case DevicePollExpired(): +return expired(_that);case DevicePollSuccess(): +return success(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull({TResult? Function( DevicePollPending value)? pending,TResult? Function( DevicePollSlowDown value)? slowDown,TResult? Function( DevicePollDenied value)? denied,TResult? Function( DevicePollExpired value)? expired,TResult? Function( DevicePollSuccess value)? success,}){ +final _that = this; +switch (_that) { +case DevicePollPending() when pending != null: +return pending(_that);case DevicePollSlowDown() when slowDown != null: +return slowDown(_that);case DevicePollDenied() when denied != null: +return denied(_that);case DevicePollExpired() when expired != null: +return expired(_that);case DevicePollSuccess() when success != null: +return success(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen({TResult Function()? pending,TResult Function()? slowDown,TResult Function()? denied,TResult Function()? expired,TResult Function( Map tokenResponse)? success,required TResult orElse(),}) {final _that = this; +switch (_that) { +case DevicePollPending() when pending != null: +return pending();case DevicePollSlowDown() when slowDown != null: +return slowDown();case DevicePollDenied() when denied != null: +return denied();case DevicePollExpired() when expired != null: +return expired();case DevicePollSuccess() when success != null: +return success(_that.tokenResponse);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when({required TResult Function() pending,required TResult Function() slowDown,required TResult Function() denied,required TResult Function() expired,required TResult Function( Map tokenResponse) success,}) {final _that = this; +switch (_that) { +case DevicePollPending(): +return pending();case DevicePollSlowDown(): +return slowDown();case DevicePollDenied(): +return denied();case DevicePollExpired(): +return expired();case DevicePollSuccess(): +return success(_that.tokenResponse);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull({TResult? Function()? pending,TResult? Function()? slowDown,TResult? Function()? denied,TResult? Function()? expired,TResult? Function( Map tokenResponse)? success,}) {final _that = this; +switch (_that) { +case DevicePollPending() when pending != null: +return pending();case DevicePollSlowDown() when slowDown != null: +return slowDown();case DevicePollDenied() when denied != null: +return denied();case DevicePollExpired() when expired != null: +return expired();case DevicePollSuccess() when success != null: +return success(_that.tokenResponse);case _: + return null; + +} +} + +} + +/// @nodoc + + +class DevicePollPending implements DevicePollEvent { + const DevicePollPending(); + + + + + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DevicePollPending); +} + + +@override +int get hashCode => runtimeType.hashCode; + +@override +String toString() { + return 'DevicePollEvent.pending()'; +} + + +} + +/// @nodoc +class $DevicePollPendingCopyWith<$Res> implements $DevicePollEventCopyWith<$Res> { +$DevicePollPendingCopyWith(DevicePollPending _, $Res Function(DevicePollPending) __); +} +/// @nodoc +class _$DevicePollPendingCopyWithImpl<$Res> + implements $DevicePollPendingCopyWith<$Res> { + _$DevicePollPendingCopyWithImpl(this._self, this._then); + + final DevicePollPending _self; + final $Res Function(DevicePollPending) _then; + + + + +} + +/// @nodoc + + +class DevicePollSlowDown implements DevicePollEvent { + const DevicePollSlowDown(); + + + + + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DevicePollSlowDown); +} + + +@override +int get hashCode => runtimeType.hashCode; + +@override +String toString() { + return 'DevicePollEvent.slowDown()'; +} + + +} + +/// @nodoc +class $DevicePollSlowDownCopyWith<$Res> implements $DevicePollEventCopyWith<$Res> { +$DevicePollSlowDownCopyWith(DevicePollSlowDown _, $Res Function(DevicePollSlowDown) __); +} +/// @nodoc +class _$DevicePollSlowDownCopyWithImpl<$Res> + implements $DevicePollSlowDownCopyWith<$Res> { + _$DevicePollSlowDownCopyWithImpl(this._self, this._then); + + final DevicePollSlowDown _self; + final $Res Function(DevicePollSlowDown) _then; + + + + +} + +/// @nodoc + + +class DevicePollDenied implements DevicePollEvent { + const DevicePollDenied(); + + + + + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DevicePollDenied); +} + + +@override +int get hashCode => runtimeType.hashCode; + +@override +String toString() { + return 'DevicePollEvent.denied()'; +} + + +} + +/// @nodoc +class $DevicePollDeniedCopyWith<$Res> implements $DevicePollEventCopyWith<$Res> { +$DevicePollDeniedCopyWith(DevicePollDenied _, $Res Function(DevicePollDenied) __); +} +/// @nodoc +class _$DevicePollDeniedCopyWithImpl<$Res> + implements $DevicePollDeniedCopyWith<$Res> { + _$DevicePollDeniedCopyWithImpl(this._self, this._then); + + final DevicePollDenied _self; + final $Res Function(DevicePollDenied) _then; + + + + +} + +/// @nodoc + + +class DevicePollExpired implements DevicePollEvent { + const DevicePollExpired(); + + + + + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DevicePollExpired); +} + + +@override +int get hashCode => runtimeType.hashCode; + +@override +String toString() { + return 'DevicePollEvent.expired()'; +} + + +} + +/// @nodoc +class $DevicePollExpiredCopyWith<$Res> implements $DevicePollEventCopyWith<$Res> { +$DevicePollExpiredCopyWith(DevicePollExpired _, $Res Function(DevicePollExpired) __); +} +/// @nodoc +class _$DevicePollExpiredCopyWithImpl<$Res> + implements $DevicePollExpiredCopyWith<$Res> { + _$DevicePollExpiredCopyWithImpl(this._self, this._then); + + final DevicePollExpired _self; + final $Res Function(DevicePollExpired) _then; + + + + +} + +/// @nodoc + + +class DevicePollSuccess implements DevicePollEvent { + const DevicePollSuccess(final Map tokenResponse): _tokenResponse = tokenResponse; + + + final Map _tokenResponse; + Map get tokenResponse { + if (_tokenResponse is EqualUnmodifiableMapView) return _tokenResponse; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_tokenResponse); +} + + +/// Create a copy of DevicePollEvent +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$DevicePollSuccessCopyWith get copyWith => _$DevicePollSuccessCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is DevicePollSuccess&&const DeepCollectionEquality().equals(other._tokenResponse, _tokenResponse)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_tokenResponse)); + +@override +String toString() { + return 'DevicePollEvent.success(tokenResponse: $tokenResponse)'; +} + + +} + +/// @nodoc +abstract mixin class $DevicePollSuccessCopyWith<$Res> implements $DevicePollEventCopyWith<$Res> { + factory $DevicePollSuccessCopyWith(DevicePollSuccess value, $Res Function(DevicePollSuccess) _then) = _$DevicePollSuccessCopyWithImpl; +@useResult +$Res call({ + Map tokenResponse +}); + + + + +} +/// @nodoc +class _$DevicePollSuccessCopyWithImpl<$Res> + implements $DevicePollSuccessCopyWith<$Res> { + _$DevicePollSuccessCopyWithImpl(this._self, this._then); + + final DevicePollSuccess _self; + final $Res Function(DevicePollSuccess) _then; + +/// Create a copy of DevicePollEvent +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') $Res call({Object? tokenResponse = null,}) { + return _then(DevicePollSuccess( +null == tokenResponse ? _self._tokenResponse : tokenResponse // ignore: cast_nullable_to_non_nullable +as Map, + )); +} + + +} + +// dart format on diff --git a/lib/models/trackers/fribb_mapping_row.dart b/lib/models/trackers/fribb_mapping_row.dart index 01cb87df..9a2a0d5b 100644 --- a/lib/models/trackers/fribb_mapping_row.dart +++ b/lib/models/trackers/fribb_mapping_row.dart @@ -1,16 +1,42 @@ +// ignore_for_file: invalid_annotation_target +import 'package:json_annotation/json_annotation.dart'; + +import '../../utils/json_utils.dart'; + +part 'fribb_mapping_row.g.dart'; + +Object? _readTvdbSeason(Map json, String key) { + final season = json['season']; + return season is Map ? season['tvdb'] : null; +} + +Object? _readTmdbSeason(Map json, String key) { + final season = json['season']; + return season is Map ? season['tmdb'] : null; +} + /// One row from `anime-list-mini.json` (Fribb/anime-lists). +@JsonSerializable(createToJson: false) class FribbMappingRow { + @JsonKey(name: 'anilist_id', fromJson: flexibleInt) final int? anilistId; + @JsonKey(name: 'imdb_id') final String? imdbId; + @JsonKey(name: 'mal_id', fromJson: flexibleInt) final int? malId; + @JsonKey(name: 'simkl_id', fromJson: flexibleInt) final int? simklId; + @JsonKey(name: 'themoviedb_id', fromJson: flexibleInt) final int? tmdbId; + @JsonKey(name: 'tvdb_id', fromJson: flexibleInt) final int? tvdbId; /// Plex season number this mapping corresponds to. A single show-level /// external ID can resolve to multiple rows for split-cour anime; the /// resolver picks by matching the episode's `parentIndex` against these. + @JsonKey(readValue: _readTvdbSeason, fromJson: flexibleInt) final int? tvdbSeason; + @JsonKey(readValue: _readTmdbSeason, fromJson: flexibleInt) final int? tmdbSeason; /// `TV` / `MOVIE` / `OVA` / `ONA` / `SPECIAL` / `UNKNOWN` / `null`. @@ -30,24 +56,5 @@ class FribbMappingRow { bool get isMovie => type == 'MOVIE'; - factory FribbMappingRow.fromJson(Map json) { - final season = json['season']; - int? tvdbSeason; - int? tmdbSeason; - if (season is Map) { - tvdbSeason = (season['tvdb'] as num?)?.toInt(); - tmdbSeason = (season['tmdb'] as num?)?.toInt(); - } - return FribbMappingRow( - anilistId: (json['anilist_id'] as num?)?.toInt(), - imdbId: json['imdb_id'] as String?, - malId: (json['mal_id'] as num?)?.toInt(), - simklId: (json['simkl_id'] as num?)?.toInt(), - tmdbId: (json['themoviedb_id'] as num?)?.toInt(), - tvdbId: (json['tvdb_id'] as num?)?.toInt(), - tvdbSeason: tvdbSeason, - tmdbSeason: tmdbSeason, - type: json['type'] as String?, - ); - } + factory FribbMappingRow.fromJson(Map json) => _$FribbMappingRowFromJson(json); } diff --git a/lib/models/trackers/fribb_mapping_row.g.dart b/lib/models/trackers/fribb_mapping_row.g.dart new file mode 100644 index 00000000..832505e5 --- /dev/null +++ b/lib/models/trackers/fribb_mapping_row.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'fribb_mapping_row.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FribbMappingRow _$FribbMappingRowFromJson(Map json) => + FribbMappingRow( + anilistId: flexibleInt(json['anilist_id']), + imdbId: json['imdb_id'] as String?, + malId: flexibleInt(json['mal_id']), + simklId: flexibleInt(json['simkl_id']), + tmdbId: flexibleInt(json['themoviedb_id']), + tvdbId: flexibleInt(json['tvdb_id']), + tvdbSeason: flexibleInt(_readTvdbSeason(json, 'tvdbSeason')), + tmdbSeason: flexibleInt(_readTmdbSeason(json, 'tmdbSeason')), + type: json['type'] as String?, + ); diff --git a/lib/models/trakt/trakt_scrobble_request.dart b/lib/models/trakt/trakt_scrobble_request.dart index 9b243f84..d15b8d8a 100644 --- a/lib/models/trakt/trakt_scrobble_request.dart +++ b/lib/models/trakt/trakt_scrobble_request.dart @@ -1,110 +1,94 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + import 'trakt_ids.dart'; +part 'trakt_scrobble_request.freezed.dart'; + /// Body for `POST /scrobble/{start|pause|stop}` and `POST /sync/history`. /// /// Either movie IDs or show IDs + season/episode are set, never both. /// [progress] is the percent (0–100) for scrobble; ignored for `/sync/history`. -class TraktScrobbleRequest { - final TraktIds? _movieIds; - final TraktIds? _showIds; - final int? _season; - final int? _episode; - final double? progress; - - const TraktScrobbleRequest._({TraktIds? movieIds, TraktIds? showIds, int? season, int? episode, this.progress}) - : _movieIds = movieIds, - _showIds = showIds, - _season = season, - _episode = episode; - - bool get isMovie => _movieIds != null; - bool get isEpisode => _showIds != null; - - TraktScrobbleRequest copyWith({double? progress}) => TraktScrobbleRequest._( - movieIds: _movieIds, - showIds: _showIds, - season: _season, - episode: _episode, - progress: progress ?? this.progress, - ); +@freezed +sealed class TraktScrobbleRequest with _$TraktScrobbleRequest { + const TraktScrobbleRequest._(); /// Build a movie scrobble payload. - factory TraktScrobbleRequest.movie({required TraktIds ids, double? progress}) { - return TraktScrobbleRequest._(movieIds: ids, progress: progress); - } + const factory TraktScrobbleRequest.movie({required TraktIds ids, double? progress}) = TraktScrobbleMovieRequest; /// Build an episode scrobble payload using the show's external IDs plus /// season/episode index. Trakt prefers this shape over an episode-IDs-only /// payload because it works even when the episode itself isn't in Trakt's /// catalog yet. - factory TraktScrobbleRequest.episode({ + const factory TraktScrobbleRequest.episode({ required TraktIds showIds, required int season, required int number, double? progress, - }) { - return TraktScrobbleRequest._(showIds: showIds, season: season, episode: number, progress: progress); - } + }) = TraktScrobbleEpisodeRequest; - Map toJson() => { - if (_movieIds != null) 'movie': {'ids': _movieIds.toJson()}, - if (_showIds != null) 'show': {'ids': _showIds.toJson()}, - if (_season != null && _episode != null) 'episode': {'season': _season, 'number': _episode}, - 'progress': ?progress, + bool get isMovie => this is TraktScrobbleMovieRequest; + bool get isEpisode => this is TraktScrobbleEpisodeRequest; + + Map toJson() => switch (this) { + TraktScrobbleMovieRequest(:final ids, :final progress) => { + 'movie': {'ids': ids.toJson()}, + 'progress': ?progress, + }, + TraktScrobbleEpisodeRequest(:final showIds, :final season, :final number, :final progress) => { + 'show': {'ids': showIds.toJson()}, + 'episode': {'season': season, 'number': number}, + 'progress': ?progress, + }, }; /// Build a `POST /sync/history` body that adds this item to history. /// /// Optional [watchedAt] (ISO-8601 UTC) lets the server attribute the play /// to a specific point in time; defaults to "now" on Trakt's side. - Map toHistoryAddBody({String? watchedAt}) { - if (isMovie) { - return { - 'movies': [ - {'watched_at': ?watchedAt, 'ids': _movieIds!.toJson()}, - ], - }; - } - return { + Map toHistoryAddBody({String? watchedAt}) => switch (this) { + TraktScrobbleMovieRequest(:final ids) => { + 'movies': [ + {'watched_at': ?watchedAt, 'ids': ids.toJson()}, + ], + }, + TraktScrobbleEpisodeRequest(:final showIds, :final season, :final number) => { 'shows': [ { - 'ids': _showIds!.toJson(), + 'ids': showIds.toJson(), 'seasons': [ { - 'number': _season, + 'number': season, 'episodes': [ - {'watched_at': ?watchedAt, 'number': _episode}, + {'watched_at': ?watchedAt, 'number': number}, ], }, ], }, ], - }; - } + }, + }; /// Build a `POST /sync/history/remove` body that removes this item from history. - Map toHistoryRemoveBody() { - if (isMovie) { - return { - 'movies': [ - {'ids': _movieIds!.toJson()}, - ], - }; - } - return { + Map toHistoryRemoveBody() => switch (this) { + TraktScrobbleMovieRequest(:final ids) => { + 'movies': [ + {'ids': ids.toJson()}, + ], + }, + TraktScrobbleEpisodeRequest(:final showIds, :final season, :final number) => { 'shows': [ { - 'ids': _showIds!.toJson(), + 'ids': showIds.toJson(), 'seasons': [ { - 'number': _season, + 'number': season, 'episodes': [ - {'number': _episode}, + {'number': number}, ], }, ], }, ], - }; - } + }, + }; } diff --git a/lib/models/trakt/trakt_scrobble_request.freezed.dart b/lib/models/trakt/trakt_scrobble_request.freezed.dart new file mode 100644 index 00000000..c1d1531c --- /dev/null +++ b/lib/models/trakt/trakt_scrobble_request.freezed.dart @@ -0,0 +1,345 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'trakt_scrobble_request.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$TraktScrobbleRequest { + + double? get progress; +/// Create a copy of TraktScrobbleRequest +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TraktScrobbleRequestCopyWith get copyWith => _$TraktScrobbleRequestCopyWithImpl(this as TraktScrobbleRequest, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TraktScrobbleRequest&&(identical(other.progress, progress) || other.progress == progress)); +} + + +@override +int get hashCode => Object.hash(runtimeType,progress); + +@override +String toString() { + return 'TraktScrobbleRequest(progress: $progress)'; +} + + +} + +/// @nodoc +abstract mixin class $TraktScrobbleRequestCopyWith<$Res> { + factory $TraktScrobbleRequestCopyWith(TraktScrobbleRequest value, $Res Function(TraktScrobbleRequest) _then) = _$TraktScrobbleRequestCopyWithImpl; +@useResult +$Res call({ + double? progress +}); + + + + +} +/// @nodoc +class _$TraktScrobbleRequestCopyWithImpl<$Res> + implements $TraktScrobbleRequestCopyWith<$Res> { + _$TraktScrobbleRequestCopyWithImpl(this._self, this._then); + + final TraktScrobbleRequest _self; + final $Res Function(TraktScrobbleRequest) _then; + +/// Create a copy of TraktScrobbleRequest +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? progress = freezed,}) { + return _then(_self.copyWith( +progress: freezed == progress ? _self.progress : progress // ignore: cast_nullable_to_non_nullable +as double?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [TraktScrobbleRequest]. +extension TraktScrobbleRequestPatterns on TraktScrobbleRequest { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap({TResult Function( TraktScrobbleMovieRequest value)? movie,TResult Function( TraktScrobbleEpisodeRequest value)? episode,required TResult orElse(),}){ +final _that = this; +switch (_that) { +case TraktScrobbleMovieRequest() when movie != null: +return movie(_that);case TraktScrobbleEpisodeRequest() when episode != null: +return episode(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map({required TResult Function( TraktScrobbleMovieRequest value) movie,required TResult Function( TraktScrobbleEpisodeRequest value) episode,}){ +final _that = this; +switch (_that) { +case TraktScrobbleMovieRequest(): +return movie(_that);case TraktScrobbleEpisodeRequest(): +return episode(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull({TResult? Function( TraktScrobbleMovieRequest value)? movie,TResult? Function( TraktScrobbleEpisodeRequest value)? episode,}){ +final _that = this; +switch (_that) { +case TraktScrobbleMovieRequest() when movie != null: +return movie(_that);case TraktScrobbleEpisodeRequest() when episode != null: +return episode(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen({TResult Function( TraktIds ids, double? progress)? movie,TResult Function( TraktIds showIds, int season, int number, double? progress)? episode,required TResult orElse(),}) {final _that = this; +switch (_that) { +case TraktScrobbleMovieRequest() when movie != null: +return movie(_that.ids,_that.progress);case TraktScrobbleEpisodeRequest() when episode != null: +return episode(_that.showIds,_that.season,_that.number,_that.progress);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when({required TResult Function( TraktIds ids, double? progress) movie,required TResult Function( TraktIds showIds, int season, int number, double? progress) episode,}) {final _that = this; +switch (_that) { +case TraktScrobbleMovieRequest(): +return movie(_that.ids,_that.progress);case TraktScrobbleEpisodeRequest(): +return episode(_that.showIds,_that.season,_that.number,_that.progress);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull({TResult? Function( TraktIds ids, double? progress)? movie,TResult? Function( TraktIds showIds, int season, int number, double? progress)? episode,}) {final _that = this; +switch (_that) { +case TraktScrobbleMovieRequest() when movie != null: +return movie(_that.ids,_that.progress);case TraktScrobbleEpisodeRequest() when episode != null: +return episode(_that.showIds,_that.season,_that.number,_that.progress);case _: + return null; + +} +} + +} + +/// @nodoc + + +class TraktScrobbleMovieRequest extends TraktScrobbleRequest { + const TraktScrobbleMovieRequest({required this.ids, this.progress}): super._(); + + + final TraktIds ids; +@override final double? progress; + +/// Create a copy of TraktScrobbleRequest +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TraktScrobbleMovieRequestCopyWith get copyWith => _$TraktScrobbleMovieRequestCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TraktScrobbleMovieRequest&&(identical(other.ids, ids) || other.ids == ids)&&(identical(other.progress, progress) || other.progress == progress)); +} + + +@override +int get hashCode => Object.hash(runtimeType,ids,progress); + +@override +String toString() { + return 'TraktScrobbleRequest.movie(ids: $ids, progress: $progress)'; +} + + +} + +/// @nodoc +abstract mixin class $TraktScrobbleMovieRequestCopyWith<$Res> implements $TraktScrobbleRequestCopyWith<$Res> { + factory $TraktScrobbleMovieRequestCopyWith(TraktScrobbleMovieRequest value, $Res Function(TraktScrobbleMovieRequest) _then) = _$TraktScrobbleMovieRequestCopyWithImpl; +@override @useResult +$Res call({ + TraktIds ids, double? progress +}); + + + + +} +/// @nodoc +class _$TraktScrobbleMovieRequestCopyWithImpl<$Res> + implements $TraktScrobbleMovieRequestCopyWith<$Res> { + _$TraktScrobbleMovieRequestCopyWithImpl(this._self, this._then); + + final TraktScrobbleMovieRequest _self; + final $Res Function(TraktScrobbleMovieRequest) _then; + +/// Create a copy of TraktScrobbleRequest +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? ids = null,Object? progress = freezed,}) { + return _then(TraktScrobbleMovieRequest( +ids: null == ids ? _self.ids : ids // ignore: cast_nullable_to_non_nullable +as TraktIds,progress: freezed == progress ? _self.progress : progress // ignore: cast_nullable_to_non_nullable +as double?, + )); +} + + +} + +/// @nodoc + + +class TraktScrobbleEpisodeRequest extends TraktScrobbleRequest { + const TraktScrobbleEpisodeRequest({required this.showIds, required this.season, required this.number, this.progress}): super._(); + + + final TraktIds showIds; + final int season; + final int number; +@override final double? progress; + +/// Create a copy of TraktScrobbleRequest +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TraktScrobbleEpisodeRequestCopyWith get copyWith => _$TraktScrobbleEpisodeRequestCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TraktScrobbleEpisodeRequest&&(identical(other.showIds, showIds) || other.showIds == showIds)&&(identical(other.season, season) || other.season == season)&&(identical(other.number, number) || other.number == number)&&(identical(other.progress, progress) || other.progress == progress)); +} + + +@override +int get hashCode => Object.hash(runtimeType,showIds,season,number,progress); + +@override +String toString() { + return 'TraktScrobbleRequest.episode(showIds: $showIds, season: $season, number: $number, progress: $progress)'; +} + + +} + +/// @nodoc +abstract mixin class $TraktScrobbleEpisodeRequestCopyWith<$Res> implements $TraktScrobbleRequestCopyWith<$Res> { + factory $TraktScrobbleEpisodeRequestCopyWith(TraktScrobbleEpisodeRequest value, $Res Function(TraktScrobbleEpisodeRequest) _then) = _$TraktScrobbleEpisodeRequestCopyWithImpl; +@override @useResult +$Res call({ + TraktIds showIds, int season, int number, double? progress +}); + + + + +} +/// @nodoc +class _$TraktScrobbleEpisodeRequestCopyWithImpl<$Res> + implements $TraktScrobbleEpisodeRequestCopyWith<$Res> { + _$TraktScrobbleEpisodeRequestCopyWithImpl(this._self, this._then); + + final TraktScrobbleEpisodeRequest _self; + final $Res Function(TraktScrobbleEpisodeRequest) _then; + +/// Create a copy of TraktScrobbleRequest +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? showIds = null,Object? season = null,Object? number = null,Object? progress = freezed,}) { + return _then(TraktScrobbleEpisodeRequest( +showIds: null == showIds ? _self.showIds : showIds // ignore: cast_nullable_to_non_nullable +as TraktIds,season: null == season ? _self.season : season // ignore: cast_nullable_to_non_nullable +as int,number: null == number ? _self.number : number // ignore: cast_nullable_to_non_nullable +as int,progress: freezed == progress ? _self.progress : progress // ignore: cast_nullable_to_non_nullable +as double?, + )); +} + + +} + +// dart format on diff --git a/lib/models/trakt/trakt_user.dart b/lib/models/trakt/trakt_user.dart index bd023b72..4d0f283d 100644 --- a/lib/models/trakt/trakt_user.dart +++ b/lib/models/trakt/trakt_user.dart @@ -1,4 +1,9 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'trakt_user.g.dart'; + /// Minimal Trakt user info parsed from `GET /users/settings`. +@JsonSerializable(createToJson: false) class TraktUser { final String username; final String? name; @@ -10,6 +15,6 @@ class TraktUser { if (user == null) { throw const FormatException('Trakt /users/settings response missing "user" field'); } - return TraktUser(username: user['username'] as String, name: user['name'] as String?); + return _$TraktUserFromJson(user); } } diff --git a/lib/models/trakt/trakt_user.g.dart b/lib/models/trakt/trakt_user.g.dart new file mode 100644 index 00000000..6aa1d496 --- /dev/null +++ b/lib/models/trakt/trakt_user.g.dart @@ -0,0 +1,12 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'trakt_user.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TraktUser _$TraktUserFromJson(Map json) => TraktUser( + username: json['username'] as String, + name: json['name'] as String?, +); diff --git a/lib/mpv/models.dart b/lib/mpv/models.dart index d0376a56..d692ab3a 100644 --- a/lib/mpv/models.dart +++ b/lib/mpv/models.dart @@ -1,95 +1,77 @@ -class BufferRange { - final Duration start; - final Duration end; - const BufferRange({required this.start, required this.end}); +// ignore_for_file: invalid_annotation_target +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'models.freezed.dart'; + +@freezed +sealed class BufferRange with _$BufferRange { + const factory BufferRange({required Duration start, required Duration end}) = _BufferRange; } /// [cause] is an optional machine-readable tag (e.g. `server-http-500`), /// letting the UI branch without parsing [message]. -class PlayerError { +@Freezed(toStringOverride: false) +sealed class PlayerError with _$PlayerError { + const PlayerError._(); + + const factory PlayerError(String message, {String? cause}) = _PlayerError; + /// Cause tag for a server-side HTTP 500 — shared-user bandwidth or /// transcoding limit rejection set by the server owner. static const String serverHttp500 = 'server-http-500'; - final String message; - final String? cause; - const PlayerError(this.message, {this.cause}); - @override String toString() => message; } enum PlayerLogLevel { none, fatal, error, warn, info, verbose, debug, trace } -class AudioTrack { - final String id; - final String? title; - final String? language; - final String? codec; - final int? channels; - int? get channelsCount => channels; - final int? sampleRate; - final int? bitrate; - final bool isDefault; - final bool isForced; +@freezed +sealed class AudioTrack with _$AudioTrack { + const AudioTrack._(); - const AudioTrack({ - required this.id, - this.title, - this.language, - this.codec, - this.channels, - this.sampleRate, - this.bitrate, - this.isDefault = false, - this.isForced = false, - }); + const factory AudioTrack({ + required String id, + String? title, + String? language, + String? codec, + int? channels, + int? sampleRate, + int? bitrate, + @Default(false) bool isDefault, + @Default(false) bool isForced, + }) = _AudioTrack; static const auto = AudioTrack(id: 'auto', title: 'Auto'); static const off = AudioTrack(id: 'no', title: 'Off'); + int? get channelsCount => channels; + String get displayName { if (title != null && title!.isNotEmpty) return title!; if (language != null && language!.isNotEmpty) return language!; return 'Track $id'; } - - @override - String toString() => 'AudioTrack($id, $displayName)'; - - @override - bool operator ==(Object other) => - identical(this, other) || other is AudioTrack && runtimeType == other.runtimeType && id == other.id; - - @override - int get hashCode => id.hashCode; } -class SubtitleTrack { - final String id; - final String? title; - final String? language; - final String? codec; - final bool isDefault; - final bool isForced; - final bool isExternal; - final String? uri; +@freezed +sealed class SubtitleTrack with _$SubtitleTrack { + const SubtitleTrack._(); - const SubtitleTrack({ - required this.id, - this.title, - this.language, - this.codec, - this.isDefault = false, - this.isForced = false, - this.isExternal = false, - this.uri, - }); + const factory SubtitleTrack({ + required String id, + String? title, + String? language, + String? codec, + @Default(false) bool isDefault, + @Default(false) bool isForced, + @Default(false) bool isExternal, + String? uri, + }) = _SubtitleTrack; - factory SubtitleTrack.uri(String uri, {String? title, String? language}) { - return SubtitleTrack(id: 'external:$uri', title: title, language: language, isExternal: true, uri: uri); - } + factory SubtitleTrack.uri(String uri, {String? title, String? language}) => + SubtitleTrack(id: 'external:$uri', title: title, language: language, isExternal: true, uri: uri); static const auto = SubtitleTrack(id: 'auto', title: 'Auto'); @@ -101,103 +83,45 @@ class SubtitleTrack { if (isExternal) return 'External'; return 'Track $id'; } - - @override - String toString() => 'SubtitleTrack($id, $displayName)'; - - @override - bool operator ==(Object other) => - identical(this, other) || other is SubtitleTrack && runtimeType == other.runtimeType && id == other.id; - - @override - int get hashCode => id.hashCode; } -class Tracks { - final List audio; - final List subtitle; +@Freezed(toStringOverride: false) +sealed class Tracks with _$Tracks { + const Tracks._(); - const Tracks({this.audio = const [], this.subtitle = const []}); - - Tracks copyWith({List? audio, List? subtitle}) { - return Tracks(audio: audio ?? this.audio, subtitle: subtitle ?? this.subtitle); - } + const factory Tracks({ + @Default([]) List audio, + @Default([]) List subtitle, + }) = _Tracks; @override String toString() => 'Tracks(audio: ${audio.length}, subtitle: ${subtitle.length})'; } -/// Sentinel value used to distinguish "not provided" from "explicitly set to null" in copyWith. -const _sentinel = Object(); - -class TrackSelection { - final AudioTrack? audio; - final SubtitleTrack? subtitle; - final SubtitleTrack? secondarySubtitle; - - const TrackSelection({this.audio, this.subtitle, this.secondarySubtitle}); - - /// Creates a copy with the given fields replaced. - /// Use [secondarySubtitle] with explicit null to clear the secondary subtitle. - TrackSelection copyWith({AudioTrack? audio, SubtitleTrack? subtitle, Object? secondarySubtitle = _sentinel}) { - return TrackSelection( - audio: audio ?? this.audio, - subtitle: subtitle ?? this.subtitle, - secondarySubtitle: identical(secondarySubtitle, _sentinel) - ? this.secondarySubtitle - : secondarySubtitle as SubtitleTrack?, - ); - } - - @override - String toString() => 'TrackSelection(audio: $audio, subtitle: $subtitle, secondarySubtitle: $secondarySubtitle)'; +@freezed +sealed class TrackSelection with _$TrackSelection { + const factory TrackSelection({AudioTrack? audio, SubtitleTrack? subtitle, SubtitleTrack? secondarySubtitle}) = + _TrackSelection; } -class AudioDevice { - final String name; - final String description; - - const AudioDevice({required this.name, this.description = ''}); +@freezed +sealed class AudioDevice with _$AudioDevice { + const factory AudioDevice({required String name, @Default('') String description}) = _AudioDevice; static const auto = AudioDevice(name: 'auto', description: 'Auto'); - - @override - String toString() => 'AudioDevice($name, $description)'; - - @override - bool operator ==(Object other) => - identical(this, other) || other is AudioDevice && runtimeType == other.runtimeType && name == other.name; - - @override - int get hashCode => name.hashCode; } -class PlayerLog { - final PlayerLogLevel level; - final String prefix; - final String text; +@Freezed(toStringOverride: false) +sealed class PlayerLog with _$PlayerLog { + const PlayerLog._(); - const PlayerLog({required this.level, required this.prefix, required this.text}); + const factory PlayerLog({required PlayerLogLevel level, required String prefix, required String text}) = _PlayerLog; @override String toString() => '[$prefix] ${level.name}: $text'; } -class Media { - final String uri; - final Map? headers; - final Duration? start; - - const Media(this.uri, {this.headers, this.start}); - - @override - String toString() => 'Media($uri)'; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Media && runtimeType == other.runtimeType && uri == other.uri && start == other.start; - - @override - int get hashCode => uri.hashCode ^ start.hashCode; +@freezed +sealed class Media with _$Media { + const factory Media(String uri, {Map? headers, Duration? start}) = _Media; } diff --git a/lib/mpv/models.freezed.dart b/lib/mpv/models.freezed.dart new file mode 100644 index 00000000..c91ea6a1 --- /dev/null +++ b/lib/mpv/models.freezed.dart @@ -0,0 +1,2416 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'models.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$BufferRange { + + Duration get start; Duration get end; +/// Create a copy of BufferRange +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$BufferRangeCopyWith get copyWith => _$BufferRangeCopyWithImpl(this as BufferRange, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is BufferRange&&(identical(other.start, start) || other.start == start)&&(identical(other.end, end) || other.end == end)); +} + + +@override +int get hashCode => Object.hash(runtimeType,start,end); + +@override +String toString() { + return 'BufferRange(start: $start, end: $end)'; +} + + +} + +/// @nodoc +abstract mixin class $BufferRangeCopyWith<$Res> { + factory $BufferRangeCopyWith(BufferRange value, $Res Function(BufferRange) _then) = _$BufferRangeCopyWithImpl; +@useResult +$Res call({ + Duration start, Duration end +}); + + + + +} +/// @nodoc +class _$BufferRangeCopyWithImpl<$Res> + implements $BufferRangeCopyWith<$Res> { + _$BufferRangeCopyWithImpl(this._self, this._then); + + final BufferRange _self; + final $Res Function(BufferRange) _then; + +/// Create a copy of BufferRange +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? start = null,Object? end = null,}) { + return _then(_self.copyWith( +start: null == start ? _self.start : start // ignore: cast_nullable_to_non_nullable +as Duration,end: null == end ? _self.end : end // ignore: cast_nullable_to_non_nullable +as Duration, + )); +} + +} + + +/// Adds pattern-matching-related methods to [BufferRange]. +extension BufferRangePatterns on BufferRange { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _BufferRange value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _BufferRange() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _BufferRange value) $default,){ +final _that = this; +switch (_that) { +case _BufferRange(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _BufferRange value)? $default,){ +final _that = this; +switch (_that) { +case _BufferRange() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( Duration start, Duration end)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _BufferRange() when $default != null: +return $default(_that.start,_that.end);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( Duration start, Duration end) $default,) {final _that = this; +switch (_that) { +case _BufferRange(): +return $default(_that.start,_that.end);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( Duration start, Duration end)? $default,) {final _that = this; +switch (_that) { +case _BufferRange() when $default != null: +return $default(_that.start,_that.end);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _BufferRange implements BufferRange { + const _BufferRange({required this.start, required this.end}); + + +@override final Duration start; +@override final Duration end; + +/// Create a copy of BufferRange +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$BufferRangeCopyWith<_BufferRange> get copyWith => __$BufferRangeCopyWithImpl<_BufferRange>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _BufferRange&&(identical(other.start, start) || other.start == start)&&(identical(other.end, end) || other.end == end)); +} + + +@override +int get hashCode => Object.hash(runtimeType,start,end); + +@override +String toString() { + return 'BufferRange(start: $start, end: $end)'; +} + + +} + +/// @nodoc +abstract mixin class _$BufferRangeCopyWith<$Res> implements $BufferRangeCopyWith<$Res> { + factory _$BufferRangeCopyWith(_BufferRange value, $Res Function(_BufferRange) _then) = __$BufferRangeCopyWithImpl; +@override @useResult +$Res call({ + Duration start, Duration end +}); + + + + +} +/// @nodoc +class __$BufferRangeCopyWithImpl<$Res> + implements _$BufferRangeCopyWith<$Res> { + __$BufferRangeCopyWithImpl(this._self, this._then); + + final _BufferRange _self; + final $Res Function(_BufferRange) _then; + +/// Create a copy of BufferRange +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? start = null,Object? end = null,}) { + return _then(_BufferRange( +start: null == start ? _self.start : start // ignore: cast_nullable_to_non_nullable +as Duration,end: null == end ? _self.end : end // ignore: cast_nullable_to_non_nullable +as Duration, + )); +} + + +} + +/// @nodoc +mixin _$PlayerError { + + String get message; String? get cause; +/// Create a copy of PlayerError +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$PlayerErrorCopyWith get copyWith => _$PlayerErrorCopyWithImpl(this as PlayerError, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is PlayerError&&(identical(other.message, message) || other.message == message)&&(identical(other.cause, cause) || other.cause == cause)); +} + + +@override +int get hashCode => Object.hash(runtimeType,message,cause); + + + +} + +/// @nodoc +abstract mixin class $PlayerErrorCopyWith<$Res> { + factory $PlayerErrorCopyWith(PlayerError value, $Res Function(PlayerError) _then) = _$PlayerErrorCopyWithImpl; +@useResult +$Res call({ + String message, String? cause +}); + + + + +} +/// @nodoc +class _$PlayerErrorCopyWithImpl<$Res> + implements $PlayerErrorCopyWith<$Res> { + _$PlayerErrorCopyWithImpl(this._self, this._then); + + final PlayerError _self; + final $Res Function(PlayerError) _then; + +/// Create a copy of PlayerError +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? message = null,Object? cause = freezed,}) { + return _then(_self.copyWith( +message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,cause: freezed == cause ? _self.cause : cause // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [PlayerError]. +extension PlayerErrorPatterns on PlayerError { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _PlayerError value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _PlayerError() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _PlayerError value) $default,){ +final _that = this; +switch (_that) { +case _PlayerError(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _PlayerError value)? $default,){ +final _that = this; +switch (_that) { +case _PlayerError() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String message, String? cause)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _PlayerError() when $default != null: +return $default(_that.message,_that.cause);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String message, String? cause) $default,) {final _that = this; +switch (_that) { +case _PlayerError(): +return $default(_that.message,_that.cause);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String message, String? cause)? $default,) {final _that = this; +switch (_that) { +case _PlayerError() when $default != null: +return $default(_that.message,_that.cause);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _PlayerError extends PlayerError { + const _PlayerError(this.message, {this.cause}): super._(); + + +@override final String message; +@override final String? cause; + +/// Create a copy of PlayerError +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$PlayerErrorCopyWith<_PlayerError> get copyWith => __$PlayerErrorCopyWithImpl<_PlayerError>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _PlayerError&&(identical(other.message, message) || other.message == message)&&(identical(other.cause, cause) || other.cause == cause)); +} + + +@override +int get hashCode => Object.hash(runtimeType,message,cause); + + + +} + +/// @nodoc +abstract mixin class _$PlayerErrorCopyWith<$Res> implements $PlayerErrorCopyWith<$Res> { + factory _$PlayerErrorCopyWith(_PlayerError value, $Res Function(_PlayerError) _then) = __$PlayerErrorCopyWithImpl; +@override @useResult +$Res call({ + String message, String? cause +}); + + + + +} +/// @nodoc +class __$PlayerErrorCopyWithImpl<$Res> + implements _$PlayerErrorCopyWith<$Res> { + __$PlayerErrorCopyWithImpl(this._self, this._then); + + final _PlayerError _self; + final $Res Function(_PlayerError) _then; + +/// Create a copy of PlayerError +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? message = null,Object? cause = freezed,}) { + return _then(_PlayerError( +null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,cause: freezed == cause ? _self.cause : cause // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +/// @nodoc +mixin _$AudioTrack { + + String get id; String? get title; String? get language; String? get codec; int? get channels; int? get sampleRate; int? get bitrate; bool get isDefault; bool get isForced; +/// Create a copy of AudioTrack +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$AudioTrackCopyWith get copyWith => _$AudioTrackCopyWithImpl(this as AudioTrack, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is AudioTrack&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.language, language) || other.language == language)&&(identical(other.codec, codec) || other.codec == codec)&&(identical(other.channels, channels) || other.channels == channels)&&(identical(other.sampleRate, sampleRate) || other.sampleRate == sampleRate)&&(identical(other.bitrate, bitrate) || other.bitrate == bitrate)&&(identical(other.isDefault, isDefault) || other.isDefault == isDefault)&&(identical(other.isForced, isForced) || other.isForced == isForced)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,title,language,codec,channels,sampleRate,bitrate,isDefault,isForced); + +@override +String toString() { + return 'AudioTrack(id: $id, title: $title, language: $language, codec: $codec, channels: $channels, sampleRate: $sampleRate, bitrate: $bitrate, isDefault: $isDefault, isForced: $isForced)'; +} + + +} + +/// @nodoc +abstract mixin class $AudioTrackCopyWith<$Res> { + factory $AudioTrackCopyWith(AudioTrack value, $Res Function(AudioTrack) _then) = _$AudioTrackCopyWithImpl; +@useResult +$Res call({ + String id, String? title, String? language, String? codec, int? channels, int? sampleRate, int? bitrate, bool isDefault, bool isForced +}); + + + + +} +/// @nodoc +class _$AudioTrackCopyWithImpl<$Res> + implements $AudioTrackCopyWith<$Res> { + _$AudioTrackCopyWithImpl(this._self, this._then); + + final AudioTrack _self; + final $Res Function(AudioTrack) _then; + +/// Create a copy of AudioTrack +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? language = freezed,Object? codec = freezed,Object? channels = freezed,Object? sampleRate = freezed,Object? bitrate = freezed,Object? isDefault = null,Object? isForced = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable +as String?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable +as String?,codec: freezed == codec ? _self.codec : codec // ignore: cast_nullable_to_non_nullable +as String?,channels: freezed == channels ? _self.channels : channels // ignore: cast_nullable_to_non_nullable +as int?,sampleRate: freezed == sampleRate ? _self.sampleRate : sampleRate // ignore: cast_nullable_to_non_nullable +as int?,bitrate: freezed == bitrate ? _self.bitrate : bitrate // ignore: cast_nullable_to_non_nullable +as int?,isDefault: null == isDefault ? _self.isDefault : isDefault // ignore: cast_nullable_to_non_nullable +as bool,isForced: null == isForced ? _self.isForced : isForced // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + +} + + +/// Adds pattern-matching-related methods to [AudioTrack]. +extension AudioTrackPatterns on AudioTrack { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _AudioTrack value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _AudioTrack() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _AudioTrack value) $default,){ +final _that = this; +switch (_that) { +case _AudioTrack(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _AudioTrack value)? $default,){ +final _that = this; +switch (_that) { +case _AudioTrack() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? title, String? language, String? codec, int? channels, int? sampleRate, int? bitrate, bool isDefault, bool isForced)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _AudioTrack() when $default != null: +return $default(_that.id,_that.title,_that.language,_that.codec,_that.channels,_that.sampleRate,_that.bitrate,_that.isDefault,_that.isForced);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String id, String? title, String? language, String? codec, int? channels, int? sampleRate, int? bitrate, bool isDefault, bool isForced) $default,) {final _that = this; +switch (_that) { +case _AudioTrack(): +return $default(_that.id,_that.title,_that.language,_that.codec,_that.channels,_that.sampleRate,_that.bitrate,_that.isDefault,_that.isForced);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? title, String? language, String? codec, int? channels, int? sampleRate, int? bitrate, bool isDefault, bool isForced)? $default,) {final _that = this; +switch (_that) { +case _AudioTrack() when $default != null: +return $default(_that.id,_that.title,_that.language,_that.codec,_that.channels,_that.sampleRate,_that.bitrate,_that.isDefault,_that.isForced);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _AudioTrack extends AudioTrack { + const _AudioTrack({required this.id, this.title, this.language, this.codec, this.channels, this.sampleRate, this.bitrate, this.isDefault = false, this.isForced = false}): super._(); + + +@override final String id; +@override final String? title; +@override final String? language; +@override final String? codec; +@override final int? channels; +@override final int? sampleRate; +@override final int? bitrate; +@override@JsonKey() final bool isDefault; +@override@JsonKey() final bool isForced; + +/// Create a copy of AudioTrack +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$AudioTrackCopyWith<_AudioTrack> get copyWith => __$AudioTrackCopyWithImpl<_AudioTrack>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _AudioTrack&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.language, language) || other.language == language)&&(identical(other.codec, codec) || other.codec == codec)&&(identical(other.channels, channels) || other.channels == channels)&&(identical(other.sampleRate, sampleRate) || other.sampleRate == sampleRate)&&(identical(other.bitrate, bitrate) || other.bitrate == bitrate)&&(identical(other.isDefault, isDefault) || other.isDefault == isDefault)&&(identical(other.isForced, isForced) || other.isForced == isForced)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,title,language,codec,channels,sampleRate,bitrate,isDefault,isForced); + +@override +String toString() { + return 'AudioTrack(id: $id, title: $title, language: $language, codec: $codec, channels: $channels, sampleRate: $sampleRate, bitrate: $bitrate, isDefault: $isDefault, isForced: $isForced)'; +} + + +} + +/// @nodoc +abstract mixin class _$AudioTrackCopyWith<$Res> implements $AudioTrackCopyWith<$Res> { + factory _$AudioTrackCopyWith(_AudioTrack value, $Res Function(_AudioTrack) _then) = __$AudioTrackCopyWithImpl; +@override @useResult +$Res call({ + String id, String? title, String? language, String? codec, int? channels, int? sampleRate, int? bitrate, bool isDefault, bool isForced +}); + + + + +} +/// @nodoc +class __$AudioTrackCopyWithImpl<$Res> + implements _$AudioTrackCopyWith<$Res> { + __$AudioTrackCopyWithImpl(this._self, this._then); + + final _AudioTrack _self; + final $Res Function(_AudioTrack) _then; + +/// Create a copy of AudioTrack +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? language = freezed,Object? codec = freezed,Object? channels = freezed,Object? sampleRate = freezed,Object? bitrate = freezed,Object? isDefault = null,Object? isForced = null,}) { + return _then(_AudioTrack( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable +as String?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable +as String?,codec: freezed == codec ? _self.codec : codec // ignore: cast_nullable_to_non_nullable +as String?,channels: freezed == channels ? _self.channels : channels // ignore: cast_nullable_to_non_nullable +as int?,sampleRate: freezed == sampleRate ? _self.sampleRate : sampleRate // ignore: cast_nullable_to_non_nullable +as int?,bitrate: freezed == bitrate ? _self.bitrate : bitrate // ignore: cast_nullable_to_non_nullable +as int?,isDefault: null == isDefault ? _self.isDefault : isDefault // ignore: cast_nullable_to_non_nullable +as bool,isForced: null == isForced ? _self.isForced : isForced // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + +/// @nodoc +mixin _$SubtitleTrack { + + String get id; String? get title; String? get language; String? get codec; bool get isDefault; bool get isForced; bool get isExternal; String? get uri; +/// Create a copy of SubtitleTrack +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SubtitleTrackCopyWith get copyWith => _$SubtitleTrackCopyWithImpl(this as SubtitleTrack, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SubtitleTrack&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.language, language) || other.language == language)&&(identical(other.codec, codec) || other.codec == codec)&&(identical(other.isDefault, isDefault) || other.isDefault == isDefault)&&(identical(other.isForced, isForced) || other.isForced == isForced)&&(identical(other.isExternal, isExternal) || other.isExternal == isExternal)&&(identical(other.uri, uri) || other.uri == uri)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,title,language,codec,isDefault,isForced,isExternal,uri); + +@override +String toString() { + return 'SubtitleTrack(id: $id, title: $title, language: $language, codec: $codec, isDefault: $isDefault, isForced: $isForced, isExternal: $isExternal, uri: $uri)'; +} + + +} + +/// @nodoc +abstract mixin class $SubtitleTrackCopyWith<$Res> { + factory $SubtitleTrackCopyWith(SubtitleTrack value, $Res Function(SubtitleTrack) _then) = _$SubtitleTrackCopyWithImpl; +@useResult +$Res call({ + String id, String? title, String? language, String? codec, bool isDefault, bool isForced, bool isExternal, String? uri +}); + + + + +} +/// @nodoc +class _$SubtitleTrackCopyWithImpl<$Res> + implements $SubtitleTrackCopyWith<$Res> { + _$SubtitleTrackCopyWithImpl(this._self, this._then); + + final SubtitleTrack _self; + final $Res Function(SubtitleTrack) _then; + +/// Create a copy of SubtitleTrack +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? language = freezed,Object? codec = freezed,Object? isDefault = null,Object? isForced = null,Object? isExternal = null,Object? uri = freezed,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable +as String?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable +as String?,codec: freezed == codec ? _self.codec : codec // ignore: cast_nullable_to_non_nullable +as String?,isDefault: null == isDefault ? _self.isDefault : isDefault // ignore: cast_nullable_to_non_nullable +as bool,isForced: null == isForced ? _self.isForced : isForced // ignore: cast_nullable_to_non_nullable +as bool,isExternal: null == isExternal ? _self.isExternal : isExternal // ignore: cast_nullable_to_non_nullable +as bool,uri: freezed == uri ? _self.uri : uri // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [SubtitleTrack]. +extension SubtitleTrackPatterns on SubtitleTrack { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _SubtitleTrack value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _SubtitleTrack() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _SubtitleTrack value) $default,){ +final _that = this; +switch (_that) { +case _SubtitleTrack(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SubtitleTrack value)? $default,){ +final _that = this; +switch (_that) { +case _SubtitleTrack() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? title, String? language, String? codec, bool isDefault, bool isForced, bool isExternal, String? uri)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SubtitleTrack() when $default != null: +return $default(_that.id,_that.title,_that.language,_that.codec,_that.isDefault,_that.isForced,_that.isExternal,_that.uri);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String id, String? title, String? language, String? codec, bool isDefault, bool isForced, bool isExternal, String? uri) $default,) {final _that = this; +switch (_that) { +case _SubtitleTrack(): +return $default(_that.id,_that.title,_that.language,_that.codec,_that.isDefault,_that.isForced,_that.isExternal,_that.uri);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? title, String? language, String? codec, bool isDefault, bool isForced, bool isExternal, String? uri)? $default,) {final _that = this; +switch (_that) { +case _SubtitleTrack() when $default != null: +return $default(_that.id,_that.title,_that.language,_that.codec,_that.isDefault,_that.isForced,_that.isExternal,_that.uri);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _SubtitleTrack extends SubtitleTrack { + const _SubtitleTrack({required this.id, this.title, this.language, this.codec, this.isDefault = false, this.isForced = false, this.isExternal = false, this.uri}): super._(); + + +@override final String id; +@override final String? title; +@override final String? language; +@override final String? codec; +@override@JsonKey() final bool isDefault; +@override@JsonKey() final bool isForced; +@override@JsonKey() final bool isExternal; +@override final String? uri; + +/// Create a copy of SubtitleTrack +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SubtitleTrackCopyWith<_SubtitleTrack> get copyWith => __$SubtitleTrackCopyWithImpl<_SubtitleTrack>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SubtitleTrack&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.language, language) || other.language == language)&&(identical(other.codec, codec) || other.codec == codec)&&(identical(other.isDefault, isDefault) || other.isDefault == isDefault)&&(identical(other.isForced, isForced) || other.isForced == isForced)&&(identical(other.isExternal, isExternal) || other.isExternal == isExternal)&&(identical(other.uri, uri) || other.uri == uri)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,title,language,codec,isDefault,isForced,isExternal,uri); + +@override +String toString() { + return 'SubtitleTrack(id: $id, title: $title, language: $language, codec: $codec, isDefault: $isDefault, isForced: $isForced, isExternal: $isExternal, uri: $uri)'; +} + + +} + +/// @nodoc +abstract mixin class _$SubtitleTrackCopyWith<$Res> implements $SubtitleTrackCopyWith<$Res> { + factory _$SubtitleTrackCopyWith(_SubtitleTrack value, $Res Function(_SubtitleTrack) _then) = __$SubtitleTrackCopyWithImpl; +@override @useResult +$Res call({ + String id, String? title, String? language, String? codec, bool isDefault, bool isForced, bool isExternal, String? uri +}); + + + + +} +/// @nodoc +class __$SubtitleTrackCopyWithImpl<$Res> + implements _$SubtitleTrackCopyWith<$Res> { + __$SubtitleTrackCopyWithImpl(this._self, this._then); + + final _SubtitleTrack _self; + final $Res Function(_SubtitleTrack) _then; + +/// Create a copy of SubtitleTrack +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? language = freezed,Object? codec = freezed,Object? isDefault = null,Object? isForced = null,Object? isExternal = null,Object? uri = freezed,}) { + return _then(_SubtitleTrack( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable +as String?,language: freezed == language ? _self.language : language // ignore: cast_nullable_to_non_nullable +as String?,codec: freezed == codec ? _self.codec : codec // ignore: cast_nullable_to_non_nullable +as String?,isDefault: null == isDefault ? _self.isDefault : isDefault // ignore: cast_nullable_to_non_nullable +as bool,isForced: null == isForced ? _self.isForced : isForced // ignore: cast_nullable_to_non_nullable +as bool,isExternal: null == isExternal ? _self.isExternal : isExternal // ignore: cast_nullable_to_non_nullable +as bool,uri: freezed == uri ? _self.uri : uri // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +/// @nodoc +mixin _$Tracks { + + List get audio; List get subtitle; +/// Create a copy of Tracks +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TracksCopyWith get copyWith => _$TracksCopyWithImpl(this as Tracks, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Tracks&&const DeepCollectionEquality().equals(other.audio, audio)&&const DeepCollectionEquality().equals(other.subtitle, subtitle)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(audio),const DeepCollectionEquality().hash(subtitle)); + + + +} + +/// @nodoc +abstract mixin class $TracksCopyWith<$Res> { + factory $TracksCopyWith(Tracks value, $Res Function(Tracks) _then) = _$TracksCopyWithImpl; +@useResult +$Res call({ + List audio, List subtitle +}); + + + + +} +/// @nodoc +class _$TracksCopyWithImpl<$Res> + implements $TracksCopyWith<$Res> { + _$TracksCopyWithImpl(this._self, this._then); + + final Tracks _self; + final $Res Function(Tracks) _then; + +/// Create a copy of Tracks +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? audio = null,Object? subtitle = null,}) { + return _then(_self.copyWith( +audio: null == audio ? _self.audio : audio // ignore: cast_nullable_to_non_nullable +as List,subtitle: null == subtitle ? _self.subtitle : subtitle // ignore: cast_nullable_to_non_nullable +as List, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Tracks]. +extension TracksPatterns on Tracks { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Tracks value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Tracks() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Tracks value) $default,){ +final _that = this; +switch (_that) { +case _Tracks(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Tracks value)? $default,){ +final _that = this; +switch (_that) { +case _Tracks() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( List audio, List subtitle)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Tracks() when $default != null: +return $default(_that.audio,_that.subtitle);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( List audio, List subtitle) $default,) {final _that = this; +switch (_that) { +case _Tracks(): +return $default(_that.audio,_that.subtitle);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( List audio, List subtitle)? $default,) {final _that = this; +switch (_that) { +case _Tracks() when $default != null: +return $default(_that.audio,_that.subtitle);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _Tracks extends Tracks { + const _Tracks({final List audio = const [], final List subtitle = const []}): _audio = audio,_subtitle = subtitle,super._(); + + + final List _audio; +@override@JsonKey() List get audio { + if (_audio is EqualUnmodifiableListView) return _audio; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_audio); +} + + final List _subtitle; +@override@JsonKey() List get subtitle { + if (_subtitle is EqualUnmodifiableListView) return _subtitle; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_subtitle); +} + + +/// Create a copy of Tracks +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$TracksCopyWith<_Tracks> get copyWith => __$TracksCopyWithImpl<_Tracks>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Tracks&&const DeepCollectionEquality().equals(other._audio, _audio)&&const DeepCollectionEquality().equals(other._subtitle, _subtitle)); +} + + +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_audio),const DeepCollectionEquality().hash(_subtitle)); + + + +} + +/// @nodoc +abstract mixin class _$TracksCopyWith<$Res> implements $TracksCopyWith<$Res> { + factory _$TracksCopyWith(_Tracks value, $Res Function(_Tracks) _then) = __$TracksCopyWithImpl; +@override @useResult +$Res call({ + List audio, List subtitle +}); + + + + +} +/// @nodoc +class __$TracksCopyWithImpl<$Res> + implements _$TracksCopyWith<$Res> { + __$TracksCopyWithImpl(this._self, this._then); + + final _Tracks _self; + final $Res Function(_Tracks) _then; + +/// Create a copy of Tracks +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? audio = null,Object? subtitle = null,}) { + return _then(_Tracks( +audio: null == audio ? _self._audio : audio // ignore: cast_nullable_to_non_nullable +as List,subtitle: null == subtitle ? _self._subtitle : subtitle // ignore: cast_nullable_to_non_nullable +as List, + )); +} + + +} + +/// @nodoc +mixin _$TrackSelection { + + AudioTrack? get audio; SubtitleTrack? get subtitle; SubtitleTrack? get secondarySubtitle; +/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$TrackSelectionCopyWith get copyWith => _$TrackSelectionCopyWithImpl(this as TrackSelection, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is TrackSelection&&(identical(other.audio, audio) || other.audio == audio)&&(identical(other.subtitle, subtitle) || other.subtitle == subtitle)&&(identical(other.secondarySubtitle, secondarySubtitle) || other.secondarySubtitle == secondarySubtitle)); +} + + +@override +int get hashCode => Object.hash(runtimeType,audio,subtitle,secondarySubtitle); + +@override +String toString() { + return 'TrackSelection(audio: $audio, subtitle: $subtitle, secondarySubtitle: $secondarySubtitle)'; +} + + +} + +/// @nodoc +abstract mixin class $TrackSelectionCopyWith<$Res> { + factory $TrackSelectionCopyWith(TrackSelection value, $Res Function(TrackSelection) _then) = _$TrackSelectionCopyWithImpl; +@useResult +$Res call({ + AudioTrack? audio, SubtitleTrack? subtitle, SubtitleTrack? secondarySubtitle +}); + + +$AudioTrackCopyWith<$Res>? get audio;$SubtitleTrackCopyWith<$Res>? get subtitle;$SubtitleTrackCopyWith<$Res>? get secondarySubtitle; + +} +/// @nodoc +class _$TrackSelectionCopyWithImpl<$Res> + implements $TrackSelectionCopyWith<$Res> { + _$TrackSelectionCopyWithImpl(this._self, this._then); + + final TrackSelection _self; + final $Res Function(TrackSelection) _then; + +/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? audio = freezed,Object? subtitle = freezed,Object? secondarySubtitle = freezed,}) { + return _then(_self.copyWith( +audio: freezed == audio ? _self.audio : audio // ignore: cast_nullable_to_non_nullable +as AudioTrack?,subtitle: freezed == subtitle ? _self.subtitle : subtitle // ignore: cast_nullable_to_non_nullable +as SubtitleTrack?,secondarySubtitle: freezed == secondarySubtitle ? _self.secondarySubtitle : secondarySubtitle // ignore: cast_nullable_to_non_nullable +as SubtitleTrack?, + )); +} +/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AudioTrackCopyWith<$Res>? get audio { + if (_self.audio == null) { + return null; + } + + return $AudioTrackCopyWith<$Res>(_self.audio!, (value) { + return _then(_self.copyWith(audio: value)); + }); +}/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SubtitleTrackCopyWith<$Res>? get subtitle { + if (_self.subtitle == null) { + return null; + } + + return $SubtitleTrackCopyWith<$Res>(_self.subtitle!, (value) { + return _then(_self.copyWith(subtitle: value)); + }); +}/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SubtitleTrackCopyWith<$Res>? get secondarySubtitle { + if (_self.secondarySubtitle == null) { + return null; + } + + return $SubtitleTrackCopyWith<$Res>(_self.secondarySubtitle!, (value) { + return _then(_self.copyWith(secondarySubtitle: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [TrackSelection]. +extension TrackSelectionPatterns on TrackSelection { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _TrackSelection value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _TrackSelection() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _TrackSelection value) $default,){ +final _that = this; +switch (_that) { +case _TrackSelection(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _TrackSelection value)? $default,){ +final _that = this; +switch (_that) { +case _TrackSelection() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( AudioTrack? audio, SubtitleTrack? subtitle, SubtitleTrack? secondarySubtitle)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _TrackSelection() when $default != null: +return $default(_that.audio,_that.subtitle,_that.secondarySubtitle);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( AudioTrack? audio, SubtitleTrack? subtitle, SubtitleTrack? secondarySubtitle) $default,) {final _that = this; +switch (_that) { +case _TrackSelection(): +return $default(_that.audio,_that.subtitle,_that.secondarySubtitle);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( AudioTrack? audio, SubtitleTrack? subtitle, SubtitleTrack? secondarySubtitle)? $default,) {final _that = this; +switch (_that) { +case _TrackSelection() when $default != null: +return $default(_that.audio,_that.subtitle,_that.secondarySubtitle);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _TrackSelection implements TrackSelection { + const _TrackSelection({this.audio, this.subtitle, this.secondarySubtitle}); + + +@override final AudioTrack? audio; +@override final SubtitleTrack? subtitle; +@override final SubtitleTrack? secondarySubtitle; + +/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$TrackSelectionCopyWith<_TrackSelection> get copyWith => __$TrackSelectionCopyWithImpl<_TrackSelection>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _TrackSelection&&(identical(other.audio, audio) || other.audio == audio)&&(identical(other.subtitle, subtitle) || other.subtitle == subtitle)&&(identical(other.secondarySubtitle, secondarySubtitle) || other.secondarySubtitle == secondarySubtitle)); +} + + +@override +int get hashCode => Object.hash(runtimeType,audio,subtitle,secondarySubtitle); + +@override +String toString() { + return 'TrackSelection(audio: $audio, subtitle: $subtitle, secondarySubtitle: $secondarySubtitle)'; +} + + +} + +/// @nodoc +abstract mixin class _$TrackSelectionCopyWith<$Res> implements $TrackSelectionCopyWith<$Res> { + factory _$TrackSelectionCopyWith(_TrackSelection value, $Res Function(_TrackSelection) _then) = __$TrackSelectionCopyWithImpl; +@override @useResult +$Res call({ + AudioTrack? audio, SubtitleTrack? subtitle, SubtitleTrack? secondarySubtitle +}); + + +@override $AudioTrackCopyWith<$Res>? get audio;@override $SubtitleTrackCopyWith<$Res>? get subtitle;@override $SubtitleTrackCopyWith<$Res>? get secondarySubtitle; + +} +/// @nodoc +class __$TrackSelectionCopyWithImpl<$Res> + implements _$TrackSelectionCopyWith<$Res> { + __$TrackSelectionCopyWithImpl(this._self, this._then); + + final _TrackSelection _self; + final $Res Function(_TrackSelection) _then; + +/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? audio = freezed,Object? subtitle = freezed,Object? secondarySubtitle = freezed,}) { + return _then(_TrackSelection( +audio: freezed == audio ? _self.audio : audio // ignore: cast_nullable_to_non_nullable +as AudioTrack?,subtitle: freezed == subtitle ? _self.subtitle : subtitle // ignore: cast_nullable_to_non_nullable +as SubtitleTrack?,secondarySubtitle: freezed == secondarySubtitle ? _self.secondarySubtitle : secondarySubtitle // ignore: cast_nullable_to_non_nullable +as SubtitleTrack?, + )); +} + +/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AudioTrackCopyWith<$Res>? get audio { + if (_self.audio == null) { + return null; + } + + return $AudioTrackCopyWith<$Res>(_self.audio!, (value) { + return _then(_self.copyWith(audio: value)); + }); +}/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SubtitleTrackCopyWith<$Res>? get subtitle { + if (_self.subtitle == null) { + return null; + } + + return $SubtitleTrackCopyWith<$Res>(_self.subtitle!, (value) { + return _then(_self.copyWith(subtitle: value)); + }); +}/// Create a copy of TrackSelection +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SubtitleTrackCopyWith<$Res>? get secondarySubtitle { + if (_self.secondarySubtitle == null) { + return null; + } + + return $SubtitleTrackCopyWith<$Res>(_self.secondarySubtitle!, (value) { + return _then(_self.copyWith(secondarySubtitle: value)); + }); +} +} + +/// @nodoc +mixin _$AudioDevice { + + String get name; String get description; +/// Create a copy of AudioDevice +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$AudioDeviceCopyWith get copyWith => _$AudioDeviceCopyWithImpl(this as AudioDevice, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is AudioDevice&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)); +} + + +@override +int get hashCode => Object.hash(runtimeType,name,description); + +@override +String toString() { + return 'AudioDevice(name: $name, description: $description)'; +} + + +} + +/// @nodoc +abstract mixin class $AudioDeviceCopyWith<$Res> { + factory $AudioDeviceCopyWith(AudioDevice value, $Res Function(AudioDevice) _then) = _$AudioDeviceCopyWithImpl; +@useResult +$Res call({ + String name, String description +}); + + + + +} +/// @nodoc +class _$AudioDeviceCopyWithImpl<$Res> + implements $AudioDeviceCopyWith<$Res> { + _$AudioDeviceCopyWithImpl(this._self, this._then); + + final AudioDevice _self; + final $Res Function(AudioDevice) _then; + +/// Create a copy of AudioDevice +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? description = null,}) { + return _then(_self.copyWith( +name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [AudioDevice]. +extension AudioDevicePatterns on AudioDevice { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _AudioDevice value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _AudioDevice() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _AudioDevice value) $default,){ +final _that = this; +switch (_that) { +case _AudioDevice(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _AudioDevice value)? $default,){ +final _that = this; +switch (_that) { +case _AudioDevice() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String name, String description)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _AudioDevice() when $default != null: +return $default(_that.name,_that.description);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String name, String description) $default,) {final _that = this; +switch (_that) { +case _AudioDevice(): +return $default(_that.name,_that.description);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String name, String description)? $default,) {final _that = this; +switch (_that) { +case _AudioDevice() when $default != null: +return $default(_that.name,_that.description);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _AudioDevice implements AudioDevice { + const _AudioDevice({required this.name, this.description = ''}); + + +@override final String name; +@override@JsonKey() final String description; + +/// Create a copy of AudioDevice +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$AudioDeviceCopyWith<_AudioDevice> get copyWith => __$AudioDeviceCopyWithImpl<_AudioDevice>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _AudioDevice&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)); +} + + +@override +int get hashCode => Object.hash(runtimeType,name,description); + +@override +String toString() { + return 'AudioDevice(name: $name, description: $description)'; +} + + +} + +/// @nodoc +abstract mixin class _$AudioDeviceCopyWith<$Res> implements $AudioDeviceCopyWith<$Res> { + factory _$AudioDeviceCopyWith(_AudioDevice value, $Res Function(_AudioDevice) _then) = __$AudioDeviceCopyWithImpl; +@override @useResult +$Res call({ + String name, String description +}); + + + + +} +/// @nodoc +class __$AudioDeviceCopyWithImpl<$Res> + implements _$AudioDeviceCopyWith<$Res> { + __$AudioDeviceCopyWithImpl(this._self, this._then); + + final _AudioDevice _self; + final $Res Function(_AudioDevice) _then; + +/// Create a copy of AudioDevice +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? description = null,}) { + return _then(_AudioDevice( +name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +/// @nodoc +mixin _$PlayerLog { + + PlayerLogLevel get level; String get prefix; String get text; +/// Create a copy of PlayerLog +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$PlayerLogCopyWith get copyWith => _$PlayerLogCopyWithImpl(this as PlayerLog, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is PlayerLog&&(identical(other.level, level) || other.level == level)&&(identical(other.prefix, prefix) || other.prefix == prefix)&&(identical(other.text, text) || other.text == text)); +} + + +@override +int get hashCode => Object.hash(runtimeType,level,prefix,text); + + + +} + +/// @nodoc +abstract mixin class $PlayerLogCopyWith<$Res> { + factory $PlayerLogCopyWith(PlayerLog value, $Res Function(PlayerLog) _then) = _$PlayerLogCopyWithImpl; +@useResult +$Res call({ + PlayerLogLevel level, String prefix, String text +}); + + + + +} +/// @nodoc +class _$PlayerLogCopyWithImpl<$Res> + implements $PlayerLogCopyWith<$Res> { + _$PlayerLogCopyWithImpl(this._self, this._then); + + final PlayerLog _self; + final $Res Function(PlayerLog) _then; + +/// Create a copy of PlayerLog +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? level = null,Object? prefix = null,Object? text = null,}) { + return _then(_self.copyWith( +level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable +as PlayerLogLevel,prefix: null == prefix ? _self.prefix : prefix // ignore: cast_nullable_to_non_nullable +as String,text: null == text ? _self.text : text // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [PlayerLog]. +extension PlayerLogPatterns on PlayerLog { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _PlayerLog value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _PlayerLog() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _PlayerLog value) $default,){ +final _that = this; +switch (_that) { +case _PlayerLog(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _PlayerLog value)? $default,){ +final _that = this; +switch (_that) { +case _PlayerLog() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( PlayerLogLevel level, String prefix, String text)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _PlayerLog() when $default != null: +return $default(_that.level,_that.prefix,_that.text);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( PlayerLogLevel level, String prefix, String text) $default,) {final _that = this; +switch (_that) { +case _PlayerLog(): +return $default(_that.level,_that.prefix,_that.text);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( PlayerLogLevel level, String prefix, String text)? $default,) {final _that = this; +switch (_that) { +case _PlayerLog() when $default != null: +return $default(_that.level,_that.prefix,_that.text);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _PlayerLog extends PlayerLog { + const _PlayerLog({required this.level, required this.prefix, required this.text}): super._(); + + +@override final PlayerLogLevel level; +@override final String prefix; +@override final String text; + +/// Create a copy of PlayerLog +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$PlayerLogCopyWith<_PlayerLog> get copyWith => __$PlayerLogCopyWithImpl<_PlayerLog>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _PlayerLog&&(identical(other.level, level) || other.level == level)&&(identical(other.prefix, prefix) || other.prefix == prefix)&&(identical(other.text, text) || other.text == text)); +} + + +@override +int get hashCode => Object.hash(runtimeType,level,prefix,text); + + + +} + +/// @nodoc +abstract mixin class _$PlayerLogCopyWith<$Res> implements $PlayerLogCopyWith<$Res> { + factory _$PlayerLogCopyWith(_PlayerLog value, $Res Function(_PlayerLog) _then) = __$PlayerLogCopyWithImpl; +@override @useResult +$Res call({ + PlayerLogLevel level, String prefix, String text +}); + + + + +} +/// @nodoc +class __$PlayerLogCopyWithImpl<$Res> + implements _$PlayerLogCopyWith<$Res> { + __$PlayerLogCopyWithImpl(this._self, this._then); + + final _PlayerLog _self; + final $Res Function(_PlayerLog) _then; + +/// Create a copy of PlayerLog +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? level = null,Object? prefix = null,Object? text = null,}) { + return _then(_PlayerLog( +level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable +as PlayerLogLevel,prefix: null == prefix ? _self.prefix : prefix // ignore: cast_nullable_to_non_nullable +as String,text: null == text ? _self.text : text // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +/// @nodoc +mixin _$Media { + + String get uri; Map? get headers; Duration? get start; +/// Create a copy of Media +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$MediaCopyWith get copyWith => _$MediaCopyWithImpl(this as Media, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Media&&(identical(other.uri, uri) || other.uri == uri)&&const DeepCollectionEquality().equals(other.headers, headers)&&(identical(other.start, start) || other.start == start)); +} + + +@override +int get hashCode => Object.hash(runtimeType,uri,const DeepCollectionEquality().hash(headers),start); + +@override +String toString() { + return 'Media(uri: $uri, headers: $headers, start: $start)'; +} + + +} + +/// @nodoc +abstract mixin class $MediaCopyWith<$Res> { + factory $MediaCopyWith(Media value, $Res Function(Media) _then) = _$MediaCopyWithImpl; +@useResult +$Res call({ + String uri, Map? headers, Duration? start +}); + + + + +} +/// @nodoc +class _$MediaCopyWithImpl<$Res> + implements $MediaCopyWith<$Res> { + _$MediaCopyWithImpl(this._self, this._then); + + final Media _self; + final $Res Function(Media) _then; + +/// Create a copy of Media +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? uri = null,Object? headers = freezed,Object? start = freezed,}) { + return _then(_self.copyWith( +uri: null == uri ? _self.uri : uri // ignore: cast_nullable_to_non_nullable +as String,headers: freezed == headers ? _self.headers : headers // ignore: cast_nullable_to_non_nullable +as Map?,start: freezed == start ? _self.start : start // ignore: cast_nullable_to_non_nullable +as Duration?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Media]. +extension MediaPatterns on Media { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Media value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Media() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Media value) $default,){ +final _that = this; +switch (_that) { +case _Media(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Media value)? $default,){ +final _that = this; +switch (_that) { +case _Media() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String uri, Map? headers, Duration? start)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Media() when $default != null: +return $default(_that.uri,_that.headers,_that.start);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String uri, Map? headers, Duration? start) $default,) {final _that = this; +switch (_that) { +case _Media(): +return $default(_that.uri,_that.headers,_that.start);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String uri, Map? headers, Duration? start)? $default,) {final _that = this; +switch (_that) { +case _Media() when $default != null: +return $default(_that.uri,_that.headers,_that.start);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _Media implements Media { + const _Media(this.uri, {final Map? headers, this.start}): _headers = headers; + + +@override final String uri; + final Map? _headers; +@override Map? get headers { + final value = _headers; + if (value == null) return null; + if (_headers is EqualUnmodifiableMapView) return _headers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(value); +} + +@override final Duration? start; + +/// Create a copy of Media +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$MediaCopyWith<_Media> get copyWith => __$MediaCopyWithImpl<_Media>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Media&&(identical(other.uri, uri) || other.uri == uri)&&const DeepCollectionEquality().equals(other._headers, _headers)&&(identical(other.start, start) || other.start == start)); +} + + +@override +int get hashCode => Object.hash(runtimeType,uri,const DeepCollectionEquality().hash(_headers),start); + +@override +String toString() { + return 'Media(uri: $uri, headers: $headers, start: $start)'; +} + + +} + +/// @nodoc +abstract mixin class _$MediaCopyWith<$Res> implements $MediaCopyWith<$Res> { + factory _$MediaCopyWith(_Media value, $Res Function(_Media) _then) = __$MediaCopyWithImpl; +@override @useResult +$Res call({ + String uri, Map? headers, Duration? start +}); + + + + +} +/// @nodoc +class __$MediaCopyWithImpl<$Res> + implements _$MediaCopyWith<$Res> { + __$MediaCopyWithImpl(this._self, this._then); + + final _Media _self; + final $Res Function(_Media) _then; + +/// Create a copy of Media +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? uri = null,Object? headers = freezed,Object? start = freezed,}) { + return _then(_Media( +null == uri ? _self.uri : uri // ignore: cast_nullable_to_non_nullable +as String,headers: freezed == headers ? _self._headers : headers // ignore: cast_nullable_to_non_nullable +as Map?,start: freezed == start ? _self.start : start // ignore: cast_nullable_to_non_nullable +as Duration?, + )); +} + + +} + +// dart format on diff --git a/lib/mpv/player/player_base.dart b/lib/mpv/player/player_base.dart index be242442..10c3c4da 100644 --- a/lib/mpv/player/player_base.dart +++ b/lib/mpv/player/player_base.dart @@ -438,18 +438,18 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player { selectedTrack = _state.tracks.audio.firstWhereOrNull((t) => t.id == id); } + if (selectedTrack == null) return; _state = _state.copyWith(track: _state.track.copyWith(audio: selectedTrack)); trackController.add(_state.track); } void updateSelectedSubtitleTrack(dynamic trackId) { final id = trackId?.toString(); - SubtitleTrack? selectedTrack; - - selectedTrack = (id == null || id == 'no') + final selectedTrack = (id == null || id == 'no') ? SubtitleTrack.off : _state.tracks.subtitle.firstWhereOrNull((t) => t.id == id); + if (selectedTrack == null) return; _state = _state.copyWith(track: _state.track.copyWith(subtitle: selectedTrack)); trackController.add(_state.track); } diff --git a/lib/profiles/profile.dart b/lib/profiles/profile.dart index f22631af..ad18e480 100644 --- a/lib/profiles/profile.dart +++ b/lib/profiles/profile.dart @@ -1,148 +1,83 @@ import 'dart:convert'; import 'package:crypto/crypto.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import '../models/plex/plex_home_user.dart'; +part 'profile.freezed.dart'; + /// Top-level profile — the user-facing identity in the app. /// /// Two kinds: -/// - [ProfileKind.local]: a Plezy-only profile created by the user. May have +/// - [LocalProfile]: a Plezy-only profile created by the user. May have /// an optional 4-digit PIN. -/// - [ProfileKind.plexHome]: auto-surfaced from a connected Plex account's +/// - [PlexHomeProfile]: auto-surfaced from a connected Plex account's /// Home users. PIN protection is handled server-side by Plex via the /// `/home/users/{uuid}/switch` flow — `pinHash` is unused. /// /// A profile owns 1+ connections via the `profile_connections` join table. /// The join row carries the per-profile user-level token used to talk to /// each connection. -class Profile { - final String id; - final ProfileKind kind; - final String displayName; - final String? avatarThumbUrl; +@freezed +sealed class Profile with _$Profile { + const Profile._(); - /// Hashed PIN if set — only meaningful for [ProfileKind.local]. The raw - /// PIN is never persisted; see [computePinHash]. - final String? pinHash; + const factory Profile.local({ + required String id, + required String displayName, + String? avatarThumbUrl, - /// For [ProfileKind.plexHome]: the parent Plex account's connection id. - /// `null` for local profiles. - final String? parentConnectionId; + /// Hashed PIN if set. The raw PIN is never persisted; see [computePinHash]. + String? pinHash, + @Default(0) int sortOrder, + required DateTime createdAt, + DateTime? lastUsedAt, + }) = LocalProfile; - /// For [ProfileKind.plexHome]: the Plex Home user UUID. Used by the - /// active-profile binder to call `/home/users/{uuid}/switch`. `null` for - /// local profiles. - final String? plexHomeUserUuid; + const factory Profile.plexHome({ + required String id, + required String displayName, + String? avatarThumbUrl, - /// Plex Home flags — only meaningful for [ProfileKind.plexHome]. - final bool plexRestricted; - final bool plexAdmin; + /// The parent Plex account's connection id. + String? parentConnectionId, - /// Plex's `protected` flag — true when the home user has a PIN that must - /// be entered before `/home/users/{uuid}/switch` will succeed. - final bool plexProtected; + /// The Plex Home user UUID. Used by the active-profile binder to call + /// `/home/users/{uuid}/switch`. + String? plexHomeUserUuid, + @Default(false) bool plexRestricted, + @Default(false) bool plexAdmin, - final int sortOrder; - final DateTime createdAt; - final DateTime? lastUsedAt; - - Profile({ - required this.id, - required this.kind, - required this.displayName, - this.avatarThumbUrl, - this.pinHash, - this.parentConnectionId, - this.plexHomeUserUuid, - this.plexRestricted = false, - this.plexAdmin = false, - this.plexProtected = false, - this.sortOrder = 0, - required this.createdAt, - this.lastUsedAt, - }); + /// Plex's `protected` flag — true when the home user has a PIN that must + /// be entered before `/home/users/{uuid}/switch` will succeed. + @Default(false) bool plexProtected, + @Default(0) int sortOrder, + required DateTime createdAt, + DateTime? lastUsedAt, + }) = PlexHomeProfile; /// Construct an in-memory virtual `Profile` for a Plex Home user. These /// are never persisted — Plex owns the Home user list, so the picker /// reads them live from [PlexHomeService] and merges them with the local - /// rows from [ProfileRegistry]. + /// rows from `ProfileRegistry`. factory Profile.virtualPlexHome({ required String connectionId, required PlexHomeUser homeUser, DateTime? lastUsedAt, - }) { - return Profile( - id: plexHomeProfileId(accountConnectionId: connectionId, homeUserUuid: homeUser.uuid), - kind: ProfileKind.plexHome, - displayName: homeUser.displayName, - avatarThumbUrl: homeUser.thumb.isNotEmpty ? homeUser.thumb : null, - parentConnectionId: connectionId, - plexHomeUserUuid: homeUser.uuid, - plexRestricted: homeUser.restricted, - plexAdmin: homeUser.admin, - plexProtected: homeUser.protected, - sortOrder: homeUser.admin ? 0 : 1, - createdAt: DateTime.fromMillisecondsSinceEpoch(0), - lastUsedAt: lastUsedAt, - ); - } - - bool get isLocal => kind == ProfileKind.local; - bool get isPlexHome => kind == ProfileKind.plexHome; - - /// True when entering this profile requires user-supplied PIN. - /// - /// Locals: gated by their own [pinHash]. - /// Plex Home: gated by Plex's own protected flag (`plexProtected`). - bool get isPinProtected => isLocal ? (pinHash != null && pinHash!.isNotEmpty) : plexProtected; - - Profile copyWith({ - String? id, - ProfileKind? kind, - String? displayName, - String? avatarThumbUrl, - bool clearAvatar = false, - String? pinHash, - bool clearPin = false, - String? parentConnectionId, - String? plexHomeUserUuid, - bool? plexRestricted, - bool? plexAdmin, - bool? plexProtected, - int? sortOrder, - DateTime? createdAt, - DateTime? lastUsedAt, - bool clearLastUsedAt = false, - }) { - return Profile( - id: id ?? this.id, - kind: kind ?? this.kind, - displayName: displayName ?? this.displayName, - avatarThumbUrl: clearAvatar ? null : (avatarThumbUrl ?? this.avatarThumbUrl), - pinHash: clearPin ? null : (pinHash ?? this.pinHash), - parentConnectionId: parentConnectionId ?? this.parentConnectionId, - plexHomeUserUuid: plexHomeUserUuid ?? this.plexHomeUserUuid, - plexRestricted: plexRestricted ?? this.plexRestricted, - plexAdmin: plexAdmin ?? this.plexAdmin, - plexProtected: plexProtected ?? this.plexProtected, - sortOrder: sortOrder ?? this.sortOrder, - createdAt: createdAt ?? this.createdAt, - lastUsedAt: clearLastUsedAt ? null : (lastUsedAt ?? this.lastUsedAt), - ); - } - - Map toConfigJson() { - return switch (kind) { - ProfileKind.local => {'pinHash': pinHash}, - ProfileKind.plexHome => { - 'parentConnectionId': parentConnectionId, - 'restricted': plexRestricted, - 'admin': plexAdmin, - 'protected': plexProtected, - }, - }; - } + }) => Profile.plexHome( + id: plexHomeProfileId(accountConnectionId: connectionId, homeUserUuid: homeUser.uuid), + displayName: homeUser.displayName, + avatarThumbUrl: homeUser.thumb.isNotEmpty ? homeUser.thumb : null, + parentConnectionId: connectionId, + plexHomeUserUuid: homeUser.uuid, + plexRestricted: homeUser.restricted, + plexAdmin: homeUser.admin, + plexProtected: homeUser.protected, + sortOrder: homeUser.admin ? 0 : 1, + createdAt: DateTime.fromMillisecondsSinceEpoch(0), + lastUsedAt: lastUsedAt, + ); factory Profile.fromRow({ required String id, @@ -156,9 +91,8 @@ class Profile { }) { final parsedKind = ProfileKind.fromId(kind); return switch (parsedKind) { - ProfileKind.local => Profile( + ProfileKind.local => Profile.local( id: id, - kind: parsedKind, displayName: displayName, avatarThumbUrl: avatarThumbUrl, pinHash: json['pinHash'] as String?, @@ -166,9 +100,8 @@ class Profile { createdAt: createdAt, lastUsedAt: lastUsedAt, ), - ProfileKind.plexHome => Profile( + ProfileKind.plexHome => Profile.plexHome( id: id, - kind: parsedKind, displayName: displayName, avatarThumbUrl: avatarThumbUrl, parentConnectionId: json['parentConnectionId'] as String?, @@ -181,6 +114,66 @@ class Profile { ), }; } + + bool get isLocal => this is LocalProfile; + bool get isPlexHome => this is PlexHomeProfile; + + ProfileKind get kind => switch (this) { + LocalProfile() => ProfileKind.local, + PlexHomeProfile() => ProfileKind.plexHome, + }; + + /// True when entering this profile requires user-supplied PIN. + /// + /// Locals: gated by their own [pinHash]. + /// Plex Home: gated by Plex's own protected flag (`plexProtected`). + bool get isPinProtected => switch (this) { + LocalProfile(:final pinHash) => pinHash != null && pinHash.isNotEmpty, + PlexHomeProfile(:final plexProtected) => plexProtected, + }; + + /// Hashed PIN, only set for [LocalProfile]. Returns null for plexHome. + String? get pinHash => switch (this) { + LocalProfile(:final pinHash) => pinHash, + PlexHomeProfile() => null, + }; + + /// Parent Plex account connection id, only set for [PlexHomeProfile]. + String? get parentConnectionId => switch (this) { + LocalProfile() => null, + PlexHomeProfile(:final parentConnectionId) => parentConnectionId, + }; + + /// Plex Home user UUID, only set for [PlexHomeProfile]. + String? get plexHomeUserUuid => switch (this) { + LocalProfile() => null, + PlexHomeProfile(:final plexHomeUserUuid) => plexHomeUserUuid, + }; + + bool get plexRestricted => switch (this) { + LocalProfile() => false, + PlexHomeProfile(:final plexRestricted) => plexRestricted, + }; + + bool get plexAdmin => switch (this) { + LocalProfile() => false, + PlexHomeProfile(:final plexAdmin) => plexAdmin, + }; + + bool get plexProtected => switch (this) { + LocalProfile() => false, + PlexHomeProfile(:final plexProtected) => plexProtected, + }; + + Map toConfigJson() => switch (this) { + LocalProfile(:final pinHash) => {'pinHash': pinHash}, + PlexHomeProfile(:final parentConnectionId, :final plexRestricted, :final plexAdmin, :final plexProtected) => { + 'parentConnectionId': parentConnectionId, + 'restricted': plexRestricted, + 'admin': plexAdmin, + 'protected': plexProtected, + }, + }; } enum ProfileKind { diff --git a/lib/profiles/profile.freezed.dart b/lib/profiles/profile.freezed.dart new file mode 100644 index 00000000..fb79382d --- /dev/null +++ b/lib/profiles/profile.freezed.dart @@ -0,0 +1,380 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'profile.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$Profile { + + String get id; String get displayName; String? get avatarThumbUrl; int get sortOrder; DateTime get createdAt; DateTime? get lastUsedAt; +/// Create a copy of Profile +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ProfileCopyWith get copyWith => _$ProfileCopyWithImpl(this as Profile, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Profile&&(identical(other.id, id) || other.id == id)&&(identical(other.displayName, displayName) || other.displayName == displayName)&&(identical(other.avatarThumbUrl, avatarThumbUrl) || other.avatarThumbUrl == avatarThumbUrl)&&(identical(other.sortOrder, sortOrder) || other.sortOrder == sortOrder)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.lastUsedAt, lastUsedAt) || other.lastUsedAt == lastUsedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,displayName,avatarThumbUrl,sortOrder,createdAt,lastUsedAt); + +@override +String toString() { + return 'Profile(id: $id, displayName: $displayName, avatarThumbUrl: $avatarThumbUrl, sortOrder: $sortOrder, createdAt: $createdAt, lastUsedAt: $lastUsedAt)'; +} + + +} + +/// @nodoc +abstract mixin class $ProfileCopyWith<$Res> { + factory $ProfileCopyWith(Profile value, $Res Function(Profile) _then) = _$ProfileCopyWithImpl; +@useResult +$Res call({ + String id, String displayName, String? avatarThumbUrl, int sortOrder, DateTime createdAt, DateTime? lastUsedAt +}); + + + + +} +/// @nodoc +class _$ProfileCopyWithImpl<$Res> + implements $ProfileCopyWith<$Res> { + _$ProfileCopyWithImpl(this._self, this._then); + + final Profile _self; + final $Res Function(Profile) _then; + +/// Create a copy of Profile +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? displayName = null,Object? avatarThumbUrl = freezed,Object? sortOrder = null,Object? createdAt = null,Object? lastUsedAt = freezed,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,displayName: null == displayName ? _self.displayName : displayName // ignore: cast_nullable_to_non_nullable +as String,avatarThumbUrl: freezed == avatarThumbUrl ? _self.avatarThumbUrl : avatarThumbUrl // ignore: cast_nullable_to_non_nullable +as String?,sortOrder: null == sortOrder ? _self.sortOrder : sortOrder // ignore: cast_nullable_to_non_nullable +as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,lastUsedAt: freezed == lastUsedAt ? _self.lastUsedAt : lastUsedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Profile]. +extension ProfilePatterns on Profile { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap({TResult Function( LocalProfile value)? local,TResult Function( PlexHomeProfile value)? plexHome,required TResult orElse(),}){ +final _that = this; +switch (_that) { +case LocalProfile() when local != null: +return local(_that);case PlexHomeProfile() when plexHome != null: +return plexHome(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map({required TResult Function( LocalProfile value) local,required TResult Function( PlexHomeProfile value) plexHome,}){ +final _that = this; +switch (_that) { +case LocalProfile(): +return local(_that);case PlexHomeProfile(): +return plexHome(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull({TResult? Function( LocalProfile value)? local,TResult? Function( PlexHomeProfile value)? plexHome,}){ +final _that = this; +switch (_that) { +case LocalProfile() when local != null: +return local(_that);case PlexHomeProfile() when plexHome != null: +return plexHome(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen({TResult Function( String id, String displayName, String? avatarThumbUrl, String? pinHash, int sortOrder, DateTime createdAt, DateTime? lastUsedAt)? local,TResult Function( String id, String displayName, String? avatarThumbUrl, String? parentConnectionId, String? plexHomeUserUuid, bool plexRestricted, bool plexAdmin, bool plexProtected, int sortOrder, DateTime createdAt, DateTime? lastUsedAt)? plexHome,required TResult orElse(),}) {final _that = this; +switch (_that) { +case LocalProfile() when local != null: +return local(_that.id,_that.displayName,_that.avatarThumbUrl,_that.pinHash,_that.sortOrder,_that.createdAt,_that.lastUsedAt);case PlexHomeProfile() when plexHome != null: +return plexHome(_that.id,_that.displayName,_that.avatarThumbUrl,_that.parentConnectionId,_that.plexHomeUserUuid,_that.plexRestricted,_that.plexAdmin,_that.plexProtected,_that.sortOrder,_that.createdAt,_that.lastUsedAt);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when({required TResult Function( String id, String displayName, String? avatarThumbUrl, String? pinHash, int sortOrder, DateTime createdAt, DateTime? lastUsedAt) local,required TResult Function( String id, String displayName, String? avatarThumbUrl, String? parentConnectionId, String? plexHomeUserUuid, bool plexRestricted, bool plexAdmin, bool plexProtected, int sortOrder, DateTime createdAt, DateTime? lastUsedAt) plexHome,}) {final _that = this; +switch (_that) { +case LocalProfile(): +return local(_that.id,_that.displayName,_that.avatarThumbUrl,_that.pinHash,_that.sortOrder,_that.createdAt,_that.lastUsedAt);case PlexHomeProfile(): +return plexHome(_that.id,_that.displayName,_that.avatarThumbUrl,_that.parentConnectionId,_that.plexHomeUserUuid,_that.plexRestricted,_that.plexAdmin,_that.plexProtected,_that.sortOrder,_that.createdAt,_that.lastUsedAt);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull({TResult? Function( String id, String displayName, String? avatarThumbUrl, String? pinHash, int sortOrder, DateTime createdAt, DateTime? lastUsedAt)? local,TResult? Function( String id, String displayName, String? avatarThumbUrl, String? parentConnectionId, String? plexHomeUserUuid, bool plexRestricted, bool plexAdmin, bool plexProtected, int sortOrder, DateTime createdAt, DateTime? lastUsedAt)? plexHome,}) {final _that = this; +switch (_that) { +case LocalProfile() when local != null: +return local(_that.id,_that.displayName,_that.avatarThumbUrl,_that.pinHash,_that.sortOrder,_that.createdAt,_that.lastUsedAt);case PlexHomeProfile() when plexHome != null: +return plexHome(_that.id,_that.displayName,_that.avatarThumbUrl,_that.parentConnectionId,_that.plexHomeUserUuid,_that.plexRestricted,_that.plexAdmin,_that.plexProtected,_that.sortOrder,_that.createdAt,_that.lastUsedAt);case _: + return null; + +} +} + +} + +/// @nodoc + + +class LocalProfile extends Profile { + const LocalProfile({required this.id, required this.displayName, this.avatarThumbUrl, this.pinHash, this.sortOrder = 0, required this.createdAt, this.lastUsedAt}): super._(); + + +@override final String id; +@override final String displayName; +@override final String? avatarThumbUrl; +/// Hashed PIN if set. The raw PIN is never persisted; see [computePinHash]. + final String? pinHash; +@override@JsonKey() final int sortOrder; +@override final DateTime createdAt; +@override final DateTime? lastUsedAt; + +/// Create a copy of Profile +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LocalProfileCopyWith get copyWith => _$LocalProfileCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LocalProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.displayName, displayName) || other.displayName == displayName)&&(identical(other.avatarThumbUrl, avatarThumbUrl) || other.avatarThumbUrl == avatarThumbUrl)&&(identical(other.pinHash, pinHash) || other.pinHash == pinHash)&&(identical(other.sortOrder, sortOrder) || other.sortOrder == sortOrder)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.lastUsedAt, lastUsedAt) || other.lastUsedAt == lastUsedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,displayName,avatarThumbUrl,pinHash,sortOrder,createdAt,lastUsedAt); + +@override +String toString() { + return 'Profile.local(id: $id, displayName: $displayName, avatarThumbUrl: $avatarThumbUrl, pinHash: $pinHash, sortOrder: $sortOrder, createdAt: $createdAt, lastUsedAt: $lastUsedAt)'; +} + + +} + +/// @nodoc +abstract mixin class $LocalProfileCopyWith<$Res> implements $ProfileCopyWith<$Res> { + factory $LocalProfileCopyWith(LocalProfile value, $Res Function(LocalProfile) _then) = _$LocalProfileCopyWithImpl; +@override @useResult +$Res call({ + String id, String displayName, String? avatarThumbUrl, String? pinHash, int sortOrder, DateTime createdAt, DateTime? lastUsedAt +}); + + + + +} +/// @nodoc +class _$LocalProfileCopyWithImpl<$Res> + implements $LocalProfileCopyWith<$Res> { + _$LocalProfileCopyWithImpl(this._self, this._then); + + final LocalProfile _self; + final $Res Function(LocalProfile) _then; + +/// Create a copy of Profile +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? displayName = null,Object? avatarThumbUrl = freezed,Object? pinHash = freezed,Object? sortOrder = null,Object? createdAt = null,Object? lastUsedAt = freezed,}) { + return _then(LocalProfile( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,displayName: null == displayName ? _self.displayName : displayName // ignore: cast_nullable_to_non_nullable +as String,avatarThumbUrl: freezed == avatarThumbUrl ? _self.avatarThumbUrl : avatarThumbUrl // ignore: cast_nullable_to_non_nullable +as String?,pinHash: freezed == pinHash ? _self.pinHash : pinHash // ignore: cast_nullable_to_non_nullable +as String?,sortOrder: null == sortOrder ? _self.sortOrder : sortOrder // ignore: cast_nullable_to_non_nullable +as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,lastUsedAt: freezed == lastUsedAt ? _self.lastUsedAt : lastUsedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} + + +} + +/// @nodoc + + +class PlexHomeProfile extends Profile { + const PlexHomeProfile({required this.id, required this.displayName, this.avatarThumbUrl, this.parentConnectionId, this.plexHomeUserUuid, this.plexRestricted = false, this.plexAdmin = false, this.plexProtected = false, this.sortOrder = 0, required this.createdAt, this.lastUsedAt}): super._(); + + +@override final String id; +@override final String displayName; +@override final String? avatarThumbUrl; +/// The parent Plex account's connection id. + final String? parentConnectionId; +/// The Plex Home user UUID. Used by the active-profile binder to call +/// `/home/users/{uuid}/switch`. + final String? plexHomeUserUuid; +@JsonKey() final bool plexRestricted; +@JsonKey() final bool plexAdmin; +/// Plex's `protected` flag — true when the home user has a PIN that must +/// be entered before `/home/users/{uuid}/switch` will succeed. +@JsonKey() final bool plexProtected; +@override@JsonKey() final int sortOrder; +@override final DateTime createdAt; +@override final DateTime? lastUsedAt; + +/// Create a copy of Profile +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$PlexHomeProfileCopyWith get copyWith => _$PlexHomeProfileCopyWithImpl(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is PlexHomeProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.displayName, displayName) || other.displayName == displayName)&&(identical(other.avatarThumbUrl, avatarThumbUrl) || other.avatarThumbUrl == avatarThumbUrl)&&(identical(other.parentConnectionId, parentConnectionId) || other.parentConnectionId == parentConnectionId)&&(identical(other.plexHomeUserUuid, plexHomeUserUuid) || other.plexHomeUserUuid == plexHomeUserUuid)&&(identical(other.plexRestricted, plexRestricted) || other.plexRestricted == plexRestricted)&&(identical(other.plexAdmin, plexAdmin) || other.plexAdmin == plexAdmin)&&(identical(other.plexProtected, plexProtected) || other.plexProtected == plexProtected)&&(identical(other.sortOrder, sortOrder) || other.sortOrder == sortOrder)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.lastUsedAt, lastUsedAt) || other.lastUsedAt == lastUsedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,id,displayName,avatarThumbUrl,parentConnectionId,plexHomeUserUuid,plexRestricted,plexAdmin,plexProtected,sortOrder,createdAt,lastUsedAt); + +@override +String toString() { + return 'Profile.plexHome(id: $id, displayName: $displayName, avatarThumbUrl: $avatarThumbUrl, parentConnectionId: $parentConnectionId, plexHomeUserUuid: $plexHomeUserUuid, plexRestricted: $plexRestricted, plexAdmin: $plexAdmin, plexProtected: $plexProtected, sortOrder: $sortOrder, createdAt: $createdAt, lastUsedAt: $lastUsedAt)'; +} + + +} + +/// @nodoc +abstract mixin class $PlexHomeProfileCopyWith<$Res> implements $ProfileCopyWith<$Res> { + factory $PlexHomeProfileCopyWith(PlexHomeProfile value, $Res Function(PlexHomeProfile) _then) = _$PlexHomeProfileCopyWithImpl; +@override @useResult +$Res call({ + String id, String displayName, String? avatarThumbUrl, String? parentConnectionId, String? plexHomeUserUuid, bool plexRestricted, bool plexAdmin, bool plexProtected, int sortOrder, DateTime createdAt, DateTime? lastUsedAt +}); + + + + +} +/// @nodoc +class _$PlexHomeProfileCopyWithImpl<$Res> + implements $PlexHomeProfileCopyWith<$Res> { + _$PlexHomeProfileCopyWithImpl(this._self, this._then); + + final PlexHomeProfile _self; + final $Res Function(PlexHomeProfile) _then; + +/// Create a copy of Profile +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? displayName = null,Object? avatarThumbUrl = freezed,Object? parentConnectionId = freezed,Object? plexHomeUserUuid = freezed,Object? plexRestricted = null,Object? plexAdmin = null,Object? plexProtected = null,Object? sortOrder = null,Object? createdAt = null,Object? lastUsedAt = freezed,}) { + return _then(PlexHomeProfile( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,displayName: null == displayName ? _self.displayName : displayName // ignore: cast_nullable_to_non_nullable +as String,avatarThumbUrl: freezed == avatarThumbUrl ? _self.avatarThumbUrl : avatarThumbUrl // ignore: cast_nullable_to_non_nullable +as String?,parentConnectionId: freezed == parentConnectionId ? _self.parentConnectionId : parentConnectionId // ignore: cast_nullable_to_non_nullable +as String?,plexHomeUserUuid: freezed == plexHomeUserUuid ? _self.plexHomeUserUuid : plexHomeUserUuid // ignore: cast_nullable_to_non_nullable +as String?,plexRestricted: null == plexRestricted ? _self.plexRestricted : plexRestricted // ignore: cast_nullable_to_non_nullable +as bool,plexAdmin: null == plexAdmin ? _self.plexAdmin : plexAdmin // ignore: cast_nullable_to_non_nullable +as bool,plexProtected: null == plexProtected ? _self.plexProtected : plexProtected // ignore: cast_nullable_to_non_nullable +as bool,sortOrder: null == sortOrder ? _self.sortOrder : sortOrder // ignore: cast_nullable_to_non_nullable +as int,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as DateTime,lastUsedAt: freezed == lastUsedAt ? _self.lastUsedAt : lastUsedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} + + +} + +// dart format on diff --git a/lib/profiles/profile_connection.dart b/lib/profiles/profile_connection.dart index 0b23c9a1..471f4447 100644 --- a/lib/profiles/profile_connection.dart +++ b/lib/profiles/profile_connection.dart @@ -1,3 +1,7 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'profile_connection.freezed.dart'; + /// A binding between a [Profile] and a [Connection], carrying the /// per-profile user-level token used when the profile is active. /// @@ -9,47 +13,19 @@ /// /// For Jellyfin: [userToken] mirrors the Connection's accessToken (one /// user per connection); [userIdentifier] is the Jellyfin user id. -class ProfileConnection { - final String profileId; - final String connectionId; - final String? userToken; - final String userIdentifier; - final bool isDefault; - final DateTime? tokenAcquiredAt; - final DateTime? lastUsedAt; +@freezed +sealed class ProfileConnection with _$ProfileConnection { + const ProfileConnection._(); - const ProfileConnection({ - required this.profileId, - required this.connectionId, - this.userToken, - required this.userIdentifier, - this.isDefault = false, - this.tokenAcquiredAt, - this.lastUsedAt, - }); + const factory ProfileConnection({ + required String profileId, + required String connectionId, + String? userToken, + required String userIdentifier, + @Default(false) bool isDefault, + DateTime? tokenAcquiredAt, + DateTime? lastUsedAt, + }) = _ProfileConnection; bool get hasToken => userToken != null && userToken!.isNotEmpty; - - ProfileConnection copyWith({ - String? profileId, - String? connectionId, - String? userToken, - bool clearUserToken = false, - String? userIdentifier, - bool? isDefault, - DateTime? tokenAcquiredAt, - bool clearTokenAcquiredAt = false, - DateTime? lastUsedAt, - bool clearLastUsedAt = false, - }) { - return ProfileConnection( - profileId: profileId ?? this.profileId, - connectionId: connectionId ?? this.connectionId, - userToken: clearUserToken ? null : (userToken ?? this.userToken), - userIdentifier: userIdentifier ?? this.userIdentifier, - isDefault: isDefault ?? this.isDefault, - tokenAcquiredAt: clearTokenAcquiredAt ? null : (tokenAcquiredAt ?? this.tokenAcquiredAt), - lastUsedAt: clearLastUsedAt ? null : (lastUsedAt ?? this.lastUsedAt), - ); - } } diff --git a/lib/profiles/profile_connection.freezed.dart b/lib/profiles/profile_connection.freezed.dart new file mode 100644 index 00000000..4be544bb --- /dev/null +++ b/lib/profiles/profile_connection.freezed.dart @@ -0,0 +1,283 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'profile_connection.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ProfileConnection { + + String get profileId; String get connectionId; String? get userToken; String get userIdentifier; bool get isDefault; DateTime? get tokenAcquiredAt; DateTime? get lastUsedAt; +/// Create a copy of ProfileConnection +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ProfileConnectionCopyWith get copyWith => _$ProfileConnectionCopyWithImpl(this as ProfileConnection, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ProfileConnection&&(identical(other.profileId, profileId) || other.profileId == profileId)&&(identical(other.connectionId, connectionId) || other.connectionId == connectionId)&&(identical(other.userToken, userToken) || other.userToken == userToken)&&(identical(other.userIdentifier, userIdentifier) || other.userIdentifier == userIdentifier)&&(identical(other.isDefault, isDefault) || other.isDefault == isDefault)&&(identical(other.tokenAcquiredAt, tokenAcquiredAt) || other.tokenAcquiredAt == tokenAcquiredAt)&&(identical(other.lastUsedAt, lastUsedAt) || other.lastUsedAt == lastUsedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,profileId,connectionId,userToken,userIdentifier,isDefault,tokenAcquiredAt,lastUsedAt); + +@override +String toString() { + return 'ProfileConnection(profileId: $profileId, connectionId: $connectionId, userToken: $userToken, userIdentifier: $userIdentifier, isDefault: $isDefault, tokenAcquiredAt: $tokenAcquiredAt, lastUsedAt: $lastUsedAt)'; +} + + +} + +/// @nodoc +abstract mixin class $ProfileConnectionCopyWith<$Res> { + factory $ProfileConnectionCopyWith(ProfileConnection value, $Res Function(ProfileConnection) _then) = _$ProfileConnectionCopyWithImpl; +@useResult +$Res call({ + String profileId, String connectionId, String? userToken, String userIdentifier, bool isDefault, DateTime? tokenAcquiredAt, DateTime? lastUsedAt +}); + + + + +} +/// @nodoc +class _$ProfileConnectionCopyWithImpl<$Res> + implements $ProfileConnectionCopyWith<$Res> { + _$ProfileConnectionCopyWithImpl(this._self, this._then); + + final ProfileConnection _self; + final $Res Function(ProfileConnection) _then; + +/// Create a copy of ProfileConnection +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? profileId = null,Object? connectionId = null,Object? userToken = freezed,Object? userIdentifier = null,Object? isDefault = null,Object? tokenAcquiredAt = freezed,Object? lastUsedAt = freezed,}) { + return _then(_self.copyWith( +profileId: null == profileId ? _self.profileId : profileId // ignore: cast_nullable_to_non_nullable +as String,connectionId: null == connectionId ? _self.connectionId : connectionId // ignore: cast_nullable_to_non_nullable +as String,userToken: freezed == userToken ? _self.userToken : userToken // ignore: cast_nullable_to_non_nullable +as String?,userIdentifier: null == userIdentifier ? _self.userIdentifier : userIdentifier // ignore: cast_nullable_to_non_nullable +as String,isDefault: null == isDefault ? _self.isDefault : isDefault // ignore: cast_nullable_to_non_nullable +as bool,tokenAcquiredAt: freezed == tokenAcquiredAt ? _self.tokenAcquiredAt : tokenAcquiredAt // ignore: cast_nullable_to_non_nullable +as DateTime?,lastUsedAt: freezed == lastUsedAt ? _self.lastUsedAt : lastUsedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ProfileConnection]. +extension ProfileConnectionPatterns on ProfileConnection { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _ProfileConnection value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ProfileConnection() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _ProfileConnection value) $default,){ +final _that = this; +switch (_that) { +case _ProfileConnection(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _ProfileConnection value)? $default,){ +final _that = this; +switch (_that) { +case _ProfileConnection() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String profileId, String connectionId, String? userToken, String userIdentifier, bool isDefault, DateTime? tokenAcquiredAt, DateTime? lastUsedAt)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ProfileConnection() when $default != null: +return $default(_that.profileId,_that.connectionId,_that.userToken,_that.userIdentifier,_that.isDefault,_that.tokenAcquiredAt,_that.lastUsedAt);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String profileId, String connectionId, String? userToken, String userIdentifier, bool isDefault, DateTime? tokenAcquiredAt, DateTime? lastUsedAt) $default,) {final _that = this; +switch (_that) { +case _ProfileConnection(): +return $default(_that.profileId,_that.connectionId,_that.userToken,_that.userIdentifier,_that.isDefault,_that.tokenAcquiredAt,_that.lastUsedAt);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String profileId, String connectionId, String? userToken, String userIdentifier, bool isDefault, DateTime? tokenAcquiredAt, DateTime? lastUsedAt)? $default,) {final _that = this; +switch (_that) { +case _ProfileConnection() when $default != null: +return $default(_that.profileId,_that.connectionId,_that.userToken,_that.userIdentifier,_that.isDefault,_that.tokenAcquiredAt,_that.lastUsedAt);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ProfileConnection extends ProfileConnection { + const _ProfileConnection({required this.profileId, required this.connectionId, this.userToken, required this.userIdentifier, this.isDefault = false, this.tokenAcquiredAt, this.lastUsedAt}): super._(); + + +@override final String profileId; +@override final String connectionId; +@override final String? userToken; +@override final String userIdentifier; +@override@JsonKey() final bool isDefault; +@override final DateTime? tokenAcquiredAt; +@override final DateTime? lastUsedAt; + +/// Create a copy of ProfileConnection +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ProfileConnectionCopyWith<_ProfileConnection> get copyWith => __$ProfileConnectionCopyWithImpl<_ProfileConnection>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProfileConnection&&(identical(other.profileId, profileId) || other.profileId == profileId)&&(identical(other.connectionId, connectionId) || other.connectionId == connectionId)&&(identical(other.userToken, userToken) || other.userToken == userToken)&&(identical(other.userIdentifier, userIdentifier) || other.userIdentifier == userIdentifier)&&(identical(other.isDefault, isDefault) || other.isDefault == isDefault)&&(identical(other.tokenAcquiredAt, tokenAcquiredAt) || other.tokenAcquiredAt == tokenAcquiredAt)&&(identical(other.lastUsedAt, lastUsedAt) || other.lastUsedAt == lastUsedAt)); +} + + +@override +int get hashCode => Object.hash(runtimeType,profileId,connectionId,userToken,userIdentifier,isDefault,tokenAcquiredAt,lastUsedAt); + +@override +String toString() { + return 'ProfileConnection(profileId: $profileId, connectionId: $connectionId, userToken: $userToken, userIdentifier: $userIdentifier, isDefault: $isDefault, tokenAcquiredAt: $tokenAcquiredAt, lastUsedAt: $lastUsedAt)'; +} + + +} + +/// @nodoc +abstract mixin class _$ProfileConnectionCopyWith<$Res> implements $ProfileConnectionCopyWith<$Res> { + factory _$ProfileConnectionCopyWith(_ProfileConnection value, $Res Function(_ProfileConnection) _then) = __$ProfileConnectionCopyWithImpl; +@override @useResult +$Res call({ + String profileId, String connectionId, String? userToken, String userIdentifier, bool isDefault, DateTime? tokenAcquiredAt, DateTime? lastUsedAt +}); + + + + +} +/// @nodoc +class __$ProfileConnectionCopyWithImpl<$Res> + implements _$ProfileConnectionCopyWith<$Res> { + __$ProfileConnectionCopyWithImpl(this._self, this._then); + + final _ProfileConnection _self; + final $Res Function(_ProfileConnection) _then; + +/// Create a copy of ProfileConnection +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? profileId = null,Object? connectionId = null,Object? userToken = freezed,Object? userIdentifier = null,Object? isDefault = null,Object? tokenAcquiredAt = freezed,Object? lastUsedAt = freezed,}) { + return _then(_ProfileConnection( +profileId: null == profileId ? _self.profileId : profileId // ignore: cast_nullable_to_non_nullable +as String,connectionId: null == connectionId ? _self.connectionId : connectionId // ignore: cast_nullable_to_non_nullable +as String,userToken: freezed == userToken ? _self.userToken : userToken // ignore: cast_nullable_to_non_nullable +as String?,userIdentifier: null == userIdentifier ? _self.userIdentifier : userIdentifier // ignore: cast_nullable_to_non_nullable +as String,isDefault: null == isDefault ? _self.isDefault : isDefault // ignore: cast_nullable_to_non_nullable +as bool,tokenAcquiredAt: freezed == tokenAcquiredAt ? _self.tokenAcquiredAt : tokenAcquiredAt // ignore: cast_nullable_to_non_nullable +as DateTime?,lastUsedAt: freezed == lastUsedAt ? _self.lastUsedAt : lastUsedAt // ignore: cast_nullable_to_non_nullable +as DateTime?, + )); +} + + +} + +// dart format on diff --git a/lib/providers/companion_remote_provider.dart b/lib/providers/companion_remote_provider.dart index 93c26503..f0b9a4eb 100644 --- a/lib/providers/companion_remote_provider.dart +++ b/lib/providers/companion_remote_provider.dart @@ -459,7 +459,11 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin final contexts = List.unmodifiable(_authContexts); final result = await _peerService!.createSessionForContexts(_deviceName, _platform, contexts); - _session = RemoteSession(role: RemoteSessionRole.host, status: RemoteSessionStatus.connected); + _session = RemoteSession( + role: RemoteSessionRole.host, + status: RemoteSessionStatus.connected, + createdAt: DateTime.now(), + ); safeNotifyListeners(); // Start LAN discovery broadcasting @@ -480,6 +484,7 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin role: RemoteSessionRole.host, status: RemoteSessionStatus.error, errorMessage: e.toString(), + createdAt: DateTime.now(), ); safeNotifyListeners(); } @@ -538,7 +543,11 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin _peerService = CompanionRemotePeerService(); _setupPeerServiceListeners(); - _session = RemoteSession(role: RemoteSessionRole.remote, status: RemoteSessionStatus.connecting); + _session = RemoteSession( + role: RemoteSessionRole.remote, + status: RemoteSessionStatus.connecting, + createdAt: DateTime.now(), + ); safeNotifyListeners(); try { @@ -582,7 +591,11 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin _peerService = CompanionRemotePeerService(); _setupPeerServiceListeners(); - _session = RemoteSession(role: RemoteSessionRole.remote, status: RemoteSessionStatus.connecting); + _session = RemoteSession( + role: RemoteSessionRole.remote, + status: RemoteSessionStatus.connecting, + createdAt: DateTime.now(), + ); safeNotifyListeners(); try { @@ -629,13 +642,13 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin _deviceDisconnectedSubscription = _peerService!.onDeviceDisconnected.listen((_) { appLogger.d('CompanionRemote: Device disconnected (intentional: $_intentionalDisconnect)'); if (_intentionalDisconnect) { - _session = _session?.copyWith(status: RemoteSessionStatus.disconnected, clearConnectedDevice: true); + _session = _session?.copyWith(status: RemoteSessionStatus.disconnected, connectedDevice: null); safeNotifyListeners(); } else if (isHost) { _session = _session?.copyWith( status: RemoteSessionStatus.reconnecting, - clearConnectedDevice: true, - clearErrorMessage: true, + connectedDevice: null, + errorMessage: null, ); safeNotifyListeners(); appLogger.d('CompanionRemote: Host waiting for client to reconnect'); @@ -668,7 +681,7 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin appLogger.d('CompanionRemote: Device info - name: $name, platform: $platform, role: $role'); - final device = RemoteDevice(id: id, name: name, platform: platform); + final device = RemoteDevice(id: id, name: name, platform: platform, connectedAt: DateTime.now()); _session = _session?.copyWith(connectedDevice: device); safeNotifyListeners(); @@ -756,7 +769,7 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin _lastAuthContextId = _peerService!.selectedAuthContextId ?? authContextId; _lastHostClientId = _peerService!.selectedHostClientId ?? _lastHostClientId; - _session = _session?.copyWith(status: RemoteSessionStatus.connected, clearErrorMessage: true); + _session = _session?.copyWith(status: RemoteSessionStatus.connected, errorMessage: null); _reconnectAttempts = 0; safeNotifyListeners(); appLogger.d('CompanionRemote: Reconnected successfully'); @@ -777,7 +790,7 @@ class CompanionRemoteProvider with ChangeNotifier, DisposableChangeNotifierMixin void cancelReconnect() { _reconnectTimer?.cancel(); _reconnectAttempts = 0; - _session = _session?.copyWith(status: RemoteSessionStatus.disconnected, clearConnectedDevice: true); + _session = _session?.copyWith(status: RemoteSessionStatus.disconnected, connectedDevice: null); safeNotifyListeners(); } diff --git a/lib/screens/profile/add_local_profile_screen.dart b/lib/screens/profile/add_local_profile_screen.dart index d05d2a89..bfeda97e 100644 --- a/lib/screens/profile/add_local_profile_screen.dart +++ b/lib/screens/profile/add_local_profile_screen.dart @@ -64,9 +64,8 @@ class _AddLocalProfileScreenState extends State with Cont setState(() => _saving = true); final registry = context.read(); - final profile = Profile( + final profile = Profile.local( id: 'local-${const Uuid().v4()}', - kind: ProfileKind.local, displayName: name, pinHash: _pinHash, sortOrder: DateTime.now().millisecondsSinceEpoch, diff --git a/lib/screens/profile/profile_detail_screen.dart b/lib/screens/profile/profile_detail_screen.dart index 175e1b26..9f63fd48 100644 --- a/lib/screens/profile/profile_detail_screen.dart +++ b/lib/screens/profile/profile_detail_screen.dart @@ -87,14 +87,18 @@ class _ProfileDetailScreenState extends State with Controll onMismatch: (ctx) => showErrorSnackBar(ctx, t.profiles.pinsDontMatch), ); if (pin == null || !mounted) return; - final updated = _profile.copyWith(pinHash: computePinHash(pin)); + final profile = _profile; + if (profile is! LocalProfile) return; + final updated = profile.copyWith(pinHash: computePinHash(pin)); await context.read().upsert(updated); if (!mounted) return; setState(() => _profile = updated); } Future _clearPin() async { - final updated = _profile.copyWith(clearPin: true); + final profile = _profile; + if (profile is! LocalProfile) return; + final updated = profile.copyWith(pinHash: null); await context.read().upsert(updated); if (!mounted) return; setState(() => _profile = updated); diff --git a/lib/screens/settings/add_jellyfin_screen.dart b/lib/screens/settings/add_jellyfin_screen.dart index 62214675..ebf23436 100644 --- a/lib/screens/settings/add_jellyfin_screen.dart +++ b/lib/screens/settings/add_jellyfin_screen.dart @@ -264,9 +264,8 @@ class _AddJellyfinScreenState extends State with AsyncFormSta hasProfiles: activeProvider.profiles.isNotEmpty, )) { final now = DateTime.now(); - final profile = Profile( + final profile = Profile.local( id: 'local-${const Uuid().v4()}', - kind: ProfileKind.local, displayName: connection.userName.isNotEmpty ? connection.userName : connection.serverName, sortOrder: now.millisecondsSinceEpoch, createdAt: now, diff --git a/lib/services/companion_remote/companion_remote_peer_service.dart b/lib/services/companion_remote/companion_remote_peer_service.dart index e8b3356e..59f43d39 100644 --- a/lib/services/companion_remote/companion_remote_peer_service.dart +++ b/lib/services/companion_remote/companion_remote_peer_service.dart @@ -343,7 +343,12 @@ class CompanionRemotePeerService with KeepaliveMixin { await _sendEncryptedToSocket(socket, jsonEncode({'type': 'authSuccess'})); // Notify connection - final device = RemoteDevice(id: 'remote-client', name: deviceName, platform: platform); + final device = RemoteDevice( + id: 'remote-client', + name: deviceName, + platform: platform, + connectedAt: DateTime.now(), + ); _deviceConnectedController.add(device); _connectionStateController.add(RemoteSessionStatus.connected); @@ -516,7 +521,12 @@ class CompanionRemotePeerService with KeepaliveMixin { completer.complete(); } - final device = RemoteDevice(id: 'host', name: 'Desktop', platform: 'desktop'); + final device = RemoteDevice( + id: 'host', + name: 'Desktop', + platform: 'desktop', + connectedAt: DateTime.now(), + ); _deviceConnectedController.add(device); _connectionStateController.add(RemoteSessionStatus.connected); diff --git a/lib/utils/json_converters.dart b/lib/utils/json_converters.dart new file mode 100644 index 00000000..e726d5b7 --- /dev/null +++ b/lib/utils/json_converters.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; + +/// Maps an enum value to/from its `int` index. Useful for compact wire formats +/// (e.g. companion-remote commands) where the over-the-wire size matters and +/// new enum cases are always appended. +/// +/// Out-of-range indices on the wire fall back to [_fallback] instead of +/// throwing — important for forward-compat with newer clients sending +/// commands the host doesn't yet understand. +class IndexedEnumConverter implements JsonConverter { + const IndexedEnumConverter(this._values, this._fallback); + + final List _values; + final T _fallback; + + @override + T fromJson(int json) => json >= 0 && json < _values.length ? _values[json] : _fallback; + + @override + int toJson(T object) => object.index; +} diff --git a/lib/watch_together/models/watch_session.dart b/lib/watch_together/models/watch_session.dart index ea933d8b..28c47213 100644 --- a/lib/watch_together/models/watch_session.dart +++ b/lib/watch_together/models/watch_session.dart @@ -1,98 +1,43 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'watch_session.freezed.dart'; + enum SessionRole { host, guest } enum ControlMode { hostOnly, anyone } enum SessionState { disconnected, connecting, connected, error } -class Participant { - final String peerId; - final String displayName; - final bool isHost; - final Duration lastKnownPosition; - final bool isBuffering; - - const Participant({ - required this.peerId, - required this.displayName, - required this.isHost, - this.lastKnownPosition = Duration.zero, - this.isBuffering = false, - }); - - Participant copyWith({ - String? peerId, - String? displayName, - bool? isHost, - Duration? lastKnownPosition, - bool? isBuffering, - }) { - return Participant( - peerId: peerId ?? this.peerId, - displayName: displayName ?? this.displayName, - isHost: isHost ?? this.isHost, - lastKnownPosition: lastKnownPosition ?? this.lastKnownPosition, - isBuffering: isBuffering ?? this.isBuffering, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || other is Participant && runtimeType == other.runtimeType && peerId == other.peerId; - - @override - int get hashCode => peerId.hashCode; +@freezed +sealed class Participant with _$Participant { + const factory Participant({ + required String peerId, + required String displayName, + required bool isHost, + @Default(Duration.zero) Duration lastKnownPosition, + @Default(false) bool isBuffering, + }) = _Participant; } -class WatchSession { - final String sessionId; - final SessionRole role; - final ControlMode controlMode; - final SessionState state; - final String? errorMessage; - final String? mediaRatingKey; - final String? mediaServerId; - final String? mediaTitle; - final String? hostPeerId; +@freezed +sealed class WatchSession with _$WatchSession { + const WatchSession._(); - const WatchSession({ - required this.sessionId, - required this.role, - required this.controlMode, - required this.state, - this.errorMessage, - this.mediaRatingKey, - this.mediaServerId, - this.mediaTitle, - this.hostPeerId, - }); - - bool get isHost => role == SessionRole.host; - - bool get isConnected => state == SessionState.connected; - - WatchSession copyWith({ - String? sessionId, - SessionRole? role, - ControlMode? controlMode, - SessionState? state, + const factory WatchSession({ + required String sessionId, + required SessionRole role, + required ControlMode controlMode, + required SessionState state, String? errorMessage, String? mediaRatingKey, String? mediaServerId, String? mediaTitle, String? hostPeerId, - }) { - return WatchSession( - sessionId: sessionId ?? this.sessionId, - role: role ?? this.role, - controlMode: controlMode ?? this.controlMode, - state: state ?? this.state, - errorMessage: errorMessage ?? this.errorMessage, - mediaRatingKey: mediaRatingKey ?? this.mediaRatingKey, - mediaServerId: mediaServerId ?? this.mediaServerId, - mediaTitle: mediaTitle ?? this.mediaTitle, - hostPeerId: hostPeerId ?? this.hostPeerId, - ); - } + }) = _WatchSession; + + bool get isHost => role == SessionRole.host; + + bool get isConnected => state == SessionState.connected; /// Create a new session as host factory WatchSession.createAsHost({ @@ -102,26 +47,22 @@ class WatchSession { String? mediaRatingKey, String? mediaServerId, String? mediaTitle, - }) { - return WatchSession( - sessionId: sessionId, - role: SessionRole.host, - controlMode: controlMode, - state: SessionState.connecting, - hostPeerId: hostPeerId, - mediaRatingKey: mediaRatingKey, - mediaServerId: mediaServerId, - mediaTitle: mediaTitle, - ); - } + }) => WatchSession( + sessionId: sessionId, + role: SessionRole.host, + controlMode: controlMode, + state: SessionState.connecting, + hostPeerId: hostPeerId, + mediaRatingKey: mediaRatingKey, + mediaServerId: mediaServerId, + mediaTitle: mediaTitle, + ); /// Create a session as guest (joining) - factory WatchSession.joinAsGuest({required String sessionId}) { - return WatchSession( - sessionId: sessionId, - role: SessionRole.guest, - controlMode: ControlMode.hostOnly, // Will be updated when connected - state: SessionState.connecting, - ); - } + factory WatchSession.joinAsGuest({required String sessionId}) => WatchSession( + sessionId: sessionId, + role: SessionRole.guest, + controlMode: ControlMode.hostOnly, // Will be updated when connected + state: SessionState.connecting, + ); } diff --git a/lib/watch_together/models/watch_session.freezed.dart b/lib/watch_together/models/watch_session.freezed.dart new file mode 100644 index 00000000..1eb3ef7c --- /dev/null +++ b/lib/watch_together/models/watch_session.freezed.dart @@ -0,0 +1,552 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'watch_session.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$Participant { + + String get peerId; String get displayName; bool get isHost; Duration get lastKnownPosition; bool get isBuffering; +/// Create a copy of Participant +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ParticipantCopyWith get copyWith => _$ParticipantCopyWithImpl(this as Participant, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Participant&&(identical(other.peerId, peerId) || other.peerId == peerId)&&(identical(other.displayName, displayName) || other.displayName == displayName)&&(identical(other.isHost, isHost) || other.isHost == isHost)&&(identical(other.lastKnownPosition, lastKnownPosition) || other.lastKnownPosition == lastKnownPosition)&&(identical(other.isBuffering, isBuffering) || other.isBuffering == isBuffering)); +} + + +@override +int get hashCode => Object.hash(runtimeType,peerId,displayName,isHost,lastKnownPosition,isBuffering); + +@override +String toString() { + return 'Participant(peerId: $peerId, displayName: $displayName, isHost: $isHost, lastKnownPosition: $lastKnownPosition, isBuffering: $isBuffering)'; +} + + +} + +/// @nodoc +abstract mixin class $ParticipantCopyWith<$Res> { + factory $ParticipantCopyWith(Participant value, $Res Function(Participant) _then) = _$ParticipantCopyWithImpl; +@useResult +$Res call({ + String peerId, String displayName, bool isHost, Duration lastKnownPosition, bool isBuffering +}); + + + + +} +/// @nodoc +class _$ParticipantCopyWithImpl<$Res> + implements $ParticipantCopyWith<$Res> { + _$ParticipantCopyWithImpl(this._self, this._then); + + final Participant _self; + final $Res Function(Participant) _then; + +/// Create a copy of Participant +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? peerId = null,Object? displayName = null,Object? isHost = null,Object? lastKnownPosition = null,Object? isBuffering = null,}) { + return _then(_self.copyWith( +peerId: null == peerId ? _self.peerId : peerId // ignore: cast_nullable_to_non_nullable +as String,displayName: null == displayName ? _self.displayName : displayName // ignore: cast_nullable_to_non_nullable +as String,isHost: null == isHost ? _self.isHost : isHost // ignore: cast_nullable_to_non_nullable +as bool,lastKnownPosition: null == lastKnownPosition ? _self.lastKnownPosition : lastKnownPosition // ignore: cast_nullable_to_non_nullable +as Duration,isBuffering: null == isBuffering ? _self.isBuffering : isBuffering // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Participant]. +extension ParticipantPatterns on Participant { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Participant value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Participant() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Participant value) $default,){ +final _that = this; +switch (_that) { +case _Participant(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Participant value)? $default,){ +final _that = this; +switch (_that) { +case _Participant() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String peerId, String displayName, bool isHost, Duration lastKnownPosition, bool isBuffering)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Participant() when $default != null: +return $default(_that.peerId,_that.displayName,_that.isHost,_that.lastKnownPosition,_that.isBuffering);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String peerId, String displayName, bool isHost, Duration lastKnownPosition, bool isBuffering) $default,) {final _that = this; +switch (_that) { +case _Participant(): +return $default(_that.peerId,_that.displayName,_that.isHost,_that.lastKnownPosition,_that.isBuffering);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String peerId, String displayName, bool isHost, Duration lastKnownPosition, bool isBuffering)? $default,) {final _that = this; +switch (_that) { +case _Participant() when $default != null: +return $default(_that.peerId,_that.displayName,_that.isHost,_that.lastKnownPosition,_that.isBuffering);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _Participant implements Participant { + const _Participant({required this.peerId, required this.displayName, required this.isHost, this.lastKnownPosition = Duration.zero, this.isBuffering = false}); + + +@override final String peerId; +@override final String displayName; +@override final bool isHost; +@override@JsonKey() final Duration lastKnownPosition; +@override@JsonKey() final bool isBuffering; + +/// Create a copy of Participant +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ParticipantCopyWith<_Participant> get copyWith => __$ParticipantCopyWithImpl<_Participant>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Participant&&(identical(other.peerId, peerId) || other.peerId == peerId)&&(identical(other.displayName, displayName) || other.displayName == displayName)&&(identical(other.isHost, isHost) || other.isHost == isHost)&&(identical(other.lastKnownPosition, lastKnownPosition) || other.lastKnownPosition == lastKnownPosition)&&(identical(other.isBuffering, isBuffering) || other.isBuffering == isBuffering)); +} + + +@override +int get hashCode => Object.hash(runtimeType,peerId,displayName,isHost,lastKnownPosition,isBuffering); + +@override +String toString() { + return 'Participant(peerId: $peerId, displayName: $displayName, isHost: $isHost, lastKnownPosition: $lastKnownPosition, isBuffering: $isBuffering)'; +} + + +} + +/// @nodoc +abstract mixin class _$ParticipantCopyWith<$Res> implements $ParticipantCopyWith<$Res> { + factory _$ParticipantCopyWith(_Participant value, $Res Function(_Participant) _then) = __$ParticipantCopyWithImpl; +@override @useResult +$Res call({ + String peerId, String displayName, bool isHost, Duration lastKnownPosition, bool isBuffering +}); + + + + +} +/// @nodoc +class __$ParticipantCopyWithImpl<$Res> + implements _$ParticipantCopyWith<$Res> { + __$ParticipantCopyWithImpl(this._self, this._then); + + final _Participant _self; + final $Res Function(_Participant) _then; + +/// Create a copy of Participant +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? peerId = null,Object? displayName = null,Object? isHost = null,Object? lastKnownPosition = null,Object? isBuffering = null,}) { + return _then(_Participant( +peerId: null == peerId ? _self.peerId : peerId // ignore: cast_nullable_to_non_nullable +as String,displayName: null == displayName ? _self.displayName : displayName // ignore: cast_nullable_to_non_nullable +as String,isHost: null == isHost ? _self.isHost : isHost // ignore: cast_nullable_to_non_nullable +as bool,lastKnownPosition: null == lastKnownPosition ? _self.lastKnownPosition : lastKnownPosition // ignore: cast_nullable_to_non_nullable +as Duration,isBuffering: null == isBuffering ? _self.isBuffering : isBuffering // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + +/// @nodoc +mixin _$WatchSession { + + String get sessionId; SessionRole get role; ControlMode get controlMode; SessionState get state; String? get errorMessage; String? get mediaRatingKey; String? get mediaServerId; String? get mediaTitle; String? get hostPeerId; +/// Create a copy of WatchSession +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$WatchSessionCopyWith get copyWith => _$WatchSessionCopyWithImpl(this as WatchSession, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is WatchSession&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId)&&(identical(other.role, role) || other.role == role)&&(identical(other.controlMode, controlMode) || other.controlMode == controlMode)&&(identical(other.state, state) || other.state == state)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.mediaRatingKey, mediaRatingKey) || other.mediaRatingKey == mediaRatingKey)&&(identical(other.mediaServerId, mediaServerId) || other.mediaServerId == mediaServerId)&&(identical(other.mediaTitle, mediaTitle) || other.mediaTitle == mediaTitle)&&(identical(other.hostPeerId, hostPeerId) || other.hostPeerId == hostPeerId)); +} + + +@override +int get hashCode => Object.hash(runtimeType,sessionId,role,controlMode,state,errorMessage,mediaRatingKey,mediaServerId,mediaTitle,hostPeerId); + +@override +String toString() { + return 'WatchSession(sessionId: $sessionId, role: $role, controlMode: $controlMode, state: $state, errorMessage: $errorMessage, mediaRatingKey: $mediaRatingKey, mediaServerId: $mediaServerId, mediaTitle: $mediaTitle, hostPeerId: $hostPeerId)'; +} + + +} + +/// @nodoc +abstract mixin class $WatchSessionCopyWith<$Res> { + factory $WatchSessionCopyWith(WatchSession value, $Res Function(WatchSession) _then) = _$WatchSessionCopyWithImpl; +@useResult +$Res call({ + String sessionId, SessionRole role, ControlMode controlMode, SessionState state, String? errorMessage, String? mediaRatingKey, String? mediaServerId, String? mediaTitle, String? hostPeerId +}); + + + + +} +/// @nodoc +class _$WatchSessionCopyWithImpl<$Res> + implements $WatchSessionCopyWith<$Res> { + _$WatchSessionCopyWithImpl(this._self, this._then); + + final WatchSession _self; + final $Res Function(WatchSession) _then; + +/// Create a copy of WatchSession +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? sessionId = null,Object? role = null,Object? controlMode = null,Object? state = null,Object? errorMessage = freezed,Object? mediaRatingKey = freezed,Object? mediaServerId = freezed,Object? mediaTitle = freezed,Object? hostPeerId = freezed,}) { + return _then(_self.copyWith( +sessionId: null == sessionId ? _self.sessionId : sessionId // ignore: cast_nullable_to_non_nullable +as String,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as SessionRole,controlMode: null == controlMode ? _self.controlMode : controlMode // ignore: cast_nullable_to_non_nullable +as ControlMode,state: null == state ? _self.state : state // ignore: cast_nullable_to_non_nullable +as SessionState,errorMessage: freezed == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String?,mediaRatingKey: freezed == mediaRatingKey ? _self.mediaRatingKey : mediaRatingKey // ignore: cast_nullable_to_non_nullable +as String?,mediaServerId: freezed == mediaServerId ? _self.mediaServerId : mediaServerId // ignore: cast_nullable_to_non_nullable +as String?,mediaTitle: freezed == mediaTitle ? _self.mediaTitle : mediaTitle // ignore: cast_nullable_to_non_nullable +as String?,hostPeerId: freezed == hostPeerId ? _self.hostPeerId : hostPeerId // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [WatchSession]. +extension WatchSessionPatterns on WatchSession { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _WatchSession value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _WatchSession() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _WatchSession value) $default,){ +final _that = this; +switch (_that) { +case _WatchSession(): +return $default(_that);} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _WatchSession value)? $default,){ +final _that = this; +switch (_that) { +case _WatchSession() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String sessionId, SessionRole role, ControlMode controlMode, SessionState state, String? errorMessage, String? mediaRatingKey, String? mediaServerId, String? mediaTitle, String? hostPeerId)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _WatchSession() when $default != null: +return $default(_that.sessionId,_that.role,_that.controlMode,_that.state,_that.errorMessage,_that.mediaRatingKey,_that.mediaServerId,_that.mediaTitle,_that.hostPeerId);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String sessionId, SessionRole role, ControlMode controlMode, SessionState state, String? errorMessage, String? mediaRatingKey, String? mediaServerId, String? mediaTitle, String? hostPeerId) $default,) {final _that = this; +switch (_that) { +case _WatchSession(): +return $default(_that.sessionId,_that.role,_that.controlMode,_that.state,_that.errorMessage,_that.mediaRatingKey,_that.mediaServerId,_that.mediaTitle,_that.hostPeerId);} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String sessionId, SessionRole role, ControlMode controlMode, SessionState state, String? errorMessage, String? mediaRatingKey, String? mediaServerId, String? mediaTitle, String? hostPeerId)? $default,) {final _that = this; +switch (_that) { +case _WatchSession() when $default != null: +return $default(_that.sessionId,_that.role,_that.controlMode,_that.state,_that.errorMessage,_that.mediaRatingKey,_that.mediaServerId,_that.mediaTitle,_that.hostPeerId);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _WatchSession extends WatchSession { + const _WatchSession({required this.sessionId, required this.role, required this.controlMode, required this.state, this.errorMessage, this.mediaRatingKey, this.mediaServerId, this.mediaTitle, this.hostPeerId}): super._(); + + +@override final String sessionId; +@override final SessionRole role; +@override final ControlMode controlMode; +@override final SessionState state; +@override final String? errorMessage; +@override final String? mediaRatingKey; +@override final String? mediaServerId; +@override final String? mediaTitle; +@override final String? hostPeerId; + +/// Create a copy of WatchSession +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$WatchSessionCopyWith<_WatchSession> get copyWith => __$WatchSessionCopyWithImpl<_WatchSession>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _WatchSession&&(identical(other.sessionId, sessionId) || other.sessionId == sessionId)&&(identical(other.role, role) || other.role == role)&&(identical(other.controlMode, controlMode) || other.controlMode == controlMode)&&(identical(other.state, state) || other.state == state)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)&&(identical(other.mediaRatingKey, mediaRatingKey) || other.mediaRatingKey == mediaRatingKey)&&(identical(other.mediaServerId, mediaServerId) || other.mediaServerId == mediaServerId)&&(identical(other.mediaTitle, mediaTitle) || other.mediaTitle == mediaTitle)&&(identical(other.hostPeerId, hostPeerId) || other.hostPeerId == hostPeerId)); +} + + +@override +int get hashCode => Object.hash(runtimeType,sessionId,role,controlMode,state,errorMessage,mediaRatingKey,mediaServerId,mediaTitle,hostPeerId); + +@override +String toString() { + return 'WatchSession(sessionId: $sessionId, role: $role, controlMode: $controlMode, state: $state, errorMessage: $errorMessage, mediaRatingKey: $mediaRatingKey, mediaServerId: $mediaServerId, mediaTitle: $mediaTitle, hostPeerId: $hostPeerId)'; +} + + +} + +/// @nodoc +abstract mixin class _$WatchSessionCopyWith<$Res> implements $WatchSessionCopyWith<$Res> { + factory _$WatchSessionCopyWith(_WatchSession value, $Res Function(_WatchSession) _then) = __$WatchSessionCopyWithImpl; +@override @useResult +$Res call({ + String sessionId, SessionRole role, ControlMode controlMode, SessionState state, String? errorMessage, String? mediaRatingKey, String? mediaServerId, String? mediaTitle, String? hostPeerId +}); + + + + +} +/// @nodoc +class __$WatchSessionCopyWithImpl<$Res> + implements _$WatchSessionCopyWith<$Res> { + __$WatchSessionCopyWithImpl(this._self, this._then); + + final _WatchSession _self; + final $Res Function(_WatchSession) _then; + +/// Create a copy of WatchSession +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? sessionId = null,Object? role = null,Object? controlMode = null,Object? state = null,Object? errorMessage = freezed,Object? mediaRatingKey = freezed,Object? mediaServerId = freezed,Object? mediaTitle = freezed,Object? hostPeerId = freezed,}) { + return _then(_WatchSession( +sessionId: null == sessionId ? _self.sessionId : sessionId // ignore: cast_nullable_to_non_nullable +as String,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as SessionRole,controlMode: null == controlMode ? _self.controlMode : controlMode // ignore: cast_nullable_to_non_nullable +as ControlMode,state: null == state ? _self.state : state // ignore: cast_nullable_to_non_nullable +as SessionState,errorMessage: freezed == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable +as String?,mediaRatingKey: freezed == mediaRatingKey ? _self.mediaRatingKey : mediaRatingKey // ignore: cast_nullable_to_non_nullable +as String?,mediaServerId: freezed == mediaServerId ? _self.mediaServerId : mediaServerId // ignore: cast_nullable_to_non_nullable +as String?,mediaTitle: freezed == mediaTitle ? _self.mediaTitle : mediaTitle // ignore: cast_nullable_to_non_nullable +as String?,hostPeerId: freezed == hostPeerId ? _self.hostPeerId : hostPeerId // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/lib/watch_together/providers/watch_together_provider.dart b/lib/watch_together/providers/watch_together_provider.dart index 4d0a9702..74e04d3b 100644 --- a/lib/watch_together/providers/watch_together_provider.dart +++ b/lib/watch_together/providers/watch_together_provider.dart @@ -544,7 +544,7 @@ class WatchTogetherProvider with ChangeNotifier { if (message.peerId != null && message.position != null) { final index = _participants.indexWhere((p) => p.peerId == message.peerId); if (index >= 0) { - _participants[index] = _participants[index].copyWith(lastKnownPosition: message.position); + _participants[index] = _participants[index].copyWith(lastKnownPosition: message.position!); // Don't notify for position updates - too frequent } } @@ -606,7 +606,7 @@ class WatchTogetherProvider with ChangeNotifier { if (message.controlMode != null) { appLogger.d('WatchTogether: Received session config, controlMode: ${message.controlMode}'); - _session = _session!.copyWith(controlMode: message.controlMode); + _session = _session!.copyWith(controlMode: message.controlMode!); _syncManager?.updateSession(_session!); // Update sync manager if it exists notifyListeners(); } diff --git a/scripts/ci_checks.sh b/scripts/ci_checks.sh index 14695f45..6b487a31 100755 --- a/scripts/ci_checks.sh +++ b/scripts/ci_checks.sh @@ -59,7 +59,27 @@ else rm -f "$out" fi -# 2. Native formatting +# 2. Codegen freshness (build_runner outputs newer than their sources) +section "codegen freshness" +stale=() +while IFS= read -r -d '' src; do + for gen in "${src%.dart}.g.dart" "${src%.dart}.freezed.dart"; do + if [ -f "$gen" ] && [ "$src" -nt "$gen" ]; then + stale+=("${src#./}") + break + fi + done +done < <(find lib -name "*.dart" ! -name "*.g.dart" ! -name "*.freezed.dart" -type f -print0 2>/dev/null) +if [ ${#stale[@]} -eq 0 ]; then + ok "no stale generated files" +else + fail "${#stale[@]} dart source(s) newer than their generated .g/.freezed:" + printf ' %s\n' "${stale[@]}" + echo " Run: scripts/codegen.sh" + FAILED=1 +fi + +# 3. Native formatting section "native format" out="$(mktemp)" if scripts/format_native.sh --check >"$out" 2>&1; then diff --git a/scripts/codegen.sh b/scripts/codegen.sh new file mode 100755 index 00000000..cb6042a3 --- /dev/null +++ b/scripts/codegen.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/.." +exec dart run build_runner build --delete-conflicting-outputs "$@" diff --git a/test/media/media_sort_test.dart b/test/media/media_sort_test.dart index ad2c7b30..cb1d9cb4 100644 --- a/test/media/media_sort_test.dart +++ b/test/media/media_sort_test.dart @@ -59,13 +59,19 @@ void main() { }); group('MediaSort equality & hashCode', () { - test('equality is based on key only (matches current contract)', () { + test('value equality across all fields', () { final a = MediaSort(key: 'k', descKey: 'k:desc', title: 'A', defaultDirection: 'asc'); - final b = MediaSort(key: 'k', descKey: 'other', title: 'B', defaultDirection: 'desc'); + final b = MediaSort(key: 'k', descKey: 'k:desc', title: 'A', defaultDirection: 'asc'); expect(a, equals(b)); expect(a.hashCode, b.hashCode); }); + test('differing non-key fields make instances unequal', () { + final a = MediaSort(key: 'k', descKey: 'k:desc', title: 'A', defaultDirection: 'asc'); + final b = MediaSort(key: 'k', descKey: 'other', title: 'B', defaultDirection: 'desc'); + expect(a, isNot(equals(b))); + }); + test('different keys are not equal', () { final a = MediaSort(key: 'k1', title: 'A'); final b = MediaSort(key: 'k2', title: 'A'); diff --git a/test/profiles/active_profile_binder_test.dart b/test/profiles/active_profile_binder_test.dart index 4f4312d1..050c5099 100644 --- a/test/profiles/active_profile_binder_test.dart +++ b/test/profiles/active_profile_binder_test.dart @@ -71,7 +71,7 @@ void main() { }); Future createActiveLocalProfile(String id) async { - final profile = Profile(id: id, kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); + final profile = Profile.local(id: id, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); await profiles.upsert(profile); await storage.setActiveProfileId(profile.id); await activeProfile.initialize(); @@ -79,12 +79,7 @@ void main() { } test('local profile with no connections binds successfully with empty visibility', () async { - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); await profiles.upsert(profile); await storage.setActiveProfileId(profile.id); await activeProfile.initialize(); @@ -97,12 +92,7 @@ void main() { }); test('started binder does not loop forever after empty local bind', () async { - final profile = Profile( - id: 'local-empty', - kind: ProfileKind.local, - displayName: 'Empty', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-empty', displayName: 'Empty', createdAt: DateTime(2026, 1, 1)); await profiles.upsert(profile); await storage.setActiveProfileId(profile.id); await activeProfile.initialize(); diff --git a/test/profiles/active_profile_provider_test.dart b/test/profiles/active_profile_provider_test.dart index bbe01c27..328db2f5 100644 --- a/test/profiles/active_profile_provider_test.dart +++ b/test/profiles/active_profile_provider_test.dart @@ -97,9 +97,7 @@ void main() { // Fresh state: no auto-fallback to the first profile so the UI can // force the picker. The binder skips its rebind while active is null, // which is what avoids the surprise PIN prompt at first sign-in. - await registry.upsert( - Profile(id: 'p1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1))); await provider.initialize(); expect(provider.profiles, hasLength(1)); expect(provider.activeId, isNull); @@ -127,9 +125,7 @@ void main() { test('initialize clears storage when stored id is stale', () async { // A previously-active profile that was deleted should not keep // storage-scoped settings under the removed profile id. - await registry.upsert( - Profile(id: 'p1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1))); await storage.setActiveProfileId('ghost-id-no-longer-exists'); await provider.initialize(); await Future.delayed(Duration.zero); @@ -138,24 +134,16 @@ void main() { }); test('initialize resolves the stored active profile id', () async { - await registry.upsert( - Profile(id: 'p1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)), - ); - await registry.upsert( - Profile(id: 'p2', kind: ProfileKind.local, displayName: 'Kids', createdAt: DateTime(2026, 1, 2)), - ); + await registry.upsert(Profile.local(id: 'p1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1))); + await registry.upsert(Profile.local(id: 'p2', displayName: 'Kids', createdAt: DateTime(2026, 1, 2))); await storage.setActiveProfileId('p2'); await provider.initialize(); expect(provider.activeId, 'p2'); }); test('activate without PIN switches a non-protected profile', () async { - await registry.upsert( - Profile(id: 'p1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)), - ); - await registry.upsert( - Profile(id: 'p2', kind: ProfileKind.local, displayName: 'Kids', createdAt: DateTime(2026, 1, 2)), - ); + await registry.upsert(Profile.local(id: 'p1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1))); + await registry.upsert(Profile.local(id: 'p2', displayName: 'Kids', createdAt: DateTime(2026, 1, 2))); await provider.initialize(); final p2 = provider.profiles.firstWhere((p) => p.id == 'p2'); final ok = await provider.activate(p2); @@ -164,9 +152,7 @@ void main() { }); test('clearActiveProfile clears storage and in-memory active profile', () async { - await registry.upsert( - Profile(id: 'p1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1))); await provider.initialize(); await provider.activate(provider.profiles.single); @@ -178,13 +164,7 @@ void main() { test('activate rejects wrong PIN for a protected local profile', () async { await registry.upsert( - Profile( - id: 'p1', - kind: ProfileKind.local, - displayName: 'Kids', - pinHash: computePinHash('1234'), - createdAt: DateTime(2026, 1, 1), - ), + Profile.local(id: 'p1', displayName: 'Kids', pinHash: computePinHash('1234'), createdAt: DateTime(2026, 1, 1)), ); await provider.initialize(); final p1 = provider.profiles.first; @@ -193,9 +173,7 @@ void main() { }); test('hasMultipleProfiles reflects the registry size', () async { - await registry.upsert( - Profile(id: 'p1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1))); await provider.initialize(); expect(provider.hasMultipleProfiles, isFalse); // Latch onto the next provider notification that flips the flag, @@ -211,9 +189,7 @@ void main() { provider.addListener(listener); addTearDown(() => provider.removeListener(listener)); - await registry.upsert( - Profile(id: 'p2', kind: ProfileKind.local, displayName: 'Kids', createdAt: DateTime(2026, 1, 2)), - ); + await registry.upsert(Profile.local(id: 'p2', displayName: 'Kids', createdAt: DateTime(2026, 1, 2))); await flipped.future.timeout(const Duration(seconds: 2)); expect(provider.hasMultipleProfiles, isTrue); }); diff --git a/test/profiles/profile_registry_test.dart b/test/profiles/profile_registry_test.dart index f50bfaa6..d1bf69c9 100644 --- a/test/profiles/profile_registry_test.dart +++ b/test/profiles/profile_registry_test.dart @@ -23,9 +23,8 @@ void main() { }); test('upsert + get round-trips a local profile', () async { - final profile = Profile( + final profile = Profile.local( id: 'local-1', - kind: ProfileKind.local, displayName: 'Owner', pinHash: computePinHash('1234'), createdAt: DateTime(2026, 1, 1), @@ -40,9 +39,8 @@ void main() { }); test('upsert + get round-trips a plex_home profile', () async { - final profile = Profile( + final profile = Profile.plexHome( id: 'plex-home-acct-uuid', - kind: ProfileKind.plexHome, displayName: 'Admin', avatarThumbUrl: 'https://plex.tv/users/abc/avatar?', parentConnectionId: 'acct', @@ -62,28 +60,20 @@ void main() { }); test('list orders by sortOrder then createdAt', () async { - await registry.upsert( - Profile(id: 'a', kind: ProfileKind.local, displayName: 'A', sortOrder: 1, createdAt: DateTime(2026, 1, 1)), - ); - await registry.upsert( - Profile(id: 'b', kind: ProfileKind.local, displayName: 'B', sortOrder: 0, createdAt: DateTime(2026, 1, 2)), - ); + await registry.upsert(Profile.local(id: 'a', displayName: 'A', sortOrder: 1, createdAt: DateTime(2026, 1, 1))); + await registry.upsert(Profile.local(id: 'b', displayName: 'B', sortOrder: 0, createdAt: DateTime(2026, 1, 2))); final list = await registry.list(); expect(list.map((p) => p.id).toList(), ['b', 'a']); }); test('remove deletes a profile', () async { - await registry.upsert( - Profile(id: 'p', kind: ProfileKind.local, displayName: 'P', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p', displayName: 'P', createdAt: DateTime(2026, 1, 1))); await registry.remove('p'); expect(await registry.get('p'), isNull); }); test('markUsed updates lastUsedAt', () async { - await registry.upsert( - Profile(id: 'p', kind: ProfileKind.local, displayName: 'P', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p', displayName: 'P', createdAt: DateTime(2026, 1, 1))); final ts = DateTime(2026, 1, 5, 12, 0); await registry.markUsed('p', ts); final fetched = await registry.get('p'); @@ -91,12 +81,8 @@ void main() { }); test('upsert is idempotent (replaces existing row)', () async { - await registry.upsert( - Profile(id: 'p', kind: ProfileKind.local, displayName: 'Original', createdAt: DateTime(2026, 1, 1)), - ); - await registry.upsert( - Profile(id: 'p', kind: ProfileKind.local, displayName: 'Renamed', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p', displayName: 'Original', createdAt: DateTime(2026, 1, 1))); + await registry.upsert(Profile.local(id: 'p', displayName: 'Renamed', createdAt: DateTime(2026, 1, 1))); final fetched = await registry.get('p'); expect(fetched!.displayName, 'Renamed'); }); @@ -115,9 +101,7 @@ void main() { emitsThrough(isEmpty), ]), ); - await registry.upsert( - Profile(id: 'p', kind: ProfileKind.local, displayName: 'P', createdAt: DateTime(2026, 1, 1)), - ); + await registry.upsert(Profile.local(id: 'p', displayName: 'P', createdAt: DateTime(2026, 1, 1))); await registry.remove('p'); await assertion; }); diff --git a/test/profiles/profile_test.dart b/test/profiles/profile_test.dart index 693a8573..16ce1367 100644 --- a/test/profiles/profile_test.dart +++ b/test/profiles/profile_test.dart @@ -4,7 +4,7 @@ import 'package:plezy/profiles/profile.dart'; void main() { group('Profile', () { test('local profile defaults', () { - final p = Profile(id: 'local-1', kind: ProfileKind.local, displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); + final p = Profile.local(id: 'local-1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); expect(p.isLocal, isTrue); expect(p.isPlexHome, isFalse); expect(p.isPinProtected, isFalse); @@ -12,9 +12,8 @@ void main() { }); test('local profile with PIN is pin-protected', () { - final p = Profile( + final p = Profile.local( id: 'local-1', - kind: ProfileKind.local, displayName: 'Kids', pinHash: computePinHash('1234'), createdAt: DateTime(2026, 1, 1), @@ -23,9 +22,8 @@ void main() { }); test('plex_home profile pin protection follows the protected flag', () { - final p = Profile( + final p = Profile.plexHome( id: 'plex-home-acct1-uuid1', - kind: ProfileKind.plexHome, displayName: 'Sarah', parentConnectionId: 'acct1', plexProtected: true, @@ -36,9 +34,8 @@ void main() { }); test('local PIN hash is round-tripped via configJson', () { - final p = Profile( + final p = Profile.local( id: 'local-1', - kind: ProfileKind.local, displayName: 'Kids', pinHash: computePinHash('1234'), createdAt: DateTime(2026, 1, 1), @@ -59,9 +56,8 @@ void main() { }); test('plex_home configJson round-trips with all flags', () { - final p = Profile( + final p = Profile.plexHome( id: 'plex-home-acct1-uuid1', - kind: ProfileKind.plexHome, displayName: 'Admin', parentConnectionId: 'acct1', plexAdmin: true, diff --git a/test/profiles/profiles_view_test.dart b/test/profiles/profiles_view_test.dart index 7b7a1d1c..ad32e463 100644 --- a/test/profiles/profiles_view_test.dart +++ b/test/profiles/profiles_view_test.dart @@ -6,12 +6,7 @@ import 'package:plezy/profiles/profiles_view.dart'; void main() { group('visibleProfileConnections', () { test('keeps all local profile connection rows', () { - final profile = Profile( - id: 'local-1', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-1', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); const rows = [ ProfileConnection(profileId: 'local-1', connectionId: 'plex-1', userIdentifier: 'u1'), ProfileConnection(profileId: 'local-1', connectionId: 'jellyfin-1', userIdentifier: 'u2'), @@ -21,9 +16,8 @@ void main() { }); test('filters Plex Home parent token cache row', () { - final profile = Profile( + final profile = Profile.plexHome( id: 'plex-home-plex-1-user-1', - kind: ProfileKind.plexHome, displayName: 'Kid', parentConnectionId: 'plex-1', createdAt: DateTime(2026, 1, 1), diff --git a/test/providers/companion_remote_provider_test.dart b/test/providers/companion_remote_provider_test.dart index c10840ca..c346087e 100644 --- a/test/providers/companion_remote_provider_test.dart +++ b/test/providers/companion_remote_provider_test.dart @@ -461,7 +461,7 @@ JellyfinConnection _jellyfinConnection(String id) { } Profile _localProfile(String id) { - return Profile(id: id, kind: ProfileKind.local, displayName: id, createdAt: DateTime(2026, 1, 1)); + return Profile.local(id: id, displayName: id, createdAt: DateTime(2026, 1, 1)); } PlexHome _home(String adminUuid) { diff --git a/test/providers/user_profile_provider_test.dart b/test/providers/user_profile_provider_test.dart index 03710465..e00fd305 100644 --- a/test/providers/user_profile_provider_test.dart +++ b/test/providers/user_profile_provider_test.dart @@ -80,12 +80,7 @@ void main() { await db.close(); }); - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); final plex = PlexAccountConnection( id: 'plex-a', accountToken: 'plex-token', @@ -217,12 +212,7 @@ void main() { await db.close(); }); - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); final accountA = PlexAccountConnection( id: 'plex-a', accountToken: 'wrong-owner-token', diff --git a/test/screens/auth_screen_test.dart b/test/screens/auth_screen_test.dart index 0668d56b..16240ede 100644 --- a/test/screens/auth_screen_test.dart +++ b/test/screens/auth_screen_test.dart @@ -75,12 +75,7 @@ void main() { }); test('initial profile selection is skipped when a profile was auto-selected', () { - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); expect( shouldPromptForInitialProfileSelection( @@ -94,12 +89,7 @@ void main() { }); test('initial profile selection is required when the launch setting is enabled', () { - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); expect( shouldPromptForInitialProfileSelection( diff --git a/test/screens/profile/profile_detail_screen_test.dart b/test/screens/profile/profile_detail_screen_test.dart index ec8e6561..4b6fd8c0 100644 --- a/test/screens/profile/profile_detail_screen_test.dart +++ b/test/screens/profile/profile_detail_screen_test.dart @@ -35,12 +35,7 @@ void main() { testWidgets('remote back pops the manage profile page', (tester) async { TvDetectionService.debugSetAppleTVOverride(true); final db = AppDatabase.forTesting(NativeDatabase.memory()); - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); final profiles = ProfileRegistry(db); final connections = _FakeConnectionRegistry(db); final profileConnections = _FakeProfileConnectionRegistry(db); diff --git a/test/screens/profile/profile_switch_screen_test.dart b/test/screens/profile/profile_switch_screen_test.dart index 78c72201..3eff23b6 100644 --- a/test/screens/profile/profile_switch_screen_test.dart +++ b/test/screens/profile/profile_switch_screen_test.dart @@ -28,12 +28,7 @@ void main() { testWidgets('D-pad can focus profile actions and open the manage menu', (tester) async { final db = AppDatabase.forTesting(NativeDatabase.memory()); - final profile = Profile( - id: 'local-owner', - kind: ProfileKind.local, - displayName: 'Owner', - createdAt: DateTime(2026, 1, 1), - ); + final profile = Profile.local(id: 'local-owner', displayName: 'Owner', createdAt: DateTime(2026, 1, 1)); final profiles = _FakeProfileRegistry(db, [profile]); final connections = _FakeConnectionRegistry(db); final profileConnections = _FakeProfileConnectionRegistry(db); diff --git a/test/screens/settings/add_jellyfin_screen_test.dart b/test/screens/settings/add_jellyfin_screen_test.dart index d103790c..78e33e96 100644 --- a/test/screens/settings/add_jellyfin_screen_test.dart +++ b/test/screens/settings/add_jellyfin_screen_test.dart @@ -5,13 +5,8 @@ import 'package:plezy/profiles/profile.dart'; import 'package:plezy/screens/settings/add_jellyfin_screen.dart'; import 'package:plezy/utils/platform_detector.dart'; -Profile _profile(String id) => Profile( - id: id, - kind: ProfileKind.local, - displayName: id, - sortOrder: 0, - createdAt: DateTime.fromMillisecondsSinceEpoch(0), -); +Profile _profile(String id) => + Profile.local(id: id, displayName: id, sortOrder: 0, createdAt: DateTime.fromMillisecondsSinceEpoch(0)); void main() { tearDown(() {