aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/misc/RemindersConfig.java21
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/storage/Storage.java4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/reminders/Reminder.kt37
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt249
6 files changed, 318 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
index fbd93a4d8..f021fe326 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt
@@ -63,6 +63,7 @@ import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager
import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager
import at.hannibal2.skyhanni.features.misc.limbo.LimboTimeTracker
import at.hannibal2.skyhanni.features.misc.massconfiguration.DefaultConfigFeatures
+import at.hannibal2.skyhanni.features.misc.reminders.ReminderManager
import at.hannibal2.skyhanni.features.misc.update.UpdateManager
import at.hannibal2.skyhanni.features.misc.visualwords.VisualWordGui
import at.hannibal2.skyhanni.features.rift.area.westvillage.VerminTracker
@@ -170,6 +171,7 @@ object Commands {
{ DefaultConfigFeatures.onCommand(it) },
DefaultConfigFeatures::onComplete,
)
+ registerCommand("shremind", "Set a reminder for yourself") { ReminderManager.command(it) }
registerCommand("shwords", "Opens the config list for modifying visual words") { openVisualWords() }
}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java
index 95d3281ec..54f0c7c50 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java
@@ -108,6 +108,11 @@ public class MiscConfig {
public PatcherCoordsWaypointConfig patcherCoordsWaypoint = new PatcherCoordsWaypointConfig();
@Expose
+ @ConfigOption(name = "Reminders", desc = "")
+ @Accordion
+ public RemindersConfig reminders = new RemindersConfig();
+
+ @Expose
@ConfigOption(name = "Show Outside SkyBlock", desc = "Show these features outside of SkyBlock.")
@ConfigEditorDraggableList
public List<OutsideSbFeature> showOutsideSB = new ArrayList<>();
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/RemindersConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/RemindersConfig.java
new file mode 100644
index 000000000..fb7a9b785
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/RemindersConfig.java
@@ -0,0 +1,21 @@
+package at.hannibal2.skyhanni.config.features.misc;
+
+import com.google.gson.annotations.Expose;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider;
+import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;
+
+public class RemindersConfig {
+ @Expose
+ @ConfigOption(name = "Auto Delete Reminders", desc = "Automatically deletes reminders after they have been shown once.")
+ @ConfigEditorBoolean
+ public boolean autoDeleteReminders = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Reminder Interval",
+ desc = "The interval in minutes in which reminders are shown again, after they have been shown once."
+ )
+ @ConfigEditorSlider(minValue = 0f, maxValue = 60f, minStep = 1f)
+ public float interval = 5f;
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/Storage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/Storage.java
index c37ba1dd0..252c9d8bb 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/storage/Storage.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/storage/Storage.java
@@ -1,5 +1,6 @@
package at.hannibal2.skyhanni.config.storage;
+import at.hannibal2.skyhanni.features.misc.reminders.Reminder;
import at.hannibal2.skyhanni.features.misc.visualwords.VisualWord;
import at.hannibal2.skyhanni.utils.LorenzVec;
import at.hannibal2.skyhanni.utils.tracker.SkyHanniTracker;
@@ -50,4 +51,7 @@ public class Storage {
@Expose
public List<String> blacklistedUsers = new ArrayList<>();
+
+ @Expose
+ public Map<String, Reminder> reminders = new HashMap<>();
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/Reminder.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/Reminder.kt
new file mode 100644
index 000000000..4dd08eafd
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/Reminder.kt
@@ -0,0 +1,37 @@
+package at.hannibal2.skyhanni.features.misc.reminders
+
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
+import com.google.gson.annotations.Expose
+import java.time.Instant
+import java.time.LocalDate
+import java.time.ZoneId
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
+import java.util.Locale
+import kotlin.time.Duration
+
+data class Reminder(
+ @Expose var reason: String,
+ @Expose var remindAt: SimpleTimeMark,
+ @Expose var lastReminder: SimpleTimeMark = SimpleTimeMark.farPast(),
+) {
+
+ fun formatShort(): String {
+ val time = getRemindTime()
+ val date = time.toLocalDate()
+ if (date.isEqual(LocalDate.now())) {
+ return time.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withDefaultLocale())
+ }
+ return date.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withDefaultLocale())
+ }
+
+ fun formatFull(): String = getRemindTime().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withDefaultLocale())
+
+ fun shouldRemind(interval: Duration) = remindAt.isInPast() && lastReminder.passedSince() >= interval
+
+ private fun getRemindTime(): ZonedDateTime = Instant.ofEpochMilli(remindAt.toMillis()).atZone(ZoneId.systemDefault())
+
+ private fun DateTimeFormatter.withDefaultLocale(): DateTimeFormatter = withLocale(Locale.getDefault())
+}
+
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt
new file mode 100644
index 000000000..472aac2de
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt
@@ -0,0 +1,249 @@
+package at.hannibal2.skyhanni.features.misc.reminders
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.SecondPassedEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.ChatUtils
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
+import at.hannibal2.skyhanni.utils.StringUtils
+import at.hannibal2.skyhanni.utils.TimeUtils
+import at.hannibal2.skyhanni.utils.TimeUtils.format
+import at.hannibal2.skyhanni.utils.TimeUtils.minutes
+import at.hannibal2.skyhanni.utils.chat.Text
+import at.hannibal2.skyhanni.utils.chat.Text.asComponent
+import at.hannibal2.skyhanni.utils.chat.Text.center
+import at.hannibal2.skyhanni.utils.chat.Text.command
+import at.hannibal2.skyhanni.utils.chat.Text.fitToChat
+import at.hannibal2.skyhanni.utils.chat.Text.hover
+import at.hannibal2.skyhanni.utils.chat.Text.send
+import at.hannibal2.skyhanni.utils.chat.Text.style
+import at.hannibal2.skyhanni.utils.chat.Text.suggest
+import at.hannibal2.skyhanni.utils.chat.Text.wrap
+import net.minecraft.util.EnumChatFormatting
+import net.minecraft.util.IChatComponent
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+
+@SkyHanniModule
+object ReminderManager {
+
+ private const val REMINDERS_PER_PAGE = 10
+
+ // Random numbers chosen, this will be used to delete the old list and action messages
+ private const val REMINDERS_LIST_ID = -546745
+ private const val REMINDERS_ACTION_ID = -546746
+ private const val REMINDERS_MESSAGE_ID = -546747
+
+ private val storage get() = SkyHanniMod.feature.storage.reminders
+ private val config get() = SkyHanniMod.feature.misc.reminders
+
+ private var listPage = 1
+
+ private fun getSortedReminders() = storage.entries.sortedBy { it.value.remindAt }
+
+ private fun sendMessage(message: String) = Text.join("§e[Reminder]", " ", message).send(REMINDERS_ACTION_ID)
+
+ private fun createDivider() = Text.HYPHEN.fitToChat().style {
+ strikethrough = true
+ color = EnumChatFormatting.BLUE
+ }
+
+ private fun parseDuration(text: String): Duration? = try {
+ val duration = TimeUtils.getDuration(text)
+ if (duration <= 1.seconds) null else duration
+ } catch (e: Exception) {
+ null
+ }
+
+ private fun listReminders(page: Int) {
+ val reminders = getSortedReminders()
+ val maxPage = (reminders.size + REMINDERS_PER_PAGE - 1) / REMINDERS_PER_PAGE
+
+ listPage = page.coerceIn(0, maxPage)
+
+ val text: MutableList<IChatComponent> = mutableListOf()
+
+ text.add(createDivider())
+
+ text.add(
+ Text.join(
+ if (listPage > 1) "§6§l<<".asComponent {
+ hover = "§eClick to view page ${listPage - 1}".asComponent()
+ command = "/shremind list ${listPage - 1}"
+ } else null,
+ " ",
+ "§6Reminders (Page $listPage of $maxPage)",
+ " ",
+ if (listPage < maxPage) "§6§l>>".asComponent {
+ hover = "§eClick to view page ${listPage + 1}".asComponent()
+ command = "/shremind list ${listPage + 1}"
+ } else null,
+ ).center(),
+ )
+
+ if (reminders.isNotEmpty()) {
+ for (i in (listPage - 1) * REMINDERS_PER_PAGE until listPage * REMINDERS_PER_PAGE) {
+ if (i >= reminders.size) break
+ val (id, reminder) = reminders[i]
+
+ text.add(
+ Text.join(
+ "§c✕".asComponent {
+ hover = "§7Click to remove".asComponent()
+ command = "/shremind remove -l $id"
+ }.wrap("§8[", "§8]"),
+ " ",
+ "§e✎".asComponent {
+ hover = "§7Click to start editing".asComponent()
+ suggest = "/shremind edit -l $id ${reminder.reason} "
+ }.wrap("§8[", "§8]"),
+ " ",
+ "§6${reminder.formatShort()}".asComponent {
+ hover = "§7${reminder.formatFull()}".asComponent()
+ }.wrap("§8[", "§8]"),
+ " ",
+ "§7${reminder.reason}",
+ ),
+ )
+ }
+ } else {
+ text.add(Text.EMPTY)
+ text.add("§cNo reminders found.".asComponent().center())
+ text.add(Text.EMPTY)
+ }
+
+ text.add(createDivider())
+
+ Text.join(*text.toTypedArray(), separator = Text.NEWLINE).send(REMINDERS_LIST_ID)
+ }
+
+ private fun createReminder(args: Array<String>) {
+ if (args.size < 2) return help()
+
+ val time = parseDuration(args.first()) ?: return ChatUtils.userError("Invalid time format")
+ val reminder = args.drop(1).joinToString(" ")
+ val remindAt = SimpleTimeMark.now().plus(time)
+
+ storage[StringUtils.generateRandomId()] = Reminder(reminder, remindAt)
+ sendMessage("§6Reminder set for ${time.format()}")
+ }
+
+ private fun actionReminder(
+ args: List<String>,
+ command: String,
+ vararg arguments: String,
+ action: (List<String>, Reminder) -> String,
+ ) {
+ val argumentText = arguments.joinToString(" ")
+ if (args.size < arguments.size) return ChatUtils.userError("/shremind $command $argumentText")
+
+ if (args.first() == "-l") {
+ if (args.size < arguments.size + 1) return ChatUtils.userError("/shremind $command -l $argumentText")
+ if (storage[args.drop(1).first()] == null) return ChatUtils.userError("Reminder not found!")
+ action(args.drop(2), storage[args.drop(1).first()]!!).apply {
+ listReminders(listPage)
+ sendMessage(this)
+ }
+ } else if (storage[args.first()] == null) {
+ return ChatUtils.userError("Reminder not found!")
+ } else {
+ sendMessage(action(args.drop(1), storage[args.first()]!!))
+ }
+ }
+
+ private fun removeReminder(args: List<String>) = actionReminder(
+ args,
+ "remove",
+ "[id]",
+ ) { _, reminder ->
+ storage.values.remove(reminder)
+ "§cReminder deleted."
+ }
+
+ private fun editReminder(args: List<String>) = actionReminder(
+ args,
+ "edit",
+ "[id]",
+ "[reminder]",
+ ) { arguments, reminder ->
+ reminder.reason = arguments.joinToString(" ")
+ "§6Reminder edited."
+ }
+
+ private fun moveReminder(args: List<String>) = actionReminder(
+ args,
+ "move",
+ "[id]",
+ "[time]",
+ ) { arguments, reminder ->
+ val time = parseDuration(arguments.first()) ?: return@actionReminder "§cInvalid time format!"
+ reminder.remindAt = SimpleTimeMark.now().plus(time)
+ "§6Reminder moved to ${time.format()}"
+ }
+
+ private fun help() {
+ createDivider().send()
+ "§6SkyHanni Reminder Commands:".asComponent().send()
+ "§e/shremind <time> <reminder> - §bCreates a new reminder".asComponent().send()
+ "§e/shremind list <page> - §bLists all reminders".asComponent().send()
+ "§e/shremind remove <id> - §bRemoves a reminder".asComponent().send()
+ "§e/shremind edit <id> <reminder> - §bEdits a reminder".asComponent().send()
+ "§e/shremind move <id> <time> - §bMoves a reminder".asComponent().send()
+ "§e/shremind help - §bShows this help message".asComponent().send()
+ createDivider().send()
+ }
+
+ @SubscribeEvent
+ fun onSecondPassed(event: SecondPassedEvent) {
+ val remindersToSend = mutableListOf<IChatComponent>()
+
+ for ((id, reminder) in getSortedReminders()) {
+ if (!reminder.shouldRemind(config.interval.minutes)) continue
+ reminder.lastReminder = SimpleTimeMark.now()
+ var actionsComponent: IChatComponent? = null
+
+ if (!config.autoDeleteReminders) {
+ actionsComponent = Text.join(
+ " ",
+ "§a✔".asComponent {
+ hover = "§7Click to dismiss".asComponent()
+ command = "/shremind remove $id"
+ }.wrap("§8[", "§8]"),
+ " ",
+ "§e§l⟳".asComponent {
+ hover = "§7Click to move".asComponent()
+ suggest = "/shremind move $id 1m"
+ }.wrap("§8[", "§8]"),
+ )
+ } else {
+ storage.remove(id)
+ }
+
+ remindersToSend.add(
+ Text.join(
+ "§e[Reminder]".asComponent {
+ hover = "§7Reminders by SkyHanni".asComponent()
+ },
+ actionsComponent,
+ " ",
+ "§6${reminder.reason}",
+ ),
+ )
+ }
+
+ if (remindersToSend.isNotEmpty()) {
+ val id = if (config.autoDeleteReminders) 0 else REMINDERS_MESSAGE_ID
+ Text.join(remindersToSend, separator = Text.NEWLINE).send(id)
+ }
+ }
+
+ fun command(args: Array<String>) = when (args.firstOrNull()) {
+ "list" -> listReminders(args.drop(1).firstOrNull()?.toIntOrNull() ?: 1)
+ "remove", "delete" -> removeReminder(args.drop(1))
+ "edit", "update" -> editReminder(args.drop(1))
+ "move" -> moveReminder(args.drop(1))
+ "help" -> help()
+ else -> createReminder(args)
+ }
+}