Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.polyfrost.polyplus.client

import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.gui.screens.TitleScreen
import org.apache.logging.log4j.LogManager
import org.polyfrost.polyplus.client.gui.AccountSwitcherScreen
import org.polyfrost.polyplus.client.gui.PolyPlusMainMenuScreen

//? if = 1.8.9 {
/*import org.polyfrost.polyplus.client.social.execute
import org.polyfrost.polyplus.client.social.setScreen
*///?}

object AccountSwitcherOverlay {
private val logger = LogManager.getLogger("polyplus/account-switcher-overlay")

fun open(from: Screen? = currentScreen()) {
val mc = Minecraft.getInstance()
//? if >= 26.2 {
mc.gui.setScreen(AccountSwitcherScreen(from))
//?} else {
/*mc.setScreen(AccountSwitcherScreen(from))
*///?}

}

fun close() {
val mc = Minecraft.getInstance()
mc.execute {
//? if >= 26.2 {
(mc.gui.screen() as? AccountSwitcherScreen)?.let { mc.gui.setScreen(it.previousScreen) }
//?} else {
/*(mc.screen as? AccountSwitcherScreen)?.let { mc.setScreen(it.previousScreen) }
*///?}
}
}

//? if = 1.8.9 {
/*fun restoreAfterEscape(previousScreen: Screen?) {
val mc = Minecraft.getInstance()
if (mc.screen == null || mc.screen is TitleScreen) mc.setScreen(previousScreen)
}
*///?}

private fun currentScreen(): Screen? {
val mc = Minecraft.getInstance()
//? if >= 26.2 {
return mc.gui.screen()
//?} else {
/*return mc.screen
*///?}
}
}
141 changes: 141 additions & 0 deletions src/main/kotlin/org/polyfrost/polyplus/client/gui/AccountActions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.polyfrost.polyplus.client.gui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.polyfrost.polyplus.client.launcher.MicrosoftAuth
import org.polyfrost.polyplus.client.launcher.MicrosoftAuthException
import org.polyfrost.polyplus.client.launcher.OneLauncherAccounts
import org.polyfrost.polyplus.client.utils.ClientPlatform
import org.polyfrost.polyplus.client.utils.runSuspendCatching
import java.util.UUID

internal class AccountActions(private val scope: CoroutineScope) {
var accounts by mutableStateOf<List<OneLauncherAccounts.Account>?>(null)
private set
var busy by mutableStateOf<String?>(null)
private set
var error by mutableStateOf<String?>(null)
private set
var errorSteps by mutableStateOf<List<String>?>(null)
private set
var loginSession by mutableStateOf<MicrosoftAuth.MicrosoftLoginSession?>(null)
private set
var refreshingId by mutableStateOf<UUID?>(null)
private set
private var loginJob: Job? = null

val idle: Boolean get() = busy == null

suspend fun reload() {
accounts = withContext(Dispatchers.IO) { OneLauncherAccounts.list() }
}

fun clearError() {
error = null
errorSteps = null
}

private fun fail(throwable: Throwable, fallback: String) {
error = throwable.message ?: fallback
errorSteps = (throwable as? MicrosoftAuthException)?.stepsToFix?.takeIf { it.isNotEmpty() }
}

private fun runBusy(status: String, block: suspend () -> Unit) {
if (busy != null) return
scope.launch {
busy = status
clearError()
try {
block()
reload()
} finally {
busy = null
}
}
}

fun switchTo(account: OneLauncherAccounts.Account) {
if (account.active) return
runBusy("Switching…") {
val ok = withContext(Dispatchers.IO) { OneLauncherAccounts.switchTo(account.id) }
if (!ok) error = "Couldn't switch to that account"
}
}

fun refresh(account: OneLauncherAccounts.Account) = runBusy("Refreshing session…") {
refreshingId = account.id
try {
runSuspendCatching { withContext(Dispatchers.IO) { OneLauncherAccounts.refresh(account.id) } }
.onFailure { fail(it, "Couldn't refresh that account") }
} finally {
refreshingId = null
}
}

fun addOffline(username: String, onSuccess: () -> Unit = {}) = runBusy("Adding account…") {
runSuspendCatching { withContext(Dispatchers.IO) { OneLauncherAccounts.addOffline(username) } }
.onSuccess { onSuccess() }
.onFailure { error = it.message ?: "Couldn't add that account" }
}

fun remove(account: OneLauncherAccounts.Account) = runBusy("Removing account…") {
val ok = withContext(Dispatchers.IO) { OneLauncherAccounts.remove(account.id) }
if (!ok) error = "Couldn't remove that account"
}

fun addMicrosoft() {
if (busy != null) return
loginJob = scope.launch {
clearError()
busy = "Starting Microsoft sign-in…"
var started: MicrosoftAuth.MicrosoftLoginSession? = null
try {
val session = runSuspendCatching {
withContext(Dispatchers.IO) { OneLauncherAccounts.beginLogin().also { started = it } }
}
.onFailure { fail(it, "Couldn't start sign-in") }
.getOrNull()
if (session == null) {
busy = null
loginJob = null
return@launch
}
loginSession = session
ClientPlatform.openUri(session.browserAuthUrl)
busy = "Waiting for you to finish signing in…"
runSuspendCatching { withContext(Dispatchers.IO) { OneLauncherAccounts.finishLogin(session) } }
.onFailure { fail(it, "Microsoft sign-in failed") }
} finally {
started?.let { runCatching { OneLauncherAccounts.cancelLogin(it) } }
}
loginSession = null
loginJob = null
reload()
busy = null
}
}

fun cancelLogin() {
loginJob?.cancel()
loginSession?.let { runCatching { OneLauncherAccounts.cancelLogin(it) } }
loginJob = null
loginSession = null
busy = null
clearError()
}
}

@Composable
internal fun rememberAccountActions(): AccountActions {
val scope = rememberCoroutineScope()
return remember(scope) { AccountActions(scope) }
}
Loading
Loading