commit 7881279196652bf79ae83d971689d6ea6731d833 Author: Juby210 <31005896+Juby210@users.noreply.github.com> Date: Sat Jul 17 00:26:04 2021 +0200 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aaf4467 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.iml +.gradle +/local.properties +.idea +.DS_Store +build +release +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..95230e3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,172 @@ +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of +authorship (the "Original Work") whose owner (the "Licensor") has placed the +following licensing notice adjacent to the copyright notice for the Original +Work: + +Licensed under the Open Software License version 3.0 + +1) Grant of Copyright License. Licensor grants You a worldwide, royalty-free, +non-exclusive, sublicensable license, for the duration of the copyright, to do +the following: + + a) to reproduce the Original Work in copies, either alone or as part of a + collective work; + + b) to translate, adapt, alter, transform, modify, or arrange the Original + Work, thereby creating derivative works ("Derivative Works") based upon the + Original Work; + + c) to distribute or communicate copies of the Original Work and Derivative + Works to the public, with the proviso that copies of Original Work or + Derivative Works that You distribute or communicate shall be licensed under + this Open Software License; + + d) to perform the Original Work publicly; and + + e) to display the Original Work publicly. + +2) Grant of Patent License. Licensor grants You a worldwide, royalty-free, +non-exclusive, sublicensable license, under patent claims owned or controlled +by the Licensor that are embodied in the Original Work as furnished by the +Licensor, for the duration of the patents, to make, use, sell, offer for sale, +have made, and import the Original Work and Derivative Works. + +3) Grant of Source Code License. The term "Source Code" means the preferred +form of the Original Work for making modifications to it and all available +documentation describing how to modify the Original Work. Licensor agrees to +provide a machine-readable copy of the Source Code of the Original Work along +with each copy of the Original Work that Licensor distributes. Licensor +reserves the right to satisfy this obligation by placing a machine-readable +copy of the Source Code in an information repository reasonably calculated to +permit inexpensive and convenient access by You for as long as Licensor +continues to distribute the Original Work. + +4) Exclusions From License Grant. Neither the names of Licensor, nor the names +of any contributors to the Original Work, nor any of their trademarks or +service marks, may be used to endorse or promote products derived from this +Original Work without express prior permission of the Licensor. Except as +expressly stated herein, nothing in this License grants any license to +Licensor's trademarks, copyrights, patents, trade secrets or any other +intellectual property. No patent license is granted to make, use, sell, offer +for sale, have made, or import embodiments of any patent claims other than the +licensed claims defined in Section 2. No license is granted to the trademarks +of Licensor even if such marks are included in the Original Work. Nothing in +this License shall be interpreted to prohibit Licensor from licensing under +terms different from this License any Original Work that Licensor otherwise +would have a right to license. + +5) External Deployment. The term "External Deployment" means the use, +distribution, or communication of the Original Work or Derivative Works in any +way such that the Original Work or Derivative Works may be used by anyone +other than You, whether those works are distributed or communicated to those +persons or made available as an application intended for use over a network. +As an express condition for the grants of license hereunder, You must treat +any External Deployment by You of the Original Work or a Derivative Work as a +distribution under section 1(c). + +6) Attribution Rights. You must retain, in the Source Code of any Derivative +Works that You create, all copyright, patent, or trademark notices from the +Source Code of the Original Work, as well as any notices of licensing and any +descriptive text identified therein as an "Attribution Notice." You must cause +the Source Code for any Derivative Works that You create to carry a prominent +Attribution Notice reasonably calculated to inform recipients that You have +modified the Original Work. + +7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that +the copyright in and to the Original Work and the patent rights granted herein +by Licensor are owned by the Licensor or are sublicensed to You under the +terms of this License with the permission of the contributor(s) of those +copyrights and patent rights. Except as expressly stated in the immediately +preceding sentence, the Original Work is provided under this License on an "AS +IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without +limitation, the warranties of non-infringement, merchantability or fitness for +a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK +IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this +License. No license to the Original Work is granted by this License except +under this disclaimer. + +8) Limitation of Liability. Under no circumstances and under no legal theory, +whether in tort (including negligence), contract, or otherwise, shall the +Licensor be liable to anyone for any indirect, special, incidental, or +consequential damages of any character arising as a result of this License or +the use of the Original Work including, without limitation, damages for loss +of goodwill, work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses. This limitation of liability shall not +apply to the extent applicable law prohibits such limitation. + +9) Acceptance and Termination. If, at any time, You expressly assented to this +License, that assent indicates your clear and irrevocable acceptance of this +License and all of its terms and conditions. If You distribute or communicate +copies of the Original Work or a Derivative Work, You must make a reasonable +effort under the circumstances to obtain the express assent of recipients to +the terms of this License. This License conditions your rights to undertake +the activities listed in Section 1, including your right to create Derivative +Works based upon the Original Work, and doing so without honoring these terms +and conditions is prohibited by copyright law and international treaty. +Nothing in this License is intended to affect copyright exceptions and +limitations (including "fair use" or "fair dealing"). This License shall +terminate immediately and You may no longer exercise any of the rights granted +to You by this License upon your failure to honor the conditions in Section +1(c). + +10) Termination for Patent Action. This License shall terminate automatically +and You may no longer exercise any of the rights granted to You by this +License as of the date You commence an action, including a cross-claim or +counterclaim, against Licensor or any licensee alleging that the Original Work +infringes a patent. This termination provision shall not apply for an action +alleging patent infringement by combinations of the Original Work with other +software or hardware. + +11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this +License may be brought only in the courts of a jurisdiction wherein the +Licensor resides or in which Licensor conducts its primary business, and under +the laws of that jurisdiction excluding its conflict-of-law provisions. The +application of the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. Any use of the Original +Work outside the scope of this License or after its termination shall be +subject to the requirements and penalties of copyright or patent law in the +appropriate jurisdiction. This section shall survive the termination of this +License. + +12) Attorneys' Fees. In any action to enforce the terms of this License or +seeking damages relating thereto, the prevailing party shall be entitled to +recover its costs and expenses, including, without limitation, reasonable +attorneys' fees and costs incurred in connection with such action, including +any appeal of such action. This section shall survive the termination of this +License. + +13) Miscellaneous. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent necessary +to make it enforceable. + +14) Definition of "You" in This License. "You" throughout this License, +whether in upper or lower case, means an individual or a legal entity +exercising rights under, and complying with all of the terms of, this License. +For legal entities, "You" includes any entity that controls, is controlled by, +or is under common control with you. For purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. + +15) Right to Use. You may use the Original Work in all ways not otherwise +restricted or conditioned by this License or by law, and Licensor promises not +to interfere with or be responsible for such uses by You. + +16) Modification of This License. This License is Copyright © 2005 Lawrence +Rosen. Permission is granted to copy, distribute, or communicate this License +without modification. Nothing in this License permits You to modify this +License as applied to the Original Work or to Derivative Works. However, You +may modify the text of this License and copy, distribute or communicate your +modified version (the "Modified License") and apply it to other original works +of authorship subject to the following conditions: (i) You may not indicate in +any way that your Modified License is the "Open Software License" or "OSL" and +you may not use those names in the name of your Modified License; (ii) You +must replace the notice specified in the first paragraph above with the notice +"Licensed under " or with a notice of your own +that is not confusingly similar to the notice in this License; and (iii) You +may not claim that your original works are open source software unless your +Modified License has been approved by Open Source Initiative (OSI) and You +comply with its license review and certification process. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c275b6 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Aliucord Manager +Aliucord Manager - Aliucord Installer rewrite in [Kotlin](https://kotlinlang.org) and [Jetpack Compose](https://developer.android.com/jetpack/compose). + +INFO: This app is not functional yet, if you want to install Aliucord - [read this](https://github.com/Aliucord/Aliucord#-installation) diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..af23557 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +val accompanistVersion = "0.14.0" +val composeVersion = "1.0.0-rc02" + +plugins { + id("com.android.application") + id("kotlin-android") +} + +android { + compileSdk = 30 + + defaultConfig { + applicationId = "com.aliucord.manager" + minSdk = 24 + targetSdk = 30 + versionCode = 1 + versionName = "0.0.1" + + vectorDrawables.useSupportLibrary = true + + buildConfigField("String", "TAG", "\"AliucordManager\"") + buildConfigField("String", "SUPPORT_SERVER", "\"EsNDvBaHVU\"") + } + + buildTypes { + release { + isMinifyEnabled = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn" + } + buildFeatures { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = composeVersion + } +} + +dependencies { + // core dependencies + implementation("androidx.appcompat:appcompat:1.3.0") + implementation("androidx.core:core-ktx:1.6.0") + implementation("com.google.android.material:material:1.4.0") + + // compose dependencies + implementation("androidx.activity:activity-compose:1.3.0-rc02") + implementation("androidx.compose.ui:ui:${composeVersion}") + implementation("androidx.compose.material:material:${composeVersion}") + implementation("androidx.compose.ui:ui-tooling:${composeVersion}") + implementation("androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha08") + implementation("androidx.navigation:navigation-compose:2.4.0-alpha04") + + // accompanist dependencies + implementation("com.google.accompanist:accompanist-systemuicontroller:${accompanistVersion}") + implementation("com.google.accompanist:accompanist-permissions:${accompanistVersion}") + + // other dependencies + implementation("com.google.code.gson:gson:2.8.7") +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..9f38a9b --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,19 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +-keep class com.aliucord.manager.models.** { private final *; } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f73aa81 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/aliucord/manager/models/Commit.kt b/app/src/main/java/com/aliucord/manager/models/Commit.kt new file mode 100644 index 0000000..9e07eed --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/models/Commit.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.models + +import com.google.gson.annotations.SerializedName + +class Commit( + @SerializedName("html_url") val htmlUrl: String, + val sha: String, + val commit: Commit, + val author: Author +) { + class Author(@SerializedName("login") val name: String) + class Commit(val message: String) +} diff --git a/app/src/main/java/com/aliucord/manager/preferences/Preferences.kt b/app/src/main/java/com/aliucord/manager/preferences/Preferences.kt new file mode 100644 index 0000000..e02b538 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/preferences/Preferences.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.preferences + +import android.content.SharedPreferences +import androidx.compose.runtime.mutableStateOf +import kotlin.reflect.KProperty + +var sharedPreferences: SharedPreferences? = null + +class Preference( + private val key: String, + defaultValue: T, + getter: SharedPreferences.(key: String, defaultValue: T) -> T?, + private val setter: SharedPreferences.Editor.(key: String, newValue: T) -> Unit +) { + val value = mutableStateOf(sharedPreferences!!.getter(key, defaultValue) ?: defaultValue) + + operator fun getValue(thisRef: Any?, property: KProperty<*>) = value.value + + operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: T) = set(newValue) + + fun get() = value.value + + fun set(newValue: T) { + if (value.value != newValue) { + value.value = newValue + val editor = sharedPreferences!!.edit() + editor.setter(key, newValue) + editor.apply() + } + } +} + +fun boolPreference( + key: String, + defaultValue: Boolean = false +) = Preference( + key, + defaultValue, + SharedPreferences::getBoolean, + SharedPreferences.Editor::putBoolean +) + +fun intPreference( + key: String, + defaultValue: Int = 0 +) = Preference( + key, + defaultValue, + SharedPreferences::getInt, + SharedPreferences.Editor::putInt +) + +fun stringPreference( + key: String, + defaultValue: String +) = Preference( + key, + defaultValue, + SharedPreferences::getString, + SharedPreferences.Editor::putString +) diff --git a/app/src/main/java/com/aliucord/manager/preferences/PreferencesHolder.kt b/app/src/main/java/com/aliucord/manager/preferences/PreferencesHolder.kt new file mode 100644 index 0000000..bf14bba --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/preferences/PreferencesHolder.kt @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.preferences + +import android.os.Environment + +val themePreference = intPreference("theme") +val replaceBgPreference = boolPreference("replace_bg", true) +val useDexFromStoragePreference = boolPreference("use_dex_from_storage") +val dexLocationPreference = stringPreference("dex_location", Environment.getExternalStorageDirectory().absolutePath + "/Aliucord/Aliucord.dex") diff --git a/app/src/main/java/com/aliucord/manager/ui/MainActivity.kt b/app/src/main/java/com/aliucord/manager/ui/MainActivity.kt new file mode 100644 index 0000000..c412022 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/MainActivity.kt @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui + +import android.Manifest +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import com.aliucord.manager.BuildConfig +import com.aliucord.manager.R +import com.aliucord.manager.preferences.sharedPreferences +import com.aliucord.manager.ui.theme.AliucordManagerTheme +import com.aliucord.manager.ui.theme.primaryColor +import com.aliucord.manager.ui.theme.primaryColorDark +import com.aliucord.manager.utils.Github +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.PermissionRequired +import com.google.accompanist.permissions.PermissionState +import com.google.accompanist.permissions.rememberPermissionState +import com.google.accompanist.systemuicontroller.rememberSystemUiController + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + sharedPreferences = getSharedPreferences(BuildConfig.APPLICATION_ID + "_preferences", Context.MODE_PRIVATE) + Github.checkForUpdates() + setContent { + AliucordManagerTheme { + MainActivityLayout() + } + } + } +} + +@OptIn(ExperimentalPermissionsApi::class) +@Composable +fun MainActivityLayout() { + val systemUiController = rememberSystemUiController() + val storagePermissionState = rememberPermissionState(Manifest.permission.WRITE_EXTERNAL_STORAGE) + + SideEffect { + systemUiController.setSystemBarsColor(primaryColorDark) + if (!storagePermissionState.hasPermission) storagePermissionState.launchPermissionRequest() + } + + val navController = rememberNavController() + var isMenuExpanded by remember { mutableStateOf(false) } + + Scaffold( + topBar = { + val route = navController.currentBackStackEntryAsState().value?.destination?.route ?: Screen.Home.route + TopAppBar( + title = { Text(stringResource(Screen.SCREENS.find { it.route == route }!!.displayName)) }, + backgroundColor = primaryColor, + contentColor = MaterialTheme.colors.onPrimary, + navigationIcon = if (route != Screen.Home.route) {{ + IconButton(onClick = { navController.popBackStack() }) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = null, + tint = MaterialTheme.colors.onPrimary + ) + } + }} else null, + actions = { + if (route != Screen.Home.route) return@TopAppBar + val context = LocalContext.current + IconButton(onClick = { context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://discord.gg/${BuildConfig.SUPPORT_SERVER}"))) }) { + Icon( + painter = painterResource(R.drawable.ic_discord), + contentDescription = null, + tint = MaterialTheme.colors.onPrimary + ) + } + IconButton(onClick = { isMenuExpanded = !isMenuExpanded }) { + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = stringResource(R.string.show_menu), + tint = MaterialTheme.colors.onPrimary + ) + } + DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) { + DropdownMenuItem(onClick = { + isMenuExpanded = false + navController.navigate(Screen.Settings.route) { + popUpTo(Screen.Home.route) { saveState = true } + } + }) { + Text(stringResource(id = Screen.Settings.displayName)) + } + } + } + ) + } + ) { + PermissionRequired( + permissionState = storagePermissionState, + permissionNotGrantedContent = { GrantPermission(permissionState = storagePermissionState) }, + permissionNotAvailableContent = { GrantPermission(permissionState = storagePermissionState) } + ) { + NavHost( + navController, + startDestination = Screen.Home.route + ) { + for (screen in Screen.SCREENS) { + composable(screen.route) { screen.content() } + } + } + } + } +} + +@OptIn(ExperimentalPermissionsApi::class) +@Composable +fun GrantPermission(permissionState: PermissionState) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(stringResource(R.string.permission_required), style = MaterialTheme.typography.h6, textAlign = TextAlign.Center) + Spacer(Modifier.height(8.dp)) + Row { + val context = LocalContext.current + + Button(onClick = { permissionState.launchPermissionRequest() }) { + Text(stringResource(R.string.permission_grant)) + } + Spacer(Modifier.width(8.dp)) + Button( + onClick = { + context.startActivity(Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", BuildConfig.APPLICATION_ID, null) + )) + }, + colors = ButtonDefaults.buttonColors(backgroundColor = Color.LightGray, contentColor = Color.Black) + ) { + Text(stringResource(R.string.open_settings)) + } + } + } +} diff --git a/app/src/main/java/com/aliucord/manager/ui/Screen.kt b/app/src/main/java/com/aliucord/manager/ui/Screen.kt new file mode 100644 index 0000000..73bc708 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/Screen.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui + +import androidx.annotation.StringRes +import androidx.compose.runtime.Composable +import com.aliucord.manager.R +import com.aliucord.manager.ui.screens.HomeScreen +import com.aliucord.manager.ui.screens.SettingsScreen + +sealed class Screen( + val route: String, + @StringRes val displayName: Int, + val content: @Composable () -> Unit +) { + companion object { + // NOTE: without lazy it doesn't work, kotlin moment https://youtrack.jetbrains.com/issue/KT-8970 + val SCREENS by lazy { listOf(Home, Settings) } + } + + object Home : Screen( + "home", + R.string.app_name, + { HomeScreen() } + ) + + object Settings : Screen( + "settings", + R.string.settings, + { SettingsScreen() } + ) +} diff --git a/app/src/main/java/com/aliucord/manager/ui/components/CommitsList.kt b/app/src/main/java/com/aliucord/manager/ui/components/CommitsList.kt new file mode 100644 index 0000000..5a2d245 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/components/CommitsList.kt @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.components + +import android.annotation.SuppressLint +import android.content.Intent +import android.graphics.Color +import android.net.Uri +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.viewinterop.AndroidView +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.RecyclerView +import com.aliucord.manager.BuildConfig +import com.aliucord.manager.R +import com.aliucord.manager.models.Commit +import com.aliucord.manager.ui.theme.isDark +import com.aliucord.manager.utils.Github +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +private class CommitData( + val commit: Commit, + val buildSha: String? +) + +@Composable +fun CommitsList(selectedCommit: MutableState, modifier: Modifier = Modifier) { + val coroutineScope = rememberCoroutineScope { Dispatchers.IO } + var isLoading by remember { mutableStateOf(true) } + val commits = remember { mutableStateListOf() } + + if (isLoading) { + ConstraintLayout(modifier = modifier + .fillMaxSize() + .padding(12.dp)) { + CommitsHeader() + CircularProgressIndicator(modifier = Modifier.constrainAs(createRef()) { + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + }) + } + + LaunchedEffect(null) { + coroutineScope.launch { + try { + val buildCommits = Github.getCommits(mapOf("sha" to "builds", "path" to "Aliucord.dex", "per_page" to "50")) + val commits2 = Github.getCommits(mapOf("per_page" to "50")) + commits.addAll(commits2.map { c -> CommitData(c, buildCommits.find { bc -> bc.commit.message.substring(6) == c.sha }?.sha) }) + isLoading = false + if (commits.size > 0) selectedCommit.value = commits.firstOrNull { it.buildSha != null }?.buildSha + } catch (e: Throwable) { + Log.e(BuildConfig.TAG, "Failed to get commits", e) + } + } + } + } else { + val dark = isDark() + + // LazyColumn causes too much lags, also you can't get scrollbar on it, so I used AndroidView with RecyclerView for now + Column( + modifier = modifier + .fillMaxSize() + .padding(12.dp) + ) { + CommitsHeader() + AndroidView({ context -> View.inflate(context, R.layout.recycler, null).apply { + val rv = this as RecyclerView + rv.adapter = CommitsAdapter(commits, dark) + rv.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL)) + }}) + } + } +} + +@Composable +private fun CommitsHeader() { + Text(stringResource(R.string.commits), style = MaterialTheme.typography.subtitle1) +} + +private class CommitsAdapter(private val commits: List, private val dark: Boolean) : RecyclerView.Adapter() { + class ViewHolder(view: View, dark: Boolean) : RecyclerView.ViewHolder(view) { + val sha: TextView = view.findViewById(R.id.commit_sha) + val message: TextView = view.findViewById(R.id.commit_message) + + init { + message.setTextColor(if (dark) 0xccffffff.toInt() else 0xcc000000.toInt()) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.commit, parent, false), dark) + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val data = commits[position] + val commit = data.commit + val color = if (data.buildSha != null) holder.sha.context.getColor(R.color.primary) else Color.GRAY + + holder.sha.text = commit.sha.substring(0, 7) + holder.sha.setTextColor(color) + holder.sha.setOnClickListener { it.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(commit.htmlUrl))) } + + holder.message.text = "${commit.commit.message.split("\n")[0]} - ${commit.author.name}" + } + + override fun getItemCount() = commits.size +} diff --git a/app/src/main/java/com/aliucord/manager/ui/components/ExposedDropdownMenu.kt b/app/src/main/java/com/aliucord/manager/ui/components/ExposedDropdownMenu.kt new file mode 100644 index 0000000..11da15e --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/components/ExposedDropdownMenu.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.components + +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.width +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@ExperimentalMaterialApi +@Composable +fun ExposedDropdownMenu( + items: Array, + selectedItem: Int, + selectItem: (item: Int) -> Unit = {}, + width: Dp = 200.dp +) { + var expanded by remember { mutableStateOf(false) } + val rotateAnimation by animateFloatAsState( + targetValue = if (expanded) 180F else 0F, + animationSpec = tween( + durationMillis = 250, + easing = FastOutSlowInEasing + ) + ) + + Column(modifier = Modifier.width(width)) { + ListItem( + text = { Text(items[selectedItem]) }, + trailing = { + Icon(imageVector = Icons.Filled.ArrowDropDown, contentDescription = null, modifier = Modifier.rotate(rotateAnimation)) + }, + modifier = Modifier.clickable { expanded = !expanded } + ) + if (expanded) Divider(color = MaterialTheme.colors.primary) else Divider() + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.width(width) + ) { + items.forEachIndexed { i, item -> + DropdownMenuItem( + onClick = { selectItem(i) } + ) { + Text(item) + } + } + } + } +} diff --git a/app/src/main/java/com/aliucord/manager/ui/screens/HomeScreen.kt b/app/src/main/java/com/aliucord/manager/ui/screens/HomeScreen.kt new file mode 100644 index 0000000..ba41008 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/screens/HomeScreen.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.screens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Card +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ListItem +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.aliucord.manager.ui.components.CommitsList + +@OptIn(ExperimentalMaterialApi::class) +@Composable +@Preview +fun HomeScreen() { + val selectedCommit = remember { mutableStateOf(null) } + Column(modifier = Modifier.padding(8.dp)) { + Card(modifier = Modifier.padding(bottom = 8.dp)) { + ListItem( + text = { Text("Aliucord") }, + secondaryText = { Text(buildAnnotatedString { + append("Supported version: ") + withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(selectedCommit.value ?: "blah") } + }) }, + modifier = Modifier.padding(vertical = 4.dp) + ) + } + Card { CommitsList(selectedCommit) } + } +} diff --git a/app/src/main/java/com/aliucord/manager/ui/screens/SettingsScreen.kt b/app/src/main/java/com/aliucord/manager/ui/screens/SettingsScreen.kt new file mode 100644 index 0000000..8e19c47 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/screens/SettingsScreen.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.screens + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.aliucord.manager.R +import com.aliucord.manager.preferences.dexLocationPreference +import com.aliucord.manager.preferences.replaceBgPreference +import com.aliucord.manager.preferences.themePreference +import com.aliucord.manager.preferences.useDexFromStoragePreference +import com.aliucord.manager.ui.components.ExposedDropdownMenu + +private val themes = arrayOf("System", "Light", "Dark") + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun SettingsScreen() { + Column { + val modifier = Modifier.padding(top = 8.dp) + + ListItem( + text = { Text(stringResource(R.string.theme)) }, + trailing = { + ExposedDropdownMenu( + items = themes, + selectedItem = themePreference.get(), + selectItem = themePreference::set + ) + }, + modifier = modifier + ) + ListItem( + text = { Text(stringResource(R.string.replace_bg)) }, + trailing = { + Checkbox( + checked = replaceBgPreference.get(), + onCheckedChange = replaceBgPreference::set + ) + }, + modifier = modifier.clickable { replaceBgPreference.set(!replaceBgPreference.get()) } + ) + val udfs = useDexFromStoragePreference.get() + ListItem( + text = { Text(stringResource(R.string.use_dex_from_storage)) }, + trailing = { + Checkbox( + checked = udfs, + onCheckedChange = useDexFromStoragePreference::set + ) + }, + modifier = modifier.clickable { useDexFromStoragePreference.set(!useDexFromStoragePreference.get()) } + ) + val color = if (udfs) Color.Unspecified else MaterialTheme.colors.onBackground.copy(ContentAlpha.disabled) + ListItem( + text = { Text(stringResource(R.string.dex_location), color = color) }, + secondaryText = { Text(dexLocationPreference.get(), color = color) }, + modifier = if (udfs) modifier.clickable { /*TODO*/ } else modifier + ) + Button( + onClick = { /*TODO*/ }, + Modifier + .fillMaxWidth() + .padding(8.dp) + ) { + Text(stringResource(R.string.clear_files_cache), textAlign = TextAlign.Center) + } + } +} diff --git a/app/src/main/java/com/aliucord/manager/ui/theme/Color.kt b/app/src/main/java/com/aliucord/manager/ui/theme/Color.kt new file mode 100644 index 0000000..ef7d96c --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/theme/Color.kt @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.theme + +import androidx.compose.ui.graphics.Color + +val darkBackground = Color(0xff2e2e2e) + +val primaryColor = Color(0xff00c853) +val primaryColorLight = Color(0xff5efc82) +val primaryColorDark = Color(0xff009624) diff --git a/app/src/main/java/com/aliucord/manager/ui/theme/Shape.kt b/app/src/main/java/com/aliucord/manager/ui/theme/Shape.kt new file mode 100644 index 0000000..de1a2bb --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/theme/Shape.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) diff --git a/app/src/main/java/com/aliucord/manager/ui/theme/Theme.kt b/app/src/main/java/com/aliucord/manager/ui/theme/Theme.kt new file mode 100644 index 0000000..805a8e7 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/theme/Theme.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import com.aliucord.manager.preferences.themePreference + +private val DarkColorPalette = darkColors( + primary = primaryColor, + primaryVariant = primaryColorDark, + secondary = primaryColorLight, + + onPrimary = Color.White, + background = darkBackground, + surface = Color(0xff424242) +) + +private val LightColorPalette = lightColors( + primary = primaryColor, + primaryVariant = primaryColorDark, + secondary = primaryColorLight +) + +@Composable +fun isDark() = when (themePreference.value.value) { + 0 -> isSystemInDarkTheme() + 1 -> false + else -> true +} + +@Composable +fun AliucordManagerTheme(content: @Composable () -> Unit) { + val colors = if (isDark()) DarkColorPalette else LightColorPalette + + MaterialTheme( + colors, + typography = Typography, + shapes = Shapes, + content + ) +} diff --git a/app/src/main/java/com/aliucord/manager/ui/theme/Type.kt b/app/src/main/java/com/aliucord/manager/ui/theme/Type.kt new file mode 100644 index 0000000..ee4418d --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/ui/theme/Type.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp + ) +) diff --git a/app/src/main/java/com/aliucord/manager/utils/Github.kt b/app/src/main/java/com/aliucord/manager/utils/Github.kt new file mode 100644 index 0000000..4c290d4 --- /dev/null +++ b/app/src/main/java/com/aliucord/manager/utils/Github.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +package com.aliucord.manager.utils + +import com.aliucord.manager.models.Commit +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import java.io.InputStreamReader +import java.net.URL + +object Github { + private const val org = "Aliucord" + private const val repo = "Aliucord" + + private const val commitsUrl = "https://api.github.com/repos/${org}/${repo}/commits" + + fun checkForUpdates() { + // TODO + } + + private val commitsCache = HashMap>() + private val commitsType = object : TypeToken>() {}.type + private val gson = Gson() + + fun getCommits(params: Map?): Array { + // return emptyArray() + val query = params?.map { it.key + "=" + it.value }?.joinToString("&", "?") ?: "" + if (commitsCache.containsKey(query)) return commitsCache[query] ?: emptyArray() + val res = gson.fromJson>( + InputStreamReader(URL(commitsUrl + query).openStream()), + commitsType + ) + commitsCache[query] = res + return res + } + + fun getDownloadUrl(ref: String, file: String): String { + return "'https://raw.githubusercontent.com/${org}/${repo}/${ref}/${file}"; + } +} diff --git a/app/src/main/res/drawable/divider.xml b/app/src/main/res/drawable/divider.xml new file mode 100644 index 0000000..c646b35 --- /dev/null +++ b/app/src/main/res/drawable/divider.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_discord.xml b/app/src/main/res/drawable/ic_discord.xml new file mode 100644 index 0000000..7529205 --- /dev/null +++ b/app/src/main/res/drawable/ic_discord.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..f0a6991 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/app/src/main/res/layout/commit.xml b/app/src/main/res/layout/commit.xml new file mode 100644 index 0000000..3ea4837 --- /dev/null +++ b/app/src/main/res/layout/commit.xml @@ -0,0 +1,20 @@ + + + + + diff --git a/app/src/main/res/layout/recycler.xml b/app/src/main/res/layout/recycler.xml new file mode 100644 index 0000000..634b8cd --- /dev/null +++ b/app/src/main/res/layout/recycler.xml @@ -0,0 +1,8 @@ + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..426f6f0 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..512cb0a Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..f5f0dcf Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..9c578ca Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..a5b7f6a Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b6c752c Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d6f0c21 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..41d74fe Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..c5c22b1 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..7fae848 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..dbdc918 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #00c853 + diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..476c564 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,14 @@ + + Aliucord Manager + Clear files cache (Aliucord.dex and patched manifest) + Commits + Dex location + Open settings + You need to grant storage permission to use this app + Grant permission + Replace icon background with Aliucord\'s + Settings + Show menu + Theme + Use Aliucord.dex from storage + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..8a3fc43 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000..476311e --- /dev/null +++ b/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,4 @@ + + + + diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..564619f --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:7.1.0-alpha03") + @Suppress("GradleDependency") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10") + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle.kts files + } +} + +tasks.register("clean", Delete::class) { + delete(rootProject.buildDir) +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..98bed16 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c0b2dd --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Jul 12 01:52:20 CEST 2021 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..defd771 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 Juby210 + * Licensed under the Open Software License version 3.0 + */ + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Aliucord Manager" +include(":app")