mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: replace Tenor GIF service with Klipy GIF service

+2402 -652
+106
lib/src/features/composer/domain/klipy_gif.dart
··· 1 + import 'package:freezed_annotation/freezed_annotation.dart'; 2 + 3 + part 'klipy_gif.freezed.dart'; 4 + part 'klipy_gif.g.dart'; 5 + 6 + /// Represents a media format from Klipy API (url, dimensions, size). 7 + @freezed 8 + abstract class KlipyMediaFormat with _$KlipyMediaFormat { 9 + const factory KlipyMediaFormat({ 10 + @Default('') String url, 11 + @Default(0) int width, 12 + @Default(0) int height, 13 + int? size, 14 + }) = _KlipyMediaFormat; 15 + 16 + factory KlipyMediaFormat.fromJson(Map<String, dynamic> json) => _$KlipyMediaFormatFromJson(json); 17 + } 18 + 19 + /// Represents all format variants for a single size (gif, webp, jpg, mp4, webm). 20 + @freezed 21 + abstract class KlipyFormatVariants with _$KlipyFormatVariants { 22 + const factory KlipyFormatVariants({ 23 + KlipyMediaFormat? gif, 24 + KlipyMediaFormat? webp, 25 + KlipyMediaFormat? jpg, 26 + KlipyMediaFormat? mp4, 27 + KlipyMediaFormat? webm, 28 + }) = _KlipyFormatVariants; 29 + 30 + factory KlipyFormatVariants.fromJson(Map<String, dynamic> json) => 31 + _$KlipyFormatVariantsFromJson(json); 32 + } 33 + 34 + /// Represents all size variants for a GIF (hd, md, sm, xs). 35 + @freezed 36 + abstract class KlipyFile with _$KlipyFile { 37 + const factory KlipyFile({ 38 + KlipyFormatVariants? hd, 39 + KlipyFormatVariants? md, 40 + KlipyFormatVariants? sm, 41 + KlipyFormatVariants? xs, 42 + }) = _KlipyFile; 43 + 44 + factory KlipyFile.fromJson(Map<String, dynamic> json) => _$KlipyFileFromJson(json); 45 + } 46 + 47 + /// Represents a GIF result from Klipy API. 48 + @freezed 49 + abstract class KlipyGif with _$KlipyGif { 50 + const factory KlipyGif({ 51 + @Default(0) int id, 52 + @Default('') String slug, 53 + @Default('') String title, 54 + @Default(KlipyFile()) KlipyFile file, 55 + List<String>? tags, 56 + String? type, 57 + @JsonKey(name: 'blur_preview') String? blurPreview, 58 + }) = _KlipyGif; 59 + 60 + const KlipyGif._(); 61 + 62 + factory KlipyGif.fromJson(Map<String, dynamic> json) => _$KlipyGifFromJson(json); 63 + 64 + /// URL for the thumbnail (small webp preferred, falls back to gif). 65 + String? get thumbnailUrl { 66 + return file.sm?.webp?.url ?? file.sm?.gif?.url ?? file.xs?.webp?.url ?? file.xs?.gif?.url; 67 + } 68 + 69 + /// URL for the full GIF (medium size preferred). 70 + String? get gifUrl { 71 + return file.md?.gif?.url ?? file.hd?.gif?.url ?? file.sm?.gif?.url; 72 + } 73 + 74 + /// URL to attribute/link back to Klipy. 75 + String get itemUrl => 'https://klipy.com/gif/$slug'; 76 + } 77 + 78 + /// Represents search results from Klipy API. 79 + @freezed 80 + abstract class KlipySearchResponse with _$KlipySearchResponse { 81 + const factory KlipySearchResponse({ 82 + @Default([]) List<KlipyGif> results, 83 + @JsonKey(name: 'current_page') @Default(1) int currentPage, 84 + @JsonKey(name: 'per_page') @Default(24) int perPage, 85 + @JsonKey(name: 'has_next') @Default(false) bool hasNext, 86 + }) = _KlipySearchResponse; 87 + 88 + const KlipySearchResponse._(); 89 + 90 + factory KlipySearchResponse.fromJson(Map<String, dynamic> json) => 91 + _$KlipySearchResponseFromJson(json); 92 + 93 + /// Creates a [KlipySearchResponse] from the raw Klipy API response which 94 + /// wraps the pagination data in a 'data' field. 95 + factory KlipySearchResponse.fromApiResponse(Map<String, dynamic> json) { 96 + final data = json['data'] as Map<String, dynamic>?; 97 + if (data != null) { 98 + return KlipySearchResponse.fromJson({...data, 'results': data['data']}); 99 + } 100 + 101 + return KlipySearchResponse.fromJson(json); 102 + } 103 + 104 + /// Next page number if there are more results. 105 + int? get nextPage => hasNext ? currentPage + 1 : null; 106 + }
+1634
lib/src/features/composer/domain/klipy_gif.freezed.dart
··· 1 + // GENERATED CODE - DO NOT MODIFY BY HAND 2 + // coverage:ignore-file 3 + // ignore_for_file: type=lint 4 + // 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 5 + 6 + part of 'klipy_gif.dart'; 7 + 8 + // ************************************************************************** 9 + // FreezedGenerator 10 + // ************************************************************************** 11 + 12 + // dart format off 13 + T _$identity<T>(T value) => value; 14 + 15 + /// @nodoc 16 + mixin _$KlipyMediaFormat { 17 + 18 + String get url; int get width; int get height; int? get size; 19 + /// Create a copy of KlipyMediaFormat 20 + /// with the given fields replaced by the non-null parameter values. 21 + @JsonKey(includeFromJson: false, includeToJson: false) 22 + @pragma('vm:prefer-inline') 23 + $KlipyMediaFormatCopyWith<KlipyMediaFormat> get copyWith => _$KlipyMediaFormatCopyWithImpl<KlipyMediaFormat>(this as KlipyMediaFormat, _$identity); 24 + 25 + /// Serializes this KlipyMediaFormat to a JSON map. 26 + Map<String, dynamic> toJson(); 27 + 28 + 29 + @override 30 + bool operator ==(Object other) { 31 + return identical(this, other) || (other.runtimeType == runtimeType&&other is KlipyMediaFormat&&(identical(other.url, url) || other.url == url)&&(identical(other.width, width) || other.width == width)&&(identical(other.height, height) || other.height == height)&&(identical(other.size, size) || other.size == size)); 32 + } 33 + 34 + @JsonKey(includeFromJson: false, includeToJson: false) 35 + @override 36 + int get hashCode => Object.hash(runtimeType,url,width,height,size); 37 + 38 + @override 39 + String toString() { 40 + return 'KlipyMediaFormat(url: $url, width: $width, height: $height, size: $size)'; 41 + } 42 + 43 + 44 + } 45 + 46 + /// @nodoc 47 + abstract mixin class $KlipyMediaFormatCopyWith<$Res> { 48 + factory $KlipyMediaFormatCopyWith(KlipyMediaFormat value, $Res Function(KlipyMediaFormat) _then) = _$KlipyMediaFormatCopyWithImpl; 49 + @useResult 50 + $Res call({ 51 + String url, int width, int height, int? size 52 + }); 53 + 54 + 55 + 56 + 57 + } 58 + /// @nodoc 59 + class _$KlipyMediaFormatCopyWithImpl<$Res> 60 + implements $KlipyMediaFormatCopyWith<$Res> { 61 + _$KlipyMediaFormatCopyWithImpl(this._self, this._then); 62 + 63 + final KlipyMediaFormat _self; 64 + final $Res Function(KlipyMediaFormat) _then; 65 + 66 + /// Create a copy of KlipyMediaFormat 67 + /// with the given fields replaced by the non-null parameter values. 68 + @pragma('vm:prefer-inline') @override $Res call({Object? url = null,Object? width = null,Object? height = null,Object? size = freezed,}) { 69 + return _then(_self.copyWith( 70 + url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable 71 + as String,width: null == width ? _self.width : width // ignore: cast_nullable_to_non_nullable 72 + as int,height: null == height ? _self.height : height // ignore: cast_nullable_to_non_nullable 73 + as int,size: freezed == size ? _self.size : size // ignore: cast_nullable_to_non_nullable 74 + as int?, 75 + )); 76 + } 77 + 78 + } 79 + 80 + 81 + /// Adds pattern-matching-related methods to [KlipyMediaFormat]. 82 + extension KlipyMediaFormatPatterns on KlipyMediaFormat { 83 + /// A variant of `map` that fallback to returning `orElse`. 84 + /// 85 + /// It is equivalent to doing: 86 + /// ```dart 87 + /// switch (sealedClass) { 88 + /// case final Subclass value: 89 + /// return ...; 90 + /// case _: 91 + /// return orElse(); 92 + /// } 93 + /// ``` 94 + 95 + @optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _KlipyMediaFormat value)? $default,{required TResult orElse(),}){ 96 + final _that = this; 97 + switch (_that) { 98 + case _KlipyMediaFormat() when $default != null: 99 + return $default(_that);case _: 100 + return orElse(); 101 + 102 + } 103 + } 104 + /// A `switch`-like method, using callbacks. 105 + /// 106 + /// Callbacks receives the raw object, upcasted. 107 + /// It is equivalent to doing: 108 + /// ```dart 109 + /// switch (sealedClass) { 110 + /// case final Subclass value: 111 + /// return ...; 112 + /// case final Subclass2 value: 113 + /// return ...; 114 + /// } 115 + /// ``` 116 + 117 + @optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _KlipyMediaFormat value) $default,){ 118 + final _that = this; 119 + switch (_that) { 120 + case _KlipyMediaFormat(): 121 + return $default(_that);case _: 122 + throw StateError('Unexpected subclass'); 123 + 124 + } 125 + } 126 + /// A variant of `map` that fallback to returning `null`. 127 + /// 128 + /// It is equivalent to doing: 129 + /// ```dart 130 + /// switch (sealedClass) { 131 + /// case final Subclass value: 132 + /// return ...; 133 + /// case _: 134 + /// return null; 135 + /// } 136 + /// ``` 137 + 138 + @optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _KlipyMediaFormat value)? $default,){ 139 + final _that = this; 140 + switch (_that) { 141 + case _KlipyMediaFormat() when $default != null: 142 + return $default(_that);case _: 143 + return null; 144 + 145 + } 146 + } 147 + /// A variant of `when` that fallback to an `orElse` callback. 148 + /// 149 + /// It is equivalent to doing: 150 + /// ```dart 151 + /// switch (sealedClass) { 152 + /// case Subclass(:final field): 153 + /// return ...; 154 + /// case _: 155 + /// return orElse(); 156 + /// } 157 + /// ``` 158 + 159 + @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String url, int width, int height, int? size)? $default,{required TResult orElse(),}) {final _that = this; 160 + switch (_that) { 161 + case _KlipyMediaFormat() when $default != null: 162 + return $default(_that.url,_that.width,_that.height,_that.size);case _: 163 + return orElse(); 164 + 165 + } 166 + } 167 + /// A `switch`-like method, using callbacks. 168 + /// 169 + /// As opposed to `map`, this offers destructuring. 170 + /// It is equivalent to doing: 171 + /// ```dart 172 + /// switch (sealedClass) { 173 + /// case Subclass(:final field): 174 + /// return ...; 175 + /// case Subclass2(:final field2): 176 + /// return ...; 177 + /// } 178 + /// ``` 179 + 180 + @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String url, int width, int height, int? size) $default,) {final _that = this; 181 + switch (_that) { 182 + case _KlipyMediaFormat(): 183 + return $default(_that.url,_that.width,_that.height,_that.size);case _: 184 + throw StateError('Unexpected subclass'); 185 + 186 + } 187 + } 188 + /// A variant of `when` that fallback to returning `null` 189 + /// 190 + /// It is equivalent to doing: 191 + /// ```dart 192 + /// switch (sealedClass) { 193 + /// case Subclass(:final field): 194 + /// return ...; 195 + /// case _: 196 + /// return null; 197 + /// } 198 + /// ``` 199 + 200 + @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String url, int width, int height, int? size)? $default,) {final _that = this; 201 + switch (_that) { 202 + case _KlipyMediaFormat() when $default != null: 203 + return $default(_that.url,_that.width,_that.height,_that.size);case _: 204 + return null; 205 + 206 + } 207 + } 208 + 209 + } 210 + 211 + /// @nodoc 212 + @JsonSerializable() 213 + 214 + class _KlipyMediaFormat implements KlipyMediaFormat { 215 + const _KlipyMediaFormat({this.url = '', this.width = 0, this.height = 0, this.size}); 216 + factory _KlipyMediaFormat.fromJson(Map<String, dynamic> json) => _$KlipyMediaFormatFromJson(json); 217 + 218 + @override@JsonKey() final String url; 219 + @override@JsonKey() final int width; 220 + @override@JsonKey() final int height; 221 + @override final int? size; 222 + 223 + /// Create a copy of KlipyMediaFormat 224 + /// with the given fields replaced by the non-null parameter values. 225 + @override @JsonKey(includeFromJson: false, includeToJson: false) 226 + @pragma('vm:prefer-inline') 227 + _$KlipyMediaFormatCopyWith<_KlipyMediaFormat> get copyWith => __$KlipyMediaFormatCopyWithImpl<_KlipyMediaFormat>(this, _$identity); 228 + 229 + @override 230 + Map<String, dynamic> toJson() { 231 + return _$KlipyMediaFormatToJson(this, ); 232 + } 233 + 234 + @override 235 + bool operator ==(Object other) { 236 + return identical(this, other) || (other.runtimeType == runtimeType&&other is _KlipyMediaFormat&&(identical(other.url, url) || other.url == url)&&(identical(other.width, width) || other.width == width)&&(identical(other.height, height) || other.height == height)&&(identical(other.size, size) || other.size == size)); 237 + } 238 + 239 + @JsonKey(includeFromJson: false, includeToJson: false) 240 + @override 241 + int get hashCode => Object.hash(runtimeType,url,width,height,size); 242 + 243 + @override 244 + String toString() { 245 + return 'KlipyMediaFormat(url: $url, width: $width, height: $height, size: $size)'; 246 + } 247 + 248 + 249 + } 250 + 251 + /// @nodoc 252 + abstract mixin class _$KlipyMediaFormatCopyWith<$Res> implements $KlipyMediaFormatCopyWith<$Res> { 253 + factory _$KlipyMediaFormatCopyWith(_KlipyMediaFormat value, $Res Function(_KlipyMediaFormat) _then) = __$KlipyMediaFormatCopyWithImpl; 254 + @override @useResult 255 + $Res call({ 256 + String url, int width, int height, int? size 257 + }); 258 + 259 + 260 + 261 + 262 + } 263 + /// @nodoc 264 + class __$KlipyMediaFormatCopyWithImpl<$Res> 265 + implements _$KlipyMediaFormatCopyWith<$Res> { 266 + __$KlipyMediaFormatCopyWithImpl(this._self, this._then); 267 + 268 + final _KlipyMediaFormat _self; 269 + final $Res Function(_KlipyMediaFormat) _then; 270 + 271 + /// Create a copy of KlipyMediaFormat 272 + /// with the given fields replaced by the non-null parameter values. 273 + @override @pragma('vm:prefer-inline') $Res call({Object? url = null,Object? width = null,Object? height = null,Object? size = freezed,}) { 274 + return _then(_KlipyMediaFormat( 275 + url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable 276 + as String,width: null == width ? _self.width : width // ignore: cast_nullable_to_non_nullable 277 + as int,height: null == height ? _self.height : height // ignore: cast_nullable_to_non_nullable 278 + as int,size: freezed == size ? _self.size : size // ignore: cast_nullable_to_non_nullable 279 + as int?, 280 + )); 281 + } 282 + 283 + 284 + } 285 + 286 + 287 + /// @nodoc 288 + mixin _$KlipyFormatVariants { 289 + 290 + KlipyMediaFormat? get gif; KlipyMediaFormat? get webp; KlipyMediaFormat? get jpg; KlipyMediaFormat? get mp4; KlipyMediaFormat? get webm; 291 + /// Create a copy of KlipyFormatVariants 292 + /// with the given fields replaced by the non-null parameter values. 293 + @JsonKey(includeFromJson: false, includeToJson: false) 294 + @pragma('vm:prefer-inline') 295 + $KlipyFormatVariantsCopyWith<KlipyFormatVariants> get copyWith => _$KlipyFormatVariantsCopyWithImpl<KlipyFormatVariants>(this as KlipyFormatVariants, _$identity); 296 + 297 + /// Serializes this KlipyFormatVariants to a JSON map. 298 + Map<String, dynamic> toJson(); 299 + 300 + 301 + @override 302 + bool operator ==(Object other) { 303 + return identical(this, other) || (other.runtimeType == runtimeType&&other is KlipyFormatVariants&&(identical(other.gif, gif) || other.gif == gif)&&(identical(other.webp, webp) || other.webp == webp)&&(identical(other.jpg, jpg) || other.jpg == jpg)&&(identical(other.mp4, mp4) || other.mp4 == mp4)&&(identical(other.webm, webm) || other.webm == webm)); 304 + } 305 + 306 + @JsonKey(includeFromJson: false, includeToJson: false) 307 + @override 308 + int get hashCode => Object.hash(runtimeType,gif,webp,jpg,mp4,webm); 309 + 310 + @override 311 + String toString() { 312 + return 'KlipyFormatVariants(gif: $gif, webp: $webp, jpg: $jpg, mp4: $mp4, webm: $webm)'; 313 + } 314 + 315 + 316 + } 317 + 318 + /// @nodoc 319 + abstract mixin class $KlipyFormatVariantsCopyWith<$Res> { 320 + factory $KlipyFormatVariantsCopyWith(KlipyFormatVariants value, $Res Function(KlipyFormatVariants) _then) = _$KlipyFormatVariantsCopyWithImpl; 321 + @useResult 322 + $Res call({ 323 + KlipyMediaFormat? gif, KlipyMediaFormat? webp, KlipyMediaFormat? jpg, KlipyMediaFormat? mp4, KlipyMediaFormat? webm 324 + }); 325 + 326 + 327 + $KlipyMediaFormatCopyWith<$Res>? get gif;$KlipyMediaFormatCopyWith<$Res>? get webp;$KlipyMediaFormatCopyWith<$Res>? get jpg;$KlipyMediaFormatCopyWith<$Res>? get mp4;$KlipyMediaFormatCopyWith<$Res>? get webm; 328 + 329 + } 330 + /// @nodoc 331 + class _$KlipyFormatVariantsCopyWithImpl<$Res> 332 + implements $KlipyFormatVariantsCopyWith<$Res> { 333 + _$KlipyFormatVariantsCopyWithImpl(this._self, this._then); 334 + 335 + final KlipyFormatVariants _self; 336 + final $Res Function(KlipyFormatVariants) _then; 337 + 338 + /// Create a copy of KlipyFormatVariants 339 + /// with the given fields replaced by the non-null parameter values. 340 + @pragma('vm:prefer-inline') @override $Res call({Object? gif = freezed,Object? webp = freezed,Object? jpg = freezed,Object? mp4 = freezed,Object? webm = freezed,}) { 341 + return _then(_self.copyWith( 342 + gif: freezed == gif ? _self.gif : gif // ignore: cast_nullable_to_non_nullable 343 + as KlipyMediaFormat?,webp: freezed == webp ? _self.webp : webp // ignore: cast_nullable_to_non_nullable 344 + as KlipyMediaFormat?,jpg: freezed == jpg ? _self.jpg : jpg // ignore: cast_nullable_to_non_nullable 345 + as KlipyMediaFormat?,mp4: freezed == mp4 ? _self.mp4 : mp4 // ignore: cast_nullable_to_non_nullable 346 + as KlipyMediaFormat?,webm: freezed == webm ? _self.webm : webm // ignore: cast_nullable_to_non_nullable 347 + as KlipyMediaFormat?, 348 + )); 349 + } 350 + /// Create a copy of KlipyFormatVariants 351 + /// with the given fields replaced by the non-null parameter values. 352 + @override 353 + @pragma('vm:prefer-inline') 354 + $KlipyMediaFormatCopyWith<$Res>? get gif { 355 + if (_self.gif == null) { 356 + return null; 357 + } 358 + 359 + return $KlipyMediaFormatCopyWith<$Res>(_self.gif!, (value) { 360 + return _then(_self.copyWith(gif: value)); 361 + }); 362 + }/// Create a copy of KlipyFormatVariants 363 + /// with the given fields replaced by the non-null parameter values. 364 + @override 365 + @pragma('vm:prefer-inline') 366 + $KlipyMediaFormatCopyWith<$Res>? get webp { 367 + if (_self.webp == null) { 368 + return null; 369 + } 370 + 371 + return $KlipyMediaFormatCopyWith<$Res>(_self.webp!, (value) { 372 + return _then(_self.copyWith(webp: value)); 373 + }); 374 + }/// Create a copy of KlipyFormatVariants 375 + /// with the given fields replaced by the non-null parameter values. 376 + @override 377 + @pragma('vm:prefer-inline') 378 + $KlipyMediaFormatCopyWith<$Res>? get jpg { 379 + if (_self.jpg == null) { 380 + return null; 381 + } 382 + 383 + return $KlipyMediaFormatCopyWith<$Res>(_self.jpg!, (value) { 384 + return _then(_self.copyWith(jpg: value)); 385 + }); 386 + }/// Create a copy of KlipyFormatVariants 387 + /// with the given fields replaced by the non-null parameter values. 388 + @override 389 + @pragma('vm:prefer-inline') 390 + $KlipyMediaFormatCopyWith<$Res>? get mp4 { 391 + if (_self.mp4 == null) { 392 + return null; 393 + } 394 + 395 + return $KlipyMediaFormatCopyWith<$Res>(_self.mp4!, (value) { 396 + return _then(_self.copyWith(mp4: value)); 397 + }); 398 + }/// Create a copy of KlipyFormatVariants 399 + /// with the given fields replaced by the non-null parameter values. 400 + @override 401 + @pragma('vm:prefer-inline') 402 + $KlipyMediaFormatCopyWith<$Res>? get webm { 403 + if (_self.webm == null) { 404 + return null; 405 + } 406 + 407 + return $KlipyMediaFormatCopyWith<$Res>(_self.webm!, (value) { 408 + return _then(_self.copyWith(webm: value)); 409 + }); 410 + } 411 + } 412 + 413 + 414 + /// Adds pattern-matching-related methods to [KlipyFormatVariants]. 415 + extension KlipyFormatVariantsPatterns on KlipyFormatVariants { 416 + /// A variant of `map` that fallback to returning `orElse`. 417 + /// 418 + /// It is equivalent to doing: 419 + /// ```dart 420 + /// switch (sealedClass) { 421 + /// case final Subclass value: 422 + /// return ...; 423 + /// case _: 424 + /// return orElse(); 425 + /// } 426 + /// ``` 427 + 428 + @optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _KlipyFormatVariants value)? $default,{required TResult orElse(),}){ 429 + final _that = this; 430 + switch (_that) { 431 + case _KlipyFormatVariants() when $default != null: 432 + return $default(_that);case _: 433 + return orElse(); 434 + 435 + } 436 + } 437 + /// A `switch`-like method, using callbacks. 438 + /// 439 + /// Callbacks receives the raw object, upcasted. 440 + /// It is equivalent to doing: 441 + /// ```dart 442 + /// switch (sealedClass) { 443 + /// case final Subclass value: 444 + /// return ...; 445 + /// case final Subclass2 value: 446 + /// return ...; 447 + /// } 448 + /// ``` 449 + 450 + @optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _KlipyFormatVariants value) $default,){ 451 + final _that = this; 452 + switch (_that) { 453 + case _KlipyFormatVariants(): 454 + return $default(_that);case _: 455 + throw StateError('Unexpected subclass'); 456 + 457 + } 458 + } 459 + /// A variant of `map` that fallback to returning `null`. 460 + /// 461 + /// It is equivalent to doing: 462 + /// ```dart 463 + /// switch (sealedClass) { 464 + /// case final Subclass value: 465 + /// return ...; 466 + /// case _: 467 + /// return null; 468 + /// } 469 + /// ``` 470 + 471 + @optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _KlipyFormatVariants value)? $default,){ 472 + final _that = this; 473 + switch (_that) { 474 + case _KlipyFormatVariants() when $default != null: 475 + return $default(_that);case _: 476 + return null; 477 + 478 + } 479 + } 480 + /// A variant of `when` that fallback to an `orElse` callback. 481 + /// 482 + /// It is equivalent to doing: 483 + /// ```dart 484 + /// switch (sealedClass) { 485 + /// case Subclass(:final field): 486 + /// return ...; 487 + /// case _: 488 + /// return orElse(); 489 + /// } 490 + /// ``` 491 + 492 + @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( KlipyMediaFormat? gif, KlipyMediaFormat? webp, KlipyMediaFormat? jpg, KlipyMediaFormat? mp4, KlipyMediaFormat? webm)? $default,{required TResult orElse(),}) {final _that = this; 493 + switch (_that) { 494 + case _KlipyFormatVariants() when $default != null: 495 + return $default(_that.gif,_that.webp,_that.jpg,_that.mp4,_that.webm);case _: 496 + return orElse(); 497 + 498 + } 499 + } 500 + /// A `switch`-like method, using callbacks. 501 + /// 502 + /// As opposed to `map`, this offers destructuring. 503 + /// It is equivalent to doing: 504 + /// ```dart 505 + /// switch (sealedClass) { 506 + /// case Subclass(:final field): 507 + /// return ...; 508 + /// case Subclass2(:final field2): 509 + /// return ...; 510 + /// } 511 + /// ``` 512 + 513 + @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( KlipyMediaFormat? gif, KlipyMediaFormat? webp, KlipyMediaFormat? jpg, KlipyMediaFormat? mp4, KlipyMediaFormat? webm) $default,) {final _that = this; 514 + switch (_that) { 515 + case _KlipyFormatVariants(): 516 + return $default(_that.gif,_that.webp,_that.jpg,_that.mp4,_that.webm);case _: 517 + throw StateError('Unexpected subclass'); 518 + 519 + } 520 + } 521 + /// A variant of `when` that fallback to returning `null` 522 + /// 523 + /// It is equivalent to doing: 524 + /// ```dart 525 + /// switch (sealedClass) { 526 + /// case Subclass(:final field): 527 + /// return ...; 528 + /// case _: 529 + /// return null; 530 + /// } 531 + /// ``` 532 + 533 + @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( KlipyMediaFormat? gif, KlipyMediaFormat? webp, KlipyMediaFormat? jpg, KlipyMediaFormat? mp4, KlipyMediaFormat? webm)? $default,) {final _that = this; 534 + switch (_that) { 535 + case _KlipyFormatVariants() when $default != null: 536 + return $default(_that.gif,_that.webp,_that.jpg,_that.mp4,_that.webm);case _: 537 + return null; 538 + 539 + } 540 + } 541 + 542 + } 543 + 544 + /// @nodoc 545 + @JsonSerializable() 546 + 547 + class _KlipyFormatVariants implements KlipyFormatVariants { 548 + const _KlipyFormatVariants({this.gif, this.webp, this.jpg, this.mp4, this.webm}); 549 + factory _KlipyFormatVariants.fromJson(Map<String, dynamic> json) => _$KlipyFormatVariantsFromJson(json); 550 + 551 + @override final KlipyMediaFormat? gif; 552 + @override final KlipyMediaFormat? webp; 553 + @override final KlipyMediaFormat? jpg; 554 + @override final KlipyMediaFormat? mp4; 555 + @override final KlipyMediaFormat? webm; 556 + 557 + /// Create a copy of KlipyFormatVariants 558 + /// with the given fields replaced by the non-null parameter values. 559 + @override @JsonKey(includeFromJson: false, includeToJson: false) 560 + @pragma('vm:prefer-inline') 561 + _$KlipyFormatVariantsCopyWith<_KlipyFormatVariants> get copyWith => __$KlipyFormatVariantsCopyWithImpl<_KlipyFormatVariants>(this, _$identity); 562 + 563 + @override 564 + Map<String, dynamic> toJson() { 565 + return _$KlipyFormatVariantsToJson(this, ); 566 + } 567 + 568 + @override 569 + bool operator ==(Object other) { 570 + return identical(this, other) || (other.runtimeType == runtimeType&&other is _KlipyFormatVariants&&(identical(other.gif, gif) || other.gif == gif)&&(identical(other.webp, webp) || other.webp == webp)&&(identical(other.jpg, jpg) || other.jpg == jpg)&&(identical(other.mp4, mp4) || other.mp4 == mp4)&&(identical(other.webm, webm) || other.webm == webm)); 571 + } 572 + 573 + @JsonKey(includeFromJson: false, includeToJson: false) 574 + @override 575 + int get hashCode => Object.hash(runtimeType,gif,webp,jpg,mp4,webm); 576 + 577 + @override 578 + String toString() { 579 + return 'KlipyFormatVariants(gif: $gif, webp: $webp, jpg: $jpg, mp4: $mp4, webm: $webm)'; 580 + } 581 + 582 + 583 + } 584 + 585 + /// @nodoc 586 + abstract mixin class _$KlipyFormatVariantsCopyWith<$Res> implements $KlipyFormatVariantsCopyWith<$Res> { 587 + factory _$KlipyFormatVariantsCopyWith(_KlipyFormatVariants value, $Res Function(_KlipyFormatVariants) _then) = __$KlipyFormatVariantsCopyWithImpl; 588 + @override @useResult 589 + $Res call({ 590 + KlipyMediaFormat? gif, KlipyMediaFormat? webp, KlipyMediaFormat? jpg, KlipyMediaFormat? mp4, KlipyMediaFormat? webm 591 + }); 592 + 593 + 594 + @override $KlipyMediaFormatCopyWith<$Res>? get gif;@override $KlipyMediaFormatCopyWith<$Res>? get webp;@override $KlipyMediaFormatCopyWith<$Res>? get jpg;@override $KlipyMediaFormatCopyWith<$Res>? get mp4;@override $KlipyMediaFormatCopyWith<$Res>? get webm; 595 + 596 + } 597 + /// @nodoc 598 + class __$KlipyFormatVariantsCopyWithImpl<$Res> 599 + implements _$KlipyFormatVariantsCopyWith<$Res> { 600 + __$KlipyFormatVariantsCopyWithImpl(this._self, this._then); 601 + 602 + final _KlipyFormatVariants _self; 603 + final $Res Function(_KlipyFormatVariants) _then; 604 + 605 + /// Create a copy of KlipyFormatVariants 606 + /// with the given fields replaced by the non-null parameter values. 607 + @override @pragma('vm:prefer-inline') $Res call({Object? gif = freezed,Object? webp = freezed,Object? jpg = freezed,Object? mp4 = freezed,Object? webm = freezed,}) { 608 + return _then(_KlipyFormatVariants( 609 + gif: freezed == gif ? _self.gif : gif // ignore: cast_nullable_to_non_nullable 610 + as KlipyMediaFormat?,webp: freezed == webp ? _self.webp : webp // ignore: cast_nullable_to_non_nullable 611 + as KlipyMediaFormat?,jpg: freezed == jpg ? _self.jpg : jpg // ignore: cast_nullable_to_non_nullable 612 + as KlipyMediaFormat?,mp4: freezed == mp4 ? _self.mp4 : mp4 // ignore: cast_nullable_to_non_nullable 613 + as KlipyMediaFormat?,webm: freezed == webm ? _self.webm : webm // ignore: cast_nullable_to_non_nullable 614 + as KlipyMediaFormat?, 615 + )); 616 + } 617 + 618 + /// Create a copy of KlipyFormatVariants 619 + /// with the given fields replaced by the non-null parameter values. 620 + @override 621 + @pragma('vm:prefer-inline') 622 + $KlipyMediaFormatCopyWith<$Res>? get gif { 623 + if (_self.gif == null) { 624 + return null; 625 + } 626 + 627 + return $KlipyMediaFormatCopyWith<$Res>(_self.gif!, (value) { 628 + return _then(_self.copyWith(gif: value)); 629 + }); 630 + }/// Create a copy of KlipyFormatVariants 631 + /// with the given fields replaced by the non-null parameter values. 632 + @override 633 + @pragma('vm:prefer-inline') 634 + $KlipyMediaFormatCopyWith<$Res>? get webp { 635 + if (_self.webp == null) { 636 + return null; 637 + } 638 + 639 + return $KlipyMediaFormatCopyWith<$Res>(_self.webp!, (value) { 640 + return _then(_self.copyWith(webp: value)); 641 + }); 642 + }/// Create a copy of KlipyFormatVariants 643 + /// with the given fields replaced by the non-null parameter values. 644 + @override 645 + @pragma('vm:prefer-inline') 646 + $KlipyMediaFormatCopyWith<$Res>? get jpg { 647 + if (_self.jpg == null) { 648 + return null; 649 + } 650 + 651 + return $KlipyMediaFormatCopyWith<$Res>(_self.jpg!, (value) { 652 + return _then(_self.copyWith(jpg: value)); 653 + }); 654 + }/// Create a copy of KlipyFormatVariants 655 + /// with the given fields replaced by the non-null parameter values. 656 + @override 657 + @pragma('vm:prefer-inline') 658 + $KlipyMediaFormatCopyWith<$Res>? get mp4 { 659 + if (_self.mp4 == null) { 660 + return null; 661 + } 662 + 663 + return $KlipyMediaFormatCopyWith<$Res>(_self.mp4!, (value) { 664 + return _then(_self.copyWith(mp4: value)); 665 + }); 666 + }/// Create a copy of KlipyFormatVariants 667 + /// with the given fields replaced by the non-null parameter values. 668 + @override 669 + @pragma('vm:prefer-inline') 670 + $KlipyMediaFormatCopyWith<$Res>? get webm { 671 + if (_self.webm == null) { 672 + return null; 673 + } 674 + 675 + return $KlipyMediaFormatCopyWith<$Res>(_self.webm!, (value) { 676 + return _then(_self.copyWith(webm: value)); 677 + }); 678 + } 679 + } 680 + 681 + 682 + /// @nodoc 683 + mixin _$KlipyFile { 684 + 685 + KlipyFormatVariants? get hd; KlipyFormatVariants? get md; KlipyFormatVariants? get sm; KlipyFormatVariants? get xs; 686 + /// Create a copy of KlipyFile 687 + /// with the given fields replaced by the non-null parameter values. 688 + @JsonKey(includeFromJson: false, includeToJson: false) 689 + @pragma('vm:prefer-inline') 690 + $KlipyFileCopyWith<KlipyFile> get copyWith => _$KlipyFileCopyWithImpl<KlipyFile>(this as KlipyFile, _$identity); 691 + 692 + /// Serializes this KlipyFile to a JSON map. 693 + Map<String, dynamic> toJson(); 694 + 695 + 696 + @override 697 + bool operator ==(Object other) { 698 + return identical(this, other) || (other.runtimeType == runtimeType&&other is KlipyFile&&(identical(other.hd, hd) || other.hd == hd)&&(identical(other.md, md) || other.md == md)&&(identical(other.sm, sm) || other.sm == sm)&&(identical(other.xs, xs) || other.xs == xs)); 699 + } 700 + 701 + @JsonKey(includeFromJson: false, includeToJson: false) 702 + @override 703 + int get hashCode => Object.hash(runtimeType,hd,md,sm,xs); 704 + 705 + @override 706 + String toString() { 707 + return 'KlipyFile(hd: $hd, md: $md, sm: $sm, xs: $xs)'; 708 + } 709 + 710 + 711 + } 712 + 713 + /// @nodoc 714 + abstract mixin class $KlipyFileCopyWith<$Res> { 715 + factory $KlipyFileCopyWith(KlipyFile value, $Res Function(KlipyFile) _then) = _$KlipyFileCopyWithImpl; 716 + @useResult 717 + $Res call({ 718 + KlipyFormatVariants? hd, KlipyFormatVariants? md, KlipyFormatVariants? sm, KlipyFormatVariants? xs 719 + }); 720 + 721 + 722 + $KlipyFormatVariantsCopyWith<$Res>? get hd;$KlipyFormatVariantsCopyWith<$Res>? get md;$KlipyFormatVariantsCopyWith<$Res>? get sm;$KlipyFormatVariantsCopyWith<$Res>? get xs; 723 + 724 + } 725 + /// @nodoc 726 + class _$KlipyFileCopyWithImpl<$Res> 727 + implements $KlipyFileCopyWith<$Res> { 728 + _$KlipyFileCopyWithImpl(this._self, this._then); 729 + 730 + final KlipyFile _self; 731 + final $Res Function(KlipyFile) _then; 732 + 733 + /// Create a copy of KlipyFile 734 + /// with the given fields replaced by the non-null parameter values. 735 + @pragma('vm:prefer-inline') @override $Res call({Object? hd = freezed,Object? md = freezed,Object? sm = freezed,Object? xs = freezed,}) { 736 + return _then(_self.copyWith( 737 + hd: freezed == hd ? _self.hd : hd // ignore: cast_nullable_to_non_nullable 738 + as KlipyFormatVariants?,md: freezed == md ? _self.md : md // ignore: cast_nullable_to_non_nullable 739 + as KlipyFormatVariants?,sm: freezed == sm ? _self.sm : sm // ignore: cast_nullable_to_non_nullable 740 + as KlipyFormatVariants?,xs: freezed == xs ? _self.xs : xs // ignore: cast_nullable_to_non_nullable 741 + as KlipyFormatVariants?, 742 + )); 743 + } 744 + /// Create a copy of KlipyFile 745 + /// with the given fields replaced by the non-null parameter values. 746 + @override 747 + @pragma('vm:prefer-inline') 748 + $KlipyFormatVariantsCopyWith<$Res>? get hd { 749 + if (_self.hd == null) { 750 + return null; 751 + } 752 + 753 + return $KlipyFormatVariantsCopyWith<$Res>(_self.hd!, (value) { 754 + return _then(_self.copyWith(hd: value)); 755 + }); 756 + }/// Create a copy of KlipyFile 757 + /// with the given fields replaced by the non-null parameter values. 758 + @override 759 + @pragma('vm:prefer-inline') 760 + $KlipyFormatVariantsCopyWith<$Res>? get md { 761 + if (_self.md == null) { 762 + return null; 763 + } 764 + 765 + return $KlipyFormatVariantsCopyWith<$Res>(_self.md!, (value) { 766 + return _then(_self.copyWith(md: value)); 767 + }); 768 + }/// Create a copy of KlipyFile 769 + /// with the given fields replaced by the non-null parameter values. 770 + @override 771 + @pragma('vm:prefer-inline') 772 + $KlipyFormatVariantsCopyWith<$Res>? get sm { 773 + if (_self.sm == null) { 774 + return null; 775 + } 776 + 777 + return $KlipyFormatVariantsCopyWith<$Res>(_self.sm!, (value) { 778 + return _then(_self.copyWith(sm: value)); 779 + }); 780 + }/// Create a copy of KlipyFile 781 + /// with the given fields replaced by the non-null parameter values. 782 + @override 783 + @pragma('vm:prefer-inline') 784 + $KlipyFormatVariantsCopyWith<$Res>? get xs { 785 + if (_self.xs == null) { 786 + return null; 787 + } 788 + 789 + return $KlipyFormatVariantsCopyWith<$Res>(_self.xs!, (value) { 790 + return _then(_self.copyWith(xs: value)); 791 + }); 792 + } 793 + } 794 + 795 + 796 + /// Adds pattern-matching-related methods to [KlipyFile]. 797 + extension KlipyFilePatterns on KlipyFile { 798 + /// A variant of `map` that fallback to returning `orElse`. 799 + /// 800 + /// It is equivalent to doing: 801 + /// ```dart 802 + /// switch (sealedClass) { 803 + /// case final Subclass value: 804 + /// return ...; 805 + /// case _: 806 + /// return orElse(); 807 + /// } 808 + /// ``` 809 + 810 + @optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _KlipyFile value)? $default,{required TResult orElse(),}){ 811 + final _that = this; 812 + switch (_that) { 813 + case _KlipyFile() when $default != null: 814 + return $default(_that);case _: 815 + return orElse(); 816 + 817 + } 818 + } 819 + /// A `switch`-like method, using callbacks. 820 + /// 821 + /// Callbacks receives the raw object, upcasted. 822 + /// It is equivalent to doing: 823 + /// ```dart 824 + /// switch (sealedClass) { 825 + /// case final Subclass value: 826 + /// return ...; 827 + /// case final Subclass2 value: 828 + /// return ...; 829 + /// } 830 + /// ``` 831 + 832 + @optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _KlipyFile value) $default,){ 833 + final _that = this; 834 + switch (_that) { 835 + case _KlipyFile(): 836 + return $default(_that);case _: 837 + throw StateError('Unexpected subclass'); 838 + 839 + } 840 + } 841 + /// A variant of `map` that fallback to returning `null`. 842 + /// 843 + /// It is equivalent to doing: 844 + /// ```dart 845 + /// switch (sealedClass) { 846 + /// case final Subclass value: 847 + /// return ...; 848 + /// case _: 849 + /// return null; 850 + /// } 851 + /// ``` 852 + 853 + @optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _KlipyFile value)? $default,){ 854 + final _that = this; 855 + switch (_that) { 856 + case _KlipyFile() when $default != null: 857 + return $default(_that);case _: 858 + return null; 859 + 860 + } 861 + } 862 + /// A variant of `when` that fallback to an `orElse` callback. 863 + /// 864 + /// It is equivalent to doing: 865 + /// ```dart 866 + /// switch (sealedClass) { 867 + /// case Subclass(:final field): 868 + /// return ...; 869 + /// case _: 870 + /// return orElse(); 871 + /// } 872 + /// ``` 873 + 874 + @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( KlipyFormatVariants? hd, KlipyFormatVariants? md, KlipyFormatVariants? sm, KlipyFormatVariants? xs)? $default,{required TResult orElse(),}) {final _that = this; 875 + switch (_that) { 876 + case _KlipyFile() when $default != null: 877 + return $default(_that.hd,_that.md,_that.sm,_that.xs);case _: 878 + return orElse(); 879 + 880 + } 881 + } 882 + /// A `switch`-like method, using callbacks. 883 + /// 884 + /// As opposed to `map`, this offers destructuring. 885 + /// It is equivalent to doing: 886 + /// ```dart 887 + /// switch (sealedClass) { 888 + /// case Subclass(:final field): 889 + /// return ...; 890 + /// case Subclass2(:final field2): 891 + /// return ...; 892 + /// } 893 + /// ``` 894 + 895 + @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( KlipyFormatVariants? hd, KlipyFormatVariants? md, KlipyFormatVariants? sm, KlipyFormatVariants? xs) $default,) {final _that = this; 896 + switch (_that) { 897 + case _KlipyFile(): 898 + return $default(_that.hd,_that.md,_that.sm,_that.xs);case _: 899 + throw StateError('Unexpected subclass'); 900 + 901 + } 902 + } 903 + /// A variant of `when` that fallback to returning `null` 904 + /// 905 + /// It is equivalent to doing: 906 + /// ```dart 907 + /// switch (sealedClass) { 908 + /// case Subclass(:final field): 909 + /// return ...; 910 + /// case _: 911 + /// return null; 912 + /// } 913 + /// ``` 914 + 915 + @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( KlipyFormatVariants? hd, KlipyFormatVariants? md, KlipyFormatVariants? sm, KlipyFormatVariants? xs)? $default,) {final _that = this; 916 + switch (_that) { 917 + case _KlipyFile() when $default != null: 918 + return $default(_that.hd,_that.md,_that.sm,_that.xs);case _: 919 + return null; 920 + 921 + } 922 + } 923 + 924 + } 925 + 926 + /// @nodoc 927 + @JsonSerializable() 928 + 929 + class _KlipyFile implements KlipyFile { 930 + const _KlipyFile({this.hd, this.md, this.sm, this.xs}); 931 + factory _KlipyFile.fromJson(Map<String, dynamic> json) => _$KlipyFileFromJson(json); 932 + 933 + @override final KlipyFormatVariants? hd; 934 + @override final KlipyFormatVariants? md; 935 + @override final KlipyFormatVariants? sm; 936 + @override final KlipyFormatVariants? xs; 937 + 938 + /// Create a copy of KlipyFile 939 + /// with the given fields replaced by the non-null parameter values. 940 + @override @JsonKey(includeFromJson: false, includeToJson: false) 941 + @pragma('vm:prefer-inline') 942 + _$KlipyFileCopyWith<_KlipyFile> get copyWith => __$KlipyFileCopyWithImpl<_KlipyFile>(this, _$identity); 943 + 944 + @override 945 + Map<String, dynamic> toJson() { 946 + return _$KlipyFileToJson(this, ); 947 + } 948 + 949 + @override 950 + bool operator ==(Object other) { 951 + return identical(this, other) || (other.runtimeType == runtimeType&&other is _KlipyFile&&(identical(other.hd, hd) || other.hd == hd)&&(identical(other.md, md) || other.md == md)&&(identical(other.sm, sm) || other.sm == sm)&&(identical(other.xs, xs) || other.xs == xs)); 952 + } 953 + 954 + @JsonKey(includeFromJson: false, includeToJson: false) 955 + @override 956 + int get hashCode => Object.hash(runtimeType,hd,md,sm,xs); 957 + 958 + @override 959 + String toString() { 960 + return 'KlipyFile(hd: $hd, md: $md, sm: $sm, xs: $xs)'; 961 + } 962 + 963 + 964 + } 965 + 966 + /// @nodoc 967 + abstract mixin class _$KlipyFileCopyWith<$Res> implements $KlipyFileCopyWith<$Res> { 968 + factory _$KlipyFileCopyWith(_KlipyFile value, $Res Function(_KlipyFile) _then) = __$KlipyFileCopyWithImpl; 969 + @override @useResult 970 + $Res call({ 971 + KlipyFormatVariants? hd, KlipyFormatVariants? md, KlipyFormatVariants? sm, KlipyFormatVariants? xs 972 + }); 973 + 974 + 975 + @override $KlipyFormatVariantsCopyWith<$Res>? get hd;@override $KlipyFormatVariantsCopyWith<$Res>? get md;@override $KlipyFormatVariantsCopyWith<$Res>? get sm;@override $KlipyFormatVariantsCopyWith<$Res>? get xs; 976 + 977 + } 978 + /// @nodoc 979 + class __$KlipyFileCopyWithImpl<$Res> 980 + implements _$KlipyFileCopyWith<$Res> { 981 + __$KlipyFileCopyWithImpl(this._self, this._then); 982 + 983 + final _KlipyFile _self; 984 + final $Res Function(_KlipyFile) _then; 985 + 986 + /// Create a copy of KlipyFile 987 + /// with the given fields replaced by the non-null parameter values. 988 + @override @pragma('vm:prefer-inline') $Res call({Object? hd = freezed,Object? md = freezed,Object? sm = freezed,Object? xs = freezed,}) { 989 + return _then(_KlipyFile( 990 + hd: freezed == hd ? _self.hd : hd // ignore: cast_nullable_to_non_nullable 991 + as KlipyFormatVariants?,md: freezed == md ? _self.md : md // ignore: cast_nullable_to_non_nullable 992 + as KlipyFormatVariants?,sm: freezed == sm ? _self.sm : sm // ignore: cast_nullable_to_non_nullable 993 + as KlipyFormatVariants?,xs: freezed == xs ? _self.xs : xs // ignore: cast_nullable_to_non_nullable 994 + as KlipyFormatVariants?, 995 + )); 996 + } 997 + 998 + /// Create a copy of KlipyFile 999 + /// with the given fields replaced by the non-null parameter values. 1000 + @override 1001 + @pragma('vm:prefer-inline') 1002 + $KlipyFormatVariantsCopyWith<$Res>? get hd { 1003 + if (_self.hd == null) { 1004 + return null; 1005 + } 1006 + 1007 + return $KlipyFormatVariantsCopyWith<$Res>(_self.hd!, (value) { 1008 + return _then(_self.copyWith(hd: value)); 1009 + }); 1010 + }/// Create a copy of KlipyFile 1011 + /// with the given fields replaced by the non-null parameter values. 1012 + @override 1013 + @pragma('vm:prefer-inline') 1014 + $KlipyFormatVariantsCopyWith<$Res>? get md { 1015 + if (_self.md == null) { 1016 + return null; 1017 + } 1018 + 1019 + return $KlipyFormatVariantsCopyWith<$Res>(_self.md!, (value) { 1020 + return _then(_self.copyWith(md: value)); 1021 + }); 1022 + }/// Create a copy of KlipyFile 1023 + /// with the given fields replaced by the non-null parameter values. 1024 + @override 1025 + @pragma('vm:prefer-inline') 1026 + $KlipyFormatVariantsCopyWith<$Res>? get sm { 1027 + if (_self.sm == null) { 1028 + return null; 1029 + } 1030 + 1031 + return $KlipyFormatVariantsCopyWith<$Res>(_self.sm!, (value) { 1032 + return _then(_self.copyWith(sm: value)); 1033 + }); 1034 + }/// Create a copy of KlipyFile 1035 + /// with the given fields replaced by the non-null parameter values. 1036 + @override 1037 + @pragma('vm:prefer-inline') 1038 + $KlipyFormatVariantsCopyWith<$Res>? get xs { 1039 + if (_self.xs == null) { 1040 + return null; 1041 + } 1042 + 1043 + return $KlipyFormatVariantsCopyWith<$Res>(_self.xs!, (value) { 1044 + return _then(_self.copyWith(xs: value)); 1045 + }); 1046 + } 1047 + } 1048 + 1049 + 1050 + /// @nodoc 1051 + mixin _$KlipyGif { 1052 + 1053 + int get id; String get slug; String get title; KlipyFile get file; List<String>? get tags; String? get type;@JsonKey(name: 'blur_preview') String? get blurPreview; 1054 + /// Create a copy of KlipyGif 1055 + /// with the given fields replaced by the non-null parameter values. 1056 + @JsonKey(includeFromJson: false, includeToJson: false) 1057 + @pragma('vm:prefer-inline') 1058 + $KlipyGifCopyWith<KlipyGif> get copyWith => _$KlipyGifCopyWithImpl<KlipyGif>(this as KlipyGif, _$identity); 1059 + 1060 + /// Serializes this KlipyGif to a JSON map. 1061 + Map<String, dynamic> toJson(); 1062 + 1063 + 1064 + @override 1065 + bool operator ==(Object other) { 1066 + return identical(this, other) || (other.runtimeType == runtimeType&&other is KlipyGif&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.title, title) || other.title == title)&&(identical(other.file, file) || other.file == file)&&const DeepCollectionEquality().equals(other.tags, tags)&&(identical(other.type, type) || other.type == type)&&(identical(other.blurPreview, blurPreview) || other.blurPreview == blurPreview)); 1067 + } 1068 + 1069 + @JsonKey(includeFromJson: false, includeToJson: false) 1070 + @override 1071 + int get hashCode => Object.hash(runtimeType,id,slug,title,file,const DeepCollectionEquality().hash(tags),type,blurPreview); 1072 + 1073 + @override 1074 + String toString() { 1075 + return 'KlipyGif(id: $id, slug: $slug, title: $title, file: $file, tags: $tags, type: $type, blurPreview: $blurPreview)'; 1076 + } 1077 + 1078 + 1079 + } 1080 + 1081 + /// @nodoc 1082 + abstract mixin class $KlipyGifCopyWith<$Res> { 1083 + factory $KlipyGifCopyWith(KlipyGif value, $Res Function(KlipyGif) _then) = _$KlipyGifCopyWithImpl; 1084 + @useResult 1085 + $Res call({ 1086 + int id, String slug, String title, KlipyFile file, List<String>? tags, String? type,@JsonKey(name: 'blur_preview') String? blurPreview 1087 + }); 1088 + 1089 + 1090 + $KlipyFileCopyWith<$Res> get file; 1091 + 1092 + } 1093 + /// @nodoc 1094 + class _$KlipyGifCopyWithImpl<$Res> 1095 + implements $KlipyGifCopyWith<$Res> { 1096 + _$KlipyGifCopyWithImpl(this._self, this._then); 1097 + 1098 + final KlipyGif _self; 1099 + final $Res Function(KlipyGif) _then; 1100 + 1101 + /// Create a copy of KlipyGif 1102 + /// with the given fields replaced by the non-null parameter values. 1103 + @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? slug = null,Object? title = null,Object? file = null,Object? tags = freezed,Object? type = freezed,Object? blurPreview = freezed,}) { 1104 + return _then(_self.copyWith( 1105 + id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable 1106 + as int,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable 1107 + as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable 1108 + as String,file: null == file ? _self.file : file // ignore: cast_nullable_to_non_nullable 1109 + as KlipyFile,tags: freezed == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable 1110 + as List<String>?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable 1111 + as String?,blurPreview: freezed == blurPreview ? _self.blurPreview : blurPreview // ignore: cast_nullable_to_non_nullable 1112 + as String?, 1113 + )); 1114 + } 1115 + /// Create a copy of KlipyGif 1116 + /// with the given fields replaced by the non-null parameter values. 1117 + @override 1118 + @pragma('vm:prefer-inline') 1119 + $KlipyFileCopyWith<$Res> get file { 1120 + 1121 + return $KlipyFileCopyWith<$Res>(_self.file, (value) { 1122 + return _then(_self.copyWith(file: value)); 1123 + }); 1124 + } 1125 + } 1126 + 1127 + 1128 + /// Adds pattern-matching-related methods to [KlipyGif]. 1129 + extension KlipyGifPatterns on KlipyGif { 1130 + /// A variant of `map` that fallback to returning `orElse`. 1131 + /// 1132 + /// It is equivalent to doing: 1133 + /// ```dart 1134 + /// switch (sealedClass) { 1135 + /// case final Subclass value: 1136 + /// return ...; 1137 + /// case _: 1138 + /// return orElse(); 1139 + /// } 1140 + /// ``` 1141 + 1142 + @optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _KlipyGif value)? $default,{required TResult orElse(),}){ 1143 + final _that = this; 1144 + switch (_that) { 1145 + case _KlipyGif() when $default != null: 1146 + return $default(_that);case _: 1147 + return orElse(); 1148 + 1149 + } 1150 + } 1151 + /// A `switch`-like method, using callbacks. 1152 + /// 1153 + /// Callbacks receives the raw object, upcasted. 1154 + /// It is equivalent to doing: 1155 + /// ```dart 1156 + /// switch (sealedClass) { 1157 + /// case final Subclass value: 1158 + /// return ...; 1159 + /// case final Subclass2 value: 1160 + /// return ...; 1161 + /// } 1162 + /// ``` 1163 + 1164 + @optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _KlipyGif value) $default,){ 1165 + final _that = this; 1166 + switch (_that) { 1167 + case _KlipyGif(): 1168 + return $default(_that);case _: 1169 + throw StateError('Unexpected subclass'); 1170 + 1171 + } 1172 + } 1173 + /// A variant of `map` that fallback to returning `null`. 1174 + /// 1175 + /// It is equivalent to doing: 1176 + /// ```dart 1177 + /// switch (sealedClass) { 1178 + /// case final Subclass value: 1179 + /// return ...; 1180 + /// case _: 1181 + /// return null; 1182 + /// } 1183 + /// ``` 1184 + 1185 + @optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _KlipyGif value)? $default,){ 1186 + final _that = this; 1187 + switch (_that) { 1188 + case _KlipyGif() when $default != null: 1189 + return $default(_that);case _: 1190 + return null; 1191 + 1192 + } 1193 + } 1194 + /// A variant of `when` that fallback to an `orElse` callback. 1195 + /// 1196 + /// It is equivalent to doing: 1197 + /// ```dart 1198 + /// switch (sealedClass) { 1199 + /// case Subclass(:final field): 1200 + /// return ...; 1201 + /// case _: 1202 + /// return orElse(); 1203 + /// } 1204 + /// ``` 1205 + 1206 + @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int id, String slug, String title, KlipyFile file, List<String>? tags, String? type, @JsonKey(name: 'blur_preview') String? blurPreview)? $default,{required TResult orElse(),}) {final _that = this; 1207 + switch (_that) { 1208 + case _KlipyGif() when $default != null: 1209 + return $default(_that.id,_that.slug,_that.title,_that.file,_that.tags,_that.type,_that.blurPreview);case _: 1210 + return orElse(); 1211 + 1212 + } 1213 + } 1214 + /// A `switch`-like method, using callbacks. 1215 + /// 1216 + /// As opposed to `map`, this offers destructuring. 1217 + /// It is equivalent to doing: 1218 + /// ```dart 1219 + /// switch (sealedClass) { 1220 + /// case Subclass(:final field): 1221 + /// return ...; 1222 + /// case Subclass2(:final field2): 1223 + /// return ...; 1224 + /// } 1225 + /// ``` 1226 + 1227 + @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int id, String slug, String title, KlipyFile file, List<String>? tags, String? type, @JsonKey(name: 'blur_preview') String? blurPreview) $default,) {final _that = this; 1228 + switch (_that) { 1229 + case _KlipyGif(): 1230 + return $default(_that.id,_that.slug,_that.title,_that.file,_that.tags,_that.type,_that.blurPreview);case _: 1231 + throw StateError('Unexpected subclass'); 1232 + 1233 + } 1234 + } 1235 + /// A variant of `when` that fallback to returning `null` 1236 + /// 1237 + /// It is equivalent to doing: 1238 + /// ```dart 1239 + /// switch (sealedClass) { 1240 + /// case Subclass(:final field): 1241 + /// return ...; 1242 + /// case _: 1243 + /// return null; 1244 + /// } 1245 + /// ``` 1246 + 1247 + @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int id, String slug, String title, KlipyFile file, List<String>? tags, String? type, @JsonKey(name: 'blur_preview') String? blurPreview)? $default,) {final _that = this; 1248 + switch (_that) { 1249 + case _KlipyGif() when $default != null: 1250 + return $default(_that.id,_that.slug,_that.title,_that.file,_that.tags,_that.type,_that.blurPreview);case _: 1251 + return null; 1252 + 1253 + } 1254 + } 1255 + 1256 + } 1257 + 1258 + /// @nodoc 1259 + @JsonSerializable() 1260 + 1261 + class _KlipyGif extends KlipyGif { 1262 + const _KlipyGif({this.id = 0, this.slug = '', this.title = '', this.file = const KlipyFile(), final List<String>? tags, this.type, @JsonKey(name: 'blur_preview') this.blurPreview}): _tags = tags,super._(); 1263 + factory _KlipyGif.fromJson(Map<String, dynamic> json) => _$KlipyGifFromJson(json); 1264 + 1265 + @override@JsonKey() final int id; 1266 + @override@JsonKey() final String slug; 1267 + @override@JsonKey() final String title; 1268 + @override@JsonKey() final KlipyFile file; 1269 + final List<String>? _tags; 1270 + @override List<String>? get tags { 1271 + final value = _tags; 1272 + if (value == null) return null; 1273 + if (_tags is EqualUnmodifiableListView) return _tags; 1274 + // ignore: implicit_dynamic_type 1275 + return EqualUnmodifiableListView(value); 1276 + } 1277 + 1278 + @override final String? type; 1279 + @override@JsonKey(name: 'blur_preview') final String? blurPreview; 1280 + 1281 + /// Create a copy of KlipyGif 1282 + /// with the given fields replaced by the non-null parameter values. 1283 + @override @JsonKey(includeFromJson: false, includeToJson: false) 1284 + @pragma('vm:prefer-inline') 1285 + _$KlipyGifCopyWith<_KlipyGif> get copyWith => __$KlipyGifCopyWithImpl<_KlipyGif>(this, _$identity); 1286 + 1287 + @override 1288 + Map<String, dynamic> toJson() { 1289 + return _$KlipyGifToJson(this, ); 1290 + } 1291 + 1292 + @override 1293 + bool operator ==(Object other) { 1294 + return identical(this, other) || (other.runtimeType == runtimeType&&other is _KlipyGif&&(identical(other.id, id) || other.id == id)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.title, title) || other.title == title)&&(identical(other.file, file) || other.file == file)&&const DeepCollectionEquality().equals(other._tags, _tags)&&(identical(other.type, type) || other.type == type)&&(identical(other.blurPreview, blurPreview) || other.blurPreview == blurPreview)); 1295 + } 1296 + 1297 + @JsonKey(includeFromJson: false, includeToJson: false) 1298 + @override 1299 + int get hashCode => Object.hash(runtimeType,id,slug,title,file,const DeepCollectionEquality().hash(_tags),type,blurPreview); 1300 + 1301 + @override 1302 + String toString() { 1303 + return 'KlipyGif(id: $id, slug: $slug, title: $title, file: $file, tags: $tags, type: $type, blurPreview: $blurPreview)'; 1304 + } 1305 + 1306 + 1307 + } 1308 + 1309 + /// @nodoc 1310 + abstract mixin class _$KlipyGifCopyWith<$Res> implements $KlipyGifCopyWith<$Res> { 1311 + factory _$KlipyGifCopyWith(_KlipyGif value, $Res Function(_KlipyGif) _then) = __$KlipyGifCopyWithImpl; 1312 + @override @useResult 1313 + $Res call({ 1314 + int id, String slug, String title, KlipyFile file, List<String>? tags, String? type,@JsonKey(name: 'blur_preview') String? blurPreview 1315 + }); 1316 + 1317 + 1318 + @override $KlipyFileCopyWith<$Res> get file; 1319 + 1320 + } 1321 + /// @nodoc 1322 + class __$KlipyGifCopyWithImpl<$Res> 1323 + implements _$KlipyGifCopyWith<$Res> { 1324 + __$KlipyGifCopyWithImpl(this._self, this._then); 1325 + 1326 + final _KlipyGif _self; 1327 + final $Res Function(_KlipyGif) _then; 1328 + 1329 + /// Create a copy of KlipyGif 1330 + /// with the given fields replaced by the non-null parameter values. 1331 + @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? slug = null,Object? title = null,Object? file = null,Object? tags = freezed,Object? type = freezed,Object? blurPreview = freezed,}) { 1332 + return _then(_KlipyGif( 1333 + id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable 1334 + as int,slug: null == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable 1335 + as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable 1336 + as String,file: null == file ? _self.file : file // ignore: cast_nullable_to_non_nullable 1337 + as KlipyFile,tags: freezed == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable 1338 + as List<String>?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable 1339 + as String?,blurPreview: freezed == blurPreview ? _self.blurPreview : blurPreview // ignore: cast_nullable_to_non_nullable 1340 + as String?, 1341 + )); 1342 + } 1343 + 1344 + /// Create a copy of KlipyGif 1345 + /// with the given fields replaced by the non-null parameter values. 1346 + @override 1347 + @pragma('vm:prefer-inline') 1348 + $KlipyFileCopyWith<$Res> get file { 1349 + 1350 + return $KlipyFileCopyWith<$Res>(_self.file, (value) { 1351 + return _then(_self.copyWith(file: value)); 1352 + }); 1353 + } 1354 + } 1355 + 1356 + 1357 + /// @nodoc 1358 + mixin _$KlipySearchResponse { 1359 + 1360 + List<KlipyGif> get results;@JsonKey(name: 'current_page') int get currentPage;@JsonKey(name: 'per_page') int get perPage;@JsonKey(name: 'has_next') bool get hasNext; 1361 + /// Create a copy of KlipySearchResponse 1362 + /// with the given fields replaced by the non-null parameter values. 1363 + @JsonKey(includeFromJson: false, includeToJson: false) 1364 + @pragma('vm:prefer-inline') 1365 + $KlipySearchResponseCopyWith<KlipySearchResponse> get copyWith => _$KlipySearchResponseCopyWithImpl<KlipySearchResponse>(this as KlipySearchResponse, _$identity); 1366 + 1367 + /// Serializes this KlipySearchResponse to a JSON map. 1368 + Map<String, dynamic> toJson(); 1369 + 1370 + 1371 + @override 1372 + bool operator ==(Object other) { 1373 + return identical(this, other) || (other.runtimeType == runtimeType&&other is KlipySearchResponse&&const DeepCollectionEquality().equals(other.results, results)&&(identical(other.currentPage, currentPage) || other.currentPage == currentPage)&&(identical(other.perPage, perPage) || other.perPage == perPage)&&(identical(other.hasNext, hasNext) || other.hasNext == hasNext)); 1374 + } 1375 + 1376 + @JsonKey(includeFromJson: false, includeToJson: false) 1377 + @override 1378 + int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(results),currentPage,perPage,hasNext); 1379 + 1380 + @override 1381 + String toString() { 1382 + return 'KlipySearchResponse(results: $results, currentPage: $currentPage, perPage: $perPage, hasNext: $hasNext)'; 1383 + } 1384 + 1385 + 1386 + } 1387 + 1388 + /// @nodoc 1389 + abstract mixin class $KlipySearchResponseCopyWith<$Res> { 1390 + factory $KlipySearchResponseCopyWith(KlipySearchResponse value, $Res Function(KlipySearchResponse) _then) = _$KlipySearchResponseCopyWithImpl; 1391 + @useResult 1392 + $Res call({ 1393 + List<KlipyGif> results,@JsonKey(name: 'current_page') int currentPage,@JsonKey(name: 'per_page') int perPage,@JsonKey(name: 'has_next') bool hasNext 1394 + }); 1395 + 1396 + 1397 + 1398 + 1399 + } 1400 + /// @nodoc 1401 + class _$KlipySearchResponseCopyWithImpl<$Res> 1402 + implements $KlipySearchResponseCopyWith<$Res> { 1403 + _$KlipySearchResponseCopyWithImpl(this._self, this._then); 1404 + 1405 + final KlipySearchResponse _self; 1406 + final $Res Function(KlipySearchResponse) _then; 1407 + 1408 + /// Create a copy of KlipySearchResponse 1409 + /// with the given fields replaced by the non-null parameter values. 1410 + @pragma('vm:prefer-inline') @override $Res call({Object? results = null,Object? currentPage = null,Object? perPage = null,Object? hasNext = null,}) { 1411 + return _then(_self.copyWith( 1412 + results: null == results ? _self.results : results // ignore: cast_nullable_to_non_nullable 1413 + as List<KlipyGif>,currentPage: null == currentPage ? _self.currentPage : currentPage // ignore: cast_nullable_to_non_nullable 1414 + as int,perPage: null == perPage ? _self.perPage : perPage // ignore: cast_nullable_to_non_nullable 1415 + as int,hasNext: null == hasNext ? _self.hasNext : hasNext // ignore: cast_nullable_to_non_nullable 1416 + as bool, 1417 + )); 1418 + } 1419 + 1420 + } 1421 + 1422 + 1423 + /// Adds pattern-matching-related methods to [KlipySearchResponse]. 1424 + extension KlipySearchResponsePatterns on KlipySearchResponse { 1425 + /// A variant of `map` that fallback to returning `orElse`. 1426 + /// 1427 + /// It is equivalent to doing: 1428 + /// ```dart 1429 + /// switch (sealedClass) { 1430 + /// case final Subclass value: 1431 + /// return ...; 1432 + /// case _: 1433 + /// return orElse(); 1434 + /// } 1435 + /// ``` 1436 + 1437 + @optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _KlipySearchResponse value)? $default,{required TResult orElse(),}){ 1438 + final _that = this; 1439 + switch (_that) { 1440 + case _KlipySearchResponse() when $default != null: 1441 + return $default(_that);case _: 1442 + return orElse(); 1443 + 1444 + } 1445 + } 1446 + /// A `switch`-like method, using callbacks. 1447 + /// 1448 + /// Callbacks receives the raw object, upcasted. 1449 + /// It is equivalent to doing: 1450 + /// ```dart 1451 + /// switch (sealedClass) { 1452 + /// case final Subclass value: 1453 + /// return ...; 1454 + /// case final Subclass2 value: 1455 + /// return ...; 1456 + /// } 1457 + /// ``` 1458 + 1459 + @optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _KlipySearchResponse value) $default,){ 1460 + final _that = this; 1461 + switch (_that) { 1462 + case _KlipySearchResponse(): 1463 + return $default(_that);case _: 1464 + throw StateError('Unexpected subclass'); 1465 + 1466 + } 1467 + } 1468 + /// A variant of `map` that fallback to returning `null`. 1469 + /// 1470 + /// It is equivalent to doing: 1471 + /// ```dart 1472 + /// switch (sealedClass) { 1473 + /// case final Subclass value: 1474 + /// return ...; 1475 + /// case _: 1476 + /// return null; 1477 + /// } 1478 + /// ``` 1479 + 1480 + @optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _KlipySearchResponse value)? $default,){ 1481 + final _that = this; 1482 + switch (_that) { 1483 + case _KlipySearchResponse() when $default != null: 1484 + return $default(_that);case _: 1485 + return null; 1486 + 1487 + } 1488 + } 1489 + /// A variant of `when` that fallback to an `orElse` callback. 1490 + /// 1491 + /// It is equivalent to doing: 1492 + /// ```dart 1493 + /// switch (sealedClass) { 1494 + /// case Subclass(:final field): 1495 + /// return ...; 1496 + /// case _: 1497 + /// return orElse(); 1498 + /// } 1499 + /// ``` 1500 + 1501 + @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<KlipyGif> results, @JsonKey(name: 'current_page') int currentPage, @JsonKey(name: 'per_page') int perPage, @JsonKey(name: 'has_next') bool hasNext)? $default,{required TResult orElse(),}) {final _that = this; 1502 + switch (_that) { 1503 + case _KlipySearchResponse() when $default != null: 1504 + return $default(_that.results,_that.currentPage,_that.perPage,_that.hasNext);case _: 1505 + return orElse(); 1506 + 1507 + } 1508 + } 1509 + /// A `switch`-like method, using callbacks. 1510 + /// 1511 + /// As opposed to `map`, this offers destructuring. 1512 + /// It is equivalent to doing: 1513 + /// ```dart 1514 + /// switch (sealedClass) { 1515 + /// case Subclass(:final field): 1516 + /// return ...; 1517 + /// case Subclass2(:final field2): 1518 + /// return ...; 1519 + /// } 1520 + /// ``` 1521 + 1522 + @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<KlipyGif> results, @JsonKey(name: 'current_page') int currentPage, @JsonKey(name: 'per_page') int perPage, @JsonKey(name: 'has_next') bool hasNext) $default,) {final _that = this; 1523 + switch (_that) { 1524 + case _KlipySearchResponse(): 1525 + return $default(_that.results,_that.currentPage,_that.perPage,_that.hasNext);case _: 1526 + throw StateError('Unexpected subclass'); 1527 + 1528 + } 1529 + } 1530 + /// A variant of `when` that fallback to returning `null` 1531 + /// 1532 + /// It is equivalent to doing: 1533 + /// ```dart 1534 + /// switch (sealedClass) { 1535 + /// case Subclass(:final field): 1536 + /// return ...; 1537 + /// case _: 1538 + /// return null; 1539 + /// } 1540 + /// ``` 1541 + 1542 + @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<KlipyGif> results, @JsonKey(name: 'current_page') int currentPage, @JsonKey(name: 'per_page') int perPage, @JsonKey(name: 'has_next') bool hasNext)? $default,) {final _that = this; 1543 + switch (_that) { 1544 + case _KlipySearchResponse() when $default != null: 1545 + return $default(_that.results,_that.currentPage,_that.perPage,_that.hasNext);case _: 1546 + return null; 1547 + 1548 + } 1549 + } 1550 + 1551 + } 1552 + 1553 + /// @nodoc 1554 + @JsonSerializable() 1555 + 1556 + class _KlipySearchResponse extends KlipySearchResponse { 1557 + const _KlipySearchResponse({final List<KlipyGif> results = const [], @JsonKey(name: 'current_page') this.currentPage = 1, @JsonKey(name: 'per_page') this.perPage = 24, @JsonKey(name: 'has_next') this.hasNext = false}): _results = results,super._(); 1558 + factory _KlipySearchResponse.fromJson(Map<String, dynamic> json) => _$KlipySearchResponseFromJson(json); 1559 + 1560 + final List<KlipyGif> _results; 1561 + @override@JsonKey() List<KlipyGif> get results { 1562 + if (_results is EqualUnmodifiableListView) return _results; 1563 + // ignore: implicit_dynamic_type 1564 + return EqualUnmodifiableListView(_results); 1565 + } 1566 + 1567 + @override@JsonKey(name: 'current_page') final int currentPage; 1568 + @override@JsonKey(name: 'per_page') final int perPage; 1569 + @override@JsonKey(name: 'has_next') final bool hasNext; 1570 + 1571 + /// Create a copy of KlipySearchResponse 1572 + /// with the given fields replaced by the non-null parameter values. 1573 + @override @JsonKey(includeFromJson: false, includeToJson: false) 1574 + @pragma('vm:prefer-inline') 1575 + _$KlipySearchResponseCopyWith<_KlipySearchResponse> get copyWith => __$KlipySearchResponseCopyWithImpl<_KlipySearchResponse>(this, _$identity); 1576 + 1577 + @override 1578 + Map<String, dynamic> toJson() { 1579 + return _$KlipySearchResponseToJson(this, ); 1580 + } 1581 + 1582 + @override 1583 + bool operator ==(Object other) { 1584 + return identical(this, other) || (other.runtimeType == runtimeType&&other is _KlipySearchResponse&&const DeepCollectionEquality().equals(other._results, _results)&&(identical(other.currentPage, currentPage) || other.currentPage == currentPage)&&(identical(other.perPage, perPage) || other.perPage == perPage)&&(identical(other.hasNext, hasNext) || other.hasNext == hasNext)); 1585 + } 1586 + 1587 + @JsonKey(includeFromJson: false, includeToJson: false) 1588 + @override 1589 + int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_results),currentPage,perPage,hasNext); 1590 + 1591 + @override 1592 + String toString() { 1593 + return 'KlipySearchResponse(results: $results, currentPage: $currentPage, perPage: $perPage, hasNext: $hasNext)'; 1594 + } 1595 + 1596 + 1597 + } 1598 + 1599 + /// @nodoc 1600 + abstract mixin class _$KlipySearchResponseCopyWith<$Res> implements $KlipySearchResponseCopyWith<$Res> { 1601 + factory _$KlipySearchResponseCopyWith(_KlipySearchResponse value, $Res Function(_KlipySearchResponse) _then) = __$KlipySearchResponseCopyWithImpl; 1602 + @override @useResult 1603 + $Res call({ 1604 + List<KlipyGif> results,@JsonKey(name: 'current_page') int currentPage,@JsonKey(name: 'per_page') int perPage,@JsonKey(name: 'has_next') bool hasNext 1605 + }); 1606 + 1607 + 1608 + 1609 + 1610 + } 1611 + /// @nodoc 1612 + class __$KlipySearchResponseCopyWithImpl<$Res> 1613 + implements _$KlipySearchResponseCopyWith<$Res> { 1614 + __$KlipySearchResponseCopyWithImpl(this._self, this._then); 1615 + 1616 + final _KlipySearchResponse _self; 1617 + final $Res Function(_KlipySearchResponse) _then; 1618 + 1619 + /// Create a copy of KlipySearchResponse 1620 + /// with the given fields replaced by the non-null parameter values. 1621 + @override @pragma('vm:prefer-inline') $Res call({Object? results = null,Object? currentPage = null,Object? perPage = null,Object? hasNext = null,}) { 1622 + return _then(_KlipySearchResponse( 1623 + results: null == results ? _self._results : results // ignore: cast_nullable_to_non_nullable 1624 + as List<KlipyGif>,currentPage: null == currentPage ? _self.currentPage : currentPage // ignore: cast_nullable_to_non_nullable 1625 + as int,perPage: null == perPage ? _self.perPage : perPage // ignore: cast_nullable_to_non_nullable 1626 + as int,hasNext: null == hasNext ? _self.hasNext : hasNext // ignore: cast_nullable_to_non_nullable 1627 + as bool, 1628 + )); 1629 + } 1630 + 1631 + 1632 + } 1633 + 1634 + // dart format on
+100
lib/src/features/composer/domain/klipy_gif.g.dart
··· 1 + // GENERATED CODE - DO NOT MODIFY BY HAND 2 + 3 + part of 'klipy_gif.dart'; 4 + 5 + // ************************************************************************** 6 + // JsonSerializableGenerator 7 + // ************************************************************************** 8 + 9 + _KlipyMediaFormat _$KlipyMediaFormatFromJson(Map<String, dynamic> json) => _KlipyMediaFormat( 10 + url: json['url'] as String? ?? '', 11 + width: (json['width'] as num?)?.toInt() ?? 0, 12 + height: (json['height'] as num?)?.toInt() ?? 0, 13 + size: (json['size'] as num?)?.toInt(), 14 + ); 15 + 16 + Map<String, dynamic> _$KlipyMediaFormatToJson(_KlipyMediaFormat instance) => <String, dynamic>{ 17 + 'url': instance.url, 18 + 'width': instance.width, 19 + 'height': instance.height, 20 + 'size': instance.size, 21 + }; 22 + 23 + _KlipyFormatVariants _$KlipyFormatVariantsFromJson( 24 + Map<String, dynamic> json, 25 + ) => _KlipyFormatVariants( 26 + gif: json['gif'] == null ? null : KlipyMediaFormat.fromJson(json['gif'] as Map<String, dynamic>), 27 + webp: json['webp'] == null 28 + ? null 29 + : KlipyMediaFormat.fromJson(json['webp'] as Map<String, dynamic>), 30 + jpg: json['jpg'] == null ? null : KlipyMediaFormat.fromJson(json['jpg'] as Map<String, dynamic>), 31 + mp4: json['mp4'] == null ? null : KlipyMediaFormat.fromJson(json['mp4'] as Map<String, dynamic>), 32 + webm: json['webm'] == null 33 + ? null 34 + : KlipyMediaFormat.fromJson(json['webm'] as Map<String, dynamic>), 35 + ); 36 + 37 + Map<String, dynamic> _$KlipyFormatVariantsToJson(_KlipyFormatVariants instance) => 38 + <String, dynamic>{ 39 + 'gif': instance.gif, 40 + 'webp': instance.webp, 41 + 'jpg': instance.jpg, 42 + 'mp4': instance.mp4, 43 + 'webm': instance.webm, 44 + }; 45 + 46 + _KlipyFile _$KlipyFileFromJson(Map<String, dynamic> json) => _KlipyFile( 47 + hd: json['hd'] == null ? null : KlipyFormatVariants.fromJson(json['hd'] as Map<String, dynamic>), 48 + md: json['md'] == null ? null : KlipyFormatVariants.fromJson(json['md'] as Map<String, dynamic>), 49 + sm: json['sm'] == null ? null : KlipyFormatVariants.fromJson(json['sm'] as Map<String, dynamic>), 50 + xs: json['xs'] == null ? null : KlipyFormatVariants.fromJson(json['xs'] as Map<String, dynamic>), 51 + ); 52 + 53 + Map<String, dynamic> _$KlipyFileToJson(_KlipyFile instance) => <String, dynamic>{ 54 + 'hd': instance.hd, 55 + 'md': instance.md, 56 + 'sm': instance.sm, 57 + 'xs': instance.xs, 58 + }; 59 + 60 + _KlipyGif _$KlipyGifFromJson(Map<String, dynamic> json) => _KlipyGif( 61 + id: (json['id'] as num?)?.toInt() ?? 0, 62 + slug: json['slug'] as String? ?? '', 63 + title: json['title'] as String? ?? '', 64 + file: json['file'] == null 65 + ? const KlipyFile() 66 + : KlipyFile.fromJson(json['file'] as Map<String, dynamic>), 67 + tags: (json['tags'] as List<dynamic>?)?.map((e) => e as String).toList(), 68 + type: json['type'] as String?, 69 + blurPreview: json['blur_preview'] as String?, 70 + ); 71 + 72 + Map<String, dynamic> _$KlipyGifToJson(_KlipyGif instance) => <String, dynamic>{ 73 + 'id': instance.id, 74 + 'slug': instance.slug, 75 + 'title': instance.title, 76 + 'file': instance.file, 77 + 'tags': instance.tags, 78 + 'type': instance.type, 79 + 'blur_preview': instance.blurPreview, 80 + }; 81 + 82 + _KlipySearchResponse _$KlipySearchResponseFromJson(Map<String, dynamic> json) => 83 + _KlipySearchResponse( 84 + results: 85 + (json['results'] as List<dynamic>?) 86 + ?.map((e) => KlipyGif.fromJson(e as Map<String, dynamic>)) 87 + .toList() ?? 88 + const [], 89 + currentPage: (json['current_page'] as num?)?.toInt() ?? 1, 90 + perPage: (json['per_page'] as num?)?.toInt() ?? 24, 91 + hasNext: json['has_next'] as bool? ?? false, 92 + ); 93 + 94 + Map<String, dynamic> _$KlipySearchResponseToJson(_KlipySearchResponse instance) => 95 + <String, dynamic>{ 96 + 'results': instance.results, 97 + 'current_page': instance.currentPage, 98 + 'per_page': instance.perPage, 99 + 'has_next': instance.hasNext, 100 + };
-181
lib/src/features/composer/domain/tenor_gif.dart
··· 1 - import 'package:equatable/equatable.dart'; 2 - 3 - /// Represents a GIF media object from Tenor API. 4 - class TenorMedia with EquatableMixin { 5 - factory TenorMedia.fromJson(Map<String, dynamic> json) { 6 - return TenorMedia( 7 - previewUrl: json['preview'] as String? ?? '', 8 - url: json['url'] as String? ?? '', 9 - dims: TenorDimensions.fromJson(json['dims'] as Map<String, dynamic>? ?? {}), 10 - previewSize: json['preview_size'] as int?, 11 - size: json['size'] as int?, 12 - ); 13 - } 14 - const TenorMedia({ 15 - required this.previewUrl, 16 - required this.url, 17 - required this.dims, 18 - this.previewSize, 19 - this.size, 20 - }); 21 - 22 - final String previewUrl; 23 - final String url; 24 - final TenorDimensions dims; 25 - final int? previewSize; 26 - final int? size; 27 - 28 - Map<String, dynamic> toJson() { 29 - return { 30 - 'preview': previewUrl, 31 - 'url': url, 32 - 'dims': dims.toJson(), 33 - if (previewSize != null) 'preview_size': previewSize, 34 - if (size != null) 'size': size, 35 - }; 36 - } 37 - 38 - @override 39 - List<Object?> get props => [previewUrl, url, dims, previewSize, size]; 40 - } 41 - 42 - /// Represents dimensions of a Tenor GIF. 43 - class TenorDimensions with EquatableMixin { 44 - factory TenorDimensions.fromJson(Map<String, dynamic> json) { 45 - return TenorDimensions(width: json['width'] as int? ?? 0, height: json['height'] as int? ?? 0); 46 - } 47 - const TenorDimensions({required this.width, required this.height}); 48 - 49 - final int width; 50 - final int height; 51 - 52 - Map<String, dynamic> toJson() { 53 - return {'width': width, 'height': height}; 54 - } 55 - 56 - @override 57 - List<Object?> get props => [width, height]; 58 - } 59 - 60 - /// Represents a GIF result from Tenor API. 61 - class TenorGif with EquatableMixin { 62 - factory TenorGif.fromJson(Map<String, dynamic> json) { 63 - final mediaFormats = <String, TenorMedia>{}; 64 - final mediaFormatsJson = json['media_formats']; 65 - if (mediaFormatsJson != null && mediaFormatsJson is Map) { 66 - for (final entry in mediaFormatsJson.entries) { 67 - if (entry.key is String && entry.value is Map<String, dynamic>) { 68 - mediaFormats[entry.key as String] = TenorMedia.fromJson( 69 - entry.value as Map<String, dynamic>, 70 - ); 71 - } 72 - } 73 - } 74 - 75 - return TenorGif( 76 - id: json['id'] as String? ?? '', 77 - title: json['title'] as String? ?? '', 78 - mediaFormats: mediaFormats, 79 - created: json['created'] != null 80 - ? DateTime.fromMillisecondsSinceEpoch((json['created'] as num).toInt() * 1000) 81 - : DateTime.now(), 82 - contentDescription: json['content_description'] as String?, 83 - url: json['url'] as String?, 84 - itemurl: json['itemurl'] as String?, 85 - tags: (json['tags'] as List<dynamic>?)?.cast<String>(), 86 - flags: (json['flags'] as List<dynamic>?)?.cast<String>(), 87 - hasaudio: json['hasaudio'] as bool?, 88 - ); 89 - } 90 - const TenorGif({ 91 - required this.id, 92 - required this.title, 93 - required this.mediaFormats, 94 - required this.created, 95 - this.contentDescription, 96 - this.url, 97 - this.itemurl, 98 - this.tags, 99 - this.flags, 100 - this.hasaudio, 101 - }); 102 - 103 - final String id; 104 - final String title; 105 - final Map<String, TenorMedia> mediaFormats; 106 - final DateTime created; 107 - final String? contentDescription; 108 - final String? url; 109 - final String? itemurl; 110 - final List<String>? tags; 111 - final List<String>? flags; 112 - final bool? hasaudio; 113 - 114 - Map<String, dynamic> toJson() { 115 - return { 116 - 'id': id, 117 - 'title': title, 118 - 'media_formats': mediaFormats.map((key, value) => MapEntry(key, value.toJson())), 119 - 'created': created.millisecondsSinceEpoch ~/ 1000, 120 - if (contentDescription != null) 'content_description': contentDescription, 121 - if (url != null) 'url': url, 122 - if (itemurl != null) 'itemurl': itemurl, 123 - if (tags != null) 'tags': tags, 124 - if (flags != null) 'flags': flags, 125 - if (hasaudio != null) 'hasaudio': hasaudio, 126 - }; 127 - } 128 - 129 - TenorMedia? get mediumGif => mediaFormats['mediumgif']; 130 - TenorMedia? get tinyGif => mediaFormats['tinygif']; 131 - TenorMedia? get gif => mediaFormats['gif']; 132 - 133 - String? get thumbnailUrl => tinyGif?.previewUrl ?? mediumGif?.previewUrl; 134 - 135 - String? get gifUrl => mediumGif?.url ?? gif?.url; 136 - 137 - @override 138 - List<Object?> get props => [ 139 - id, 140 - title, 141 - mediaFormats, 142 - created, 143 - contentDescription, 144 - url, 145 - itemurl, 146 - tags, 147 - flags, 148 - hasaudio, 149 - ]; 150 - } 151 - 152 - /// Represents search results from Tenor API. 153 - class TenorSearchResponse with EquatableMixin { 154 - factory TenorSearchResponse.fromJson(Map<String, dynamic> json) { 155 - final results = <TenorGif>[]; 156 - final resultsJson = json['results'] as List<dynamic>?; 157 - if (resultsJson != null) { 158 - for (final result in resultsJson) { 159 - if (result is Map<String, dynamic>) { 160 - results.add(TenorGif.fromJson(result)); 161 - } 162 - } 163 - } 164 - 165 - return TenorSearchResponse(results: results, next: json['next'] as String?); 166 - } 167 - const TenorSearchResponse({required this.results, this.next}); 168 - 169 - final List<TenorGif> results; 170 - final String? next; 171 - 172 - Map<String, dynamic> toJson() { 173 - return { 174 - 'results': results.map((gif) => gif.toJson()).toList(), 175 - if (next != null) 'next': next, 176 - }; 177 - } 178 - 179 - @override 180 - List<Object?> get props => [results, next]; 181 - }
+67
lib/src/features/composer/infrastructure/klipy_service.g.dart
··· 1 + // GENERATED CODE - DO NOT MODIFY BY HAND 2 + 3 + part of 'klipy_service.dart'; 4 + 5 + // ************************************************************************** 6 + // RiverpodGenerator 7 + // ************************************************************************** 8 + 9 + // GENERATED CODE - DO NOT MODIFY BY HAND 10 + // ignore_for_file: type=lint, type=warning 11 + /// Service for interacting with Klipy API. 12 + /// 13 + /// Provides methods for searching GIFs and getting trending GIFs. 14 + /// The API key should be configured securely via environment variables. 15 + /// Obtain your API key from https://partner.klipy.com 16 + 17 + @ProviderFor(klipyService) 18 + final klipyServiceProvider = KlipyServiceProvider._(); 19 + 20 + /// Service for interacting with Klipy API. 21 + /// 22 + /// Provides methods for searching GIFs and getting trending GIFs. 23 + /// The API key should be configured securely via environment variables. 24 + /// Obtain your API key from https://partner.klipy.com 25 + 26 + final class KlipyServiceProvider 27 + extends $FunctionalProvider<KlipyService, KlipyService, KlipyService> 28 + with $Provider<KlipyService> { 29 + /// Service for interacting with Klipy API. 30 + /// 31 + /// Provides methods for searching GIFs and getting trending GIFs. 32 + /// The API key should be configured securely via environment variables. 33 + /// Obtain your API key from https://partner.klipy.com 34 + KlipyServiceProvider._() 35 + : super( 36 + from: null, 37 + argument: null, 38 + retry: null, 39 + name: r'klipyServiceProvider', 40 + isAutoDispose: true, 41 + dependencies: null, 42 + $allTransitiveDependencies: null, 43 + ); 44 + 45 + @override 46 + String debugGetCreateSourceHash() => _$klipyServiceHash(); 47 + 48 + @$internal 49 + @override 50 + $ProviderElement<KlipyService> $createElement($ProviderPointer pointer) => 51 + $ProviderElement(pointer); 52 + 53 + @override 54 + KlipyService create(Ref ref) { 55 + return klipyService(ref); 56 + } 57 + 58 + /// {@macro riverpod.override_with_value} 59 + Override overrideWithValue(KlipyService value) { 60 + return $ProviderOverride( 61 + origin: this, 62 + providerOverride: $SyncValueProvider<KlipyService>(value), 63 + ); 64 + } 65 + } 66 + 67 + String _$klipyServiceHash() => r'b1b2821189fcb6c0381d1bad49150cb20bb6d049';
+36 -36
lib/src/features/composer/infrastructure/tenor_service.dart lib/src/features/composer/infrastructure/klipy_service.dart
··· 3 3 import 'package:dio/dio.dart'; 4 4 import 'package:riverpod_annotation/riverpod_annotation.dart'; 5 5 6 - import '../domain/tenor_gif.dart'; 6 + import '../domain/klipy_gif.dart'; 7 7 8 - part 'tenor_service.g.dart'; 8 + part 'klipy_service.g.dart'; 9 9 10 - // FIXME: Replace with Klipy (Tenor is deprecated) 11 - const String _defaultApiKey = 'AIzaSyD4HJZw9KqfVqXbQeJZxk7w7xX0Xy0X0'; 10 + // TODO: Replace with your Klipy API key from https://partner.klipy.com 11 + const String _defaultApiKey = 'YOUR_KLIPY_API_KEY'; 12 12 13 - /// Service for interacting with Tenor API. 13 + /// Service for interacting with Klipy API. 14 14 /// 15 - /// Provides methods for searching GIFs and getting featured/trending GIFs. 15 + /// Provides methods for searching GIFs and getting trending GIFs. 16 16 /// The API key should be configured securely via environment variables. 17 + /// Obtain your API key from https://partner.klipy.com 17 18 @riverpod 18 - TenorService tenorService(Ref ref) { 19 - return TenorService(apiKey: _defaultApiKey, clientKey: 'lazurite_flutter'); 19 + KlipyService klipyService(Ref ref) { 20 + return KlipyService(apiKey: _defaultApiKey); 20 21 } 21 22 22 - class TenorService { 23 - TenorService({required String apiKey, required String clientKey, Dio? dio}) 23 + class KlipyService { 24 + KlipyService({required String apiKey, String? customerId, Dio? dio}) 24 25 : _apiKey = apiKey, 25 - _clientKey = clientKey, 26 + _customerId = customerId ?? 'lazurite_user', 26 27 _dio = 27 28 dio ?? 28 29 Dio( 29 30 BaseOptions( 30 - baseUrl: 'https://tenor.googleapis.com/v2', 31 + baseUrl: 'https://api.klipy.com', 31 32 connectTimeout: const Duration(seconds: 30), 32 33 receiveTimeout: const Duration(seconds: 30), 33 34 sendTimeout: const Duration(seconds: 30), ··· 35 36 ); 36 37 37 38 final String _apiKey; 38 - final String _clientKey; 39 + final String _customerId; 39 40 final Dio _dio; 40 41 41 42 /// Searches for GIFs matching the query string. 42 43 /// 43 44 /// [query] is the search query string. 44 - /// [limit] is the number of results to return (max 50, default 20). 45 - /// [pos] is the pagination token for fetching next page. 46 - Future<TenorSearchResponse> searchGifs({ 45 + /// [perPage] is the number of results to return (max 50, default 24). 46 + /// [page] is the page number for pagination (starts at 1). 47 + Future<KlipySearchResponse> searchGifs({ 47 48 required String query, 48 - int limit = 20, 49 - String? pos, 49 + int perPage = 24, 50 + int page = 1, 50 51 }) async { 51 52 if (query.trim().isEmpty) { 52 - return getFeaturedGifs(limit: limit); 53 + return getTrendingGifs(perPage: perPage, page: page); 53 54 } 54 55 55 56 try { 56 57 final response = await _dio.get<Map<String, dynamic>>( 57 - '/search', 58 + '/api/v1/$_apiKey/gifs/search', 58 59 queryParameters: { 60 + 'customer_id': _customerId, 59 61 'q': query, 60 - 'key': _apiKey, 61 - 'client_key': _clientKey, 62 - 'limit': limit.clamp(1, 50), 63 - if (pos != null) 'pos': pos, 62 + 'per_page': perPage.clamp(1, 50), 63 + 'page': page, 64 64 }, 65 65 ); 66 66 67 - return TenorSearchResponse.fromJson(response.data ?? {}); 67 + return KlipySearchResponse.fromApiResponse(response.data ?? {}); 68 68 } on DioException catch (e) { 69 69 throw _convertDioError(e); 70 70 } 71 71 } 72 72 73 - /// Gets featured/trending GIFs. 73 + /// Gets trending GIFs. 74 74 /// 75 - /// [limit] is the number of results to return (max 50, default 20). 76 - /// [pos] is the pagination token for fetching next page. 77 - Future<TenorSearchResponse> getFeaturedGifs({int limit = 20, String? pos}) async { 75 + /// [perPage] is the number of results to return (max 50, default 24). 76 + /// [page] is the page number for pagination (starts at 1). 77 + Future<KlipySearchResponse> getTrendingGifs({int perPage = 24, int page = 1}) async { 78 78 try { 79 79 final response = await _dio.get<Map<String, dynamic>>( 80 - '/featured', 80 + '/api/v1/$_apiKey/gifs/trending', 81 81 queryParameters: { 82 - 'key': _apiKey, 83 - 'client_key': _clientKey, 84 - 'limit': limit.clamp(1, 50), 85 - if (pos != null) 'pos': pos, 82 + 'customer_id': _customerId, 83 + 'per_page': perPage.clamp(1, 50), 84 + 'page': page, 86 85 }, 87 86 ); 88 87 89 - return TenorSearchResponse.fromJson(response.data ?? {}); 88 + return KlipySearchResponse.fromApiResponse(response.data ?? {}); 90 89 } on DioException catch (e) { 91 90 throw _convertDioError(e); 92 91 } ··· 108 107 throw Exception('Failed to download thumbnail: empty response'); 109 108 } 110 109 110 + final extension = url.contains('.webp') ? 'webp' : 'jpg'; 111 111 final directory = Directory.systemTemp; 112 112 final file = File( 113 - '${directory.path}/tenor_thumb_${DateTime.now().millisecondsSinceEpoch}.jpg', 113 + '${directory.path}/klipy_thumb_${DateTime.now().millisecondsSinceEpoch}.$extension', 114 114 ); 115 115 await file.writeAsBytes(bytes); 116 116
-64
lib/src/features/composer/infrastructure/tenor_service.g.dart
··· 1 - // GENERATED CODE - DO NOT MODIFY BY HAND 2 - 3 - part of 'tenor_service.dart'; 4 - 5 - // ************************************************************************** 6 - // RiverpodGenerator 7 - // ************************************************************************** 8 - 9 - // GENERATED CODE - DO NOT MODIFY BY HAND 10 - // ignore_for_file: type=lint, type=warning 11 - /// Service for interacting with Tenor API. 12 - /// 13 - /// Provides methods for searching GIFs and getting featured/trending GIFs. 14 - /// The API key should be configured securely via environment variables. 15 - 16 - @ProviderFor(tenorService) 17 - final tenorServiceProvider = TenorServiceProvider._(); 18 - 19 - /// Service for interacting with Tenor API. 20 - /// 21 - /// Provides methods for searching GIFs and getting featured/trending GIFs. 22 - /// The API key should be configured securely via environment variables. 23 - 24 - final class TenorServiceProvider 25 - extends $FunctionalProvider<TenorService, TenorService, TenorService> 26 - with $Provider<TenorService> { 27 - /// Service for interacting with Tenor API. 28 - /// 29 - /// Provides methods for searching GIFs and getting featured/trending GIFs. 30 - /// The API key should be configured securely via environment variables. 31 - TenorServiceProvider._() 32 - : super( 33 - from: null, 34 - argument: null, 35 - retry: null, 36 - name: r'tenorServiceProvider', 37 - isAutoDispose: true, 38 - dependencies: null, 39 - $allTransitiveDependencies: null, 40 - ); 41 - 42 - @override 43 - String debugGetCreateSourceHash() => _$tenorServiceHash(); 44 - 45 - @$internal 46 - @override 47 - $ProviderElement<TenorService> $createElement($ProviderPointer pointer) => 48 - $ProviderElement(pointer); 49 - 50 - @override 51 - TenorService create(Ref ref) { 52 - return tenorService(ref); 53 - } 54 - 55 - /// {@macro riverpod.override_with_value} 56 - Override overrideWithValue(TenorService value) { 57 - return $ProviderOverride( 58 - origin: this, 59 - providerOverride: $SyncValueProvider<TenorService>(value), 60 - ); 61 - } 62 - } 63 - 64 - String _$tenorServiceHash() => r'4296b779d4b198c7cc9b1555f00a91309d4ac8af';
+23 -23
lib/src/features/composer/presentation/screens/gif_picker_screen.dart
··· 5 5 import 'package:flutter_riverpod/flutter_riverpod.dart'; 6 6 import 'package:lazurite/src/infrastructure/network/network.dart'; 7 7 8 - import '../../../composer/domain/tenor_gif.dart'; 9 - import '../../../composer/infrastructure/tenor_service.dart'; 8 + import '../../../composer/domain/klipy_gif.dart'; 9 + import '../../../composer/infrastructure/klipy_service.dart'; 10 10 11 11 /// Result data returned when user selects a GIF. 12 12 class GifSelectionResult { ··· 23 23 final String thumbBlobJson; 24 24 } 25 25 26 - /// Screen for searching and selecting GIFs from Tenor. 26 + /// Screen for searching and selecting GIFs from Klipy. 27 27 class GifPickerScreen extends ConsumerStatefulWidget { 28 28 const GifPickerScreen({super.key}); 29 29 ··· 34 34 class _GifPickerScreenState extends ConsumerState<GifPickerScreen> { 35 35 final TextEditingController _searchController = TextEditingController(); 36 36 final ScrollController _scrollController = ScrollController(); 37 - final List<TenorGif> _gifs = []; 38 - String? _nextPos; 37 + final List<KlipyGif> _gifs = []; 38 + int? _nextPage; 39 39 bool _isLoading = false; 40 40 bool _isSearching = false; 41 41 ··· 63 63 }); 64 64 65 65 try { 66 - final service = ref.read(tenorServiceProvider); 67 - final response = await service.getFeaturedGifs(); 66 + final service = ref.read(klipyServiceProvider); 67 + final response = await service.getTrendingGifs(); 68 68 69 69 if (mounted) { 70 70 setState(() { 71 71 _gifs.clear(); 72 72 _gifs.addAll(response.results); 73 - _nextPos = response.next; 73 + _nextPage = response.nextPage; 74 74 _isLoading = false; 75 75 }); 76 76 } ··· 92 92 setState(() { 93 93 _isLoading = true; 94 94 _isSearching = true; 95 - _nextPos = null; 95 + _nextPage = null; 96 96 }); 97 97 98 98 try { 99 - final service = ref.read(tenorServiceProvider); 99 + final service = ref.read(klipyServiceProvider); 100 100 final response = await service.searchGifs(query: query); 101 101 102 102 if (mounted) { 103 103 setState(() { 104 104 _gifs.clear(); 105 105 _gifs.addAll(response.results); 106 - _nextPos = response.next; 106 + _nextPage = response.nextPage; 107 107 _isLoading = false; 108 108 }); 109 109 } ··· 120 120 } 121 121 122 122 Future<void> _loadMoreGifs() async { 123 - if (_isLoading || _nextPos == null) return; 123 + if (_isLoading || _nextPage == null) return; 124 124 125 125 setState(() { 126 126 _isLoading = true; 127 127 }); 128 128 129 129 try { 130 - final service = ref.read(tenorServiceProvider); 130 + final service = ref.read(klipyServiceProvider); 131 131 132 - final TenorSearchResponse response; 132 + final KlipySearchResponse response; 133 133 if (_isSearching) { 134 - response = await service.searchGifs(query: _searchController.text, pos: _nextPos); 134 + response = await service.searchGifs(query: _searchController.text, page: _nextPage!); 135 135 } else { 136 - response = await service.getFeaturedGifs(pos: _nextPos); 136 + response = await service.getTrendingGifs(page: _nextPage!); 137 137 } 138 138 139 139 if (mounted) { 140 140 setState(() { 141 141 _gifs.addAll(response.results); 142 - _nextPos = response.next; 142 + _nextPage = response.nextPage; 143 143 _isLoading = false; 144 144 }); 145 145 } ··· 158 158 } 159 159 } 160 160 161 - Future<void> _selectGif(TenorGif gif) async { 161 + Future<void> _selectGif(KlipyGif gif) async { 162 162 try { 163 - final service = ref.read(tenorServiceProvider); 163 + final service = ref.read(klipyServiceProvider); 164 164 165 165 final thumbnailUrl = gif.thumbnailUrl; 166 166 if (thumbnailUrl == null) { ··· 194 194 if (!mounted) return; 195 195 196 196 final result = GifSelectionResult( 197 - uri: gif.itemurl ?? gif.url ?? '', 197 + uri: gif.itemUrl, 198 198 title: gif.title, 199 - description: gif.contentDescription, 199 + description: gif.tags?.join(', '), 200 200 thumbBlobJson: blobRefJson, 201 201 ); 202 202 ··· 326 326 bottomSheet: const Padding( 327 327 padding: EdgeInsets.symmetric(vertical: 8), 328 328 child: Text( 329 - 'Powered by Tenor', 329 + 'Powered by Klipy', 330 330 style: TextStyle(fontSize: 12, color: Colors.grey), 331 331 textAlign: TextAlign.center, 332 332 ), ··· 339 339 class GifGridItem extends StatelessWidget { 340 340 const GifGridItem({required this.gif, required this.onTap, super.key}); 341 341 342 - final TenorGif gif; 342 + final KlipyGif gif; 343 343 final VoidCallback onTap; 344 344 345 345 @override
+13 -5
lib/src/features/feeds/presentation/screens/feed_discovery_screen.dart
··· 86 86 ); 87 87 } 88 88 89 - // FIXME: These bools don't seem to be right 90 - if (searchState.results.isEmpty && searchState.isLoading) { 91 - return const LoadingView(); 89 + if (searchState.isLoading && searchState.results.isEmpty) { 90 + return const LoadingView(message: 'Searching feeds...'); 92 91 } 93 92 94 93 final feeds = searchState.filteredResults; 95 94 if (feeds.isEmpty) { 96 95 if (searchState.isLoading) { 97 - return const Center(child: Text('No matching feeds found.')); 96 + return const LoadingView(message: 'Searching feeds...'); 98 97 } 99 - return const Center(child: Text('No feeds found.')); 98 + 99 + return EmptyState( 100 + icon: Icons.search_off, 101 + title: 'No feeds found', 102 + subtitle: searchState.localFilter.isNotEmpty 103 + ? 'No results match your local filter.' 104 + : (searchState.query.isNotEmpty 105 + ? 'No results found for "${searchState.query}".' 106 + : 'No popular feeds found at the moment.'), 107 + ); 100 108 } 101 109 102 110 return ListView.separated(
+2 -2
lib/src/features/scheduling/infrastructure/background_infrastructure.dart
··· 68 68 ); 69 69 70 70 final videoDio = createVideoServiceDio(); 71 - final tenorDio = createTenorDio(); 71 + final klipyDio = createKlipyDio(); 72 72 73 73 Dio? pdsDio; 74 74 final session = await sessionStorage.getSession(); ··· 91 91 publicDio: publicDio, 92 92 pdsDio: pdsDio, 93 93 videoServiceDio: videoDio, 94 - tenorDio: tenorDio, 94 + klipyDio: klipyDio, 95 95 logger: const Logger('XrpcClient'), 96 96 ); 97 97
+3 -3
lib/src/infrastructure/network/dio_clients.dart
··· 121 121 return dio; 122 122 } 123 123 124 - /// Creates a Dio client configured for Tenor API access. 124 + /// Creates a Dio client configured for Klipy API access. 125 125 /// 126 126 /// This client is used for GIF search and selection. 127 - Dio createTenorDio({ 128 - String baseUrl = 'https://tenor.googleapis.com/v2', 127 + Dio createKlipyDio({ 128 + String baseUrl = 'https://api.klipy.com', 129 129 bool enableLogging = true, 130 130 List<Interceptor> interceptors = const [], 131 131 }) {
+5 -5
lib/src/infrastructure/network/host_kind.dart
··· 22 22 /// Base URL: `https://video.bsky.app` 23 23 video, 24 24 25 - /// Tenor API endpoint for GIF search and selection. 25 + /// Klipy API endpoint for GIF search and selection. 26 26 /// 27 - /// Base URL: `https://tenor.googleapis.com/v2` 28 - tenor, 27 + /// Base URL: `https://api.klipy.com` 28 + klipy, 29 29 } 30 30 31 31 /// Extension to get host-related properties. ··· 39 39 HostKind.publicApi => 'https://public.api.bsky.app', 40 40 HostKind.pds => null, 41 41 HostKind.video => 'https://video.bsky.app', 42 - HostKind.tenor => 'https://tenor.googleapis.com/v2', 42 + HostKind.klipy => 'https://api.klipy.com', 43 43 }; 44 44 } 45 45 ··· 49 49 HostKind.publicApi => false, 50 50 HostKind.pds => true, 51 51 HostKind.video => true, 52 - HostKind.tenor => false, 52 + HostKind.klipy => false, 53 53 }; 54 54 } 55 55 }
+5 -5
lib/src/infrastructure/network/providers.dart
··· 87 87 ); 88 88 } 89 89 90 - /// Provides Tenor API Dio client for GIF search. 90 + /// Provides Klipy API Dio client for GIF search. 91 91 /// 92 - /// This client is used for GIF search and selection from Tenor. 92 + /// This client is used for GIF search and selection from Klipy. 93 93 @Riverpod(keepAlive: true) 94 - Dio dioTenor(Ref ref) { 95 - return createTenorDio( 94 + Dio dioKlipy(Ref ref) { 95 + return createKlipyDio( 96 96 interceptors: [ 97 97 if (kDebugMode) DebugNetworkInterceptor(ref.watch(appDatabaseProvider).devToolsDao), 98 98 ], ··· 109 109 publicDio: ref.watch(dioPublicProvider), 110 110 pdsDio: ref.watch(dioPdsProvider), 111 111 videoServiceDio: ref.watch(dioVideoServiceProvider), 112 - tenorDio: ref.watch(dioTenorProvider), 112 + klipyDio: ref.watch(dioKlipyProvider), 113 113 logger: ref.watch(loggerProvider('XrpcClient')), 114 114 ); 115 115 }
+15 -15
lib/src/infrastructure/network/providers.g.dart
··· 150 150 151 151 String _$dioVideoServiceHash() => r'35fad9f27769840636716b14bdb28c3b43634b52'; 152 152 153 - /// Provides Tenor API Dio client for GIF search. 153 + /// Provides Klipy API Dio client for GIF search. 154 154 /// 155 - /// This client is used for GIF search and selection from Tenor. 155 + /// This client is used for GIF search and selection from Klipy. 156 156 157 - @ProviderFor(dioTenor) 158 - final dioTenorProvider = DioTenorProvider._(); 157 + @ProviderFor(dioKlipy) 158 + final dioKlipyProvider = DioKlipyProvider._(); 159 159 160 - /// Provides Tenor API Dio client for GIF search. 160 + /// Provides Klipy API Dio client for GIF search. 161 161 /// 162 - /// This client is used for GIF search and selection from Tenor. 162 + /// This client is used for GIF search and selection from Klipy. 163 163 164 - final class DioTenorProvider extends $FunctionalProvider<Dio, Dio, Dio> with $Provider<Dio> { 165 - /// Provides Tenor API Dio client for GIF search. 164 + final class DioKlipyProvider extends $FunctionalProvider<Dio, Dio, Dio> with $Provider<Dio> { 165 + /// Provides Klipy API Dio client for GIF search. 166 166 /// 167 - /// This client is used for GIF search and selection from Tenor. 168 - DioTenorProvider._() 167 + /// This client is used for GIF search and selection from Klipy. 168 + DioKlipyProvider._() 169 169 : super( 170 170 from: null, 171 171 argument: null, 172 172 retry: null, 173 - name: r'dioTenorProvider', 173 + name: r'dioKlipyProvider', 174 174 isAutoDispose: false, 175 175 dependencies: null, 176 176 $allTransitiveDependencies: null, 177 177 ); 178 178 179 179 @override 180 - String debugGetCreateSourceHash() => _$dioTenorHash(); 180 + String debugGetCreateSourceHash() => _$dioKlipyHash(); 181 181 182 182 @$internal 183 183 @override ··· 185 185 186 186 @override 187 187 Dio create(Ref ref) { 188 - return dioTenor(ref); 188 + return dioKlipy(ref); 189 189 } 190 190 191 191 /// {@macro riverpod.override_with_value} ··· 194 194 } 195 195 } 196 196 197 - String _$dioTenorHash() => r'a2e99a8a8c47829fb3aefdc8d7cdc098ead2c517'; 197 + String _$dioKlipyHash() => r'86d9a53bc4189f1293878796146efa563dfab8e1'; 198 198 199 199 /// Provides XRPC client for making API requests. 200 200 /// ··· 248 248 } 249 249 } 250 250 251 - String _$xrpcClientHash() => r'79a74523bf3f31a57602964b3989d6690bdd4903'; 251 + String _$xrpcClientHash() => r'34d0a57c4054cdc40b4671c1036ef2911436dfbf';
+6 -6
lib/src/infrastructure/network/xrpc_client.dart
··· 13 13 /// 14 14 /// This is the main entry point for making XRPC requests. It: 15 15 /// - Looks up endpoint metadata from the registry 16 - /// - Routes requests to the correct Dio client (public vs PDS vs video vs tenor) 16 + /// - Routes requests to the correct Dio client (public vs PDS vs video vs klipy) 17 17 /// - Handles response parsing and error conversion 18 18 class XrpcClient { 19 19 XrpcClient({ 20 20 required Dio publicDio, 21 21 required Dio? pdsDio, 22 22 required Dio videoServiceDio, 23 - required Dio tenorDio, 23 + required Dio klipyDio, 24 24 required Logger logger, 25 25 EndpointRegistry? registry, 26 26 }) : _publicDio = publicDio, 27 27 _pdsDio = pdsDio, 28 28 _videoServiceDio = videoServiceDio, 29 - _tenorDio = tenorDio, 29 + _klipyDio = klipyDio, 30 30 _logger = logger, 31 31 _registry = registry ?? EndpointRegistry.instance; 32 32 33 33 final Dio _publicDio; 34 34 final Dio? _pdsDio; 35 35 final Dio _videoServiceDio; 36 - final Dio _tenorDio; 36 + final Dio _klipyDio; 37 37 final Logger _logger; 38 38 final EndpointRegistry _registry; 39 39 ··· 167 167 ); 168 168 case HostKind.video: 169 169 return _videoServiceDio; 170 - case HostKind.tenor: 171 - return _tenorDio; 170 + case HostKind.klipy: 171 + return _klipyDio; 172 172 } 173 173 } 174 174
+2 -2
test/helpers/mocks.dart
··· 9 9 import 'package:lazurite/src/core/utils/logger.dart'; 10 10 import 'package:lazurite/src/features/auth/domain/auth_state.dart'; 11 11 import 'package:lazurite/src/features/composer/domain/facet_parser.dart'; 12 - import 'package:lazurite/src/features/composer/infrastructure/tenor_service.dart'; 12 + import 'package:lazurite/src/features/composer/infrastructure/klipy_service.dart'; 13 13 import 'package:lazurite/src/features/dms/infrastructure/dms_repository.dart'; 14 14 import 'package:lazurite/src/features/dms/infrastructure/outbox_repository.dart'; 15 15 import 'package:lazurite/src/features/feeds/application/feed_providers.dart'; ··· 120 120 /// Fake ServerMetadata for testing 121 121 class FakeServerMetadata extends Fake implements ServerMetadata {} 122 122 123 - class MockTenorService extends Mock implements TenorService {} 123 + class MockKlipyService extends Mock implements KlipyService {} 124 124 125 125 class MockFlutterLocalNotificationsPlugin extends Mock 126 126 implements FlutterLocalNotificationsPlugin {}
+374
test/src/features/composer/infrastructure/klipy_service_test.dart
··· 1 + import 'package:dio/dio.dart'; 2 + import 'package:flutter_test/flutter_test.dart'; 3 + import 'package:lazurite/src/features/composer/domain/klipy_gif.dart'; 4 + import 'package:lazurite/src/features/composer/infrastructure/klipy_service.dart'; 5 + import 'package:mocktail/mocktail.dart'; 6 + 7 + class MockDio extends Mock implements Dio {} 8 + 9 + void main() { 10 + test('KlipyService can be created', () { 11 + final service = KlipyService(apiKey: 'test-api-key'); 12 + 13 + expect(service, isA<KlipyService>()); 14 + }); 15 + 16 + test('KlipyGif parses complete object', () { 17 + final Map<String, dynamic> json = { 18 + 'id': 123, 19 + 'slug': 'funny-cat-abc123', 20 + 'title': 'Funny Cat', 21 + 'file': { 22 + 'hd': { 23 + 'gif': {'url': 'https://media.klipy.com/hd.gif', 'width': 1920, 'height': 1080}, 24 + 'webp': {'url': 'https://media.klipy.com/hd.webp', 'width': 1920, 'height': 1080}, 25 + }, 26 + 'md': { 27 + 'gif': {'url': 'https://media.klipy.com/md.gif', 'width': 640, 'height': 360}, 28 + }, 29 + 'sm': { 30 + 'gif': {'url': 'https://media.klipy.com/sm.gif', 'width': 320, 'height': 180}, 31 + 'webp': {'url': 'https://media.klipy.com/sm.webp', 'width': 320, 'height': 180}, 32 + }, 33 + }, 34 + 'tags': ['cat', 'funny'], 35 + 'type': 'gif', 36 + 'blur_preview': 'base64encodeddata', 37 + }; 38 + 39 + final gif = KlipyGif.fromJson(json); 40 + 41 + expect(gif.id, 123); 42 + expect(gif.slug, 'funny-cat-abc123'); 43 + expect(gif.title, 'Funny Cat'); 44 + expect(gif.tags, ['cat', 'funny']); 45 + expect(gif.type, 'gif'); 46 + expect(gif.blurPreview, 'base64encodeddata'); 47 + }); 48 + 49 + test('KlipyMediaFormat parses complete object', () { 50 + final json = { 51 + 'url': 'https://example.com/full.gif', 52 + 'width': 500, 53 + 'height': 400, 54 + 'size': 1000000, 55 + }; 56 + 57 + final format = KlipyMediaFormat.fromJson(json); 58 + 59 + expect(format.url, 'https://example.com/full.gif'); 60 + expect(format.width, 500); 61 + expect(format.height, 400); 62 + expect(format.size, 1000000); 63 + }); 64 + 65 + test('KlipySearchResponse parses complete object', () { 66 + final json = { 67 + 'result': true, 68 + 'data': { 69 + 'data': [ 70 + { 71 + 'id': 1, 72 + 'slug': 'gif-1', 73 + 'title': 'GIF 1', 74 + 'file': { 75 + 'md': { 76 + 'gif': {'url': 'https://example.com/1.gif', 'width': 400, 'height': 400}, 77 + }, 78 + }, 79 + }, 80 + ], 81 + 'current_page': 1, 82 + 'per_page': 24, 83 + 'has_next': true, 84 + }, 85 + }; 86 + 87 + final response = KlipySearchResponse.fromApiResponse(json); 88 + 89 + expect(response.results, hasLength(1)); 90 + expect(response.results.first.slug, 'gif-1'); 91 + expect(response.currentPage, 1); 92 + expect(response.perPage, 24); 93 + expect(response.hasNext, isTrue); 94 + expect(response.nextPage, 2); 95 + }); 96 + 97 + group('KlipyGif thumbnailUrl helpers', () { 98 + test('gets from sm webp', () { 99 + final json = { 100 + 'id': 789, 101 + 'slug': 'test-gif', 102 + 'title': 'Test', 103 + 'file': { 104 + 'sm': { 105 + 'webp': {'url': 'https://example.com/sm.webp', 'width': 320, 'height': 180}, 106 + }, 107 + }, 108 + }; 109 + 110 + final gif = KlipyGif.fromJson(json); 111 + expect(gif.thumbnailUrl, 'https://example.com/sm.webp'); 112 + }); 113 + 114 + test('gets from sm gif when webp not available', () { 115 + final json = { 116 + 'id': 789, 117 + 'slug': 'test-gif', 118 + 'title': 'Test', 119 + 'file': { 120 + 'sm': { 121 + 'gif': {'url': 'https://example.com/sm.gif', 'width': 320, 'height': 180}, 122 + }, 123 + }, 124 + }; 125 + 126 + final gif = KlipyGif.fromJson(json); 127 + expect(gif.thumbnailUrl, 'https://example.com/sm.gif'); 128 + }); 129 + 130 + test('falls back to xs when sm not available', () { 131 + final json = { 132 + 'id': 789, 133 + 'slug': 'test-gif', 134 + 'title': 'Test', 135 + 'file': { 136 + 'xs': { 137 + 'webp': {'url': 'https://example.com/xs.webp', 'width': 160, 'height': 90}, 138 + }, 139 + }, 140 + }; 141 + 142 + final gif = KlipyGif.fromJson(json); 143 + expect(gif.thumbnailUrl, 'https://example.com/xs.webp'); 144 + }); 145 + 146 + test('returns null when no thumbnails', () { 147 + final json = { 148 + 'id': 789, 149 + 'slug': 'test-gif', 150 + 'title': 'Test', 151 + 'file': { 152 + 'hd': { 153 + 'gif': {'url': 'https://example.com/hd.gif', 'width': 1920, 'height': 1080}, 154 + }, 155 + }, 156 + }; 157 + 158 + final gif = KlipyGif.fromJson(json); 159 + expect(gif.thumbnailUrl, isNull); 160 + }); 161 + }); 162 + 163 + group('KlipyGif gifUrl helpers', () { 164 + test('gets from md gif', () { 165 + final json = { 166 + 'id': 789, 167 + 'slug': 'test-gif', 168 + 'title': 'Test', 169 + 'file': { 170 + 'md': { 171 + 'gif': {'url': 'https://example.com/md.gif', 'width': 640, 'height': 360}, 172 + }, 173 + }, 174 + }; 175 + 176 + final gif = KlipyGif.fromJson(json); 177 + 178 + expect(gif.gifUrl, 'https://example.com/md.gif'); 179 + }); 180 + 181 + test('gets from hd when md not available', () { 182 + final json = { 183 + 'id': 789, 184 + 'slug': 'test-gif', 185 + 'title': 'Test', 186 + 'file': { 187 + 'hd': { 188 + 'gif': {'url': 'https://example.com/hd.gif', 'width': 1920, 'height': 1080}, 189 + }, 190 + }, 191 + }; 192 + 193 + final gif = KlipyGif.fromJson(json); 194 + 195 + expect(gif.gifUrl, 'https://example.com/hd.gif'); 196 + }); 197 + 198 + test('returns null when no gif format available', () { 199 + final json = { 200 + 'id': 789, 201 + 'slug': 'test-gif', 202 + 'title': 'Test', 203 + 'file': { 204 + 'md': { 205 + 'webp': {'url': 'https://example.com/md.webp', 'width': 640, 'height': 360}, 206 + }, 207 + }, 208 + }; 209 + 210 + final gif = KlipyGif.fromJson(json); 211 + 212 + expect(gif.gifUrl, isNull); 213 + }); 214 + }); 215 + 216 + group('KlipyGif itemUrl', () { 217 + test('generates correct Klipy URL', () { 218 + final Map<String, dynamic> json = { 219 + 'id': 789, 220 + 'slug': 'funny-cat-abc123', 221 + 'title': 'Funny Cat', 222 + 'file': <String, dynamic>{}, 223 + }; 224 + 225 + final gif = KlipyGif.fromJson(json); 226 + 227 + expect(gif.itemUrl, 'https://klipy.com/gif/funny-cat-abc123'); 228 + }); 229 + }); 230 + 231 + group('KlipyService', () { 232 + late MockDio mockDio; 233 + late KlipyService service; 234 + 235 + setUp(() { 236 + mockDio = MockDio(); 237 + service = KlipyService(apiKey: 'test-api-key', customerId: 'test-user', dio: mockDio); 238 + }); 239 + 240 + test('searchGifs returns correct results', () async { 241 + final responseJson = { 242 + 'result': true, 243 + 'data': { 244 + 'data': [ 245 + {'id': 1, 'slug': 'gif-1', 'title': 'Test GIF', 'file': <String, dynamic>{}}, 246 + ], 247 + 'current_page': 1, 248 + 'per_page': 24, 249 + 'has_next': false, 250 + }, 251 + }; 252 + 253 + when( 254 + () => mockDio.get<Map<String, dynamic>>( 255 + '/api/v1/test-api-key/gifs/search', 256 + queryParameters: any(named: 'queryParameters'), 257 + ), 258 + ).thenAnswer( 259 + (_) async => Response<Map<String, dynamic>>( 260 + data: responseJson, 261 + statusCode: 200, 262 + requestOptions: RequestOptions(path: '/api/v1/test-api-key/gifs/search'), 263 + ), 264 + ); 265 + 266 + final response = await service.searchGifs(query: 'funny cats'); 267 + 268 + expect(response.results, hasLength(1)); 269 + expect(response.results.first.slug, 'gif-1'); 270 + }); 271 + 272 + test('searchGifs respects pagination', () async { 273 + final responseJson = { 274 + 'result': true, 275 + 'data': {'data': [], 'current_page': 2, 'per_page': 24, 'has_next': true}, 276 + }; 277 + 278 + when( 279 + () => mockDio.get<Map<String, dynamic>>( 280 + '/api/v1/test-api-key/gifs/search', 281 + queryParameters: any(named: 'queryParameters'), 282 + ), 283 + ).thenAnswer( 284 + (_) async => Response<Map<String, dynamic>>( 285 + data: responseJson, 286 + statusCode: 200, 287 + requestOptions: RequestOptions(path: '/api/v1/test-api-key/gifs/search'), 288 + ), 289 + ); 290 + 291 + final response = await service.searchGifs(query: 'test', page: 2); 292 + 293 + expect(response.currentPage, 2); 294 + expect(response.nextPage, 3); 295 + }); 296 + 297 + test('getTrendingGifs returns correct results', () async { 298 + final responseJson = { 299 + 'result': true, 300 + 'data': { 301 + 'data': [ 302 + {'id': 1, 'slug': 'trending-1', 'title': 'Trending GIF', 'file': <String, dynamic>{}}, 303 + ], 304 + 'current_page': 1, 305 + 'per_page': 24, 306 + 'has_next': false, 307 + }, 308 + }; 309 + 310 + when( 311 + () => mockDio.get<Map<String, dynamic>>( 312 + '/api/v1/test-api-key/gifs/trending', 313 + queryParameters: any(named: 'queryParameters'), 314 + ), 315 + ).thenAnswer( 316 + (_) async => Response<Map<String, dynamic>>( 317 + data: responseJson, 318 + statusCode: 200, 319 + requestOptions: RequestOptions(path: '/api/v1/test-api-key/gifs/trending'), 320 + ), 321 + ); 322 + 323 + final response = await service.getTrendingGifs(); 324 + 325 + expect(response.results, hasLength(1)); 326 + expect(response.results.first.slug, 'trending-1'); 327 + }); 328 + 329 + test('downloadThumbnail downloads and saves file', () async { 330 + final bytes = [1, 2, 3, 4, 5]; 331 + 332 + when( 333 + () => mockDio.get<List<int>>( 334 + 'https://example.com/thumb.jpg', 335 + options: any(named: 'options'), 336 + ), 337 + ).thenAnswer( 338 + (_) async => Response<List<int>>( 339 + data: bytes, 340 + statusCode: 200, 341 + requestOptions: RequestOptions(path: 'https://example.com/thumb.jpg'), 342 + ), 343 + ); 344 + 345 + final file = await service.downloadThumbnail('https://example.com/thumb.jpg'); 346 + 347 + expect(file.existsSync(), isTrue); 348 + final readBytes = await file.readAsBytes(); 349 + expect(readBytes, bytes); 350 + 351 + await file.delete(); 352 + }); 353 + 354 + test('downloadThumbnail throws exception on empty response', () async { 355 + when( 356 + () => mockDio.get<List<int>>( 357 + 'https://example.com/thumb.jpg', 358 + options: any(named: 'options'), 359 + ), 360 + ).thenAnswer( 361 + (_) async => Response<List<int>>( 362 + data: [], 363 + statusCode: 200, 364 + requestOptions: RequestOptions(path: 'https://example.com/thumb.jpg'), 365 + ), 366 + ); 367 + 368 + expect( 369 + () => service.downloadThumbnail('https://example.com/thumb.jpg'), 370 + throwsA(isA<Exception>()), 371 + ); 372 + }); 373 + }); 374 + }
-295
test/src/features/composer/infrastructure/tenor_service_test.dart
··· 1 - import 'package:dio/dio.dart'; 2 - import 'package:flutter_test/flutter_test.dart'; 3 - import 'package:lazurite/src/features/composer/domain/tenor_gif.dart'; 4 - import 'package:lazurite/src/features/composer/infrastructure/tenor_service.dart'; 5 - import 'package:mocktail/mocktail.dart'; 6 - 7 - class MockDio extends Mock implements Dio {} 8 - 9 - void main() { 10 - test('TenorService can be created', () { 11 - final service = TenorService(apiKey: 'test-api-key', clientKey: 'test-client'); 12 - 13 - expect(service, isA<TenorService>()); 14 - }); 15 - 16 - test('TenorGif parses complete object', () { 17 - final json = { 18 - 'id': 'gif-123', 19 - 'title': 'Funny Cat', 20 - 'media_formats': { 21 - 'gif': { 22 - 'url': 'https://media.tenor.com/full.gif', 23 - 'preview': 'https://media.tenor.com/preview.gif', 24 - 'dims': {'width': 500, 'height': 500}, 25 - 'size': 1000000, 26 - 'preview_size': 50000, 27 - }, 28 - }, 29 - 'created': 1640000000, 30 - 'tags': ['cat', 'funny'], 31 - 'flags': ['trending'], 32 - 'hasaudio': false, 33 - }; 34 - 35 - final gif = TenorGif.fromJson(json); 36 - 37 - expect(gif.id, 'gif-123'); 38 - expect(gif.title, 'Funny Cat'); 39 - expect(gif.created, DateTime.fromMillisecondsSinceEpoch(1640000000000)); 40 - expect(gif.tags, ['cat', 'funny']); 41 - expect(gif.flags, ['trending']); 42 - expect(gif.hasaudio, isFalse); 43 - expect(gif.mediaFormats, hasLength(1)); 44 - }); 45 - 46 - test('TenorMedia parses complete object', () { 47 - final json = { 48 - 'url': 'https://example.com/full.gif', 49 - 'preview': 'https://example.com/preview.gif', 50 - 'dims': {'width': 500, 'height': 500}, 51 - 'size': 1000000, 52 - 'preview_size': 50000, 53 - }; 54 - 55 - final media = TenorMedia.fromJson(json); 56 - 57 - expect(media.url, 'https://example.com/full.gif'); 58 - expect(media.previewUrl, 'https://example.com/preview.gif'); 59 - expect(media.dims.width, 500); 60 - expect(media.dims.height, 500); 61 - expect(media.size, 1000000); 62 - expect(media.previewSize, 50000); 63 - }); 64 - 65 - test('TenorSearchResponse parses complete object', () { 66 - final json = { 67 - 'results': [ 68 - { 69 - 'id': 'gif-1', 70 - 'title': 'GIF 1', 71 - 'media_formats': { 72 - 'mediumgif': { 73 - 'url': 'https://example.com/1.gif', 74 - 'dims': {'width': 400, 'height': 400}, 75 - }, 76 - }, 77 - }, 78 - ], 79 - 'next': 'next-token-123', 80 - }; 81 - 82 - final response = TenorSearchResponse.fromJson(json); 83 - 84 - expect(response.results, hasLength(1)); 85 - expect(response.results.first.id, 'gif-1'); 86 - expect(response.next, 'next-token-123'); 87 - }); 88 - 89 - group('TenorGif thumbnailUrl helpers', () { 90 - test('gets from tinygif', () { 91 - final json = { 92 - 'id': 'gif-789', 93 - 'title': 'Test', 94 - 'media_formats': { 95 - 'tinygif': {'preview': 'https://example.com/preview.gif'}, 96 - }, 97 - }; 98 - 99 - final gif = TenorGif.fromJson(json); 100 - expect(gif.thumbnailUrl, 'https://example.com/preview.gif'); 101 - }); 102 - 103 - test('gets from mediumgif when tiny not available', () { 104 - final json = { 105 - 'id': 'gif-789', 106 - 'title': 'Test', 107 - 'media_formats': { 108 - 'mediumgif': {'preview': 'https://example.com/medium-preview.gif'}, 109 - }, 110 - }; 111 - 112 - final gif = TenorGif.fromJson(json); 113 - expect(gif.thumbnailUrl, 'https://example.com/medium-preview.gif'); 114 - }); 115 - 116 - test('returns null when no previews', () { 117 - final json = { 118 - 'id': 'gif-789', 119 - 'title': 'Test', 120 - 'media_formats': { 121 - 'gif': {'url': 'https://example.com/gif.gif'}, 122 - }, 123 - }; 124 - 125 - final gif = TenorGif.fromJson(json); 126 - expect(gif.thumbnailUrl, equals(null)); 127 - }); 128 - }); 129 - 130 - group('TenorGif gifUrl helpers', () { 131 - test('gets from mediumgif', () { 132 - final json = { 133 - 'id': 'gif-789', 134 - 'title': 'Test', 135 - 'media_formats': { 136 - 'mediumgif': {'url': 'https://example.com/medium.gif'}, 137 - }, 138 - }; 139 - 140 - final gif = TenorGif.fromJson(json); 141 - 142 - expect(gif.gifUrl, 'https://example.com/medium.gif'); 143 - }); 144 - 145 - test('gets from gif when medium not available', () { 146 - final json = { 147 - 'id': 'gif-789', 148 - 'title': 'Test', 149 - 'media_formats': { 150 - 'gif': {'url': 'https://example.com/gif.gif'}, 151 - }, 152 - }; 153 - 154 - final gif = TenorGif.fromJson(json); 155 - 156 - expect(gif.gifUrl, 'https://example.com/gif.gif'); 157 - }); 158 - 159 - test('returns null when neither format available', () { 160 - final json = {'id': 'gif-789', 'title': 'Test', 'media_formats': {}}; 161 - 162 - final gif = TenorGif.fromJson(json); 163 - 164 - expect(gif.gifUrl, equals(null)); 165 - }); 166 - }); 167 - 168 - group('TenorService', () { 169 - late MockDio mockDio; 170 - late TenorService service; 171 - 172 - setUp(() { 173 - mockDio = MockDio(); 174 - service = TenorService(apiKey: 'test-api-key', clientKey: 'test-client', dio: mockDio); 175 - }); 176 - 177 - test('searchGifs returns correct results', () async { 178 - final responseJson = { 179 - 'results': [ 180 - {'id': 'gif-1', 'title': 'Test GIF', 'media_formats': {}}, 181 - ], 182 - }; 183 - 184 - when( 185 - () => mockDio.get<Map<String, dynamic>>( 186 - '/search', 187 - queryParameters: any(named: 'queryParameters'), 188 - ), 189 - ).thenAnswer( 190 - (_) async => Response<Map<String, dynamic>>( 191 - data: responseJson, 192 - statusCode: 200, 193 - requestOptions: RequestOptions(path: '/search'), 194 - ), 195 - ); 196 - 197 - final response = await service.searchGifs(query: 'funny cats'); 198 - 199 - expect(response.results, hasLength(1)); 200 - expect(response.results.first.id, 'gif-1'); 201 - }); 202 - 203 - test('searchGifs respects pagination', () async { 204 - final responseJson = {'results': [], 'next': 'token-123'}; 205 - 206 - when( 207 - () => mockDio.get<Map<String, dynamic>>( 208 - '/search', 209 - queryParameters: any(named: 'queryParameters'), 210 - ), 211 - ).thenAnswer( 212 - (_) async => Response<Map<String, dynamic>>( 213 - data: responseJson, 214 - statusCode: 200, 215 - requestOptions: RequestOptions(path: '/search'), 216 - ), 217 - ); 218 - 219 - final response = await service.searchGifs(query: 'test', pos: 'token-123'); 220 - 221 - expect(response.next, 'token-123'); 222 - }); 223 - 224 - test('getFeaturedGifs returns correct results', () async { 225 - final responseJson = { 226 - 'results': [ 227 - {'id': 'featured-1', 'title': 'Featured GIF', 'media_formats': {}}, 228 - ], 229 - }; 230 - 231 - when( 232 - () => mockDio.get<Map<String, dynamic>>( 233 - '/featured', 234 - queryParameters: any(named: 'queryParameters'), 235 - ), 236 - ).thenAnswer( 237 - (_) async => Response<Map<String, dynamic>>( 238 - data: responseJson, 239 - statusCode: 200, 240 - requestOptions: RequestOptions(path: '/featured'), 241 - ), 242 - ); 243 - 244 - final response = await service.getFeaturedGifs(); 245 - 246 - expect(response.results, hasLength(1)); 247 - expect(response.results.first.id, 'featured-1'); 248 - }); 249 - 250 - test('downloadThumbnail downloads and saves file', () async { 251 - final bytes = [1, 2, 3, 4, 5]; 252 - 253 - when( 254 - () => mockDio.get<List<int>>( 255 - 'https://example.com/thumb.jpg', 256 - options: any(named: 'options'), 257 - ), 258 - ).thenAnswer( 259 - (_) async => Response<List<int>>( 260 - data: bytes, 261 - statusCode: 200, 262 - requestOptions: RequestOptions(path: 'https://example.com/thumb.jpg'), 263 - ), 264 - ); 265 - 266 - final file = await service.downloadThumbnail('https://example.com/thumb.jpg'); 267 - 268 - expect(file.existsSync(), isTrue); 269 - final readBytes = await file.readAsBytes(); 270 - expect(readBytes, bytes); 271 - 272 - await file.delete(); 273 - }); 274 - 275 - test('downloadThumbnail throws exception on empty response', () async { 276 - when( 277 - () => mockDio.get<List<int>>( 278 - 'https://example.com/thumb.jpg', 279 - options: any(named: 'options'), 280 - ), 281 - ).thenAnswer( 282 - (_) async => Response<List<int>>( 283 - data: [], 284 - statusCode: 200, 285 - requestOptions: RequestOptions(path: 'https://example.com/thumb.jpg'), 286 - ), 287 - ); 288 - 289 - expect( 290 - () => service.downloadThumbnail('https://example.com/thumb.jpg'), 291 - throwsA(isA<Exception>()), 292 - ); 293 - }); 294 - }); 295 - }
+5 -4
test/src/features/composer/infrastructure/video_upload_service_test.dart
··· 238 238 group('VideoUploadService - cancelUpload', () { 239 239 test('cancels active upload', () async { 240 240 var getJobStatusCallCount = 0; 241 - final shouldCancel = Completer<bool>(); 241 + final pollingStarted = Completer<void>(); 242 + final shouldCancel = Completer<void>(); 242 243 243 244 when( 244 245 () => mockApi.callRaw<Map<String, dynamic>>( ··· 264 265 getJobStatusCallCount++; 265 266 266 267 if (getJobStatusCallCount == 1) { 268 + pollingStarted.complete(); 267 269 await shouldCancel.future; 268 270 } 269 271 ··· 278 280 mimeType: 'video/mp4', 279 281 ); 280 282 281 - await Future.delayed(const Duration(milliseconds: 10)); 282 - 283 - shouldCancel.complete(true); 283 + await pollingStarted.future; 284 284 285 285 videoUploadService.cancelUpload('test-job-cancel'); 286 + shouldCancel.complete(); 286 287 287 288 await expectLater( 288 289 uploadFuture,
+6 -6
test/src/infrastructure/network/xrpc_client_test.dart
··· 11 11 late Dio publicDio; 12 12 late Dio pdsDio; 13 13 late Dio videoServiceDio; 14 - late Dio tenorDio; 14 + late Dio klipyDio; 15 15 late DioAdapter publicAdapter; 16 16 late DioAdapter pdsAdapter; 17 17 late XrpcClient client; ··· 20 20 publicDio = Dio(BaseOptions(baseUrl: 'https://public.api.bsky.app')); 21 21 pdsDio = Dio(BaseOptions(baseUrl: 'https://user.pds.example')); 22 22 videoServiceDio = Dio(BaseOptions(baseUrl: 'https://video.bsky.app')); 23 - tenorDio = Dio(BaseOptions(baseUrl: 'https://tenor.googleapis.com/v2')); 23 + klipyDio = Dio(BaseOptions(baseUrl: 'https://api.klipy.com')); 24 24 publicAdapter = DioAdapter(dio: publicDio); 25 25 pdsAdapter = DioAdapter(dio: pdsDio); 26 26 DioAdapter(dio: videoServiceDio); ··· 28 28 publicDio: publicDio, 29 29 pdsDio: pdsDio, 30 30 videoServiceDio: videoServiceDio, 31 - tenorDio: tenorDio, 31 + klipyDio: klipyDio, 32 32 logger: MockLogger(), 33 33 ); 34 34 }); ··· 41 41 publicDio: publicDio, 42 42 pdsDio: null, 43 43 videoServiceDio: videoServiceDio, 44 - tenorDio: tenorDio, 44 + klipyDio: klipyDio, 45 45 logger: MockLogger(), 46 46 ); 47 47 }); ··· 129 129 publicDio: publicDio, 130 130 pdsDio: null, 131 131 videoServiceDio: videoServiceDio, 132 - tenorDio: tenorDio, 132 + klipyDio: klipyDio, 133 133 logger: MockLogger(), 134 134 ); 135 135 ··· 231 231 publicDio: mockDio, 232 232 pdsDio: mockDio, 233 233 videoServiceDio: videoServiceDio, 234 - tenorDio: tenorDio, 234 + klipyDio: klipyDio, 235 235 logger: MockLogger(), 236 236 ); 237 237