✨ Playback server
This commit is contained in:
		@@ -1,34 +1,77 @@
 | 
				
			|||||||
PODS:
 | 
					PODS:
 | 
				
			||||||
 | 
					  - audio_service (0.0.1):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
 | 
					  - audio_session (0.0.1):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
 | 
					  - device_info_plus (0.0.1):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
  - Flutter (1.0.0)
 | 
					  - Flutter (1.0.0)
 | 
				
			||||||
 | 
					  - flutter_broadcasts (0.0.1):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
 | 
					  - media_kit_libs_ios_audio (1.0.4):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
 | 
					  - media_kit_native_event_loop (1.0.0):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
  - package_info_plus (0.4.5):
 | 
					  - package_info_plus (0.4.5):
 | 
				
			||||||
    - Flutter
 | 
					    - Flutter
 | 
				
			||||||
  - path_provider_foundation (0.0.1):
 | 
					  - path_provider_foundation (0.0.1):
 | 
				
			||||||
    - Flutter
 | 
					    - Flutter
 | 
				
			||||||
    - FlutterMacOS
 | 
					    - FlutterMacOS
 | 
				
			||||||
 | 
					  - shared_preferences_foundation (0.0.1):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
 | 
					    - FlutterMacOS
 | 
				
			||||||
  - sqflite (0.0.3):
 | 
					  - sqflite (0.0.3):
 | 
				
			||||||
    - Flutter
 | 
					    - Flutter
 | 
				
			||||||
    - FlutterMacOS
 | 
					    - FlutterMacOS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES:
 | 
					DEPENDENCIES:
 | 
				
			||||||
 | 
					  - audio_service (from `.symlinks/plugins/audio_service/ios`)
 | 
				
			||||||
 | 
					  - audio_session (from `.symlinks/plugins/audio_session/ios`)
 | 
				
			||||||
 | 
					  - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
 | 
				
			||||||
  - Flutter (from `Flutter`)
 | 
					  - Flutter (from `Flutter`)
 | 
				
			||||||
 | 
					  - flutter_broadcasts (from `.symlinks/plugins/flutter_broadcasts/ios`)
 | 
				
			||||||
 | 
					  - media_kit_libs_ios_audio (from `.symlinks/plugins/media_kit_libs_ios_audio/ios`)
 | 
				
			||||||
 | 
					  - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
 | 
				
			||||||
  - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
 | 
					  - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
 | 
				
			||||||
  - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
 | 
					  - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
 | 
				
			||||||
 | 
					  - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
 | 
				
			||||||
  - sqflite (from `.symlinks/plugins/sqflite/darwin`)
 | 
					  - sqflite (from `.symlinks/plugins/sqflite/darwin`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTERNAL SOURCES:
 | 
					EXTERNAL SOURCES:
 | 
				
			||||||
 | 
					  audio_service:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/audio_service/ios"
 | 
				
			||||||
 | 
					  audio_session:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/audio_session/ios"
 | 
				
			||||||
 | 
					  device_info_plus:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/device_info_plus/ios"
 | 
				
			||||||
  Flutter:
 | 
					  Flutter:
 | 
				
			||||||
    :path: Flutter
 | 
					    :path: Flutter
 | 
				
			||||||
 | 
					  flutter_broadcasts:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/flutter_broadcasts/ios"
 | 
				
			||||||
 | 
					  media_kit_libs_ios_audio:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/media_kit_libs_ios_audio/ios"
 | 
				
			||||||
 | 
					  media_kit_native_event_loop:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/media_kit_native_event_loop/ios"
 | 
				
			||||||
  package_info_plus:
 | 
					  package_info_plus:
 | 
				
			||||||
    :path: ".symlinks/plugins/package_info_plus/ios"
 | 
					    :path: ".symlinks/plugins/package_info_plus/ios"
 | 
				
			||||||
  path_provider_foundation:
 | 
					  path_provider_foundation:
 | 
				
			||||||
    :path: ".symlinks/plugins/path_provider_foundation/darwin"
 | 
					    :path: ".symlinks/plugins/path_provider_foundation/darwin"
 | 
				
			||||||
 | 
					  shared_preferences_foundation:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
 | 
				
			||||||
  sqflite:
 | 
					  sqflite:
 | 
				
			||||||
    :path: ".symlinks/plugins/sqflite/darwin"
 | 
					    :path: ".symlinks/plugins/sqflite/darwin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPEC CHECKSUMS:
 | 
					SPEC CHECKSUMS:
 | 
				
			||||||
 | 
					  audio_service: f509d65da41b9521a61f1c404dd58651f265a567
 | 
				
			||||||
 | 
					  audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207
 | 
				
			||||||
 | 
					  device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
 | 
				
			||||||
  Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
 | 
					  Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
 | 
				
			||||||
 | 
					  flutter_broadcasts: 3ece15b27d8ccbe2132c3df303e7c3401feab882
 | 
				
			||||||
 | 
					  media_kit_libs_ios_audio: 8f39d96a9c630685dfb844c289bd1d114c486fb3
 | 
				
			||||||
 | 
					  media_kit_native_event_loop: 99111eded5acbdc9c2738021ea6550dd36ca8837
 | 
				
			||||||
  package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
 | 
					  package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
 | 
				
			||||||
  path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
 | 
					  path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
 | 
				
			||||||
 | 
					  shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
 | 
				
			||||||
  sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
 | 
					  sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
 | 
					PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										192
									
								
								lib/collections/assets.gen.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										192
									
								
								lib/collections/assets.gen.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					/// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
				
			||||||
 | 
					/// *****************************************************
 | 
				
			||||||
 | 
					///  FlutterGen
 | 
				
			||||||
 | 
					/// *****************************************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// coverage:ignore-file
 | 
				
			||||||
 | 
					// ignore_for_file: type=lint
 | 
				
			||||||
 | 
					// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/widgets.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $AssetsLogosGen {
 | 
				
			||||||
 | 
					  const $AssetsLogosGen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// File path: assets/logos/songlink-transparent.png
 | 
				
			||||||
 | 
					  AssetGenImage get songlinkTransparent =>
 | 
				
			||||||
 | 
					      const AssetGenImage('assets/logos/songlink-transparent.png');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// File path: assets/logos/songlink.png
 | 
				
			||||||
 | 
					  AssetGenImage get songlink =>
 | 
				
			||||||
 | 
					      const AssetGenImage('assets/logos/songlink.png');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// List of all assets
 | 
				
			||||||
 | 
					  List<AssetGenImage> get values => [songlinkTransparent, songlink];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $AssetsTutorialGen {
 | 
				
			||||||
 | 
					  const $AssetsTutorialGen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// File path: assets/tutorial/step-1.png
 | 
				
			||||||
 | 
					  AssetGenImage get step1 => const AssetGenImage('assets/tutorial/step-1.png');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// File path: assets/tutorial/step-2.png
 | 
				
			||||||
 | 
					  AssetGenImage get step2 => const AssetGenImage('assets/tutorial/step-2.png');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// File path: assets/tutorial/step-3.png
 | 
				
			||||||
 | 
					  AssetGenImage get step3 => const AssetGenImage('assets/tutorial/step-3.png');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// List of all assets
 | 
				
			||||||
 | 
					  List<AssetGenImage> get values => [step1, step2, step3];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Assets {
 | 
				
			||||||
 | 
					  Assets._();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const AssetGenImage albumPlaceholder =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/album-placeholder.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage bengaliPatternsBg =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/bengali-patterns-bg.jpg');
 | 
				
			||||||
 | 
					  static const AssetGenImage branding = AssetGenImage('assets/branding.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage likedTracks =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/liked-tracks.jpg');
 | 
				
			||||||
 | 
					  static const $AssetsLogosGen logos = $AssetsLogosGen();
 | 
				
			||||||
 | 
					  static const AssetGenImage placeholder =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/placeholder.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxHeroBanner =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-hero-banner.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxLogoForeground =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-logo-foreground.jpg');
 | 
				
			||||||
 | 
					  static const String rhythm_boxLogoIco = 'assets/rhythm_box-logo.ico';
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxLogoPng =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-logo.png');
 | 
				
			||||||
 | 
					  static const String rhythm_boxLogoSvg = 'assets/rhythm_box-logo.svg';
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxLogoAndroid12 =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-logo_android12.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxNightlyLogoForeground =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-nightly-logo-foreground.jpg');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxNightlyLogoPng =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-nightly-logo.png');
 | 
				
			||||||
 | 
					  static const String rhythm_boxNightlyLogoSvg =
 | 
				
			||||||
 | 
					      'assets/rhythm_box-nightly-logo.svg';
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxNightlyLogoAndroid12 =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-nightly-logo_android12.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxScreenshot =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-screenshot.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxTallCapsule =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-tall-capsule.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxWideCapsuleLarge =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-wide-capsule-large.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxWideCapsuleSmall =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box-wide-capsule-small.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage rhythm_boxBanner =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/rhythm_box_banner.png');
 | 
				
			||||||
 | 
					  static const AssetGenImage success = AssetGenImage('assets/success.png');
 | 
				
			||||||
 | 
					  static const $AssetsTutorialGen tutorial = $AssetsTutorialGen();
 | 
				
			||||||
 | 
					  static const AssetGenImage userPlaceholder =
 | 
				
			||||||
 | 
					      AssetGenImage('assets/user-placeholder.png');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// List of all assets
 | 
				
			||||||
 | 
					  static List<dynamic> get values => [
 | 
				
			||||||
 | 
					        albumPlaceholder,
 | 
				
			||||||
 | 
					        bengaliPatternsBg,
 | 
				
			||||||
 | 
					        branding,
 | 
				
			||||||
 | 
					        emptyBox,
 | 
				
			||||||
 | 
					        jiosaavn,
 | 
				
			||||||
 | 
					        likedTracks,
 | 
				
			||||||
 | 
					        placeholder,
 | 
				
			||||||
 | 
					        rhythm_boxHeroBanner,
 | 
				
			||||||
 | 
					        rhythm_boxLogoForeground,
 | 
				
			||||||
 | 
					        rhythm_boxLogoIco,
 | 
				
			||||||
 | 
					        rhythm_boxLogoPng,
 | 
				
			||||||
 | 
					        rhythm_boxLogoSvg,
 | 
				
			||||||
 | 
					        rhythm_boxLogoAndroid12,
 | 
				
			||||||
 | 
					        rhythm_boxNightlyLogoForeground,
 | 
				
			||||||
 | 
					        rhythm_boxNightlyLogoPng,
 | 
				
			||||||
 | 
					        rhythm_boxNightlyLogoSvg,
 | 
				
			||||||
 | 
					        rhythm_boxNightlyLogoAndroid12,
 | 
				
			||||||
 | 
					        rhythm_boxScreenshot,
 | 
				
			||||||
 | 
					        rhythm_boxTallCapsule,
 | 
				
			||||||
 | 
					        rhythm_boxWideCapsuleLarge,
 | 
				
			||||||
 | 
					        rhythm_boxWideCapsuleSmall,
 | 
				
			||||||
 | 
					        rhythm_boxBanner,
 | 
				
			||||||
 | 
					        success,
 | 
				
			||||||
 | 
					        userPlaceholder
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AssetGenImage {
 | 
				
			||||||
 | 
					  const AssetGenImage(this._assetName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final String _assetName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Image image({
 | 
				
			||||||
 | 
					    Key? key,
 | 
				
			||||||
 | 
					    AssetBundle? bundle,
 | 
				
			||||||
 | 
					    ImageFrameBuilder? frameBuilder,
 | 
				
			||||||
 | 
					    ImageErrorWidgetBuilder? errorBuilder,
 | 
				
			||||||
 | 
					    String? semanticLabel,
 | 
				
			||||||
 | 
					    bool excludeFromSemantics = false,
 | 
				
			||||||
 | 
					    double? scale,
 | 
				
			||||||
 | 
					    double? width,
 | 
				
			||||||
 | 
					    double? height,
 | 
				
			||||||
 | 
					    Color? color,
 | 
				
			||||||
 | 
					    Animation<double>? opacity,
 | 
				
			||||||
 | 
					    BlendMode? colorBlendMode,
 | 
				
			||||||
 | 
					    BoxFit? fit,
 | 
				
			||||||
 | 
					    AlignmentGeometry alignment = Alignment.center,
 | 
				
			||||||
 | 
					    ImageRepeat repeat = ImageRepeat.noRepeat,
 | 
				
			||||||
 | 
					    Rect? centerSlice,
 | 
				
			||||||
 | 
					    bool matchTextDirection = false,
 | 
				
			||||||
 | 
					    bool gaplessPlayback = false,
 | 
				
			||||||
 | 
					    bool isAntiAlias = false,
 | 
				
			||||||
 | 
					    String? package,
 | 
				
			||||||
 | 
					    FilterQuality filterQuality = FilterQuality.low,
 | 
				
			||||||
 | 
					    int? cacheWidth,
 | 
				
			||||||
 | 
					    int? cacheHeight,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    return Image.asset(
 | 
				
			||||||
 | 
					      _assetName,
 | 
				
			||||||
 | 
					      key: key,
 | 
				
			||||||
 | 
					      bundle: bundle,
 | 
				
			||||||
 | 
					      frameBuilder: frameBuilder,
 | 
				
			||||||
 | 
					      errorBuilder: errorBuilder,
 | 
				
			||||||
 | 
					      semanticLabel: semanticLabel,
 | 
				
			||||||
 | 
					      excludeFromSemantics: excludeFromSemantics,
 | 
				
			||||||
 | 
					      scale: scale,
 | 
				
			||||||
 | 
					      width: width,
 | 
				
			||||||
 | 
					      height: height,
 | 
				
			||||||
 | 
					      color: color,
 | 
				
			||||||
 | 
					      opacity: opacity,
 | 
				
			||||||
 | 
					      colorBlendMode: colorBlendMode,
 | 
				
			||||||
 | 
					      fit: fit,
 | 
				
			||||||
 | 
					      alignment: alignment,
 | 
				
			||||||
 | 
					      repeat: repeat,
 | 
				
			||||||
 | 
					      centerSlice: centerSlice,
 | 
				
			||||||
 | 
					      matchTextDirection: matchTextDirection,
 | 
				
			||||||
 | 
					      gaplessPlayback: gaplessPlayback,
 | 
				
			||||||
 | 
					      isAntiAlias: isAntiAlias,
 | 
				
			||||||
 | 
					      package: package,
 | 
				
			||||||
 | 
					      filterQuality: filterQuality,
 | 
				
			||||||
 | 
					      cacheWidth: cacheWidth,
 | 
				
			||||||
 | 
					      cacheHeight: cacheHeight,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ImageProvider provider({
 | 
				
			||||||
 | 
					    AssetBundle? bundle,
 | 
				
			||||||
 | 
					    String? package,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    return AssetImage(
 | 
				
			||||||
 | 
					      _assetName,
 | 
				
			||||||
 | 
					      bundle: bundle,
 | 
				
			||||||
 | 
					      package: package,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String get path => _assetName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String get keyName => _assetName;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								lib/collections/formatters.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								lib/collections/formatters.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import 'package:intl/intl.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final compactNumberFormatter = NumberFormat.compact();
 | 
				
			||||||
 | 
					final usdFormatter = NumberFormat.compactCurrency(
 | 
				
			||||||
 | 
					  locale: 'en-US',
 | 
				
			||||||
 | 
					  symbol: r"$",
 | 
				
			||||||
 | 
					  decimalDigits: 2,
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
							
								
								
									
										232
									
								
								lib/collections/gradients.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										232
									
								
								lib/collections/gradients.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,232 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const gradients = [
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(123, 102, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(95, 189, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(150, 239, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(197, 255, 248, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(245, 204, 160, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(228, 143, 69, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(153, 77, 28, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(107, 36, 12, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(243, 243, 243, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(197, 232, 152, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(41, 173, 178, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(7, 102, 173, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(240, 89, 65, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(190, 49, 68, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(135, 35, 65, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(34, 9, 44, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(119, 107, 93, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(176, 166, 149, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(235, 227, 213, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(243, 238, 234, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(208, 162, 247, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(220, 191, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(229, 212, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(241, 234, 255, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(221, 242, 253, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(155, 190, 200, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(66, 125, 157, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(22, 72, 99, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(119, 67, 219, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(195, 172, 208, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(247, 239, 229, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 251, 245, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(194, 217, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(142, 143, 250, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(119, 82, 254, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(25, 4, 130, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(104, 126, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(128, 179, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(152, 228, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(182, 255, 250, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(176, 87, 141, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(217, 136, 185, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(250, 203, 234, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 228, 214, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(190, 255, 247, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(166, 246, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(158, 221, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(100, 153, 233, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(245, 252, 205, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(120, 214, 198, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(65, 145, 151, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(18, 72, 107, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(229, 207, 247, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(157, 118, 193, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(113, 58, 190, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(91, 8, 136, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(249, 222, 201, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(247, 140, 162, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(216, 0, 50, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(61, 12, 17, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(242, 247, 161, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(53, 162, 159, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(8, 131, 149, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(7, 25, 82, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(243, 159, 90, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(174, 68, 90, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(102, 37, 73, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(69, 25, 82, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 200, 200, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 155, 130, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 63, 164, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(87, 55, 93, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(238, 238, 238, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(100, 204, 197, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(23, 107, 135, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(5, 59, 80, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(198, 61, 47, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(226, 94, 62, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 155, 80, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 187, 92, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(236, 83, 176, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(157, 68, 192, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(77, 45, 183, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(14, 33, 160, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(242, 236, 190, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(226, 199, 153, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(192, 130, 97, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(154, 59, 59, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 253, 140, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(151, 255, 244, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(112, 145, 245, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(121, 63, 223, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(67, 83, 52, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(158, 179, 132, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(206, 222, 189, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(250, 241, 228, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(250, 240, 230, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(185, 180, 199, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(92, 84, 112, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(53, 47, 68, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 186, 134, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(246, 99, 92, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(194, 51, 115, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(121, 21, 91, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(213, 255, 208, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(64, 248, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(39, 158, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(12, 53, 106, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(131, 96, 150, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(237, 123, 123, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(240, 184, 110, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(235, 231, 108, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(63, 29, 56, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(77, 60, 119, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(162, 103, 138, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(225, 152, 152, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(254, 123, 229, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(151, 78, 195, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(80, 64, 153, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(49, 56, 102, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(248, 222, 34, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(249, 76, 16, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(199, 0, 57, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(144, 12, 63, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(101, 69, 31, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(118, 88, 39, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(200, 174, 125, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(234, 198, 150, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 246, 224, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(216, 217, 218, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(97, 103, 122, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(39, 40, 41, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(145, 109, 179, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(228, 133, 134, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(252, 186, 173, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(253, 229, 236, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(124, 115, 192, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(148, 173, 215, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(172, 250, 223, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(232, 255, 206, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(174, 216, 204, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(205, 102, 136, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(122, 49, 111, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(70, 25, 89, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(237, 228, 255, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(215, 187, 245, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(160, 118, 249, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(101, 40, 247, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					  LinearGradient(colors: [
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 236, 175, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 176, 127, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(255, 82, 162, 1),
 | 
				
			||||||
 | 
					    Color.fromRGBO(243, 21, 89, 1)
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
							
								
								
									
										26
									
								
								lib/collections/initializers.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								lib/collections/initializers.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:rhythm_box/platform.dart';
 | 
				
			||||||
 | 
					import 'package:win32_registry/win32_registry.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Future<void> registerWindowsScheme(String scheme) async {
 | 
				
			||||||
 | 
					  if (!PlatformInfo.isWindows) return;
 | 
				
			||||||
 | 
					  String appPath = Platform.resolvedExecutable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String protocolRegKey = 'Software\\Classes\\$scheme';
 | 
				
			||||||
 | 
					  RegistryValue protocolRegValue = const RegistryValue(
 | 
				
			||||||
 | 
					    'URL Protocol',
 | 
				
			||||||
 | 
					    RegistryValueType.string,
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  String protocolCmdRegKey = 'shell\\open\\command';
 | 
				
			||||||
 | 
					  RegistryValue protocolCmdRegValue = RegistryValue(
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    RegistryValueType.string,
 | 
				
			||||||
 | 
					    '"$appPath" "%1"',
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final regKey = Registry.currentUser.createKey(protocolRegKey);
 | 
				
			||||||
 | 
					  regKey.createValue(protocolRegValue);
 | 
				
			||||||
 | 
					  regKey.createKey(protocolCmdRegKey).createValue(protocolCmdRegValue);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										88
									
								
								lib/collections/intents.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										88
									
								
								lib/collections/intents.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
 | 
					import 'package:go_router/go_router.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/platform.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PlayPauseIntent extends Intent {
 | 
				
			||||||
 | 
					  const PlayPauseIntent();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PlayPauseAction extends Action<PlayPauseIntent> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  invoke(intent) async {
 | 
				
			||||||
 | 
					    if (!audioPlayer.isPlaying) {
 | 
				
			||||||
 | 
					      await audioPlayer.resume();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      await audioPlayer.pause();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NavigationIntent extends Intent {
 | 
				
			||||||
 | 
					  final GoRouter router;
 | 
				
			||||||
 | 
					  final String path;
 | 
				
			||||||
 | 
					  const NavigationIntent(this.router, this.path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NavigationAction extends Action<NavigationIntent> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  invoke(intent) {
 | 
				
			||||||
 | 
					    intent.router.go(intent.path);
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum HomeTabs {
 | 
				
			||||||
 | 
					  browse,
 | 
				
			||||||
 | 
					  search,
 | 
				
			||||||
 | 
					  library,
 | 
				
			||||||
 | 
					  lyrics,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HomeTabIntent extends Intent {
 | 
				
			||||||
 | 
					  final HomeTabs tab;
 | 
				
			||||||
 | 
					  const HomeTabIntent({required this.tab});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HomeTabAction extends Action<HomeTabIntent> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  invoke(intent) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SeekIntent extends Intent {
 | 
				
			||||||
 | 
					  final bool forward;
 | 
				
			||||||
 | 
					  const SeekIntent(this.forward);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SeekAction extends Action<SeekIntent> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  invoke(intent) async {
 | 
				
			||||||
 | 
					    final position = audioPlayer.position.inSeconds;
 | 
				
			||||||
 | 
					    await audioPlayer.seek(
 | 
				
			||||||
 | 
					      Duration(
 | 
				
			||||||
 | 
					        seconds: intent.forward ? position + 5 : position - 5,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CloseAppIntent extends Intent {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CloseAppAction extends Action<CloseAppIntent> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  invoke(intent) {
 | 
				
			||||||
 | 
					    if (PlatformInfo.isDesktop) {
 | 
				
			||||||
 | 
					      exit(0);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      SystemNavigator.pop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										757
									
								
								lib/collections/language_codes.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										757
									
								
								lib/collections/language_codes.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,757 @@
 | 
				
			|||||||
 | 
					class ISOLanguageName {
 | 
				
			||||||
 | 
					  final String name;
 | 
				
			||||||
 | 
					  final String nativeName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ISOLanguageName({
 | 
				
			||||||
 | 
					    required this.name,
 | 
				
			||||||
 | 
					    required this.nativeName,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return "$name ($nativeName)";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Uncomment the languages as we add support for them
 | 
				
			||||||
 | 
					// Currently supported: bn,en,fr,hi,zh
 | 
				
			||||||
 | 
					abstract class LanguageLocals {
 | 
				
			||||||
 | 
					  static final Map isoLangs = {
 | 
				
			||||||
 | 
					    // "ab": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Abkhaz",
 | 
				
			||||||
 | 
					    //   nativeName: "аҧсуа",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "aa": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Afar",
 | 
				
			||||||
 | 
					    //   nativeName: "Afaraf",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "af": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Afrikaans",
 | 
				
			||||||
 | 
					    //   nativeName: "Afrikaans",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ak": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Akan",
 | 
				
			||||||
 | 
					    //   nativeName: "Akan",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sq": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Albanian",
 | 
				
			||||||
 | 
					    //   nativeName: "Shqip",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "am": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Amharic",
 | 
				
			||||||
 | 
					    //   nativeName: "አማርኛ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ar": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Arabic",
 | 
				
			||||||
 | 
					      nativeName: "العربية",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "an": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Aragonese",
 | 
				
			||||||
 | 
					    //   nativeName: "Aragonés",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "hy": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Armenian",
 | 
				
			||||||
 | 
					    //   nativeName: "Հայերեն",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "as": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Assamese",
 | 
				
			||||||
 | 
					    //   nativeName: "অসমীয়া",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "av": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Avaric",
 | 
				
			||||||
 | 
					    //   nativeName: "авар мацӀ, магӀарул мацӀ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ae": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Avestan",
 | 
				
			||||||
 | 
					    //   nativeName: "avesta",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ay": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Aymara",
 | 
				
			||||||
 | 
					    //   nativeName: "aymar aru",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "az": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Azerbaijani",
 | 
				
			||||||
 | 
					    //   nativeName: "azərbaycan dili",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "bm": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Bambara",
 | 
				
			||||||
 | 
					    //   nativeName: "bamanankan",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ba": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Bashkir",
 | 
				
			||||||
 | 
					    //   nativeName: "башҡорт теле",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "eu": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Basque",
 | 
				
			||||||
 | 
					      nativeName: "Euskara",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "be": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Belarusian",
 | 
				
			||||||
 | 
					    //   nativeName: "Беларуская",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "bn": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Bengali",
 | 
				
			||||||
 | 
					      nativeName: "বাংলা",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "bh": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Bihari",
 | 
				
			||||||
 | 
					    //   nativeName: "भोजपुरी",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "bi": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Bislama",
 | 
				
			||||||
 | 
					    //   nativeName: "Bislama",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "bs": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Bosnian",
 | 
				
			||||||
 | 
					    //   nativeName: "bosanski jezik",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "br": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Breton",
 | 
				
			||||||
 | 
					    //   nativeName: "brezhoneg",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "bg": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Bulgarian",
 | 
				
			||||||
 | 
					    //   nativeName: "български език",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "my": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Burmese",
 | 
				
			||||||
 | 
					    //   nativeName: "ဗမာစာ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ca": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Catalan",
 | 
				
			||||||
 | 
					      nativeName: "Català",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ch": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Chamorro",
 | 
				
			||||||
 | 
					    //   nativeName: "Chamoru",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ce": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Chechen",
 | 
				
			||||||
 | 
					    //   nativeName: "нохчийн мотт",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ny": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Chichewa",
 | 
				
			||||||
 | 
					    //   nativeName: "chiCheŵa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "zh": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Simplified Chinese",
 | 
				
			||||||
 | 
					      nativeName: "简体中文",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "cv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Chuvash",
 | 
				
			||||||
 | 
					    //   nativeName: "чӑваш чӗлхи",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kw": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Cornish",
 | 
				
			||||||
 | 
					    //   nativeName: "Kernewek",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "co": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Corsican",
 | 
				
			||||||
 | 
					    //   nativeName: "lingua corsa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "cr": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Cree",
 | 
				
			||||||
 | 
					    //   nativeName: "ᓀᐦᐃᔭᐍᐏᐣ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "hr": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Croatian",
 | 
				
			||||||
 | 
					    //   nativeName: "hrvatski",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "cs": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Czech",
 | 
				
			||||||
 | 
					      nativeName: "česky, čeština",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "da": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Danish",
 | 
				
			||||||
 | 
					    //   nativeName: "dansk",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "dv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Maldivian;",
 | 
				
			||||||
 | 
					    //   nativeName: "ދިވެހި",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "nl": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Dutch",
 | 
				
			||||||
 | 
					      nativeName: "Nederlands",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    "en": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "English",
 | 
				
			||||||
 | 
					      nativeName: "English",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "eo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Esperanto",
 | 
				
			||||||
 | 
					    //   nativeName: "Esperanto",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "et": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Estonian",
 | 
				
			||||||
 | 
					    //   nativeName: "eesti",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ee": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Ewe",
 | 
				
			||||||
 | 
					    //   nativeName: "Eʋegbe",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "fo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Faroese",
 | 
				
			||||||
 | 
					    //   nativeName: "føroyskt",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "fj": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Fijian",
 | 
				
			||||||
 | 
					    //   nativeName: "vosa Vakaviti",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "fi": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Finnish",
 | 
				
			||||||
 | 
					      nativeName: "suomi",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    "fr": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "French",
 | 
				
			||||||
 | 
					      nativeName: "français",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ff": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Fula; Fulah; Pulaar; Pular",
 | 
				
			||||||
 | 
					    //   nativeName: "Fulfulde, Pulaar, Pular",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "gl": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Galician",
 | 
				
			||||||
 | 
					    //   nativeName: "Galego",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ka": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Georgian",
 | 
				
			||||||
 | 
					      nativeName: "ქართული",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    "de": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "German",
 | 
				
			||||||
 | 
					      nativeName: "Deutsch",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "el": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Greek, Modern",
 | 
				
			||||||
 | 
					    //   nativeName: "Ελληνικά",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "gn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Guaraní",
 | 
				
			||||||
 | 
					    //   nativeName: "Avañeẽ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "gu": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Gujarati",
 | 
				
			||||||
 | 
					    //   nativeName: "ગુજરાતી",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ht": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Haitian; Haitian Creole",
 | 
				
			||||||
 | 
					    //   nativeName: "Kreyòl ayisyen",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ha": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Hausa",
 | 
				
			||||||
 | 
					    //   nativeName: "Hausa, هَوُسَ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "he": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Hebrew (modern)",
 | 
				
			||||||
 | 
					    //   nativeName: "עברית",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "hz": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Herero",
 | 
				
			||||||
 | 
					    //   nativeName: "Otjiherero",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "hi": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Hindi",
 | 
				
			||||||
 | 
					      nativeName: "हिन्दी, हिंदी",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ho": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Hiri Motu",
 | 
				
			||||||
 | 
					    //   nativeName: "Hiri Motu",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "hu": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Hungarian",
 | 
				
			||||||
 | 
					    //   nativeName: "Magyar",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ia": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Interlingua",
 | 
				
			||||||
 | 
					    //   nativeName: "Interlingua",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "id": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Indonesian",
 | 
				
			||||||
 | 
					      nativeName: "Bahasa Indonesia",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ie": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Interlingue",
 | 
				
			||||||
 | 
					    //   nativeName: "Occidental",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ga": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Irish",
 | 
				
			||||||
 | 
					    //   nativeName: "Gaeilge",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ig": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Igbo",
 | 
				
			||||||
 | 
					    //   nativeName: "Asụsụ Igbo",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ik": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Inupiaq",
 | 
				
			||||||
 | 
					    //   nativeName: "Iñupiaq, Iñupiatun",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "io": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Ido",
 | 
				
			||||||
 | 
					    //   nativeName: "Ido",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "is": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Icelandic",
 | 
				
			||||||
 | 
					    //   nativeName: "Íslenska",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "it": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Italian",
 | 
				
			||||||
 | 
					      nativeName: "Italiano",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "iu": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Inuktitut",
 | 
				
			||||||
 | 
					    //   nativeName: "ᐃᓄᒃᑎᑐᑦ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ja": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Japanese",
 | 
				
			||||||
 | 
					      nativeName: "日本語",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "jv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Javanese",
 | 
				
			||||||
 | 
					    //   nativeName: "basa Jawa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kl": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kalaallisut, Greenlandic",
 | 
				
			||||||
 | 
					    //   nativeName: "kalaallisut, kalaallit oqaasii",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kannada",
 | 
				
			||||||
 | 
					    //   nativeName: "ಕನ್ನಡ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kr": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kanuri",
 | 
				
			||||||
 | 
					    //   nativeName: "Kanuri",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ks": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kashmiri",
 | 
				
			||||||
 | 
					    //   nativeName: "कश्मीरी, كشميري",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kk": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kazakh",
 | 
				
			||||||
 | 
					    //   nativeName: "Қазақ тілі",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "km": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Khmer",
 | 
				
			||||||
 | 
					    //   nativeName: "ភាសាខ្មែរ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ki": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kikuyu, Gikuyu",
 | 
				
			||||||
 | 
					    //   nativeName: "Gĩkũyũ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "rw": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kinyarwanda",
 | 
				
			||||||
 | 
					    //   nativeName: "Ikinyarwanda",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ky": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kirghiz, Kyrgyz",
 | 
				
			||||||
 | 
					    //   nativeName: "кыргыз тили",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Komi",
 | 
				
			||||||
 | 
					    //   nativeName: "коми кыв",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kg": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kongo",
 | 
				
			||||||
 | 
					    //   nativeName: "KiKongo",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ko": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Korean",
 | 
				
			||||||
 | 
					      nativeName: "한국어 (韓國語), 조선말 (朝鮮語)",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ku": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kurdish",
 | 
				
			||||||
 | 
					    //   nativeName: "Kurdî, كوردی",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "kj": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kwanyama, Kuanyama",
 | 
				
			||||||
 | 
					    //   nativeName: "Kuanyama",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "la": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Latin",
 | 
				
			||||||
 | 
					    //   nativeName: "latine, lingua latina",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "lb": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Luxembourgish, Letzeburgesch",
 | 
				
			||||||
 | 
					    //   nativeName: "Lëtzebuergesch",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "lg": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Luganda",
 | 
				
			||||||
 | 
					    //   nativeName: "Luganda",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "li": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Limburgish, Limburgan, Limburger",
 | 
				
			||||||
 | 
					    //   nativeName: "Limburgs",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ln": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Lingala",
 | 
				
			||||||
 | 
					    //   nativeName: "Lingála",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "lo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Lao",
 | 
				
			||||||
 | 
					    //   nativeName: "ພາສາລາວ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "lt": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Lithuanian",
 | 
				
			||||||
 | 
					    //   nativeName: "lietuvių kalba",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "lu": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Luba-Katanga",
 | 
				
			||||||
 | 
					    //   nativeName: "",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "lv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Latvian",
 | 
				
			||||||
 | 
					    //   nativeName: "latviešu valoda",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "gv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Manx",
 | 
				
			||||||
 | 
					    //   nativeName: "Gaelg, Gailck",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mk": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Macedonian",
 | 
				
			||||||
 | 
					    //   nativeName: "македонски јазик",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mg": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Malagasy",
 | 
				
			||||||
 | 
					    //   nativeName: "Malagasy fiteny",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ms": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Malay",
 | 
				
			||||||
 | 
					    //   nativeName: "bahasa Melayu, بهاس ملايو",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ml": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Malayalam",
 | 
				
			||||||
 | 
					    //   nativeName: "മലയാളം",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mt": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Maltese",
 | 
				
			||||||
 | 
					    //   nativeName: "Malti",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mi": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Māori",
 | 
				
			||||||
 | 
					    //   nativeName: "te reo Māori",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mr": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Marathi (Marāṭhī)",
 | 
				
			||||||
 | 
					    //   nativeName: "मराठी",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mh": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Marshallese",
 | 
				
			||||||
 | 
					    //   nativeName: "Kajin M̧ajeļ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "mn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Mongolian",
 | 
				
			||||||
 | 
					    //   nativeName: "монгол",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "na": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Nauru",
 | 
				
			||||||
 | 
					    //   nativeName: "Ekakairũ Naoero",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "nv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Navajo, Navaho",
 | 
				
			||||||
 | 
					    //   nativeName: "Diné bizaad, Dinékʼehǰí",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "nb": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Norwegian Bokmål",
 | 
				
			||||||
 | 
					    //   nativeName: "Norsk bokmål",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "nd": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "North Ndebele",
 | 
				
			||||||
 | 
					    //   nativeName: "isiNdebele",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ne": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Nepali",
 | 
				
			||||||
 | 
					      nativeName: "नेपाली",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ng": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Ndonga",
 | 
				
			||||||
 | 
					    //   nativeName: "Owambo",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "nn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Norwegian Nynorsk",
 | 
				
			||||||
 | 
					    //   nativeName: "Norsk nynorsk",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "no": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Norwegian",
 | 
				
			||||||
 | 
					    //   nativeName: "Norsk",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ii": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Nuosu",
 | 
				
			||||||
 | 
					    //   nativeName: "ꆈꌠ꒿ Nuosuhxop",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "nr": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "South Ndebele",
 | 
				
			||||||
 | 
					    //   nativeName: "isiNdebele",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "oc": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Occitan",
 | 
				
			||||||
 | 
					    //   nativeName: "Occitan",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "oj": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Ojibwe, Ojibwa",
 | 
				
			||||||
 | 
					    //   nativeName: "ᐊᓂᔑᓈᐯᒧᐎᓐ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "cu": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Old Church Slavonic",
 | 
				
			||||||
 | 
					    //   nativeName: "ѩзыкъ словѣньскъ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "om": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Oromo",
 | 
				
			||||||
 | 
					    //   nativeName: "Afaan Oromoo",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "or": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Oriya",
 | 
				
			||||||
 | 
					    //   nativeName: "ଓଡ଼ିଆ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "os": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Ossetian, Ossetic",
 | 
				
			||||||
 | 
					    //   nativeName: "ирон æвзаг",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "pa": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Panjabi, Punjabi",
 | 
				
			||||||
 | 
					    //   nativeName: "ਪੰਜਾਬੀ, پنجابی",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "pi": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Pāli",
 | 
				
			||||||
 | 
					    //   nativeName: "पाऴि",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "fa": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Persian",
 | 
				
			||||||
 | 
					      nativeName: "فارسی",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    "pl": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Polish",
 | 
				
			||||||
 | 
					      nativeName: "polski",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ps": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Pashto, Pushto",
 | 
				
			||||||
 | 
					    //   nativeName: "پښتو",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "pt": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Portuguese",
 | 
				
			||||||
 | 
					      nativeName: "Português",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "qu": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Quechua",
 | 
				
			||||||
 | 
					    //   nativeName: "Runa Simi, Kichwa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "rm": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Romansh",
 | 
				
			||||||
 | 
					    //   nativeName: "rumantsch grischun",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "rn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Kirundi",
 | 
				
			||||||
 | 
					    //   nativeName: "kiRundi",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ro": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Romanian, Moldavian, Moldovan",
 | 
				
			||||||
 | 
					    //   nativeName: "română",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "ru": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Russian",
 | 
				
			||||||
 | 
					      nativeName: "русский язык",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "sa": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Sanskrit (Saṁskṛta)",
 | 
				
			||||||
 | 
					    //   nativeName: "संस्कृतम्",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sc": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Sardinian",
 | 
				
			||||||
 | 
					    //   nativeName: "sardu",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sd": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Sindhi",
 | 
				
			||||||
 | 
					    //   nativeName: "सिन्धी, سنڌي، سندھی",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "se": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Northern Sami",
 | 
				
			||||||
 | 
					    //   nativeName: "Davvisámegiella",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sm": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Samoan",
 | 
				
			||||||
 | 
					    //   nativeName: "gagana faa Samoa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sg": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Sango",
 | 
				
			||||||
 | 
					    //   nativeName: "yângâ tî sängö",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sr": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Serbian",
 | 
				
			||||||
 | 
					    //   nativeName: "српски језик",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "gd": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Scottish Gaelic; Gaelic",
 | 
				
			||||||
 | 
					    //   nativeName: "Gàidhlig",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Shona",
 | 
				
			||||||
 | 
					    //   nativeName: "chiShona",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "si": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Sinhala, Sinhalese",
 | 
				
			||||||
 | 
					    //   nativeName: "සිංහල",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sk": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Slovak",
 | 
				
			||||||
 | 
					    //   nativeName: "slovenčina",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sl": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Slovene",
 | 
				
			||||||
 | 
					    //   nativeName: "slovenščina",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "so": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Somali",
 | 
				
			||||||
 | 
					    //   nativeName: "Soomaaliga, af Soomaali",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "st": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Southern Sotho",
 | 
				
			||||||
 | 
					    //   nativeName: "Sesotho",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "es": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Spanish",
 | 
				
			||||||
 | 
					      nativeName: "español",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "su": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Sundanese",
 | 
				
			||||||
 | 
					    //   nativeName: "Basa Sunda",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sw": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Swahili",
 | 
				
			||||||
 | 
					    //   nativeName: "Kiswahili",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ss": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Swati",
 | 
				
			||||||
 | 
					    //   nativeName: "SiSwati",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "sv": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Swedish",
 | 
				
			||||||
 | 
					    //   nativeName: "svenska",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ta": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tamil",
 | 
				
			||||||
 | 
					    //   nativeName: "தமிழ்",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "te": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Telugu",
 | 
				
			||||||
 | 
					    //   nativeName: "తెలుగు",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "tg": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tajik",
 | 
				
			||||||
 | 
					    //   nativeName: "тоҷикӣ, toğikī, تاجیکی",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "th": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Thai",
 | 
				
			||||||
 | 
					      nativeName: "ไทย",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ti": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tigrinya",
 | 
				
			||||||
 | 
					    //   nativeName: "ትግርኛ",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "bo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tibetan Standard, Tibetan, Central",
 | 
				
			||||||
 | 
					    //   nativeName: "བོད་ཡིག",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "tk": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Turkmen",
 | 
				
			||||||
 | 
					    //   nativeName: "Türkmen, Түркмен",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "tl": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tagalog",
 | 
				
			||||||
 | 
					    //   nativeName: "Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "tn": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tswana",
 | 
				
			||||||
 | 
					    //   nativeName: "Setswana",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "to": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tonga (Tonga Islands)",
 | 
				
			||||||
 | 
					    //   nativeName: "faka Tonga",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "tr": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Turkish",
 | 
				
			||||||
 | 
					      nativeName: "Türkçe",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ts": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tsonga",
 | 
				
			||||||
 | 
					    //   nativeName: "Xitsonga",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "tt": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tatar",
 | 
				
			||||||
 | 
					    //   nativeName: "татарча, tatarça, تاتارچا",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "tw": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Twi",
 | 
				
			||||||
 | 
					    //   nativeName: "Twi",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ty": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Tahitian",
 | 
				
			||||||
 | 
					    //   nativeName: "Reo Tahiti",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ug": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Uighur, Uyghur",
 | 
				
			||||||
 | 
					    //   nativeName: "Uyƣurqə, ئۇيغۇرچە",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "uk": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Ukrainian",
 | 
				
			||||||
 | 
					      nativeName: "українська",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "ur": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Urdu",
 | 
				
			||||||
 | 
					    //   nativeName: "اردو",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "uz": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Uzbek",
 | 
				
			||||||
 | 
					    //   nativeName: "zbek, Ўзбек, أۇزبېك",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "ve": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Venda",
 | 
				
			||||||
 | 
					    //   nativeName: "Tshivenḓa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    "vi": const ISOLanguageName(
 | 
				
			||||||
 | 
					      name: "Vietnamese",
 | 
				
			||||||
 | 
					      nativeName: "Tiếng Việt",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    // "vo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Volapük",
 | 
				
			||||||
 | 
					    //   nativeName: "Volapük",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "wa": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Walloon",
 | 
				
			||||||
 | 
					    //   nativeName: "Walon",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "cy": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Welsh",
 | 
				
			||||||
 | 
					    //   nativeName: "Cymraeg",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "wo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Wolof",
 | 
				
			||||||
 | 
					    //   nativeName: "Wollof",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "fy": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Western Frisian",
 | 
				
			||||||
 | 
					    //   nativeName: "Frysk",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "xh": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Xhosa",
 | 
				
			||||||
 | 
					    //   nativeName: "isiXhosa",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "yi": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Yiddish",
 | 
				
			||||||
 | 
					    //   nativeName: "ייִדיש",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "yo": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Yoruba",
 | 
				
			||||||
 | 
					    //   nativeName: "Yorùbá",
 | 
				
			||||||
 | 
					    // ),
 | 
				
			||||||
 | 
					    // "za": const ISOLanguageName(
 | 
				
			||||||
 | 
					    //   name: "Zhuang, Chuang",
 | 
				
			||||||
 | 
					    //   nativeName: "Saɯ cueŋƅ, Saw cuengh",
 | 
				
			||||||
 | 
					    // )
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static ISOLanguageName getDisplayLanguage(key) {
 | 
				
			||||||
 | 
					    if (isoLangs.containsKey(key)) {
 | 
				
			||||||
 | 
					      return isoLangs[key]!;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw Exception("Language key incorrect");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										189
									
								
								lib/collections/spotify_markets.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										189
									
								
								lib/collections/spotify_markets.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,189 @@
 | 
				
			|||||||
 | 
					// Country Codes contributed by momobobe <https://github.com/momobobe>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:spotify/spotify.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final spotifyMarkets = [
 | 
				
			||||||
 | 
					  (Market.AL, "Albania (AL)"),
 | 
				
			||||||
 | 
					  (Market.DZ, "Algeria (DZ)"),
 | 
				
			||||||
 | 
					  (Market.AD, "Andorra (AD)"),
 | 
				
			||||||
 | 
					  (Market.AO, "Angola (AO)"),
 | 
				
			||||||
 | 
					  (Market.AG, "Antigua and Barbuda (AG)"),
 | 
				
			||||||
 | 
					  (Market.AR, "Argentina (AR)"),
 | 
				
			||||||
 | 
					  (Market.AM, "Armenia (AM)"),
 | 
				
			||||||
 | 
					  (Market.AU, "Australia (AU)"),
 | 
				
			||||||
 | 
					  (Market.AT, "Austria (AT)"),
 | 
				
			||||||
 | 
					  (Market.AZ, "Azerbaijan (AZ)"),
 | 
				
			||||||
 | 
					  (Market.BH, "Bahrain (BH)"),
 | 
				
			||||||
 | 
					  (Market.BD, "Bangladesh (BD)"),
 | 
				
			||||||
 | 
					  (Market.BB, "Barbados (BB)"),
 | 
				
			||||||
 | 
					  (Market.BY, "Belarus (BY)"),
 | 
				
			||||||
 | 
					  (Market.BE, "Belgium (BE)"),
 | 
				
			||||||
 | 
					  (Market.BZ, "Belize (BZ)"),
 | 
				
			||||||
 | 
					  (Market.BJ, "Benin (BJ)"),
 | 
				
			||||||
 | 
					  (Market.BT, "Bhutan (BT)"),
 | 
				
			||||||
 | 
					  (Market.BO, "Bolivia (BO)"),
 | 
				
			||||||
 | 
					  (Market.BA, "Bosnia and Herzegovina (BA)"),
 | 
				
			||||||
 | 
					  (Market.BW, "Botswana (BW)"),
 | 
				
			||||||
 | 
					  (Market.BR, "Brazil (BR)"),
 | 
				
			||||||
 | 
					  (Market.BN, "Brunei Darussalam (BN)"),
 | 
				
			||||||
 | 
					  (Market.BG, "Bulgaria (BG)"),
 | 
				
			||||||
 | 
					  (Market.BF, "Burkina Faso (BF)"),
 | 
				
			||||||
 | 
					  (Market.BI, "Burundi (BI)"),
 | 
				
			||||||
 | 
					  (Market.CV, "Cabo Verde / Cape Verde (CV)"),
 | 
				
			||||||
 | 
					  (Market.KH, "Cambodia (KH)"),
 | 
				
			||||||
 | 
					  (Market.CM, "Cameroon (CM)"),
 | 
				
			||||||
 | 
					  (Market.CA, "Canada (CA)"),
 | 
				
			||||||
 | 
					  (Market.TD, "Chad (TD)"),
 | 
				
			||||||
 | 
					  (Market.CL, "Chile (CL)"),
 | 
				
			||||||
 | 
					  (Market.CO, "Colombia (CO)"),
 | 
				
			||||||
 | 
					  (Market.KM, "Comoros (KM)"),
 | 
				
			||||||
 | 
					  (Market.CR, "Costa Rica (CR)"),
 | 
				
			||||||
 | 
					  (Market.HR, "Croatia (HR)"),
 | 
				
			||||||
 | 
					  (Market.CW, "Curaçao (CW)"),
 | 
				
			||||||
 | 
					  (Market.CY, "Cyprus (CY)"),
 | 
				
			||||||
 | 
					  (Market.CZ, "Czech Republic (CZ)"),
 | 
				
			||||||
 | 
					  (Market.CI, "Ivory Coast (CI)"),
 | 
				
			||||||
 | 
					  (Market.CD, "Congo (CD)"),
 | 
				
			||||||
 | 
					  (Market.DK, "Denmark (DK)"),
 | 
				
			||||||
 | 
					  (Market.DJ, "Djibouti (DJ)"),
 | 
				
			||||||
 | 
					  (Market.DM, "Dominica (DM)"),
 | 
				
			||||||
 | 
					  (Market.DO, "Dominican Republic (DO)"),
 | 
				
			||||||
 | 
					  (Market.EC, "Ecuador (EC)"),
 | 
				
			||||||
 | 
					  (Market.EG, "Egypt (EG)"),
 | 
				
			||||||
 | 
					  (Market.SV, "El Salvador (SV)"),
 | 
				
			||||||
 | 
					  (Market.GQ, "Equatorial Guinea (GQ)"),
 | 
				
			||||||
 | 
					  (Market.EE, "Estonia (EE)"),
 | 
				
			||||||
 | 
					  (Market.SZ, "Eswatini (SZ)"),
 | 
				
			||||||
 | 
					  (Market.FJ, "Fiji (FJ)"),
 | 
				
			||||||
 | 
					  (Market.FI, "Finland (FI)"),
 | 
				
			||||||
 | 
					  (Market.FR, "France (FR)"),
 | 
				
			||||||
 | 
					  (Market.GA, "Gabon (GA)"),
 | 
				
			||||||
 | 
					  (Market.GE, "Georgia (GE)"),
 | 
				
			||||||
 | 
					  (Market.DE, "Germany (DE)"),
 | 
				
			||||||
 | 
					  (Market.GH, "Ghana (GH)"),
 | 
				
			||||||
 | 
					  (Market.GR, "Greece (GR)"),
 | 
				
			||||||
 | 
					  (Market.GD, "Grenada (GD)"),
 | 
				
			||||||
 | 
					  (Market.GT, "Guatemala (GT)"),
 | 
				
			||||||
 | 
					  (Market.GN, "Guinea (GN)"),
 | 
				
			||||||
 | 
					  (Market.GW, "Guinea-Bissau (GW)"),
 | 
				
			||||||
 | 
					  (Market.GY, "Guyana (GY)"),
 | 
				
			||||||
 | 
					  (Market.HT, "Haiti (HT)"),
 | 
				
			||||||
 | 
					  (Market.HN, "Honduras (HN)"),
 | 
				
			||||||
 | 
					  (Market.HK, "Hong Kong (HK)"),
 | 
				
			||||||
 | 
					  (Market.HU, "Hungary (HU)"),
 | 
				
			||||||
 | 
					  (Market.IS, "Iceland (IS)"),
 | 
				
			||||||
 | 
					  (Market.IN, "India (IN)"),
 | 
				
			||||||
 | 
					  (Market.ID, "Indonesia (ID)"),
 | 
				
			||||||
 | 
					  (Market.IQ, "Iraq (IQ)"),
 | 
				
			||||||
 | 
					  (Market.IE, "Ireland (IE)"),
 | 
				
			||||||
 | 
					  (Market.IL, "Israel (IL)"),
 | 
				
			||||||
 | 
					  (Market.IT, "Italy (IT)"),
 | 
				
			||||||
 | 
					  (Market.JM, "Jamaica (JM)"),
 | 
				
			||||||
 | 
					  (Market.JP, "Japan (JP)"),
 | 
				
			||||||
 | 
					  (Market.JO, "Jordan (JO)"),
 | 
				
			||||||
 | 
					  (Market.KZ, "Kazakhstan (KZ)"),
 | 
				
			||||||
 | 
					  (Market.KE, "Kenya (KE)"),
 | 
				
			||||||
 | 
					  (Market.KI, "Kiribati (KI)"),
 | 
				
			||||||
 | 
					  (Market.XK, "Kosovo (XK)"),
 | 
				
			||||||
 | 
					  (Market.KW, "Kuwait (KW)"),
 | 
				
			||||||
 | 
					  (Market.KG, "Kyrgyzstan (KG)"),
 | 
				
			||||||
 | 
					  (Market.LA, "Laos (LA)"),
 | 
				
			||||||
 | 
					  (Market.LV, "Latvia (LV)"),
 | 
				
			||||||
 | 
					  (Market.LB, "Lebanon (LB)"),
 | 
				
			||||||
 | 
					  (Market.LS, "Lesotho (LS)"),
 | 
				
			||||||
 | 
					  (Market.LR, "Liberia (LR)"),
 | 
				
			||||||
 | 
					  (Market.LY, "Libya (LY)"),
 | 
				
			||||||
 | 
					  (Market.LI, "Liechtenstein (LI)"),
 | 
				
			||||||
 | 
					  (Market.LT, "Lithuania (LT)"),
 | 
				
			||||||
 | 
					  (Market.LU, "Luxembourg (LU)"),
 | 
				
			||||||
 | 
					  (Market.MO, "Macao / Macau (MO)"),
 | 
				
			||||||
 | 
					  (Market.MG, "Madagascar (MG)"),
 | 
				
			||||||
 | 
					  (Market.MW, "Malawi (MW)"),
 | 
				
			||||||
 | 
					  (Market.MY, "Malaysia (MY)"),
 | 
				
			||||||
 | 
					  (Market.MV, "Maldives (MV)"),
 | 
				
			||||||
 | 
					  (Market.ML, "Mali (ML)"),
 | 
				
			||||||
 | 
					  (Market.MT, "Malta (MT)"),
 | 
				
			||||||
 | 
					  (Market.MH, "Marshall Islands (MH)"),
 | 
				
			||||||
 | 
					  (Market.MR, "Mauritania (MR)"),
 | 
				
			||||||
 | 
					  (Market.MU, "Mauritius (MU)"),
 | 
				
			||||||
 | 
					  (Market.MX, "Mexico (MX)"),
 | 
				
			||||||
 | 
					  (Market.FM, "Micronesia (FM)"),
 | 
				
			||||||
 | 
					  (Market.MD, "Moldova (MD)"),
 | 
				
			||||||
 | 
					  (Market.MC, "Monaco (MC)"),
 | 
				
			||||||
 | 
					  (Market.MN, "Mongolia (MN)"),
 | 
				
			||||||
 | 
					  (Market.ME, "Montenegro (ME)"),
 | 
				
			||||||
 | 
					  (Market.MA, "Morocco (MA)"),
 | 
				
			||||||
 | 
					  (Market.MZ, "Mozambique (MZ)"),
 | 
				
			||||||
 | 
					  (Market.NA, "Namibia (NA)"),
 | 
				
			||||||
 | 
					  (Market.NR, "Nauru (NR)"),
 | 
				
			||||||
 | 
					  (Market.NP, "Nepal (NP)"),
 | 
				
			||||||
 | 
					  (Market.NL, "Netherlands (NL)"),
 | 
				
			||||||
 | 
					  (Market.NZ, "New Zealand (NZ)"),
 | 
				
			||||||
 | 
					  (Market.NI, "Nicaragua (NI)"),
 | 
				
			||||||
 | 
					  (Market.NE, "Niger (NE)"),
 | 
				
			||||||
 | 
					  (Market.NG, "Nigeria (NG)"),
 | 
				
			||||||
 | 
					  (Market.MK, "North Macedonia (MK)"),
 | 
				
			||||||
 | 
					  (Market.NO, "Norway (NO)"),
 | 
				
			||||||
 | 
					  (Market.OM, "Oman (OM)"),
 | 
				
			||||||
 | 
					  (Market.PK, "Pakistan (PK)"),
 | 
				
			||||||
 | 
					  (Market.PW, "Palau (PW)"),
 | 
				
			||||||
 | 
					  (Market.PS, "Palestine (PS)"),
 | 
				
			||||||
 | 
					  (Market.PA, "Panama (PA)"),
 | 
				
			||||||
 | 
					  (Market.PG, "Papua New Guinea (PG)"),
 | 
				
			||||||
 | 
					  (Market.PY, "Paraguay (PY)"),
 | 
				
			||||||
 | 
					  (Market.PE, "Peru (PE)"),
 | 
				
			||||||
 | 
					  (Market.PH, "Philippines (PH)"),
 | 
				
			||||||
 | 
					  (Market.PL, "Poland (PL)"),
 | 
				
			||||||
 | 
					  (Market.PT, "Portugal (PT)"),
 | 
				
			||||||
 | 
					  (Market.QA, "Qatar (QA)"),
 | 
				
			||||||
 | 
					  (Market.CG, "Congo (CG)"),
 | 
				
			||||||
 | 
					  (Market.RO, "Romania (RO)"),
 | 
				
			||||||
 | 
					  (Market.RU, "Russia (RU)"),
 | 
				
			||||||
 | 
					  (Market.RW, "Rwanda (RW)"),
 | 
				
			||||||
 | 
					  (Market.WS, "Samoa (WS)"),
 | 
				
			||||||
 | 
					  (Market.SM, "San Marino (SM)"),
 | 
				
			||||||
 | 
					  (Market.SA, "Saudi Arabia (SA)"),
 | 
				
			||||||
 | 
					  (Market.SN, "Senegal (SN)"),
 | 
				
			||||||
 | 
					  (Market.RS, "Serbia (RS)"),
 | 
				
			||||||
 | 
					  (Market.SC, "Seychelles (SC)"),
 | 
				
			||||||
 | 
					  (Market.SL, "Sierra Leone (SL)"),
 | 
				
			||||||
 | 
					  (Market.SG, "Singapore (SG)"),
 | 
				
			||||||
 | 
					  (Market.SK, "Slovakia (SK)"),
 | 
				
			||||||
 | 
					  (Market.SI, "Slovenia (SI)"),
 | 
				
			||||||
 | 
					  (Market.SB, "Solomon Islands (SB)"),
 | 
				
			||||||
 | 
					  (Market.ZA, "South Africa (ZA)"),
 | 
				
			||||||
 | 
					  (Market.KR, "South Korea (KR)"),
 | 
				
			||||||
 | 
					  (Market.ES, "Spain (ES)"),
 | 
				
			||||||
 | 
					  (Market.LK, "Sri Lanka (LK)"),
 | 
				
			||||||
 | 
					  (Market.KN, "St. Kitts and Nevis (KN)"),
 | 
				
			||||||
 | 
					  (Market.LC, "St. Lucia (LC)"),
 | 
				
			||||||
 | 
					  (Market.SR, "Suriname (SR)"),
 | 
				
			||||||
 | 
					  (Market.SE, "Sweden (SE)"),
 | 
				
			||||||
 | 
					  (Market.CH, "Switzerland (CH)"),
 | 
				
			||||||
 | 
					  (Market.ST, "São Tomé and Príncipe (ST)"),
 | 
				
			||||||
 | 
					  (Market.TW, "Taiwan (TW)"),
 | 
				
			||||||
 | 
					  (Market.TJ, "Tajikistan (TJ)"),
 | 
				
			||||||
 | 
					  (Market.TZ, "Tanzania (TZ)"),
 | 
				
			||||||
 | 
					  (Market.TH, "Thailand (TH)"),
 | 
				
			||||||
 | 
					  (Market.BS, "The Bahamas (BS)"),
 | 
				
			||||||
 | 
					  (Market.GM, "The Gambia (GM)"),
 | 
				
			||||||
 | 
					  (Market.TL, "East Timor (TL)"),
 | 
				
			||||||
 | 
					  (Market.TG, "Togo (TG)"),
 | 
				
			||||||
 | 
					  (Market.TO, "Tonga (TO)"),
 | 
				
			||||||
 | 
					  (Market.TT, "Trinidad and Tobago (TT)"),
 | 
				
			||||||
 | 
					  (Market.TN, "Tunisia (TN)"),
 | 
				
			||||||
 | 
					  (Market.TR, "Turkey (TR)"),
 | 
				
			||||||
 | 
					  (Market.TV, "Tuvalu (TV)"),
 | 
				
			||||||
 | 
					  (Market.UG, "Uganda (UG)"),
 | 
				
			||||||
 | 
					  (Market.UA, "Ukraine (UA)"),
 | 
				
			||||||
 | 
					  (Market.AE, "United Arab Emirates (AE)"),
 | 
				
			||||||
 | 
					  (Market.GB, "United Kingdom (GB)"),
 | 
				
			||||||
 | 
					  (Market.US, "United States (US)"),
 | 
				
			||||||
 | 
					  (Market.UY, "Uruguay (UY)"),
 | 
				
			||||||
 | 
					  (Market.UZ, "Uzbekistan (UZ)"),
 | 
				
			||||||
 | 
					  (Market.VU, "Vanuatu (VU)"),
 | 
				
			||||||
 | 
					  (Market.VE, "Venezuela (VE)"),
 | 
				
			||||||
 | 
					  (Market.VN, "Vietnam (VN)"),
 | 
				
			||||||
 | 
					  (Market.ZM, "Zambia (ZM)"),
 | 
				
			||||||
 | 
					  (Market.ZW, "Zimbabwe (ZW)"),
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
@@ -1,10 +1,18 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:media_kit/media_kit.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/providers/audio_player.dart';
 | 
				
			||||||
import 'package:rhythm_box/providers/spotify.dart';
 | 
					import 'package:rhythm_box/providers/spotify.dart';
 | 
				
			||||||
import 'package:rhythm_box/router.dart';
 | 
					import 'package:rhythm_box/router.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/active_sourced_track.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/routes/playback.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/server.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/sourced_track.dart';
 | 
				
			||||||
import 'package:rhythm_box/translations.dart';
 | 
					import 'package:rhythm_box/translations.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
 | 
					  MediaKit.ensureInitialized();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  runApp(const MyApp());
 | 
					  runApp(const MyApp());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,5 +50,10 @@ class MyApp extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void _initializeProviders(BuildContext context) async {
 | 
					  void _initializeProviders(BuildContext context) async {
 | 
				
			||||||
    Get.lazyPut(() => SpotifyProvider());
 | 
					    Get.lazyPut(() => SpotifyProvider());
 | 
				
			||||||
 | 
					    Get.lazyPut(() => AudioPlayerProvider());
 | 
				
			||||||
 | 
					    Get.lazyPut(() => ActiveSourcedTrackProvider());
 | 
				
			||||||
 | 
					    Get.lazyPut(() => SourcedTrackProvider());
 | 
				
			||||||
 | 
					    Get.lazyPut(() => ServerPlaybackRoutesProvider());
 | 
				
			||||||
 | 
					    Get.lazyPut(() => PlaybackServerProvider());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										122
									
								
								lib/providers/audio_player.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								lib/providers/audio_player.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					import 'dart:math';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:media_kit/media_kit.dart' hide Track;
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/state.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/local_track.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/sourced_track/sourced_track.dart';
 | 
				
			||||||
 | 
					import 'package:spotify/spotify.dart' hide Playlist;
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:shared_preferences/shared_preferences.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AudioPlayerProvider extends GetxController {
 | 
				
			||||||
 | 
					  late final SharedPreferences _prefs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Rx<AudioPlayerState> state = Rx(AudioPlayerState(
 | 
				
			||||||
 | 
					    playing: false,
 | 
				
			||||||
 | 
					    shuffled: false,
 | 
				
			||||||
 | 
					    loopMode: PlaylistMode.none,
 | 
				
			||||||
 | 
					    playlist: const Playlist([]),
 | 
				
			||||||
 | 
					    collections: [],
 | 
				
			||||||
 | 
					  ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AudioPlayerProvider() {
 | 
				
			||||||
 | 
					    SharedPreferences.getInstance().then((ins) {
 | 
				
			||||||
 | 
					      _prefs = ins;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _syncSavedState() async {
 | 
				
			||||||
 | 
					    final data = _prefs.getBool("player_state");
 | 
				
			||||||
 | 
					    if (data == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO Serilize and deserilize this state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO Sync saved playlist
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> load(
 | 
				
			||||||
 | 
					    List<Track> tracks, {
 | 
				
			||||||
 | 
					    int initialIndex = 0,
 | 
				
			||||||
 | 
					    bool autoPlay = false,
 | 
				
			||||||
 | 
					  }) async {
 | 
				
			||||||
 | 
					    final medias = tracks.map((x) => RhythmMedia(x)).toList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Giving the initial track a boost so MediaKit won't skip
 | 
				
			||||||
 | 
					    // because of timeout
 | 
				
			||||||
 | 
					    final intendedActiveTrack = medias.elementAt(initialIndex);
 | 
				
			||||||
 | 
					    if (intendedActiveTrack.track is! LocalTrack) {
 | 
				
			||||||
 | 
					      await SourcedTrack.fetchFromTrack(track: intendedActiveTrack.track);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (medias.isEmpty) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await audioPlayer.openPlaylist(
 | 
				
			||||||
 | 
					      medias.map((s) => s as Media).toList(),
 | 
				
			||||||
 | 
					      initialIndex: initialIndex,
 | 
				
			||||||
 | 
					      autoPlay: autoPlay,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> addTracksAtFirst(Iterable<Track> tracks) async {
 | 
				
			||||||
 | 
					    if (state.value.tracks.length == 1) {
 | 
				
			||||||
 | 
					      return addTracks(tracks);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < tracks.length; i++) {
 | 
				
			||||||
 | 
					      final track = tracks.elementAt(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await audioPlayer.addTrackAt(
 | 
				
			||||||
 | 
					        RhythmMedia(track),
 | 
				
			||||||
 | 
					        max(state.value.playlist.index, 0) + i + 1,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> addTrack(Track track) async {
 | 
				
			||||||
 | 
					    await audioPlayer.addTrack(RhythmMedia(track));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> addTracks(Iterable<Track> tracks) async {
 | 
				
			||||||
 | 
					    for (final track in tracks) {
 | 
				
			||||||
 | 
					      await audioPlayer.addTrack(RhythmMedia(track));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> removeTrack(String trackId) async {
 | 
				
			||||||
 | 
					    final index =
 | 
				
			||||||
 | 
					        state.value.tracks.indexWhere((element) => element.id == trackId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (index == -1) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await audioPlayer.removeTrack(index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> removeTracks(Iterable<String> trackIds) async {
 | 
				
			||||||
 | 
					    for (final trackId in trackIds) {
 | 
				
			||||||
 | 
					      await removeTrack(trackId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> jumpToTrack(Track track) async {
 | 
				
			||||||
 | 
					    final index = state.value.tracks
 | 
				
			||||||
 | 
					        .toList()
 | 
				
			||||||
 | 
					        .indexWhere((element) => element.id == track.id);
 | 
				
			||||||
 | 
					    if (index == -1) return;
 | 
				
			||||||
 | 
					    await audioPlayer.jumpTo(index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> moveTrack(int oldIndex, int newIndex) async {
 | 
				
			||||||
 | 
					    if (oldIndex == newIndex ||
 | 
				
			||||||
 | 
					        newIndex < 0 ||
 | 
				
			||||||
 | 
					        oldIndex < 0 ||
 | 
				
			||||||
 | 
					        newIndex > state.value.tracks.length - 1 ||
 | 
				
			||||||
 | 
					        oldIndex > state.value.tracks.length - 1) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await audioPlayer.moveTrack(oldIndex, newIndex);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> stop() async {
 | 
				
			||||||
 | 
					    await audioPlayer.stop();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,3 +0,0 @@
 | 
				
			|||||||
import 'package:get/get.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PipedProvider extends GetxController {}
 | 
					 | 
				
			||||||
@@ -13,13 +13,6 @@ final router = GoRouter(routes: [
 | 
				
			|||||||
        name: "explore",
 | 
					        name: "explore",
 | 
				
			||||||
        builder: (context, state) => const ExploreScreen(),
 | 
					        builder: (context, state) => const ExploreScreen(),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      GoRoute(
 | 
					 | 
				
			||||||
        path: "/playlist/:id",
 | 
					 | 
				
			||||||
        name: "playlistView",
 | 
					 | 
				
			||||||
        builder: (context, state) => PlaylistViewScreen(
 | 
					 | 
				
			||||||
          playlistId: state.pathParameters['id']!,
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      GoRoute(
 | 
					      GoRoute(
 | 
				
			||||||
        path: "/settings",
 | 
					        path: "/settings",
 | 
				
			||||||
        name: "settings",
 | 
					        name: "settings",
 | 
				
			||||||
@@ -27,4 +20,11 @@ final router = GoRouter(routes: [
 | 
				
			|||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
 | 
					  GoRoute(
 | 
				
			||||||
 | 
					    path: "/playlist/:id",
 | 
				
			||||||
 | 
					    name: "playlistView",
 | 
				
			||||||
 | 
					    builder: (context, state) => PlaylistViewScreen(
 | 
				
			||||||
 | 
					      playlistId: state.pathParameters['id']!,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								lib/services/artist.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								lib/services/artist.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					import 'package:spotify/spotify.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extension ArtistExtension on List<ArtistSimple> {
 | 
				
			||||||
 | 
					  String asString() {
 | 
				
			||||||
 | 
					    return map((e) => e.name?.replaceAll(",", " ")).join(", ");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										108
									
								
								lib/services/audio_player/state.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								lib/services/audio_player/state.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					import 'package:media_kit/media_kit.dart' hide Track;
 | 
				
			||||||
 | 
					import 'package:spotify/spotify.dart' hide Playlist;
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AudioPlayerState {
 | 
				
			||||||
 | 
					  final bool playing;
 | 
				
			||||||
 | 
					  final PlaylistMode loopMode;
 | 
				
			||||||
 | 
					  final bool shuffled;
 | 
				
			||||||
 | 
					  final Playlist playlist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final List<Track> tracks;
 | 
				
			||||||
 | 
					  final List<String> collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AudioPlayerState({
 | 
				
			||||||
 | 
					    required this.playing,
 | 
				
			||||||
 | 
					    required this.loopMode,
 | 
				
			||||||
 | 
					    required this.shuffled,
 | 
				
			||||||
 | 
					    required this.playlist,
 | 
				
			||||||
 | 
					    required this.collections,
 | 
				
			||||||
 | 
					    List<Track>? tracks,
 | 
				
			||||||
 | 
					  }) : tracks = tracks ??
 | 
				
			||||||
 | 
					            playlist.medias
 | 
				
			||||||
 | 
					                .map((media) => RhythmMedia.fromMedia(media).track)
 | 
				
			||||||
 | 
					                .toList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory AudioPlayerState.fromJson(Map<String, dynamic> json) {
 | 
				
			||||||
 | 
					    return AudioPlayerState(
 | 
				
			||||||
 | 
					      playing: json['playing'],
 | 
				
			||||||
 | 
					      loopMode: PlaylistMode.values.firstWhere(
 | 
				
			||||||
 | 
					        (e) => e.name == json['loopMode'],
 | 
				
			||||||
 | 
					        orElse: () => audioPlayer.loopMode,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      shuffled: json['shuffled'],
 | 
				
			||||||
 | 
					      playlist: Playlist(
 | 
				
			||||||
 | 
					        json['playlist']['medias']
 | 
				
			||||||
 | 
					            .map(
 | 
				
			||||||
 | 
					              (media) => RhythmMedia.fromMedia(Media(
 | 
				
			||||||
 | 
					                media['uri'],
 | 
				
			||||||
 | 
					                extras: media['extras'],
 | 
				
			||||||
 | 
					                httpHeaders: media['httpHeaders'],
 | 
				
			||||||
 | 
					              )),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .cast<Media>()
 | 
				
			||||||
 | 
					            .toList(),
 | 
				
			||||||
 | 
					        index: json['playlist']['index'],
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      collections: List<String>.from(json['collections']),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      'playing': playing,
 | 
				
			||||||
 | 
					      'loopMode': loopMode.name,
 | 
				
			||||||
 | 
					      'shuffled': shuffled,
 | 
				
			||||||
 | 
					      'playlist': {
 | 
				
			||||||
 | 
					        'medias': playlist.medias
 | 
				
			||||||
 | 
					            .map((media) => {
 | 
				
			||||||
 | 
					                  'uri': media.uri,
 | 
				
			||||||
 | 
					                  'extras': media.extras,
 | 
				
			||||||
 | 
					                  'httpHeaders': media.httpHeaders,
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .toList(),
 | 
				
			||||||
 | 
					        'index': playlist.index,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      'collections': collections,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AudioPlayerState copyWith({
 | 
				
			||||||
 | 
					    bool? playing,
 | 
				
			||||||
 | 
					    PlaylistMode? loopMode,
 | 
				
			||||||
 | 
					    bool? shuffled,
 | 
				
			||||||
 | 
					    Playlist? playlist,
 | 
				
			||||||
 | 
					    List<String>? collections,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    return AudioPlayerState(
 | 
				
			||||||
 | 
					      playing: playing ?? this.playing,
 | 
				
			||||||
 | 
					      loopMode: loopMode ?? this.loopMode,
 | 
				
			||||||
 | 
					      shuffled: shuffled ?? this.shuffled,
 | 
				
			||||||
 | 
					      playlist: playlist ?? this.playlist,
 | 
				
			||||||
 | 
					      collections: collections ?? this.collections,
 | 
				
			||||||
 | 
					      tracks: playlist == null ? tracks : null,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Track? get activeTrack {
 | 
				
			||||||
 | 
					    if (playlist.index == -1) return null;
 | 
				
			||||||
 | 
					    return tracks.elementAtOrNull(playlist.index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Media? get activeMedia {
 | 
				
			||||||
 | 
					    if (playlist.index == -1 || playlist.medias.isEmpty) return null;
 | 
				
			||||||
 | 
					    return playlist.medias.elementAt(playlist.index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool containsTrack(Track track) {
 | 
				
			||||||
 | 
					    return tracks.any((t) => t.id == track.id);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool containsTracks(List<Track> tracks) {
 | 
				
			||||||
 | 
					    return tracks.every(containsTrack);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool containsCollection(String collectionId) {
 | 
				
			||||||
 | 
					    return collections.contains(collectionId);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								lib/services/audio_services/audio_services.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										84
									
								
								lib/services/audio_services/audio_services.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					import 'package:audio_service/audio_service.dart';
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/platform.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_services/image.dart';
 | 
				
			||||||
 | 
					import 'package:spotify/spotify.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_services/mobile_audio_service.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_services/windows_audio_service.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/sourced_track/sourced_track.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/artist.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AudioServices with WidgetsBindingObserver {
 | 
				
			||||||
 | 
					  final MobileAudioService? mobile;
 | 
				
			||||||
 | 
					  final WindowsAudioService? smtc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AudioServices(this.mobile, this.smtc) {
 | 
				
			||||||
 | 
					    WidgetsBinding.instance.addObserver(this);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static Future<AudioServices> create() async {
 | 
				
			||||||
 | 
					    final mobile =
 | 
				
			||||||
 | 
					        PlatformInfo.isMobile || PlatformInfo.isMacOS || PlatformInfo.isLinux
 | 
				
			||||||
 | 
					            ? await AudioService.init(
 | 
				
			||||||
 | 
					                builder: () => MobileAudioService(),
 | 
				
			||||||
 | 
					                config: AudioServiceConfig(
 | 
				
			||||||
 | 
					                  androidNotificationChannelId: PlatformInfo.isLinux
 | 
				
			||||||
 | 
					                      ? 'RhythmBox'
 | 
				
			||||||
 | 
					                      : 'dev.solsynth.rhythmBox',
 | 
				
			||||||
 | 
					                  androidNotificationChannelName: 'RhythmBox',
 | 
				
			||||||
 | 
					                  androidNotificationOngoing: false,
 | 
				
			||||||
 | 
					                  androidNotificationIcon: "drawable/ic_launcher_monochrome",
 | 
				
			||||||
 | 
					                  androidStopForegroundOnPause: false,
 | 
				
			||||||
 | 
					                  androidNotificationChannelDescription: "RhythmBox Music",
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            : null;
 | 
				
			||||||
 | 
					    final smtc = PlatformInfo.isWindows ? WindowsAudioService() : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return AudioServices(mobile, smtc);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> addTrack(Track track) async {
 | 
				
			||||||
 | 
					    await smtc?.addTrack(track);
 | 
				
			||||||
 | 
					    mobile?.addItem(MediaItem(
 | 
				
			||||||
 | 
					      id: track.id!,
 | 
				
			||||||
 | 
					      album: track.album?.name ?? "",
 | 
				
			||||||
 | 
					      title: track.name!,
 | 
				
			||||||
 | 
					      artist: (track.artists)?.asString() ?? "",
 | 
				
			||||||
 | 
					      duration: track is SourcedTrack
 | 
				
			||||||
 | 
					          ? track.sourceInfo.duration
 | 
				
			||||||
 | 
					          : Duration(milliseconds: track.durationMs ?? 0),
 | 
				
			||||||
 | 
					      artUri: Uri.parse(
 | 
				
			||||||
 | 
					        (track.album?.images).asUrlString(
 | 
				
			||||||
 | 
					          placeholder: ImagePlaceholder.albumArt,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      playable: true,
 | 
				
			||||||
 | 
					    ));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void activateSession() {
 | 
				
			||||||
 | 
					    mobile?.session?.setActive(true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void deactivateSession() {
 | 
				
			||||||
 | 
					    mobile?.session?.setActive(false);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void didChangeAppLifecycleState(AppLifecycleState state) {
 | 
				
			||||||
 | 
					    switch (state) {
 | 
				
			||||||
 | 
					      case AppLifecycleState.detached:
 | 
				
			||||||
 | 
					        deactivateSession();
 | 
				
			||||||
 | 
					        mobile?.stop();
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    smtc?.dispose();
 | 
				
			||||||
 | 
					    WidgetsBinding.instance.removeObserver(this);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								lib/services/audio_services/image.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/services/audio_services/image.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					import 'package:rhythm_box/services/primitive.dart';
 | 
				
			||||||
 | 
					import 'package:spotify/spotify.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/collections/assets.gen.dart';
 | 
				
			||||||
 | 
					import 'package:collection/collection.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ImagePlaceholder {
 | 
				
			||||||
 | 
					  albumArt,
 | 
				
			||||||
 | 
					  artist,
 | 
				
			||||||
 | 
					  collection,
 | 
				
			||||||
 | 
					  online,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extension SpotifyImageExtensions on List<Image>? {
 | 
				
			||||||
 | 
					  String asUrlString({
 | 
				
			||||||
 | 
					    int index = 1,
 | 
				
			||||||
 | 
					    required ImagePlaceholder placeholder,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    final String placeholderUrl = {
 | 
				
			||||||
 | 
					      ImagePlaceholder.albumArt: Assets.albumPlaceholder.path,
 | 
				
			||||||
 | 
					      ImagePlaceholder.artist: Assets.userPlaceholder.path,
 | 
				
			||||||
 | 
					      ImagePlaceholder.collection: Assets.placeholder.path,
 | 
				
			||||||
 | 
					      ImagePlaceholder.online:
 | 
				
			||||||
 | 
					          "https://avatars.dicebear.com/api/bottts/${PrimitiveUtils.uuid.v4()}.png",
 | 
				
			||||||
 | 
					    }[placeholder]!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final sortedImage = this?.sorted((a, b) => a.width!.compareTo(b.width!));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return sortedImage != null && sortedImage.isNotEmpty
 | 
				
			||||||
 | 
					        ? sortedImage[
 | 
				
			||||||
 | 
					                index > sortedImage.length - 1 ? sortedImage.length - 1 : index]
 | 
				
			||||||
 | 
					            .url!
 | 
				
			||||||
 | 
					        : placeholderUrl;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										153
									
								
								lib/services/audio_services/mobile_audio_service.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										153
									
								
								lib/services/audio_services/mobile_audio_service.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:audio_service/audio_service.dart';
 | 
				
			||||||
 | 
					import 'package:audio_session/audio_session.dart';
 | 
				
			||||||
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/providers/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:media_kit/media_kit.dart' hide Track;
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/state.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MobileAudioService extends BaseAudioHandler {
 | 
				
			||||||
 | 
					  AudioSession? session;
 | 
				
			||||||
 | 
					  // ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
 | 
				
			||||||
 | 
					  AudioPlayerState get playlist => Get.find<AudioPlayerProvider>().state.value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MobileAudioService() {
 | 
				
			||||||
 | 
					    AudioSession.instance.then((s) {
 | 
				
			||||||
 | 
					      session = s;
 | 
				
			||||||
 | 
					      session?.configure(const AudioSessionConfiguration.music());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bool wasPausedByBeginEvent = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      s.interruptionEventStream.listen((event) async {
 | 
				
			||||||
 | 
					        if (event.begin) {
 | 
				
			||||||
 | 
					          switch (event.type) {
 | 
				
			||||||
 | 
					            case AudioInterruptionType.duck:
 | 
				
			||||||
 | 
					              await audioPlayer.setVolume(0.5);
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            case AudioInterruptionType.pause:
 | 
				
			||||||
 | 
					            case AudioInterruptionType.unknown:
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                wasPausedByBeginEvent = audioPlayer.isPlaying;
 | 
				
			||||||
 | 
					                await audioPlayer.pause();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          switch (event.type) {
 | 
				
			||||||
 | 
					            case AudioInterruptionType.duck:
 | 
				
			||||||
 | 
					              await audioPlayer.setVolume(1.0);
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            case AudioInterruptionType.pause when wasPausedByBeginEvent:
 | 
				
			||||||
 | 
					            case AudioInterruptionType.unknown when wasPausedByBeginEvent:
 | 
				
			||||||
 | 
					              await audioPlayer.resume();
 | 
				
			||||||
 | 
					              wasPausedByBeginEvent = false;
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      s.becomingNoisyEventStream.listen((_) {
 | 
				
			||||||
 | 
					        audioPlayer.pause();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    audioPlayer.playerStateStream.listen((state) async {
 | 
				
			||||||
 | 
					      playbackState.add(await _transformEvent());
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    audioPlayer.positionStream.listen((pos) async {
 | 
				
			||||||
 | 
					      playbackState.add(await _transformEvent());
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    audioPlayer.bufferedPositionStream.listen((pos) async {
 | 
				
			||||||
 | 
					      playbackState.add(await _transformEvent());
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void addItem(MediaItem item) {
 | 
				
			||||||
 | 
					    session?.setActive(true);
 | 
				
			||||||
 | 
					    mediaItem.add(item);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> play() => audioPlayer.resume();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> pause() => audioPlayer.pause();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> seek(Duration position) => audioPlayer.seek(position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> setShuffleMode(AudioServiceShuffleMode shuffleMode) async {
 | 
				
			||||||
 | 
					    await super.setShuffleMode(shuffleMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    audioPlayer.setShuffle(shuffleMode == AudioServiceShuffleMode.all);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> setRepeatMode(AudioServiceRepeatMode repeatMode) async {
 | 
				
			||||||
 | 
					    super.setRepeatMode(repeatMode);
 | 
				
			||||||
 | 
					    audioPlayer.setLoopMode(switch (repeatMode) {
 | 
				
			||||||
 | 
					      AudioServiceRepeatMode.all ||
 | 
				
			||||||
 | 
					      AudioServiceRepeatMode.group =>
 | 
				
			||||||
 | 
					        PlaylistMode.loop,
 | 
				
			||||||
 | 
					      AudioServiceRepeatMode.one => PlaylistMode.single,
 | 
				
			||||||
 | 
					      _ => PlaylistMode.none,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> stop() async {
 | 
				
			||||||
 | 
					    await Get.find<AudioPlayerProvider>().stop();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> skipToNext() async {
 | 
				
			||||||
 | 
					    await audioPlayer.skipToNext();
 | 
				
			||||||
 | 
					    await super.skipToNext();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> skipToPrevious() async {
 | 
				
			||||||
 | 
					    await audioPlayer.skipToPrevious();
 | 
				
			||||||
 | 
					    await super.skipToPrevious();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Future<void> onTaskRemoved() async {
 | 
				
			||||||
 | 
					    await Get.find<AudioPlayerProvider>().stop();
 | 
				
			||||||
 | 
					    return super.onTaskRemoved();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<PlaybackState> _transformEvent() async {
 | 
				
			||||||
 | 
					    return PlaybackState(
 | 
				
			||||||
 | 
					      controls: [
 | 
				
			||||||
 | 
					        MediaControl.skipToPrevious,
 | 
				
			||||||
 | 
					        audioPlayer.isPlaying ? MediaControl.pause : MediaControl.play,
 | 
				
			||||||
 | 
					        MediaControl.skipToNext,
 | 
				
			||||||
 | 
					        MediaControl.stop,
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      systemActions: {
 | 
				
			||||||
 | 
					        MediaAction.seek,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      androidCompactActionIndices: const [0, 1, 2],
 | 
				
			||||||
 | 
					      playing: audioPlayer.isPlaying,
 | 
				
			||||||
 | 
					      updatePosition: audioPlayer.position,
 | 
				
			||||||
 | 
					      bufferedPosition: audioPlayer.bufferedPosition,
 | 
				
			||||||
 | 
					      shuffleMode: audioPlayer.isShuffled == true
 | 
				
			||||||
 | 
					          ? AudioServiceShuffleMode.all
 | 
				
			||||||
 | 
					          : AudioServiceShuffleMode.none,
 | 
				
			||||||
 | 
					      repeatMode: switch (audioPlayer.loopMode) {
 | 
				
			||||||
 | 
					        PlaylistMode.loop => AudioServiceRepeatMode.all,
 | 
				
			||||||
 | 
					        PlaylistMode.single => AudioServiceRepeatMode.one,
 | 
				
			||||||
 | 
					        _ => AudioServiceRepeatMode.none,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      processingState: audioPlayer.isBuffering
 | 
				
			||||||
 | 
					          ? AudioProcessingState.loading
 | 
				
			||||||
 | 
					          : AudioProcessingState.ready,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										101
									
								
								lib/services/audio_services/windows_audio_service.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										101
									
								
								lib/services/audio_services/windows_audio_service.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/providers/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_services/image.dart';
 | 
				
			||||||
 | 
					import 'package:smtc_windows/smtc_windows.dart';
 | 
				
			||||||
 | 
					import 'package:spotify/spotify.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/playback_state.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/artist.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WindowsAudioService {
 | 
				
			||||||
 | 
					  final SMTCWindows smtc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final subscriptions = <StreamSubscription>[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  WindowsAudioService() : smtc = SMTCWindows(enabled: false) {
 | 
				
			||||||
 | 
					    smtc.setPlaybackStatus(PlaybackStatus.Stopped);
 | 
				
			||||||
 | 
					    final buttonStream = smtc.buttonPressStream.listen((event) {
 | 
				
			||||||
 | 
					      switch (event) {
 | 
				
			||||||
 | 
					        case PressedButton.play:
 | 
				
			||||||
 | 
					          audioPlayer.resume();
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case PressedButton.pause:
 | 
				
			||||||
 | 
					          audioPlayer.pause();
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case PressedButton.next:
 | 
				
			||||||
 | 
					          audioPlayer.skipToNext();
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case PressedButton.previous:
 | 
				
			||||||
 | 
					          audioPlayer.skipToPrevious();
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case PressedButton.stop:
 | 
				
			||||||
 | 
					          Get.find<AudioPlayerProvider>().stop();
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final playerStateStream =
 | 
				
			||||||
 | 
					        audioPlayer.playerStateStream.listen((state) async {
 | 
				
			||||||
 | 
					      switch (state) {
 | 
				
			||||||
 | 
					        case AudioPlaybackState.playing:
 | 
				
			||||||
 | 
					          await smtc.setPlaybackStatus(PlaybackStatus.Playing);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case AudioPlaybackState.paused:
 | 
				
			||||||
 | 
					          await smtc.setPlaybackStatus(PlaybackStatus.Paused);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case AudioPlaybackState.stopped:
 | 
				
			||||||
 | 
					          await smtc.setPlaybackStatus(PlaybackStatus.Stopped);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case AudioPlaybackState.completed:
 | 
				
			||||||
 | 
					          await smtc.setPlaybackStatus(PlaybackStatus.Changing);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final positionStream = audioPlayer.positionStream.listen((pos) async {
 | 
				
			||||||
 | 
					      await smtc.setPosition(pos);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final durationStream = audioPlayer.durationStream.listen((duration) async {
 | 
				
			||||||
 | 
					      await smtc.setEndTime(duration);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subscriptions.addAll([
 | 
				
			||||||
 | 
					      buttonStream,
 | 
				
			||||||
 | 
					      playerStateStream,
 | 
				
			||||||
 | 
					      positionStream,
 | 
				
			||||||
 | 
					      durationStream,
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> addTrack(Track track) async {
 | 
				
			||||||
 | 
					    if (!smtc.enabled) {
 | 
				
			||||||
 | 
					      await smtc.enableSmtc();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await smtc.updateMetadata(
 | 
				
			||||||
 | 
					      MusicMetadata(
 | 
				
			||||||
 | 
					        title: track.name!,
 | 
				
			||||||
 | 
					        albumArtist: track.artists?.firstOrNull?.name ?? "Unknown",
 | 
				
			||||||
 | 
					        artist: track.artists?.asString() ?? "Unknown",
 | 
				
			||||||
 | 
					        album: track.album?.name ?? "Unknown",
 | 
				
			||||||
 | 
					        thumbnail: (track.album?.images).asUrlString(
 | 
				
			||||||
 | 
					          placeholder: ImagePlaceholder.albumArt,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    smtc.disableSmtc();
 | 
				
			||||||
 | 
					    smtc.dispose();
 | 
				
			||||||
 | 
					    for (var element in subscriptions) {
 | 
				
			||||||
 | 
					      element.cancel();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								lib/services/primitive.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								lib/services/primitive.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					import 'dart:math';
 | 
				
			||||||
 | 
					import 'package:uuid/uuid.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class PrimitiveUtils {
 | 
				
			||||||
 | 
					  static bool containsTextInBracket(String matcher, String text) {
 | 
				
			||||||
 | 
					    final allMatches = RegExp(r"(?<=\().+?(?=\))").allMatches(matcher);
 | 
				
			||||||
 | 
					    if (allMatches.isEmpty) return false;
 | 
				
			||||||
 | 
					    return allMatches
 | 
				
			||||||
 | 
					        .map((e) => e.group(0))
 | 
				
			||||||
 | 
					        .every((match) => match?.contains(text) ?? false);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static final Random _random = Random();
 | 
				
			||||||
 | 
					  static T getRandomElement<T>(List<T> list) {
 | 
				
			||||||
 | 
					    return list[_random.nextInt(list.length)];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const uuid = Uuid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static String toReadableNumber(double num) {
 | 
				
			||||||
 | 
					    if (num > 999 && num < 99999) {
 | 
				
			||||||
 | 
					      return "${(num / 1000).toStringAsFixed(0)}K";
 | 
				
			||||||
 | 
					    } else if (num > 99999 && num < 999999) {
 | 
				
			||||||
 | 
					      return "${(num / 1000).toStringAsFixed(0)}K";
 | 
				
			||||||
 | 
					    } else if (num > 999999 && num < 999999999) {
 | 
				
			||||||
 | 
					      return "${(num / 1000000).toStringAsFixed(0)}M";
 | 
				
			||||||
 | 
					    } else if (num > 999999999) {
 | 
				
			||||||
 | 
					      return "${(num / 1000000000).toStringAsFixed(0)}B";
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return num.toStringAsFixed(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static Future<T> raceMultiple<T>(
 | 
				
			||||||
 | 
					    Future<T> Function() inner, {
 | 
				
			||||||
 | 
					    Duration timeout = const Duration(milliseconds: 2500),
 | 
				
			||||||
 | 
					    int retryCount = 4,
 | 
				
			||||||
 | 
					  }) async {
 | 
				
			||||||
 | 
					    return Future.any(
 | 
				
			||||||
 | 
					      List.generate(retryCount, (i) {
 | 
				
			||||||
 | 
					        if (i == 0) return inner();
 | 
				
			||||||
 | 
					        return Future.delayed(
 | 
				
			||||||
 | 
					          Duration(milliseconds: timeout.inMilliseconds * i),
 | 
				
			||||||
 | 
					          inner,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static String toSafeFileName(String str) {
 | 
				
			||||||
 | 
					    return str.replaceAll(RegExp(r'[/\?%*:|"<>]'), ' ');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								lib/services/server/active_sourced_track.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										39
									
								
								lib/services/server/active_sourced_track.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/providers/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/sourced_track/models/source_info.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/sourced_track/sourced_track.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ActiveSourcedTrackProvider extends GetxController {
 | 
				
			||||||
 | 
					  Rx<SourcedTrack?> state = Rx(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void updateTrack(SourcedTrack? sourcedTrack) {
 | 
				
			||||||
 | 
					    state.value = sourcedTrack;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> populateSibling() async {
 | 
				
			||||||
 | 
					    if (state.value == null) return;
 | 
				
			||||||
 | 
					    state.value = await state.value!.copyWithSibling();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> swapSibling(SourceInfo sibling) async {
 | 
				
			||||||
 | 
					    if (state.value == null) return;
 | 
				
			||||||
 | 
					    await populateSibling();
 | 
				
			||||||
 | 
					    final newTrack = await state.value!.swapWithSibling(sibling);
 | 
				
			||||||
 | 
					    if (newTrack == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state.value = newTrack;
 | 
				
			||||||
 | 
					    await audioPlayer.pause();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final playback = Get.find<AudioPlayerProvider>();
 | 
				
			||||||
 | 
					    final oldActiveIndex = audioPlayer.currentIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await playback.addTracksAtFirst([newTrack]);
 | 
				
			||||||
 | 
					    await Future.delayed(const Duration(milliseconds: 50));
 | 
				
			||||||
 | 
					    await playback.jumpToTrack(newTrack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await audioPlayer.removeTrack(oldActiveIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await audioPlayer.resume();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										66
									
								
								lib/services/server/routes/playback.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										66
									
								
								lib/services/server/routes/playback.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					import 'dart:developer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:dio/dio.dart' hide Response;
 | 
				
			||||||
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
 | 
					import 'package:get/get.dart' hide Response;
 | 
				
			||||||
 | 
					import 'package:rhythm_box/providers/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/active_sourced_track.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/sourced_track.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/sourced_track/sourced_track.dart';
 | 
				
			||||||
 | 
					import 'package:shelf/shelf.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ServerPlaybackRoutesProvider {
 | 
				
			||||||
 | 
					  /// @get('/stream/<trackId>')
 | 
				
			||||||
 | 
					  Future<Response> getStreamTrackId(Request request, String trackId) async {
 | 
				
			||||||
 | 
					    final AudioPlayerProvider playback = Get.find();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      final track = playback.state.value.tracks
 | 
				
			||||||
 | 
					          .firstWhere((element) => element.id == trackId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      final ActiveSourcedTrackProvider activeSourcedTrack = Get.find();
 | 
				
			||||||
 | 
					      final sourcedTrack = activeSourcedTrack.state.value?.id == track.id
 | 
				
			||||||
 | 
					          ? activeSourcedTrack
 | 
				
			||||||
 | 
					          : await Get.find<SourcedTrackProvider>().fetch(RhythmMedia(track));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      activeSourcedTrack.updateTrack(sourcedTrack as SourcedTrack?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      final res = await Dio().get(
 | 
				
			||||||
 | 
					        sourcedTrack!.url,
 | 
				
			||||||
 | 
					        options: Options(
 | 
				
			||||||
 | 
					          headers: {
 | 
				
			||||||
 | 
					            ...request.headers,
 | 
				
			||||||
 | 
					            "User-Agent":
 | 
				
			||||||
 | 
					                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
 | 
				
			||||||
 | 
					            "host": Uri.parse(sourcedTrack.url).host,
 | 
				
			||||||
 | 
					            "Cache-Control": "max-age=0",
 | 
				
			||||||
 | 
					            "Connection": "keep-alive",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          responseType: ResponseType.stream,
 | 
				
			||||||
 | 
					          validateStatus: (status) => status! < 500,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      final audioStream =
 | 
				
			||||||
 | 
					          (res.data?.stream as Stream<Uint8List>?)?.asBroadcastStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      audioStream!.listen(
 | 
				
			||||||
 | 
					        (event) {},
 | 
				
			||||||
 | 
					        cancelOnError: true,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return Response(
 | 
				
			||||||
 | 
					        res.statusCode!,
 | 
				
			||||||
 | 
					        body: audioStream,
 | 
				
			||||||
 | 
					        context: {
 | 
				
			||||||
 | 
					          "shelf.io.buffer_output": false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        headers: res.headers.map,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      log('[PlaybackSever] Error: $e');
 | 
				
			||||||
 | 
					      return Response.internalServerError();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								lib/services/server/server.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								lib/services/server/server.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					import 'dart:developer';
 | 
				
			||||||
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					import 'dart:math' hide log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
 | 
					import 'package:get/get.dart' hide Response;
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/rhythm_media.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/server/routes/playback.dart';
 | 
				
			||||||
 | 
					import 'package:shelf/shelf.dart';
 | 
				
			||||||
 | 
					import 'package:shelf/shelf_io.dart';
 | 
				
			||||||
 | 
					import 'package:shelf_router/shelf_router.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PlaybackServerProvider extends GetxController {
 | 
				
			||||||
 | 
					  HttpServer? _server;
 | 
				
			||||||
 | 
					  Router? _router;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void onInit() {
 | 
				
			||||||
 | 
					    _initServer();
 | 
				
			||||||
 | 
					    super.onInit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _initServer() async {
 | 
				
			||||||
 | 
					    const pipeline = Pipeline();
 | 
				
			||||||
 | 
					    if (kDebugMode) {
 | 
				
			||||||
 | 
					      pipeline.addMiddleware(logRequests());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final port = Random().nextInt(17500) + 5000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RhythmMedia.serverPort = port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _router = Router();
 | 
				
			||||||
 | 
					    _router!.get("/ping", (Request request) => Response.ok("pong"));
 | 
				
			||||||
 | 
					    _router!.get(
 | 
				
			||||||
 | 
					      "/stream/<trackId>",
 | 
				
			||||||
 | 
					      Get.find<ServerPlaybackRoutesProvider>().getStreamTrackId,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _server = await serve(
 | 
				
			||||||
 | 
					      pipeline.addHandler(_router!.call),
 | 
				
			||||||
 | 
					      InternetAddress.anyIPv4,
 | 
				
			||||||
 | 
					      port,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log('[Playback] Playback server at http://${_server!.address.host}:${_server!.port}');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								lib/services/server/sourced_track.dart
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								lib/services/server/sourced_track.dart
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/audio_player/audio_player.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/local_track.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/services/sourced_track/sourced_track.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SourcedTrackProvider extends GetxController {
 | 
				
			||||||
 | 
					  Future<SourcedTrack?> fetch(RhythmMedia? media) async {
 | 
				
			||||||
 | 
					    final track = media?.track;
 | 
				
			||||||
 | 
					    if (track == null || track is LocalTrack) {
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final sourcedTrack = await SourcedTrack.fetchFromTrack(track: track);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return sourcedTrack;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
 | 
					import 'package:rhythm_box/providers/audio_player.dart';
 | 
				
			||||||
import 'package:rhythm_box/providers/spotify.dart';
 | 
					import 'package:rhythm_box/providers/spotify.dart';
 | 
				
			||||||
import 'package:rhythm_box/widgets/auto_cache_image.dart';
 | 
					import 'package:rhythm_box/widgets/auto_cache_image.dart';
 | 
				
			||||||
import 'package:skeletonizer/skeletonizer.dart';
 | 
					import 'package:skeletonizer/skeletonizer.dart';
 | 
				
			||||||
@@ -65,6 +66,10 @@ class _PlaylistTrackListState extends State<PlaylistTrackList> {
 | 
				
			|||||||
              item?.artists!.map((x) => x.name!).join(', ') ??
 | 
					              item?.artists!.map((x) => x.name!).join(', ') ??
 | 
				
			||||||
                  'Please stand by...',
 | 
					                  'Please stand by...',
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            onTap: () {
 | 
				
			||||||
 | 
					              if (item == null) return;
 | 
				
			||||||
 | 
					              Get.find<AudioPlayerProvider>().load([item], autoPlay: true);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,16 +5,22 @@
 | 
				
			|||||||
import FlutterMacOS
 | 
					import FlutterMacOS
 | 
				
			||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import audio_service
 | 
				
			||||||
import audio_session
 | 
					import audio_session
 | 
				
			||||||
 | 
					import device_info_plus
 | 
				
			||||||
import media_kit_libs_macos_audio
 | 
					import media_kit_libs_macos_audio
 | 
				
			||||||
import package_info_plus
 | 
					import package_info_plus
 | 
				
			||||||
import path_provider_foundation
 | 
					import path_provider_foundation
 | 
				
			||||||
 | 
					import shared_preferences_foundation
 | 
				
			||||||
import sqflite
 | 
					import sqflite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
 | 
					func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
 | 
				
			||||||
 | 
					  AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
 | 
				
			||||||
  AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
 | 
					  AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
 | 
				
			||||||
 | 
					  DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
 | 
				
			||||||
  MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin"))
 | 
					  MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin"))
 | 
				
			||||||
  FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
 | 
					  FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
 | 
				
			||||||
  PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
 | 
					  PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
 | 
				
			||||||
 | 
					  SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
 | 
				
			||||||
  SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
 | 
					  SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										228
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										228
									
								
								pubspec.lock
									
									
									
									
									
								
							@@ -9,6 +9,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "3.6.1"
 | 
					    version: "3.6.1"
 | 
				
			||||||
 | 
					  args:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: args
 | 
				
			||||||
 | 
					      sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.5.0"
 | 
				
			||||||
  async:
 | 
					  async:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -17,6 +25,30 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.11.0"
 | 
					    version: "2.11.0"
 | 
				
			||||||
 | 
					  audio_service:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: audio_service
 | 
				
			||||||
 | 
					      sha256: "9dd5ba7e77567b290c35908b1950d61485b4dfdd3a0ac398e98cfeec04651b75"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.18.15"
 | 
				
			||||||
 | 
					  audio_service_platform_interface:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: audio_service_platform_interface
 | 
				
			||||||
 | 
					      sha256: "8431a455dac9916cc9ee6f7da5620a666436345c906ad2ebb7fa41d18b3c1bf4"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.1.1"
 | 
				
			||||||
 | 
					  audio_service_web:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: audio_service_web
 | 
				
			||||||
 | 
					      sha256: "4cdc2127cd4562b957fb49227dc58e3303fafb09bde2573bc8241b938cf759d9"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.1.3"
 | 
				
			||||||
  audio_session:
 | 
					  audio_session:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -33,6 +65,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.1.1"
 | 
					    version: "2.1.1"
 | 
				
			||||||
 | 
					  build_cli_annotations:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: build_cli_annotations
 | 
				
			||||||
 | 
					      sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.1.0"
 | 
				
			||||||
  cached_network_image:
 | 
					  cached_network_image:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -113,8 +153,24 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.0.8"
 | 
					    version: "1.0.8"
 | 
				
			||||||
  dio:
 | 
					  device_info_plus:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: device_info_plus
 | 
				
			||||||
 | 
					      sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "10.1.2"
 | 
				
			||||||
 | 
					  device_info_plus_platform_interface:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: device_info_plus_platform_interface
 | 
				
			||||||
 | 
					      sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "7.0.1"
 | 
				
			||||||
 | 
					  dio:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: dio
 | 
					      name: dio
 | 
				
			||||||
      sha256: "0dfb6b6a1979dac1c1245e17cef824d7b452ea29bd33d3467269f9bef3715fb0"
 | 
					      sha256: "0dfb6b6a1979dac1c1245e17cef824d7b452ea29bd33d3467269f9bef3715fb0"
 | 
				
			||||||
@@ -198,6 +254,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "4.0.0"
 | 
					    version: "4.0.0"
 | 
				
			||||||
 | 
					  flutter_rust_bridge:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: flutter_rust_bridge
 | 
				
			||||||
 | 
					      sha256: "02720226035257ad0b571c1256f43df3e1556a499f6bcb004849a0faaa0e87f0"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.82.6"
 | 
				
			||||||
  flutter_test:
 | 
					  flutter_test:
 | 
				
			||||||
    dependency: "direct dev"
 | 
					    dependency: "direct dev"
 | 
				
			||||||
    description: flutter
 | 
					    description: flutter
 | 
				
			||||||
@@ -272,6 +336,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.2.2"
 | 
					    version: "1.2.2"
 | 
				
			||||||
 | 
					  http_methods:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: http_methods
 | 
				
			||||||
 | 
					      sha256: "6bccce8f1ec7b5d701e7921dca35e202d425b57e317ba1a37f2638590e29e566"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.1.1"
 | 
				
			||||||
  http_parser:
 | 
					  http_parser:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -440,6 +512,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.15.0"
 | 
					    version: "1.15.0"
 | 
				
			||||||
 | 
					  mime:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: mime
 | 
				
			||||||
 | 
					      sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.0.6"
 | 
				
			||||||
  oauth2:
 | 
					  oauth2:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -560,6 +640,22 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.1.8"
 | 
					    version: "2.1.8"
 | 
				
			||||||
 | 
					  pool:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: pool
 | 
				
			||||||
 | 
					      sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.5.1"
 | 
				
			||||||
 | 
					  puppeteer:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: puppeteer
 | 
				
			||||||
 | 
					      sha256: a6752d4f09b510ae41911bfd0997f957e723d38facf320dd9ee0e5661108744a
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "3.13.0"
 | 
				
			||||||
  rxdart:
 | 
					  rxdart:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -576,6 +672,94 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.0.2"
 | 
					    version: "1.0.2"
 | 
				
			||||||
 | 
					  shared_preferences:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences
 | 
				
			||||||
 | 
					      sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.3.2"
 | 
				
			||||||
 | 
					  shared_preferences_android:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences_android
 | 
				
			||||||
 | 
					      sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.3.2"
 | 
				
			||||||
 | 
					  shared_preferences_foundation:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences_foundation
 | 
				
			||||||
 | 
					      sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.5.2"
 | 
				
			||||||
 | 
					  shared_preferences_linux:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences_linux
 | 
				
			||||||
 | 
					      sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.4.1"
 | 
				
			||||||
 | 
					  shared_preferences_platform_interface:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences_platform_interface
 | 
				
			||||||
 | 
					      sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.4.1"
 | 
				
			||||||
 | 
					  shared_preferences_web:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences_web
 | 
				
			||||||
 | 
					      sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.4.2"
 | 
				
			||||||
 | 
					  shared_preferences_windows:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shared_preferences_windows
 | 
				
			||||||
 | 
					      sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.4.1"
 | 
				
			||||||
 | 
					  shelf:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shelf
 | 
				
			||||||
 | 
					      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.4.1"
 | 
				
			||||||
 | 
					  shelf_router:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shelf_router
 | 
				
			||||||
 | 
					      sha256: f5e5d492440a7fb165fe1e2e1a623f31f734d3370900070b2b1e0d0428d59864
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.1.4"
 | 
				
			||||||
 | 
					  shelf_static:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shelf_static
 | 
				
			||||||
 | 
					      sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.1.2"
 | 
				
			||||||
 | 
					  shelf_web_socket:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: shelf_web_socket
 | 
				
			||||||
 | 
					      sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.0.4"
 | 
				
			||||||
  skeletonizer:
 | 
					  skeletonizer:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -589,6 +773,14 @@ packages:
 | 
				
			|||||||
    description: flutter
 | 
					    description: flutter
 | 
				
			||||||
    source: sdk
 | 
					    source: sdk
 | 
				
			||||||
    version: "0.0.99"
 | 
					    version: "0.0.99"
 | 
				
			||||||
 | 
					  smtc_windows:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: smtc_windows
 | 
				
			||||||
 | 
					      sha256: "0fd64d0c6a0c8ea4ea7908d31195eadc8f6d45d5245159fc67259e9e8704100f"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.1.3"
 | 
				
			||||||
  source_span:
 | 
					  source_span:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -685,6 +877,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "0.7.2"
 | 
					    version: "0.7.2"
 | 
				
			||||||
 | 
					  tuple:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: tuple
 | 
				
			||||||
 | 
					      sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.0.2"
 | 
				
			||||||
  typed_data:
 | 
					  typed_data:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -710,7 +910,7 @@ packages:
 | 
				
			|||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.0.2"
 | 
					    version: "2.0.2"
 | 
				
			||||||
  uuid:
 | 
					  uuid:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: uuid
 | 
					      name: uuid
 | 
				
			||||||
      sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
 | 
					      sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
 | 
				
			||||||
@@ -741,6 +941,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.0.0"
 | 
					    version: "1.0.0"
 | 
				
			||||||
 | 
					  web_socket_channel:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: web_socket_channel
 | 
				
			||||||
 | 
					      sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.4.0"
 | 
				
			||||||
  win32:
 | 
					  win32:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -749,6 +957,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "5.5.4"
 | 
					    version: "5.5.4"
 | 
				
			||||||
 | 
					  win32_registry:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: win32_registry
 | 
				
			||||||
 | 
					      sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.1.4"
 | 
				
			||||||
  xdg_directories:
 | 
					  xdg_directories:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -765,6 +981,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "6.5.0"
 | 
					    version: "6.5.0"
 | 
				
			||||||
 | 
					  yaml:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: yaml
 | 
				
			||||||
 | 
					      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "3.1.2"
 | 
				
			||||||
  youtube_explode_dart:
 | 
					  youtube_explode_dart:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,15 @@ dependencies:
 | 
				
			|||||||
  piped_client: ^0.1.1
 | 
					  piped_client: ^0.1.1
 | 
				
			||||||
  flutter_broadcasts: ^0.4.0
 | 
					  flutter_broadcasts: ^0.4.0
 | 
				
			||||||
  audio_session: ^0.1.21
 | 
					  audio_session: ^0.1.21
 | 
				
			||||||
 | 
					  shared_preferences: ^2.3.2
 | 
				
			||||||
 | 
					  audio_service: ^0.18.15
 | 
				
			||||||
 | 
					  smtc_windows: ^0.1.3
 | 
				
			||||||
 | 
					  win32_registry: ^1.1.4
 | 
				
			||||||
 | 
					  uuid: ^4.4.2
 | 
				
			||||||
 | 
					  device_info_plus: ^10.1.2
 | 
				
			||||||
 | 
					  shelf: ^1.4.1
 | 
				
			||||||
 | 
					  shelf_router: ^1.1.4
 | 
				
			||||||
 | 
					  dio: ^5.6.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
  flutter_test:
 | 
					  flutter_test:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
 | 
					list(APPEND FLUTTER_FFI_PLUGIN_LIST
 | 
				
			||||||
  media_kit_native_event_loop
 | 
					  media_kit_native_event_loop
 | 
				
			||||||
 | 
					  smtc_windows
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(PLUGIN_BUNDLED_LIBRARIES)
 | 
					set(PLUGIN_BUNDLED_LIBRARIES)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user