Skip to content

Commit

Permalink
fix: android notification media controls and improve player style (#1058
Browse files Browse the repository at this point in the history
)
  • Loading branch information
Feichtmeier authored Nov 27, 2024
1 parent a788794 commit af273cc
Show file tree
Hide file tree
Showing 9 changed files with 657 additions and 61 deletions.
62 changes: 14 additions & 48 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,41 +1,18 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<!--
Internet access permissions.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<!--
Media access permissions.
Android 13 or higher.
https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
-->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- ALSO ADD THIS PERMISSION IF TARGETING SDK 34 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<!-- Android 13+ notification -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- !DANGER! Delete, update songs/playlists -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

<!-- Android 12 or below -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<!-- Android 13 or greater -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

<!-- Permissions options for the `access notification policy` group -->
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />


<!-- Permissions options for the `notification` group -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
Expand All @@ -50,10 +27,6 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
Expand All @@ -64,29 +37,22 @@
</intent-filter>
</activity>

<!-- ADD THIS "SERVICE" element -->
<service android:name="com.ryanheise.audioservice.AudioService"
android:foregroundServiceType="mediaPlayback"
android:exported="true" tools:ignore="Instantiatable">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
android:foregroundServiceType="mediaPlayback"
android:exported="true" tools:ignore="Instantiatable">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>

<!-- ADD THIS "RECEIVER" element -->
<receiver android:name="com.ryanheise.audioservice.MediaButtonReceiver"
android:exported="true" tools:ignore="Instantiatable">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<meta-data
android:name="flutterEmbedding"
android:value="2" />

</application>


</manifest>
8 changes: 6 additions & 2 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,12 @@ class _MobileMusicPodAppState extends State<_MobileMusicPodApp> {
},
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.values[themeIndex],
theme: phoenix.lightTheme,
darkTheme: phoenix.darkTheme,
theme: phoenix.lightTheme.copyWith(
navigationBarTheme: navigationBarTheme(theme: phoenix.lightTheme),
),
darkTheme: phoenix.darkTheme.copyWith(
navigationBarTheme: navigationBarTheme(theme: phoenix.darkTheme),
),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: supportedLocales,
onGenerateTitle: (context) => kAppTitle,
Expand Down
9 changes: 8 additions & 1 deletion lib/app/view/mobile_navigation_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import 'package:watch_it/watch_it.dart';

