mangayomi-mirror/lib/utils/discord_rpc.dart
2025-11-08 23:57:32 +01:00

233 lines
6.3 KiB
Dart

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
bool rpcShowReadingWatchingProgress = false;
/// 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<void> initialize() async {
await FlutterDiscordRPC.initialize(applicationId);
}
Future<void> 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<void> showIdleText() async {
await updateActivity(
details: "Idle",
state: "-----",
assets: const RPCAssets(largeImage: "app-icon", largeText: "Mangayomi"),
);
}
Future<void> 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<void> showLargeImage() async {
await updateActivity(
assets: const RPCAssets(largeImage: "app-icon", largeText: "Mangayomi"),
);
}
Future<void> showSmallImage(String largeImage, String largeText) async {
await updateActivity(
assets: RPCAssets(
largeImage: largeImage,
largeText: largeText,
smallImage: "app-icon",
smallText: "Mangayomi",
),
);
}
Future<void> showOriginalTimestamp() async {
await updateActivity(timestamps: RPCTimestamps(start: startAt));
}
Future<void> 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<void> updateActivity({
String? state,
String? details,
RPCTimestamps? timestamps,
RPCParty? party,
RPCAssets? assets,
RPCSecrets? secrets,
List<RPCButton>? 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<void> disconnect() async {
if (!FlutterDiscordRPC.instance.isConnected) return;
await FlutterDiscordRPC.instance.disconnect();
}
Future<void> 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<RPCButton>? 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,
);
}
}