feat: add opt-in Discord Rich Presence on Android

Use the official Discord Social SDK through JNI to share built-in player activity, clear presence when playback stops, and guard against late callbacks after disabling. Package the SDK optionally through SPOTIFLAC_DISCORD_SDK_DIR with license notices.

Credit: @itsmegaaa for the Rich Presence initiative and contribution in #575 and #576.

Validation: 15 Dart tests, scoped Flutter analysis, and one Android 16 ARM64 SDK/JNI instrumentation test passed. Visible presence on a signed-in Discord profile remains unverified.
This commit is contained in:
zarzet committed 2026-09-17 02:12:24 +07:00
1 parent b2ea07c41e
commit f0ed293d48
17 files changed
+662 -1

No files matched your search

+12
View File
@@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotiflac_android/l10n/l10n.dart';
import 'package:spotiflac_android/services/discord_presence_service.dart';
import 'package:spotiflac_android/providers/download_queue_provider.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/providers/repo_provider.dart';
@@ -79,6 +80,11 @@ class _MainShellState extends ConsumerState<MainShell>
setPlaybackNormalizationEnabled(
ref.read(settingsProvider).playbackNormalization,
);
unawaited(
DiscordPresenceService.instance.setEnabled(
ref.read(settingsProvider).discordRichPresence,
),
);
// Deezer & co. localize artist/genre names by IP unless told the app's
// language (issue #480).
unawaited(
@@ -631,6 +637,12 @@ class _MainShellState extends ConsumerState<MainShell>
@override
Widget build(BuildContext context) {
ref.listen(settingsProvider.select((s) => s.discordRichPresence), (
_,
enabled,
) {
unawaited(DiscordPresenceService.instance.setEnabled(enabled));
});
ref.listen(settingsProvider.select((s) => s.playbackNormalization), (
_,
enabled,