redesign app phase 2
This commit is contained in:
+84
-68
@@ -9,6 +9,7 @@ import 'package:finamp/screens/interaction_settings_screen.dart';
|
||||
import 'package:finamp/services/finamp_settings_helper.dart';
|
||||
import 'package:finamp/services/finamp_user_helper.dart';
|
||||
import 'package:finamp/services/offline_listen_helper.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
@@ -122,6 +123,10 @@ Future<void> _setupDownloader() async {
|
||||
GetIt.instance.registerSingleton(DownloadUpdateStream());
|
||||
GetIt.instance<DownloadUpdateStream>().setupSendPort();
|
||||
|
||||
if (!_isDownloaderSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await FlutterDownloader.initialize(debug: true);
|
||||
|
||||
@@ -132,6 +137,15 @@ Future<void> _setupDownloader() async {
|
||||
FlutterDownloader.registerCallback(_DummyCallback.callback);
|
||||
}
|
||||
|
||||
bool get _isDownloaderSupported {
|
||||
if (kIsWeb) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return defaultTargetPlatform == TargetPlatform.android ||
|
||||
defaultTargetPlatform == TargetPlatform.iOS;
|
||||
}
|
||||
|
||||
Future<void> setupHive() async {
|
||||
await Hive.initFlutter();
|
||||
Hive.registerAdapter(BaseItemDtoAdapter());
|
||||
@@ -301,76 +315,78 @@ class Finamp extends StatelessWidget {
|
||||
valueListenable: LocaleHelper.localeListener,
|
||||
builder: (_, __, ___) {
|
||||
return ValueListenableBuilder<Box<ThemeMode>>(
|
||||
valueListenable: ThemeModeHelper.themeModeListener,
|
||||
builder: (_, box, __) {
|
||||
return MaterialApp(
|
||||
title: "Finamp",
|
||||
routes: {
|
||||
SplashScreen.routeName: (context) => const SplashScreen(),
|
||||
UserSelector.routeName: (context) => const UserSelector(),
|
||||
ViewSelector.routeName: (context) => const ViewSelector(),
|
||||
MusicScreen.routeName: (context) => const MusicScreen(),
|
||||
AlbumScreen.routeName: (context) => const AlbumScreen(),
|
||||
ArtistScreen.routeName: (context) => const ArtistScreen(),
|
||||
AddToPlaylistScreen.routeName: (context) =>
|
||||
const AddToPlaylistScreen(),
|
||||
PlayerScreen.routeName: (context) => const PlayerScreen(),
|
||||
DownloadsScreen.routeName: (context) =>
|
||||
const DownloadsScreen(),
|
||||
DownloadsErrorScreen.routeName: (context) =>
|
||||
const DownloadsErrorScreen(),
|
||||
LogsScreen.routeName: (context) => const LogsScreen(),
|
||||
SettingsScreen.routeName: (context) =>
|
||||
const SettingsScreen(),
|
||||
TranscodingSettingsScreen.routeName: (context) =>
|
||||
const TranscodingSettingsScreen(),
|
||||
DownloadsSettingsScreen.routeName: (context) =>
|
||||
const DownloadsSettingsScreen(),
|
||||
AddDownloadLocationScreen.routeName: (context) =>
|
||||
const AddDownloadLocationScreen(),
|
||||
AudioServiceSettingsScreen.routeName: (context) =>
|
||||
const AudioServiceSettingsScreen(),
|
||||
InteractionSettingsScreen.routeName: (context) =>
|
||||
const InteractionSettingsScreen(),
|
||||
TabsSettingsScreen.routeName: (context) =>
|
||||
const TabsSettingsScreen(),
|
||||
LayoutSettingsScreen.routeName: (context) =>
|
||||
const LayoutSettingsScreen(),
|
||||
LanguageSelectionScreen.routeName: (context) =>
|
||||
const LanguageSelectionScreen(),
|
||||
},
|
||||
initialRoute: SplashScreen.routeName,
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.light,
|
||||
colorScheme: lightColorScheme,
|
||||
appBarTheme: const AppBarTheme(
|
||||
systemOverlayStyle: SystemUiOverlayStyle(
|
||||
statusBarBrightness: Brightness.light,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
valueListenable: ThemeModeHelper.themeModeListener,
|
||||
builder: (_, box, __) {
|
||||
return MaterialApp(
|
||||
title: "Finamp",
|
||||
routes: {
|
||||
SplashScreen.routeName: (context) => const SplashScreen(),
|
||||
UserSelector.routeName: (context) => const UserSelector(),
|
||||
ViewSelector.routeName: (context) => const ViewSelector(),
|
||||
MusicScreen.routeName: (context) => const MusicScreen(),
|
||||
AlbumScreen.routeName: (context) => const AlbumScreen(),
|
||||
ArtistScreen.routeName: (context) => const ArtistScreen(),
|
||||
AddToPlaylistScreen.routeName: (context) =>
|
||||
const AddToPlaylistScreen(),
|
||||
PlayerScreen.routeName: (context) => const PlayerScreen(),
|
||||
DownloadsScreen.routeName: (context) =>
|
||||
const DownloadsScreen(),
|
||||
DownloadsErrorScreen.routeName: (context) =>
|
||||
const DownloadsErrorScreen(),
|
||||
LogsScreen.routeName: (context) => const LogsScreen(),
|
||||
SettingsScreen.routeName: (context) =>
|
||||
const SettingsScreen(),
|
||||
TranscodingSettingsScreen.routeName: (context) =>
|
||||
const TranscodingSettingsScreen(),
|
||||
DownloadsSettingsScreen.routeName: (context) =>
|
||||
const DownloadsSettingsScreen(),
|
||||
AddDownloadLocationScreen.routeName: (context) =>
|
||||
const AddDownloadLocationScreen(),
|
||||
AudioServiceSettingsScreen.routeName: (context) =>
|
||||
const AudioServiceSettingsScreen(),
|
||||
InteractionSettingsScreen.routeName: (context) =>
|
||||
const InteractionSettingsScreen(),
|
||||
TabsSettingsScreen.routeName: (context) =>
|
||||
const TabsSettingsScreen(),
|
||||
LayoutSettingsScreen.routeName: (context) =>
|
||||
const LayoutSettingsScreen(),
|
||||
LanguageSelectionScreen.routeName: (context) =>
|
||||
const LanguageSelectionScreen(),
|
||||
},
|
||||
initialRoute: SplashScreen.routeName,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.light,
|
||||
colorScheme: lightColorScheme,
|
||||
appBarTheme: const AppBarTheme(
|
||||
systemOverlayStyle: SystemUiOverlayStyle(
|
||||
statusBarBrightness: Brightness.light,
|
||||
statusBarIconBrightness: Brightness.dark,
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: darkColorScheme,
|
||||
),
|
||||
themeMode: box.get("ThemeMode"),
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
// We awkwardly put English as the first supported locale so
|
||||
// that basicLocaleListResolution falls back to it instead of
|
||||
// the first language in supportedLocales (Arabic as of writing)
|
||||
localeListResolutionCallback: (locales, supportedLocales) =>
|
||||
basicLocaleListResolution(locales,
|
||||
[const Locale("en")].followedBy(supportedLocales)),
|
||||
locale: LocaleHelper.locale,
|
||||
);
|
||||
},
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
useMaterial3: true,
|
||||
brightness: Brightness.dark,
|
||||
colorScheme: darkColorScheme,
|
||||
),
|
||||
themeMode: box.get("ThemeMode"),
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
// We awkwardly put English as the first supported locale so
|
||||
// that basicLocaleListResolution falls back to it instead of
|
||||
// the first language in supportedLocales (Arabic as of writing)
|
||||
localeListResolutionCallback: (locales, supportedLocales) =>
|
||||
basicLocaleListResolution(locales,
|
||||
[const Locale("en")].followedBy(supportedLocales)),
|
||||
locale: LocaleHelper.locale,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
+279
-30
@@ -52,6 +52,7 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
.where((element) => element.value)
|
||||
.elementAt(_tabController!.index)
|
||||
.key;
|
||||
setState(() {});
|
||||
if (_tabController != null &&
|
||||
(tabKey == TabContentType.songs ||
|
||||
tabKey == TabContentType.artists ||
|
||||
@@ -186,7 +187,11 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
return true;
|
||||
},
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
title: isSearching
|
||||
? TextField(
|
||||
controller: textEditingController,
|
||||
@@ -200,25 +205,19 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
.searchFieldLabel,
|
||||
),
|
||||
)
|
||||
: Text(_finampUserHelper.currentUser?.currentView?.name ??
|
||||
AppLocalizations.of(context)!.music),
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
tabs: tabs
|
||||
.map((tabType) => Tab(
|
||||
text: tabType
|
||||
.toLocalisedString(context)
|
||||
.toUpperCase(),
|
||||
))
|
||||
.toList(),
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
),
|
||||
: null,
|
||||
leading: isSearching
|
||||
? BackButton(
|
||||
onPressed: () => _stopSearching(),
|
||||
)
|
||||
: null,
|
||||
: Builder(
|
||||
builder: (context) => IconButton.filledTonal(
|
||||
icon: const Icon(Icons.menu_rounded),
|
||||
onPressed: () => Scaffold.of(context).openDrawer(),
|
||||
tooltip: MaterialLocalizations.of(context)
|
||||
.openAppDrawerTooltip,
|
||||
),
|
||||
),
|
||||
actions: isSearching
|
||||
? [
|
||||
IconButton(
|
||||
@@ -242,8 +241,8 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
),
|
||||
IconButton(
|
||||
icon: finampSettings.isFavourite
|
||||
? const Icon(Icons.favorite)
|
||||
: const Icon(Icons.favorite_outline),
|
||||
? const Icon(Icons.favorite_rounded)
|
||||
: const Icon(Icons.favorite_outline_rounded),
|
||||
onPressed: finampSettings.isOffline
|
||||
? null
|
||||
: () => FinampSettingsHelper.setIsFavourite(
|
||||
@@ -251,7 +250,7 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
tooltip: AppLocalizations.of(context)!.favourites,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.search),
|
||||
icon: const Icon(Icons.search_rounded),
|
||||
onPressed: () => setState(() {
|
||||
isSearching = true;
|
||||
}),
|
||||
@@ -266,18 +265,91 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: getFloatingActionButton(),
|
||||
),
|
||||
body: TabBarView(
|
||||
controller: _tabController,
|
||||
children: tabs
|
||||
.map((tabType) => MusicScreenTabView(
|
||||
tabContentType: tabType,
|
||||
searchTerm: searchQuery,
|
||||
body: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer
|
||||
.withOpacity(0.45),
|
||||
Theme.of(context).colorScheme.surface,
|
||||
Theme.of(context).colorScheme.surface,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Column(
|
||||
children: [
|
||||
if (!isSearching)
|
||||
_MusicHeroHeader(
|
||||
title: _finampUserHelper
|
||||
.currentUser?.currentView?.name ??
|
||||
AppLocalizations.of(context)!.music,
|
||||
activeTab: tabs
|
||||
.elementAt(_tabController!.index)
|
||||
.toLocalisedString(context),
|
||||
isFavourite: finampSettings.isFavourite,
|
||||
sortBy: finampSettings.getTabSortBy(tabType),
|
||||
sortOrder: finampSettings.getSortOrder(tabType),
|
||||
view: _finampUserHelper.currentUser?.currentView,
|
||||
))
|
||||
.toList(),
|
||||
isOffline: finampSettings.isOffline,
|
||||
onShuffle: () async {
|
||||
try {
|
||||
await _audioServiceHelper.shuffleAll(
|
||||
FinampSettingsHelper
|
||||
.finampSettings.isFavourite,
|
||||
);
|
||||
} catch (e) {
|
||||
errorSnackbar(e, context);
|
||||
}
|
||||
},
|
||||
),
|
||||
_ModernMusicTabBar(
|
||||
controller: _tabController!,
|
||||
tabs: tabs.toList(),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.fromLTRB(12, 8, 12, 0),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(28),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.shadow
|
||||
.withOpacity(0.08),
|
||||
blurRadius: 24,
|
||||
offset: const Offset(0, -6),
|
||||
),
|
||||
],
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: tabs
|
||||
.map((tabType) => MusicScreenTabView(
|
||||
tabContentType: tabType,
|
||||
searchTerm: searchQuery,
|
||||
isFavourite: finampSettings.isFavourite,
|
||||
sortBy: finampSettings
|
||||
.getTabSortBy(tabType),
|
||||
sortOrder: finampSettings
|
||||
.getSortOrder(tabType),
|
||||
view: _finampUserHelper
|
||||
.currentUser?.currentView,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -286,4 +358,181 @@ class _MusicScreenState extends State<MusicScreen>
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _MusicHeroHeader extends StatelessWidget {
|
||||
const _MusicHeroHeader({
|
||||
required this.title,
|
||||
required this.activeTab,
|
||||
required this.isFavourite,
|
||||
required this.isOffline,
|
||||
required this.onShuffle,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final String activeTab;
|
||||
final bool isFavourite;
|
||||
final bool isOffline;
|
||||
final VoidCallback onShuffle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 86, 20, 12),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(32),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
colorScheme.primary.withOpacity(0.95),
|
||||
colorScheme.tertiary.withOpacity(0.78),
|
||||
],
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: colorScheme.primary.withOpacity(0.28),
|
||||
blurRadius: 34,
|
||||
offset: const Offset(0, 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
isOffline ? 'Offline library' : 'Your Jellyfin music',
|
||||
style: theme.textTheme.labelLarge?.copyWith(
|
||||
color: colorScheme.onPrimary.withOpacity(0.76),
|
||||
letterSpacing: 0.6,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
title,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: theme.textTheme.headlineMedium?.copyWith(
|
||||
color: colorScheme.onPrimary,
|
||||
fontWeight: FontWeight.w800,
|
||||
height: 1.04,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: [
|
||||
FilledButton.icon(
|
||||
onPressed: onShuffle,
|
||||
icon: const Icon(Icons.shuffle_rounded),
|
||||
label: const Text('Shuffle'),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: colorScheme.onPrimary,
|
||||
foregroundColor: colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
_HeroChip(
|
||||
icon: isFavourite
|
||||
? Icons.favorite_rounded
|
||||
: Icons.library_music_rounded,
|
||||
label: isFavourite ? 'Favourites' : activeTab,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _HeroChip extends StatelessWidget {
|
||||
const _HeroChip({required this.icon, required this.label});
|
||||
|
||||
final IconData icon;
|
||||
final String label;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.onPrimary.withOpacity(0.14),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: colorScheme.onPrimary.withOpacity(0.16)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(icon, color: colorScheme.onPrimary, size: 18),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: colorScheme.onPrimary,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ModernMusicTabBar extends StatelessWidget {
|
||||
const _ModernMusicTabBar({required this.controller, required this.tabs});
|
||||
|
||||
final TabController controller;
|
||||
final List<TabContentType> tabs;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.surface.withOpacity(0.7),
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border:
|
||||
Border.all(color: colorScheme.outlineVariant.withOpacity(0.4)),
|
||||
),
|
||||
child: TabBar(
|
||||
controller: controller,
|
||||
tabs: tabs
|
||||
.map((tabType) => Tab(text: tabType.toLocalisedString(context)))
|
||||
.toList(),
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
dividerColor: Colors.transparent,
|
||||
indicatorSize: TabBarIndicatorSize.tab,
|
||||
indicator: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
labelColor: colorScheme.onPrimary,
|
||||
unselectedLabelColor: colorScheme.onSurfaceVariant,
|
||||
labelStyle: Theme.of(context).textTheme.labelLarge?.copyWith(
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
unselectedLabelStyle:
|
||||
Theme.of(context).textTheme.labelLarge?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
padding: const EdgeInsets.all(4),
|
||||
labelPadding: const EdgeInsets.symmetric(horizontal: 18),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class ChopperAggregateLogger implements Logger {
|
||||
}
|
||||
|
||||
void onEndRequest(chopper.Request request) {
|
||||
info(_requests.remove(request)?.toString().trim());
|
||||
info(_censorSensitiveLog(_requests.remove(request)?.toString().trim()));
|
||||
}
|
||||
|
||||
void onStartResponse(chopper.Response response) {
|
||||
@@ -65,7 +65,18 @@ class ChopperAggregateLogger implements Logger {
|
||||
}
|
||||
|
||||
void onEndResponse(chopper.Response response) {
|
||||
info(_responses.remove(response)?.toString().trim());
|
||||
info(_censorSensitiveLog(_responses.remove(response)?.toString().trim()));
|
||||
}
|
||||
|
||||
String? _censorSensitiveLog(String? message) {
|
||||
if (message == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return message
|
||||
.replaceAll(RegExp(r'Token="[^"]*"'), 'Token="TOKEN"')
|
||||
.replaceAll(RegExp(r'"Username":"[^"]*"'), '"Username":"USER"')
|
||||
.replaceAll(RegExp(r'"Pw":"[^"]*"'), '"Pw":"PASSWORD"');
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:android_id/android_id.dart';
|
||||
import 'package:chopper/chopper.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:finamp/services/http_aggregate_logging_interceptor.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
@@ -422,19 +423,28 @@ Future<String> getAuthHeader() async {
|
||||
}
|
||||
|
||||
authHeader = '${authHeader}Client="Finamp", ';
|
||||
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
if (Platform.isAndroid) {
|
||||
if (kIsWeb) {
|
||||
authHeader = '${authHeader}Device="Web Browser", ';
|
||||
authHeader = '${authHeader}DeviceId="finamp-web", ';
|
||||
} else if (Platform.isAndroid) {
|
||||
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
AndroidDeviceInfo androidDeviceInfo = await deviceInfo.androidInfo;
|
||||
authHeader = '${authHeader}Device="${androidDeviceInfo.model}", ';
|
||||
final androidId = await const AndroidId().getId();
|
||||
authHeader = '${authHeader}DeviceId="$androidId", ';
|
||||
} else if (Platform.isIOS) {
|
||||
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
|
||||
authHeader = '${authHeader}Device="${iosDeviceInfo.name}", ';
|
||||
authHeader =
|
||||
'${authHeader}DeviceId="${iosDeviceInfo.identifierForVendor}", ';
|
||||
} else {
|
||||
throw "getAuthHeader() only supports Android and iOS";
|
||||
final deviceName = "Finamp ${Platform.operatingSystem}";
|
||||
final deviceId =
|
||||
"finamp-${Platform.operatingSystem}-${Platform.localHostname}";
|
||||
|
||||
authHeader = '${authHeader}Device="$deviceName", ';
|
||||
authHeader = '${authHeader}DeviceId="$deviceId", ';
|
||||
}
|
||||
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
@@ -702,21 +702,12 @@ class MusicPlayerBackgroundTask extends BaseAudioHandler {
|
||||
}
|
||||
|
||||
Future<Uri> _songUri(MediaItem mediaItem) async {
|
||||
// We need the platform to be Android or iOS to get device info
|
||||
assert(Platform.isAndroid || Platform.isIOS,
|
||||
"_songUri() only supports Android and iOS");
|
||||
|
||||
// When creating the MediaItem (usually in AudioServiceHelper), we specify
|
||||
// whether or not to transcode. We used to pull from FinampSettings here,
|
||||
// but since audio_service runs in an isolate (or at least, it does until
|
||||
// 0.18), the value would be wrong if changed while a song was playing since
|
||||
// Hive is bad at multi-isolate stuff.
|
||||
|
||||
final androidId =
|
||||
Platform.isAndroid ? await const AndroidId().getId() : null;
|
||||
final iosDeviceInfo =
|
||||
Platform.isIOS ? await DeviceInfoPlugin().iosInfo : null;
|
||||
|
||||
final parsedBaseUrl = Uri.parse(_finampUserHelper.currentUser!.baseUrl);
|
||||
|
||||
List<String> builtPath = List.from(parsedBaseUrl.pathSegments);
|
||||
@@ -795,4 +786,4 @@ String _jellyfinRepeatModeFromRepeatMode(AudioServiceRepeatMode repeatMode) {
|
||||
case AudioServiceRepeatMode.group:
|
||||
return "RepeatAll";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user