Compare commits
No commits in common. "main" and "v1.1.3" have entirely different histories.
|
|
@ -26,7 +26,7 @@ Goon Manager makes installing and managing Discord mods simple and safe. It's bu
|
||||||
|
|
||||||
<p><strong>Download & run</strong> — get a released APK from Releases and install with:</p>
|
<p><strong>Download & run</strong> — get a released APK from Releases and install with:</p>
|
||||||
|
|
||||||
Get newest apk from [release list](https://github.com/OTKUSteyler/GoonManager/releases/tag/v1.1.3) and install it.
|
Get newest apk from [release list](https://github.com/OTKUSteyler/GoonManager/releases/tag/v1.1.2) and install it.
|
||||||
|
|
||||||
<p><strong>Build from source</strong> — clone and assemble:</p>
|
<p><strong>Build from source</strong> — clone and assemble:</p>
|
||||||
|
|
||||||
|
|
@ -127,5 +127,3 @@ Goon Manager is open source under the OSL License. See `LICENSE` for details.
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>Made with ❤️ for the GoonCord community — keep it playful, keep it safe.</strong>
|
<strong>Made with ❤️ for the GoonCord community — keep it playful, keep it safe.</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||

|
|
||||||
|
|
|
||||||
|
|
@ -19,20 +19,20 @@ val gitHasLocalCommits = gitCurrentBranch?.let { providers.execIgnoreCode("git",
|
||||||
val gitHasHasLocalChanges = providers.execIgnoreCode("git", "status", "-s").isNotEmpty()
|
val gitHasHasLocalChanges = providers.execIgnoreCode("git", "status", "-s").isNotEmpty()
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "dev.shiggy.manager"
|
namespace = "dev.goon.manager"
|
||||||
compileSdk = 37
|
compileSdk = 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 37
|
targetSdk = 36
|
||||||
versionCode = 10_12_01
|
versionCode = 10_11_00
|
||||||
versionName = "1.1.2"
|
versionName = "1.1.1"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
useSupportLibrary = true
|
useSupportLibrary = true
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConfigField("String", "APPLICATION_NAME", "\"Shiggy Manager\"")
|
buildConfigField("String", "APPLICATION_NAME", "\"Goon Manager\"")
|
||||||
buildConfigField("String", "TAG", "\"ShiggyManager\"")
|
buildConfigField("String", "TAG", "\"GoonManager\"")
|
||||||
|
|
||||||
buildConfigField("String", "GITHUB_ORG", "\"ShiggyCord\"")
|
buildConfigField("String", "GITHUB_ORG", "\"ShiggyCord\"")
|
||||||
buildConfigField("String", "SUPPORT_SERVER", "\"\"")
|
buildConfigField("String", "SUPPORT_SERVER", "\"\"")
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
# Download LSPatch jar and convert it to an aar
|
|
||||||
# Jars cannot be used as a dependency without breaking R8 optimization
|
|
||||||
|
|
||||||
LSPATCH_URL="https://github.com/JingMatrix/LSPatch/releases/latest/download/lspatch.jar"
|
|
||||||
LSPATCH_FILE_NAME="lspatch"
|
|
||||||
|
|
||||||
function cleanup {
|
|
||||||
rm -rf $LSPATCH_FILE_NAME.jar META-INF AndroidManifest.xml classes.jar R.txt
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup
|
|
||||||
|
|
||||||
# download lspatch
|
|
||||||
curl -sSL -o $LSPATCH_FILE_NAME.jar $LSPATCH_URL
|
|
||||||
|
|
||||||
# prepare aar contents
|
|
||||||
unzip -q $LSPATCH_FILE_NAME.jar "META-INF/**"
|
|
||||||
mv $LSPATCH_FILE_NAME.jar classes.jar
|
|
||||||
touch R.txt
|
|
||||||
cat >AndroidManifest.xml <<EOF
|
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.lsposed.lspatch">
|
|
||||||
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="36" />
|
|
||||||
</manifest>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# add everything to aar
|
|
||||||
rm -f $LSPATCH_FILE_NAME.aar
|
|
||||||
zip -rq $LSPATCH_FILE_NAME.aar R.txt AndroidManifest.xml META-INF classes.jar
|
|
||||||
cleanup
|
|
||||||
|
|
@ -18,11 +18,11 @@
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.aliucord.manager.ManagerApplication"
|
android:name="com.aliucord.manager.ManagerApplication"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:largeHeap="true"
|
android:largeHeap="true"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:roundIcon="@drawable/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.AppCompat.NoActionBar"
|
android:theme="@style/Theme.AppCompat.NoActionBar"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ class MainActivity : ComponentActivity() {
|
||||||
ManagerTheme(
|
ManagerTheme(
|
||||||
theme = preferences.theme,
|
theme = preferences.theme,
|
||||||
dynamicColor = preferences.dynamicColor,
|
dynamicColor = preferences.dynamicColor,
|
||||||
amoled = preferences.amoled,
|
|
||||||
) {
|
) {
|
||||||
if (BuildConfig.RELEASE) {
|
if (BuildConfig.RELEASE) {
|
||||||
UpdaterDialog()
|
UpdaterDialog()
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import com.aliucord.manager.ui.theme.Theme
|
||||||
@Stable
|
@Stable
|
||||||
class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager(preferences) {
|
class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager(preferences) {
|
||||||
var theme by enumPreference("theme", Theme.System)
|
var theme by enumPreference("theme", Theme.System)
|
||||||
var amoled by booleanPreference("amoled", false)
|
|
||||||
var dynamicColor by booleanPreference("dynamic_color", true)
|
var dynamicColor by booleanPreference("dynamic_color", true)
|
||||||
var devMode by booleanPreference("dev_mode", false)
|
var devMode by booleanPreference("dev_mode", false)
|
||||||
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PM)
|
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PM)
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,11 @@ import io.ktor.client.request.prepareGet
|
||||||
import io.ktor.client.statement.bodyAsChannel
|
import io.ktor.client.statement.bodyAsChannel
|
||||||
import io.ktor.http.HttpHeaders
|
import io.ktor.http.HttpHeaders
|
||||||
import io.ktor.http.contentLength
|
import io.ktor.http.contentLength
|
||||||
import io.ktor.http.isSuccess
|
|
||||||
import io.ktor.utils.io.readAvailable
|
import io.ktor.utils.io.readAvailable
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle downloading remote urls to a path with Ktor.
|
* Handle downloading remote urls to a path with Ktor.
|
||||||
|
|
@ -41,108 +39,55 @@ class KtorDownloadManager(
|
||||||
.apply { exists() || createNewFile() }
|
.apply { exists() || createNewFile() }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val downloadUrl = rewriteRawGithubUrl(url)
|
val httpStmt = http.prepareGet(url) {
|
||||||
|
header(HttpHeaders.CacheControl, "no-cache, no-store")
|
||||||
|
|
||||||
|
// Disable compression due to bug on emulators
|
||||||
|
// This header cannot be set with Android's DownloadManager
|
||||||
|
if (IS_PROBABLY_EMULATOR) {
|
||||||
|
header(HttpHeaders.AcceptEncoding, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
httpStmt.execute { resp ->
|
||||||
|
val channel = resp.bodyAsChannel()
|
||||||
|
val total = resp.contentLength() ?: 0
|
||||||
|
var retrieved = 0L
|
||||||
|
|
||||||
|
val buf = ByteArray(1024 * 1024 * 1)
|
||||||
|
var bufLen: Int
|
||||||
|
|
||||||
|
tmpOut.outputStream().use { stream ->
|
||||||
|
// Preallocate space for this file
|
||||||
|
if (total > 0 && Build.VERSION.SDK_INT >= 26) {
|
||||||
|
val storageManager = application.getSystemService<StorageManager>()!!
|
||||||
|
|
||||||
// Try the CDN first (jsDelivr), then an alternate raw proxy (raw.githack.com), and finally
|
|
||||||
// fall back to the original URL if all CDN attempts fail.
|
|
||||||
val rawGithack = try {
|
|
||||||
when {
|
|
||||||
// direct raw.githubusercontent.com -> raw.githack.com
|
|
||||||
url.contains("raw.githubusercontent.com", ignoreCase = true) ->
|
|
||||||
url.replace("raw.githubusercontent.com", "raw.githack.com")
|
|
||||||
// github.com/.../raw/... -> convert to raw.githack.com/ORG/REPO/BRANCH/path
|
|
||||||
url.contains("/raw/", ignoreCase = true) && url.contains("github.com", ignoreCase = true) -> {
|
|
||||||
try {
|
try {
|
||||||
val u = URI(url)
|
storageManager.allocateBytes(stream.fd, total)
|
||||||
val segs = u.path.trimStart('/').split('/', limit = 6)
|
} catch (e: IOException) {
|
||||||
if (segs.size >= 5 && segs[2].equals("raw", ignoreCase = true)) {
|
throw InsufficientStorageException(e.message)
|
||||||
"https://raw.githack.com/${segs[0]}/${segs[1]}/${segs.subList(3, segs.size).joinToString("/")}"
|
|
||||||
} else url
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> url
|
|
||||||
}
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
url
|
|
||||||
}
|
|
||||||
val attempts = listOf(downloadUrl, rawGithack, url).distinct()
|
|
||||||
var lastException: Throwable? = null
|
|
||||||
var downloaded = false
|
|
||||||
|
|
||||||
for (attemptUrl in attempts) {
|
|
||||||
val httpStmt = http.prepareGet(attemptUrl) {
|
|
||||||
header(HttpHeaders.CacheControl, "no-cache, no-store")
|
|
||||||
|
|
||||||
// Disable compression due to bug on emulators
|
|
||||||
// This header cannot be set with Android's DownloadManager
|
|
||||||
if (IS_PROBABLY_EMULATOR) {
|
|
||||||
header(HttpHeaders.AcceptEncoding, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
httpStmt.execute { resp ->
|
|
||||||
if (!resp.status.isSuccess()) {
|
|
||||||
throw IOException("HTTP error ${resp.status.value} for $attemptUrl")
|
|
||||||
}
|
|
||||||
|
|
||||||
val channel = resp.bodyAsChannel()
|
|
||||||
val total = resp.contentLength() ?: 0
|
|
||||||
var retrieved = 0L
|
|
||||||
|
|
||||||
val buf = ByteArray(1024 * 1024 * 1)
|
|
||||||
var bufLen: Int
|
|
||||||
|
|
||||||
tmpOut.outputStream().use { stream ->
|
|
||||||
// Preallocate space for this file
|
|
||||||
if (total > 0 && Build.VERSION.SDK_INT >= 26) {
|
|
||||||
val storageManager = application.getSystemService<StorageManager>()!!
|
|
||||||
|
|
||||||
try {
|
|
||||||
storageManager.allocateBytes(stream.fd, total)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw InsufficientStorageException(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!channel.isClosedForRead) {
|
|
||||||
bufLen = channel.readAvailable(buf)
|
|
||||||
if (bufLen <= 0) break
|
|
||||||
|
|
||||||
stream.write(buf, 0, bufLen)
|
|
||||||
stream.flush()
|
|
||||||
|
|
||||||
retrieved += bufLen
|
|
||||||
|
|
||||||
if (total > 0) {
|
|
||||||
if (retrieved > total)
|
|
||||||
throw IOException("Total bytes received exceeds header total!")
|
|
||||||
|
|
||||||
onProgressUpdate?.onUpdate(retrieved / total.toFloat())
|
|
||||||
} else {
|
|
||||||
onProgressUpdate?.onUpdate(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we reach here, the attempt succeeded
|
while (!channel.isClosedForRead) {
|
||||||
downloaded = true
|
bufLen = channel.readAvailable(buf)
|
||||||
break
|
if (bufLen <= 0) break
|
||||||
} catch (e: CancellationException) {
|
|
||||||
// Propagate cancellations immediately
|
|
||||||
throw e
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
// Record the last exception and try the next URL (if any)
|
|
||||||
lastException = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!downloaded) {
|
stream.write(buf, 0, bufLen)
|
||||||
// No attempt succeeded, throw the last failure to be handled by outer catch blocks
|
stream.flush()
|
||||||
throw lastException ?: IOException("Failed to download resource from $url")
|
|
||||||
|
retrieved += bufLen
|
||||||
|
|
||||||
|
if (total > 0) {
|
||||||
|
if (retrieved > total)
|
||||||
|
throw IOException("Total bytes received exceeds header total!")
|
||||||
|
|
||||||
|
onProgressUpdate?.onUpdate(retrieved / total.toFloat())
|
||||||
|
} else {
|
||||||
|
onProgressUpdate?.onUpdate(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (_: CancellationException) {
|
} catch (_: CancellationException) {
|
||||||
tmpOut.delete()
|
tmpOut.delete()
|
||||||
|
|
@ -162,17 +107,6 @@ class KtorDownloadManager(
|
||||||
return Result.Success(out)
|
return Result.Success(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rewriteRawGithubUrl(url: String): String {
|
|
||||||
val regex = Regex("^https?://raw\\.githubusercontent\\.com/([^/]+)/([^/]+)/([^/]+)/(.*)$", RegexOption.IGNORE_CASE)
|
|
||||||
val match = regex.matchEntire(url)
|
|
||||||
return if (match != null) {
|
|
||||||
val (org, repo, branch, path) = match.destructured
|
|
||||||
"https://cdn.jsdelivr.net/gh/$org/$repo@$branch/$path"
|
|
||||||
} else {
|
|
||||||
url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around an exception that occurred from invoking Ktor
|
* Wrapper around an exception that occurred from invoking Ktor
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class DownloadShiggyXposedStep : DownloadStep() {
|
||||||
|
|
||||||
override suspend fun execute(container: StepRunner) {
|
override suspend fun execute(container: StepRunner) {
|
||||||
val latestRelease = shiggyGithubService.getLatestXposedRelease().getOrThrow()
|
val latestRelease = shiggyGithubService.getLatestXposedRelease().getOrThrow()
|
||||||
container.log("Latest GoonXposed release is ${latestRelease.name}")
|
container.log("Latest ShiggyXposed release is ${latestRelease.name}")
|
||||||
|
|
||||||
targetVersion = SemVer.parse(latestRelease.name)
|
targetVersion = SemVer.parse(latestRelease.name)
|
||||||
targetUrl = latestRelease.assets.first { it.name == "app-release.apk" }.browserDownloadUrl
|
targetUrl = latestRelease.assets.first { it.name == "app-release.apk" }.browserDownloadUrl
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,10 @@ import org.lsposed.lspatch.share.LSPConfig
|
||||||
import org.lsposed.patch.LSPatch
|
import org.lsposed.patch.LSPatch
|
||||||
import org.lsposed.patch.util.Logger
|
import org.lsposed.patch.util.Logger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class InjectGoonXposedStep : Step() {
|
class InjectShiggyXposedStep : Step() {
|
||||||
override val group: StepGroup = StepGroup.Install
|
override val group: StepGroup = StepGroup.Install
|
||||||
override val localizedName: Int = R.string.patch_step_inject_goon
|
override val localizedName: Int = R.string.patch_step_inject_shiggy
|
||||||
|
|
||||||
suspend fun patch(
|
suspend fun patch(
|
||||||
container: StepRunner,
|
container: StepRunner,
|
||||||
|
|
@ -83,15 +82,7 @@ class InjectGoonXposedStep : Step() {
|
||||||
// FilenameUtils.getBaseName(apkFileName),
|
// FilenameUtils.getBaseName(apkFileName),
|
||||||
// LSPConfig.instance.VERSION_CODE)
|
// LSPConfig.instance.VERSION_CODE)
|
||||||
// )
|
// )
|
||||||
// Note: LSPatch uses Locale.getDefault() which can produce locale-specific numerals
|
val patchedApkName = "${baseName}-${LSPConfig.instance.VERSION_CODE}-lspatched.apk"
|
||||||
// (e.g., Arabic numerals on Arabic locales). We must use Locale.US to ensure
|
|
||||||
// consistent filename matching regardless of device locale.
|
|
||||||
val patchedApkName = String.format(
|
|
||||||
Locale.US,
|
|
||||||
"%s-%d-lspatched.apk",
|
|
||||||
baseName,
|
|
||||||
LSPConfig.instance.VERSION_CODE
|
|
||||||
)
|
|
||||||
val patchedApk = File(tempDir, patchedApkName)
|
val patchedApk = File(tempDir, patchedApkName)
|
||||||
|
|
||||||
if (patchedApk.exists()) {
|
if (patchedApk.exists()) {
|
||||||
|
|
|
||||||
|
|
@ -252,8 +252,6 @@ object ManifestPatcher {
|
||||||
extractNativeLibs ?: false
|
extractNativeLibs ?: false
|
||||||
private var shouldAddMetadata =
|
private var shouldAddMetadata =
|
||||||
addManagerMetadata ?: false
|
addManagerMetadata ?: false
|
||||||
private var shouldAddCleartext = true
|
|
||||||
|
|
||||||
|
|
||||||
override fun attr(
|
override fun attr(
|
||||||
ns: String?,
|
ns: String?,
|
||||||
|
|
@ -271,12 +269,6 @@ object ManifestPatcher {
|
||||||
shouldAddExtractNativeLibs = false
|
shouldAddExtractNativeLibs = false
|
||||||
if (name == DEBUGGABLE)
|
if (name == DEBUGGABLE)
|
||||||
shouldAddDebuggable = false
|
shouldAddDebuggable = false
|
||||||
if (name == "usesCleartextTraffic") {
|
|
||||||
shouldAddCleartext = false
|
|
||||||
super.attr(ns, name, 0x010104ec, TYPE_INT_BOOLEAN, 1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
super.attr(
|
super.attr(
|
||||||
ns,
|
ns,
|
||||||
name,
|
name,
|
||||||
|
|
@ -433,15 +425,7 @@ object ManifestPatcher {
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (shouldAddCleartext) {
|
|
||||||
super.attr(
|
|
||||||
ANDROID_NAMESPACE,
|
|
||||||
"usesCleartextTraffic",
|
|
||||||
0x010104ec,
|
|
||||||
TYPE_INT_BOOLEAN,
|
|
||||||
1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
super.end()
|
super.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,6 @@ class SettingsScreen : Screen, Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SettingsSwitch(
|
|
||||||
label = stringResource(R.string.setting_amoled),
|
|
||||||
secondaryLabel = stringResource(R.string.setting_amoled_desc),
|
|
||||||
pref = preferences.amoled,
|
|
||||||
icon = { Icon(painterResource(R.drawable.ic_night), null) },
|
|
||||||
onPrefChange = { preferences.amoled = it },
|
|
||||||
)
|
|
||||||
|
|
||||||
// Material You theming on Android 12+
|
// Material You theming on Android 12+
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
if (Build.VERSION.SDK_INT >= 31) {
|
||||||
SettingsSwitch(
|
SettingsSwitch(
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import dev.goon.manager.R
|
||||||
fun ManagerTheme(
|
fun ManagerTheme(
|
||||||
theme: Theme = Theme.System,
|
theme: Theme = Theme.System,
|
||||||
dynamicColor: Boolean = true,
|
dynamicColor: Boolean = true,
|
||||||
amoled: Boolean = false,
|
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
val dynamicColor = dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
val dynamicColor = dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||||
|
|
@ -29,63 +28,12 @@ fun ManagerTheme(
|
||||||
Theme.Dark -> true
|
Theme.Dark -> true
|
||||||
Theme.Light -> false
|
Theme.Light -> false
|
||||||
}
|
}
|
||||||
|
val colorScheme = when {
|
||||||
val context = LocalContext.current
|
dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
|
||||||
|
dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
|
||||||
val baseScheme = when {
|
|
||||||
dynamicColor && darkTheme -> dynamicDarkColorScheme(context)
|
|
||||||
dynamicColor && !darkTheme -> dynamicLightColorScheme(context)
|
|
||||||
darkTheme -> darkColorScheme()
|
darkTheme -> darkColorScheme()
|
||||||
else -> lightColorScheme()
|
else -> lightColorScheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
val colorScheme = if (amoled && darkTheme) {
|
|
||||||
baseScheme.copy(
|
|
||||||
// Core surfaces: true black with white content
|
|
||||||
background = Color(0xFF000000),
|
|
||||||
onBackground = Color(0xFFFFFFFF),
|
|
||||||
surface = Color(0xFF000000),
|
|
||||||
onSurface = Color(0xFFFFFFFF),
|
|
||||||
|
|
||||||
// Surface variants / tints for containers and subtle surfaces
|
|
||||||
surfaceVariant = Color(0xFF000000),
|
|
||||||
onSurfaceVariant = Color(0xFFFFFFFF),
|
|
||||||
surfaceTint = Color(0xFF000000),
|
|
||||||
|
|
||||||
// Primary (controls). Set both primary and primaryContainer to white so
|
|
||||||
// Filled / FilledTonal controls and other components using either token
|
|
||||||
// will have a white container with black text/icons.
|
|
||||||
primary = Color(0xFFFFFFFF),
|
|
||||||
onPrimary = Color(0xFF000000),
|
|
||||||
primaryContainer = Color(0xFFFFFFFF),
|
|
||||||
onPrimaryContainer = Color(0xFF000000),
|
|
||||||
|
|
||||||
// Secondary / tertiary: match primary behavior for consistency across different control types
|
|
||||||
secondary = Color(0xFFFFFFFF),
|
|
||||||
onSecondary = Color(0xFF000000),
|
|
||||||
secondaryContainer = Color(0xFFFFFFFF),
|
|
||||||
onSecondaryContainer = Color(0xFF000000),
|
|
||||||
|
|
||||||
tertiary = Color(0xFFFFFFFF),
|
|
||||||
onTertiary = Color(0xFF000000),
|
|
||||||
tertiaryContainer = Color(0xFFFFFFFF),
|
|
||||||
onTertiaryContainer = Color(0xFF000000),
|
|
||||||
|
|
||||||
// Inverse surfaces for components that might use them
|
|
||||||
inverseSurface = Color(0xFF121212),
|
|
||||||
inverseOnSurface = Color(0xFFFFFFFF),
|
|
||||||
|
|
||||||
// Outline and subtle elements: semi-transparent white for edges/highlights
|
|
||||||
outline = Color(0x66FFFFFF),
|
|
||||||
|
|
||||||
// Preserve error semantics from base (keeps readable error colors)
|
|
||||||
error = baseScheme.error,
|
|
||||||
onError = baseScheme.onError,
|
|
||||||
errorContainer = baseScheme.errorContainer,
|
|
||||||
onErrorContainer = baseScheme.onErrorContainer,
|
|
||||||
)
|
|
||||||
} else baseScheme
|
|
||||||
|
|
||||||
val customColors = when (darkTheme) {
|
val customColors = when (darkTheme) {
|
||||||
true -> DarkCustomColors
|
true -> DarkCustomColors
|
||||||
false -> LightCustomColors
|
false -> LightCustomColors
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,6 @@ data class CustomColors(
|
||||||
val onWarning: Color,
|
val onWarning: Color,
|
||||||
val warningContainer: Color,
|
val warningContainer: Color,
|
||||||
val onWarningContainer: Color,
|
val onWarningContainer: Color,
|
||||||
val instanceCardBackground: Color,
|
|
||||||
val instanceCardContent: Color,
|
|
||||||
val instanceCardButtonContainer: Color,
|
|
||||||
val instanceCardButtonContent: Color,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val YellowAlt1 = Color(0xFFE9C414)
|
private val YellowAlt1 = Color(0xFFE9C414)
|
||||||
|
|
@ -36,10 +32,6 @@ val DarkCustomColors = CustomColors(
|
||||||
onWarning = DarkBrown,
|
onWarning = DarkBrown,
|
||||||
warningContainer = DarkBronze,
|
warningContainer = DarkBronze,
|
||||||
onWarningContainer = Shandy,
|
onWarningContainer = Shandy,
|
||||||
instanceCardBackground = Color(0xFF0E0E0E),
|
|
||||||
instanceCardContent = Color(0xFFFFFFFF),
|
|
||||||
instanceCardButtonContainer = Color(0xFFF2F2F2),
|
|
||||||
instanceCardButtonContent = Color(0xFF000000),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val LightCustomColors = CustomColors(
|
val LightCustomColors = CustomColors(
|
||||||
|
|
@ -47,8 +39,4 @@ val LightCustomColors = CustomColors(
|
||||||
onWarning = Color.White,
|
onWarning = Color.White,
|
||||||
warningContainer = Shandy,
|
warningContainer = Shandy,
|
||||||
onWarningContainer = DarkerBrown,
|
onWarningContainer = DarkerBrown,
|
||||||
instanceCardBackground = Color(0xFFFFFFFF),
|
|
||||||
instanceCardContent = Color(0xFF000000),
|
|
||||||
instanceCardButtonContainer = Color(0xFFFAFAFA),
|
|
||||||
instanceCardButtonContent = Color(0xFF000000),
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
<vector
|
<vector
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="108dp"
|
android:width="24dp"
|
||||||
android:height="108dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="256"
|
android:viewportWidth="256"
|
||||||
android:viewportHeight="256"
|
android:viewportHeight="256"
|
||||||
>
|
>
|
||||||
<!-- Solid circular background (Shiggy yellow) -->
|
|
||||||
<path android:fillColor="#fcc680" android:pathData="M256,128 A128,128 0 1,1 0,128 A128,128 0 1,1 256,128 Z" />
|
<!-- Solid circular background (Discord blurple) -->
|
||||||
<!-- White droplet -->
|
<path android:fillColor="#5865F2" android:pathData="M256,128 A128,128 0 1,1 0,128 A128,128 0 1,1 256,128 Z" />
|
||||||
|
|
||||||
|
<!-- White Discord mark (borrowed path scaled by viewport) -->
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FFFFFF"
|
android:fillColor="#FFFFFFFF"
|
||||||
android:pathData="M128,38.4 C64,89.6 51.2,166.4 76.8,204.8 Q102.4,230.4 128,217.6 Q153.6,230.4 179.2,204.8 C204.8,166.4 192,89.6 128,38.4 Z"
|
android:pathData="M216.86,45.1C200.29,37.34 182.57,31.71 164.04,28.5C161.77,32.61 159.11,38.15 157.28,42.55C137.58,39.58 118.07,39.58 98.74,42.55C96.91,38.15 94.19,32.61 91.9,28.5C73.35,31.71 55.61,37.36 39.04,45.14C5.62,95.65 -3.44,144.9 1.09,193.46C23.26,210.01 44.74,220.07 65.86,226.65C71.08,219.47 75.73,211.84 79.74,203.8C72.1,200.9 64.79,197.32 57.89,193.17C59.72,191.81 61.51,190.39 63.24,188.93C105.37,208.63 151.13,208.63 192.75,188.93C194.51,190.39 196.3,191.81 198.11,193.17C191.18,197.34 183.85,200.92 176.22,203.82C180.23,211.84 184.86,219.49 190.1,226.67C211.24,220.09 232.74,210.03 254.91,193.46C260.23,137.17 245.83,88.37 216.86,45.1ZM85.47,163.59C72.83,163.59 62.46,151.79 62.46,137.41C62.46,123.04 72.61,111.21 85.47,111.21C98.34,111.21 108.71,123.02 108.49,137.41C108.51,151.79 98.34,163.59 85.47,163.59ZM170.53,163.59C157.88,163.59 147.51,151.79 147.51,137.41C147.51,123.04 157.66,111.21 170.53,111.21C183.39,111.21 193.76,123.02 193.54,137.41C193.54,151.79 183.39,163.59 170.53,163.59Z"
|
||||||
/>
|
/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
|
@ -6,5 +6,5 @@
|
||||||
android:viewportHeight="108"
|
android:viewportHeight="108"
|
||||||
>
|
>
|
||||||
<!-- Flat background color for launcher adaptive icon -->
|
<!-- Flat background color for launcher adaptive icon -->
|
||||||
<path android:pathData="M0,0H108V108H0Z" android:fillColor="#070700" />
|
<path android:pathData="M0,0H108V108H0Z" android:fillColor="#FFFFCB82" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB |
|
|
@ -5,8 +5,15 @@
|
||||||
android:viewportWidth="256"
|
android:viewportWidth="256"
|
||||||
android:viewportHeight="256"
|
android:viewportHeight="256"
|
||||||
>
|
>
|
||||||
<path
|
|
||||||
android:fillColor="#000000"
|
<!-- Solid circular background (Shiggy yellow) -->
|
||||||
android:pathData="M128,38.4 C64,89.6 51.2,166.4 76.8,204.8 Q102.4,230.4 128,217.6 Q153.6,230.4 179.2,204.8 C204.8,166.4 192,89.6 128,38.4 Z"
|
<path android:fillColor="#fcc680" android:pathData="M256,128 A128,128 0 1,1 0,128 A128,128 0 1,1 256,128 Z" />
|
||||||
/>
|
|
||||||
|
<!-- White Discord mark (scaled down and centered) -->
|
||||||
|
<group android:scaleX="0.7" android:scaleY="0.7" android:translateX="38.4" android:translateY="38.4">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M216.86,45.1C200.29,37.34 182.57,31.71 164.04,28.5C161.77,32.61 159.11,38.15 157.28,42.55C137.58,39.58 118.07,39.58 98.74,42.55C96.91,38.15 94.19,32.61 91.9,28.5C73.35,31.71 55.61,37.36 39.04,45.14C5.62,95.65 -3.44,144.9 1.09,193.46C23.26,210.01 44.74,220.07 65.86,226.65C71.08,219.47 75.73,211.84 79.74,203.8C72.1,200.9 64.79,197.32 57.89,193.17C59.72,191.81 61.51,190.39 63.24,188.93C105.37,208.63 151.13,208.63 192.75,188.93C194.51,190.39 196.3,191.81 198.11,193.17C191.18,197.34 183.85,200.92 176.22,203.82C180.23,211.84 184.86,219.49 190.1,226.67C211.24,220.09 232.74,210.03 254.91,193.46C260.23,137.17 245.83,88.37 216.86,45.1ZM85.47,163.59C72.83,163.59 62.46,151.79 62.46,137.41C62.46,123.04 72.61,111.21 85.47,111.21C98.34,111.21 108.71,123.02 108.49,137.41C108.51,151.79 98.34,163.59 85.47,163.59ZM170.53,163.59C157.88,163.59 147.51,151.79 147.51,137.41C147.51,123.04 157.66,111.21 170.53,111.21C183.39,111.21 193.76,123.02 193.54,137.41C193.54,151.79 183.39,163.59 170.53,163.59Z"
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB |
7
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!-- Adaptive icon updated to use Shiggy flat background and provided foreground image -->
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||||
|
</adaptive-icon>
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB |
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||||
|
</adaptive-icon>
|
||||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 8.2 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="ic_launcher_background">#FFFFFF</color>
|
<color name="ic_launcher_background">#FFFFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,8 @@
|
||||||
<string name="settings_header_info">Info</string>
|
<string name="settings_header_info">Info</string>
|
||||||
<string name="setting_theme">Theme</string>
|
<string name="setting_theme">Theme</string>
|
||||||
<string name="setting_theme_desc">The theme to apply to this app</string>
|
<string name="setting_theme_desc">The theme to apply to this app</string>
|
||||||
<string name="setting_amoled">Amoled mode</string>
|
|
||||||
<string name="setting_amoled_desc">Force true-black backgrounds for AMOLED displays</string>
|
|
||||||
<string name="setting_dynamic_color">Dynamic color</string>
|
<string name="setting_dynamic_color">Dynamic color</string>
|
||||||
<string
|
<string name="setting_dynamic_color_desc">Enables Material You theming on Android 12+</string>
|
||||||
name="setting_dynamic_color_desc"
|
|
||||||
>Enables Material You theming on Android 12+; dynamic colors will also be applied to the Amoled theme when enabled</string>
|
|
||||||
<string name="setting_installer">Installer</string>
|
<string name="setting_installer">Installer</string>
|
||||||
<string name="setting_installer_desc">The method to use for installing Goon</string>
|
<string name="setting_installer_desc">The method to use for installing Goon</string>
|
||||||
<string name="setting_developer_options">Developer options</string>
|
<string name="setting_developer_options">Developer options</string>
|
||||||
|
|
@ -76,7 +72,6 @@
|
||||||
<string name="theme_system">System</string>
|
<string name="theme_system">System</string>
|
||||||
<string name="theme_dark">Dark</string>
|
<string name="theme_dark">Dark</string>
|
||||||
<string name="theme_light">Light</string>
|
<string name="theme_light">Light</string>
|
||||||
<string name="theme_amoled">Amoled</string>
|
|
||||||
|
|
||||||
<string name="navigation_back">Back</string>
|
<string name="navigation_back">Back</string>
|
||||||
<string name="navigation_about">About</string>
|
<string name="navigation_about">About</string>
|
||||||
|
|
@ -89,7 +84,7 @@
|
||||||
<string name="lead_role_kettu">Kettu - Creator</string>
|
<string name="lead_role_kettu">Kettu - Creator</string>
|
||||||
<string name="lead_role_shiggycord">GoonCord - Creator</string>
|
<string name="lead_role_shiggycord">GoonCord - Creator</string>
|
||||||
<string name="lead_role_bunny">Bunny - Creator</string>
|
<string name="lead_role_bunny">Bunny - Creator</string>
|
||||||
<string name="role_creator_vendetta">Vendetta - Creator</string>
|
<string name="role_creator_vendetta">Creator of Vendetta</string>
|
||||||
<string name="role_original_manager_creator">Original Manager Creator</string>
|
<string name="role_original_manager_creator">Original Manager Creator</string>
|
||||||
|
|
||||||
<string name="network_load_fail">Failed to load</string>
|
<string name="network_load_fail">Failed to load</string>
|
||||||
|
|
@ -285,10 +280,10 @@
|
||||||
<string name="permissions_shizuku_denied">Failed to obtain Shizuku permissions</string>
|
<string name="permissions_shizuku_denied">Failed to obtain Shizuku permissions</string>
|
||||||
|
|
||||||
<string name="fun_fact_prefix">Fun Fact: %s</string>
|
<string name="fun_fact_prefix">Fun Fact: %s</string>
|
||||||
<string name="fun_fact_1">GoonCord on second release was meant to be custom ShiggyCord build!</string>
|
<string name="fun_fact_1">ShiggyCord on first release was meant to be custom Kettu build!</string>
|
||||||
<string name="fun_fact_2">This client is not same as CumCord i made it as an Joke</string>
|
<string name="fun_fact_2">The refreshed UI inside the settings was made from developer boredom</string>
|
||||||
<string name="fun_fact_3">GoonCord as second vendetta like client used to show users the built in plugins and even add extra ones!</string>
|
<string name="fun_fact_3">ShiggyCord as first vendetta like client used to show users the built in plugins and even add extra ones!</string>
|
||||||
<string name="fun_fact_4">You love Femboys, don\'t you?</string>
|
<string name="fun_fact_4">You love boys, don\'t you?</string>
|
||||||
<string name="fun_fact_5">Aliucord is the best client with old discord UI</string>
|
<string name="fun_fact_5">Aliucord is the best client with old discord UI</string>
|
||||||
<string name="fun_fact_6">We love you cocobo and pylix!</string>
|
<string name="fun_fact_6">We love you cocobo and pylix!</string>
|
||||||
<string name="fun_fact_7">The Vendetta react native part was a total dogshit</string>
|
<string name="fun_fact_7">The Vendetta react native part was a total dogshit</string>
|
||||||
|
|
@ -296,6 +291,7 @@
|
||||||
<string name="fun_fact_9">This client can be run on a android TV!</string>
|
<string name="fun_fact_9">This client can be run on a android TV!</string>
|
||||||
<string name="fun_fact_10">The Main Developer one and half a year ago didn\'t even know how to code</string>
|
<string name="fun_fact_10">The Main Developer one and half a year ago didn\'t even know how to code</string>
|
||||||
<string name="fun_fact_11">This client does not support iOS!</string>
|
<string name="fun_fact_11">This client does not support iOS!</string>
|
||||||
<string name="fun_fact_12">Boom :3!</string>
|
<string name="fun_fact_12">Boom!</string>
|
||||||
|
<string name="fun_fact_13">This client is not same as CumCord i made it as an Joke</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.AliucordManager.SplashScreen" parent="Theme.SplashScreen">
|
<style name="Theme.AliucordManager.SplashScreen" parent="Theme.SplashScreen">
|
||||||
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_launcher</item>
|
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_launcher_foreground</item>
|
||||||
<item name="postSplashScreenTheme">@style/Theme.AppCompat.NoActionBar</item>
|
<item name="postSplashScreenTheme">@style/Theme.AppCompat.NoActionBar</item>
|
||||||
|
|
||||||
<item name="android:windowActionBar">false</item>
|
<item name="android:windowActionBar">false</item>
|
||||||
|
|
|
||||||