import '../../common/data/audio_type.dart';
import '../../common/view/icons.dart';
import '../../common/view/theme.dart';
import '../../common/view/ui_constants.dart';
import '../../constants.dart';
import '../../extensions/build_context_x.dart';
import '../../l10n/l10n.dart';
Expand All @@ -20,17 +22,21 @@ class MobilePlayerAndNavigationBar extends StatelessWidget with WatchItMixin {

@override
Widget build(BuildContext context) {
final fullWindowMode =
watchPropertyValue((AppModel m) => m.fullWindowMode) ?? false;

return RepaintBoundary(
child: Material(
color: context.theme.cardColor,
child: watchPropertyValue((AppModel m) => m.fullWindowMode) ?? false
child: fullWindowMode
? const FullHeightPlayer(
playerPosition: PlayerPosition.fullWindow,
)
: const Column(
mainAxisSize: MainAxisSize.min,
children: [
BottomPlayer(),
SizedBox(height: kMediumSpace),
MobileNavigationBar(),
],
),
Expand Down Expand Up @@ -76,6 +82,7 @@ class MobileNavigationBar extends StatelessWidget with WatchItMixin {
};

return NavigationBar(
height: bottomPlayerHeight - 25,
backgroundColor: context.theme.cardColor,
selectedIndex: selectedPageId == null
? 0
Expand Down
2 changes: 1 addition & 1 deletion lib/app/view/music_pod_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class MusicPodScaffold extends StatelessWidget {
@override
Widget build(BuildContext context) => Scaffold(
resizeToAvoidBottomInset: isMobile ? false : null,
body: isMobile ? SafeArea(child: body) : body,
body: body,
appBar: appBar,
bottomNavigationBar:
isMobile ? const MobilePlayerAndNavigationBar() : null,
Expand Down
6 changes: 6 additions & 0 deletions lib/common/view/header_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ class HeaderBar extends StatelessWidget
}

if (isMobile) {
final fullWindowMode =
watchPropertyValue((AppModel m) => m.fullWindowMode) == true;
return AppBar(
systemOverlayStyle: systemOverlayStyle(
theme: context.theme,
fullWindowMode: fullWindowMode,
),
backgroundColor: backgroundColor,
titleSpacing: titleSpacing,
centerTitle: true,
Expand Down
36 changes: 35 additions & 1 deletion lib/common/view/theme.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:yaru/yaru.dart';

import '../../app_config.dart';
Expand Down Expand Up @@ -280,7 +281,40 @@ double get inputHeight => isMobile

double get audioCardDimension => kAudioCardDimension - (isMobile ? 15 : 0);

double get bottomPlayerHeight => isMobile ? 80.0 : 90.0;
double get bottomPlayerHeight => isMobile ? 75.0 : 90.0;

NavigationBarThemeData navigationBarTheme({required ThemeData theme}) =>
theme.navigationBarTheme.copyWith(
iconTheme: WidgetStatePropertyAll(
theme.iconTheme.copyWith(
size: 18,
applyTextScaling: true,
),
),
);

SystemUiOverlayStyle systemOverlayStyle({
required ThemeData theme,
required bool fullWindowMode,
}) {
return theme.colorScheme.isLight
? SystemUiOverlayStyle.dark.copyWith(
systemNavigationBarColor:
(fullWindowMode ? Colors.transparent : theme.cardColor),
statusBarColor: (fullWindowMode
? Colors.transparent
: theme.scaffoldBackgroundColor),
statusBarBrightness: theme.brightness,
)
: SystemUiOverlayStyle.light.copyWith(
systemNavigationBarColor:
(fullWindowMode ? Colors.transparent : theme.cardColor),
statusBarColor: (fullWindowMode
? Colors.transparent
: theme.scaffoldBackgroundColor),
statusBarBrightness: theme.brightness,
);
}

List<Widget> space({
double widthGap = kSmallestSpace,
Expand Down
1 change: 1 addition & 0 deletions lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const kAppName = 'musicpod';
const kAppTitle = 'MusicPod';
const kAppId = 'org.feichtmeier.Musicpod';
const kAndroidAppId = 'org.feichtmeier.musicpod';
const kDiscordApplicationId = '1235321910221602837';
const kLinuxDBusName = 'org.mpris.MediaPlayer2.musicpod';
const kAndroidChannelId = 'org.feichtmeier.musicpod.channel.audio';
Expand Down
7 changes: 6 additions & 1 deletion lib/player/player_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -577,9 +577,12 @@ class PlayerService {

Future<void> _initAudioService() async {
_audioHandler = await AudioService.init(
config: const AudioServiceConfig(
config: AudioServiceConfig(
androidNotificationOngoing: true,
androidNotificationChannelName: kAppName,
androidNotificationChannelId: Platform.isAndroid ? kAndroidAppId : null,
androidStopForegroundOnPause: false,
androidNotificationChannelDescription: 'MusicPod Media Controls',
),
builder: () {
return PlayerServiceAudioHandler(
Expand Down Expand Up @@ -669,6 +672,8 @@ class PlayerService {
_audioHandler!.playbackState.value.copyWith(
playing: playing,
controls: _determineMediaControls(playing),
processingState:
playing ? AudioProcessingState.ready : AudioProcessingState.idle,
),
);
} else if (_smtc != null) {
Expand Down
Loading

0 comments on commit af273cc

Please sign in to comment.