import 'package:flutter_discord_rpc_fork/flutter_discord_rpc.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/modules/more/providers/incognito_mode_state_provider.dart'; import 'package:mangayomi/modules/more/settings/general/providers/general_state_provider.dart'; class DiscordRPC { /// Id of the Discord Application final String applicationId; /// Whether it should reconnect to the discord client final bool autoRetry; /// Seconds between each attempt to reconnect final int retryDelayInSeconds; /// Start timestamp in millis final int startAt = DateTime.timestamp().millisecondsSinceEpoch; /// Temp var late bool rpcShowReadingWatchingProgress; /// Instance of the current RPC activity final RpcActivity activity = RpcActivity( assets: const RPCAssets(largeImage: "app-icon", largeText: "Mangayomi"), buttons: [ const RPCButton( label: "Get Mangayomi", url: "https://github.com/kodjodevf/mangayomi", ), const RPCButton( label: "Join us", url: "https://discord.com/invite/EjfBuYahsP", ), ], details: "Idle", state: "-----", timestamps: RPCTimestamps( start: DateTime.timestamp().millisecondsSinceEpoch, ), activityType: ActivityType.watching, ); DiscordRPC({ required this.applicationId, this.autoRetry = true, this.retryDelayInSeconds = 10, }); Future initialize() async { await FlutterDiscordRPC.initialize(applicationId); } Future connect(WidgetRef ref) async { final enableDiscordRpc = ref.read(enableDiscordRpcStateProvider); final incognitoMode = ref.read(incognitoModeStateProvider); final hideDiscordRpcInIncognito = ref.read( hideDiscordRpcInIncognitoStateProvider, ); rpcShowReadingWatchingProgress = ref.read( rpcShowReadingWatchingProgressStateProvider, ); if (enableDiscordRpc && (!hideDiscordRpcInIncognito || !incognitoMode)) { await FlutterDiscordRPC.instance.connect( autoRetry: autoRetry, retryDelay: Duration(seconds: retryDelayInSeconds), ); await Future.delayed(Duration(seconds: 3)); showIdleText(); } } Future showIdleText() async { await updateActivity( details: "Idle", state: "-----", assets: const RPCAssets(largeImage: "app-icon", largeText: "Mangayomi"), ); } Future showChapterDetails(WidgetRef ref, Chapter chapter) async { final status = chapter.manga.value!.itemType == ItemType.anime ? "Watching" : "Reading"; final title = chapter.manga.value!.name; final chapterTitle = chapter.name; final imageUrl = chapter.manga.value!.imageUrl; final rpcShowTitle = ref.read(rpcShowTitleStateProvider); final rpcShowCoverImage = ref.read(rpcShowCoverImageStateProvider); await updateActivity( details: rpcShowTitle ? "$status $title" : "Idle", state: rpcShowTitle && rpcShowReadingWatchingProgress ? chapterTitle : "-----", assets: rpcShowCoverImage && imageUrl != null && imageUrl.startsWith("http") ? RPCAssets( largeImage: imageUrl, largeText: rpcShowTitle ? chapter.manga.value!.name : "-----", smallImage: "app-icon", smallText: "Mangayomi", ) : const RPCAssets(largeImage: "app-icon", largeText: "Mangayomi"), ); } Future showLargeImage() async { await updateActivity( assets: const RPCAssets(largeImage: "app-icon", largeText: "Mangayomi"), ); } Future showSmallImage(String largeImage, String largeText) async { await updateActivity( assets: RPCAssets( largeImage: largeImage, largeText: largeText, smallImage: "app-icon", smallText: "Mangayomi", ), ); } Future showOriginalTimestamp() async { await updateActivity(timestamps: RPCTimestamps(start: startAt)); } Future updateChapterTimestamp( Duration position, Duration duration, ) async { if (!rpcShowReadingWatchingProgress) { return; } await updateActivity( timestamps: RPCTimestamps( start: DateTime.timestamp().subtract(position).millisecondsSinceEpoch, end: DateTime.timestamp() .subtract(position) .add(duration) .millisecondsSinceEpoch, ), ); } Future updateActivity({ String? state, String? details, RPCTimestamps? timestamps, RPCParty? party, RPCAssets? assets, RPCSecrets? secrets, List? buttons, ActivityType? activityType, }) async { if (!FlutterDiscordRPC.instance.isConnected) { return; } if (state != null) { activity.state = state; } if (details != null) { activity.details = details; } if (timestamps != null) { activity.timestamps = timestamps; } if (party != null) { activity.party = party; } if (assets != null) { activity.assets = assets; } if (secrets != null) { activity.secrets = secrets; } if (buttons != null) { activity.buttons = buttons; } if (activityType != null) { activity.activityType = activityType; } await FlutterDiscordRPC.instance.setActivity( activity: activity.toRPCActivity(), ); } Future disconnect() async { if (!FlutterDiscordRPC.instance.isConnected) return; await FlutterDiscordRPC.instance.disconnect(); } Future destroy() async { await FlutterDiscordRPC.instance.disconnect(); await FlutterDiscordRPC.instance.dispose(); } } class RpcActivity { String? state; String? details; RPCTimestamps? timestamps; RPCParty? party; RPCAssets? assets; RPCSecrets? secrets; List? buttons; ActivityType? activityType; RpcActivity({ this.state, this.details, this.timestamps, this.party, this.assets, this.secrets, this.buttons, this.activityType, }); RPCActivity toRPCActivity() { return RPCActivity( state: state, details: details, timestamps: timestamps, party: party, assets: assets, secrets: secrets, buttons: buttons, activityType: activityType, ); } }