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

@@ -9,6 +9,7 @@ import 'package:spotiflac_android/models/settings.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/providers/local_library_provider.dart';
import 'package:spotiflac_android/services/library_database.dart';
import 'package:spotiflac_android/services/discord_presence_service.dart';
import 'package:spotiflac_android/services/platform_bridge.dart';
import 'package:spotiflac_android/utils/adaptive_layout.dart';
import 'package:spotiflac_android/widgets/duplicate_review_sheet.dart';
@@ -910,8 +911,27 @@ class _LibrarySettingsPageState extends ConsumerState<LibrarySettingsPage> {
onChanged: (v) => ref
.read(settingsProvider.notifier)
.setPlaybackNormalization(v),
showDivider: false,
showDivider: Platform.isAndroid,
),
if (Platform.isAndroid)
ValueListenableBuilder<String>(
valueListenable: DiscordPresenceService.instance.status,
builder: (context, status, _) => SettingsSwitchItem(
icon: Icons.share_outlined,
title: context.l10n.discordRichPresence,
subtitle: status == 'discord_missing'
? context.l10n.discordPresenceMissing
: status == 'sdk_unavailable' ||
status == 'unavailable'
? context.l10n.discordPresenceUnavailable
: context.l10n.discordPresenceDescription,
value: settings.discordRichPresence,
onChanged: (value) => ref
.read(settingsProvider.notifier)
.setDiscordRichPresence(value),
showDivider: false,
),
),
],
),
),