diff --git a/app/build.gradle b/app/build.gradle index f3d811c..7db9d48 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,10 +9,10 @@ android { defaultConfig { applicationId "com.nin0dev.vendroid" - minSdk 21 + minSdk 25 targetSdk 34 - versionCode 5 - versionName "1.2" + versionCode 7 + versionName "1.4" } buildTypes { @@ -37,6 +37,7 @@ dependencies { implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.activity:activity:1.9.1' + implementation 'com.google.code.gson:gson:2.11.0' implementation 'com.android.volley:volley:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' } diff --git a/app/src/debug/res/xml/shortcuts.xml b/app/src/debug/res/xml/shortcuts.xml new file mode 100644 index 0000000..7b9f82f --- /dev/null +++ b/app/src/debug/res/xml/shortcuts.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 871864a..def834c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,11 @@ android:theme="@style/AppTheme" android:usesCleartextTraffic="true" tools:targetApi="34"> + @@ -27,6 +32,10 @@ android:exported="true" android:launchMode="singleTask" android:theme="@style/AppTheme"> + + @@ -50,4 +59,4 @@ - + \ No newline at end of file diff --git a/app/src/main/java/com/nin0dev/vendroid/HttpClient.kt b/app/src/main/java/com/nin0dev/vendroid/HttpClient.kt index 570f245..301545c 100644 --- a/app/src/main/java/com/nin0dev/vendroid/HttpClient.kt +++ b/app/src/main/java/com/nin0dev/vendroid/HttpClient.kt @@ -25,7 +25,7 @@ object HttpClient { val res = activity.resources res.openRawResource(R.raw.vencord_mobile).use { `is` -> VencordMobileRuntime = readAsText(`is`) } if (VencordRuntime != null) return - if (sPrefs.getString("vencordLocation", Constants.JS_BUNDLE_URL) == Constants.JS_BUNDLE_URL || BuildConfig.DEBUG) { // user is debugging vencord or app, always redownload + if (sPrefs.getString("vencordLocation", Constants.JS_BUNDLE_URL) != Constants.JS_BUNDLE_URL || BuildConfig.DEBUG) { // user is debugging vencord or app, always redownload Toast.makeText(activity, "Debugging app or Vencord, bundle will be redownloaded. Avoid using on limited networks", Toast.LENGTH_LONG).show() vendroidFile.delete() } diff --git a/app/src/main/java/com/nin0dev/vendroid/MainActivity.kt b/app/src/main/java/com/nin0dev/vendroid/MainActivity.kt index 7ef9160..b66c3f6 100644 --- a/app/src/main/java/com/nin0dev/vendroid/MainActivity.kt +++ b/app/src/main/java/com/nin0dev/vendroid/MainActivity.kt @@ -11,6 +11,7 @@ import android.os.Bundle import android.os.StrictMode import android.os.StrictMode.ThreadPolicy import android.view.KeyEvent +import android.view.View.VISIBLE import android.view.WindowManager import android.webkit.ValueCallback import android.webkit.WebView @@ -19,47 +20,60 @@ import com.android.volley.Request import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.Volley import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.gson.Gson import com.nin0dev.vendroid.HttpClient.fetchVencord import com.nin0dev.vendroid.Logger.e +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import pl.droidsonroids.gif.GifImageView import java.io.IOException + +@Serializable +data class UpdateData(val version: Int, val changelog: String) + class MainActivity : Activity() { private var wvInitialized = false private var wv: WebView? = null @JvmField var filePathCallback: ValueCallback?>? = null + @OptIn(ExperimentalSerializationApi::class) fun checkUpdates(ignoreSetting: Boolean = false) { val sPrefs = getSharedPreferences("settings", Context.MODE_PRIVATE) if(sPrefs.getBoolean("checkVendroidUpdates", false) || ignoreSetting) { val queue = Volley.newRequestQueue(this) - val url = "https://raw.githubusercontent.com/VendroidEnhanced/UpdateTracker/main/vendroid" + val url = "https://vendroid.nin0.dev/api/updates" val stringRequest = StringRequest( - Request.Method.GET, url, - { response -> - if(Integer.parseInt(response.trim()) != BuildConfig.VERSION_CODE) - { - val madb = MaterialAlertDialogBuilder(this) - madb.setTitle(getString(R.string.vendroid_update_available)) - madb.setMessage("To make sure that no unexpected bugs happen, it is recommended to update.") - madb.setPositiveButton(getString(R.string.update), DialogInterface.OnClickListener { dialogInterface, i -> - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/VendroidEnhanced/Vendroid/releases/latest/download/app-release.apk")) - startActivity(browserIntent) - }) - madb.setNegativeButton(getString(R.string.later), DialogInterface.OnClickListener { _, _ -> }) - madb.show() - } - if(ignoreSetting && Integer.parseInt(response.trim()) == BuildConfig.VERSION_CODE) { - showDiscordToast("No updates available", "MESSAGE") - } - }, - { error -> - if (BuildConfig.DEBUG) { - e("Network error during update check", error) - } - Toast.makeText(this, "Failed to check for updates", Toast.LENGTH_SHORT).show() + Request.Method.GET, url, + { response -> + val gson = Gson() + val updateData = gson.fromJson(response, UpdateData::class.java) + if(updateData.version != BuildConfig.VERSION_CODE) + { + val madb = MaterialAlertDialogBuilder(this) + madb.setTitle(getString(R.string.vendroid_update_available)) + madb.setMessage("Changelog:\n" + updateData.changelog) + madb.setPositiveButton(getString(R.string.update), DialogInterface.OnClickListener { dialogInterface, i -> + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/VendroidEnhanced/Vendroid/releases/latest/download/app-release.apk")) + startActivity(browserIntent) + }) + madb.setNegativeButton(getString(R.string.later), DialogInterface.OnClickListener { _, _ -> }) + madb.show() } + if(ignoreSetting && updateData.version == BuildConfig.VERSION_CODE) { + showDiscordToast("No updates available", "MESSAGE") + } + }, + { error -> + if (BuildConfig.DEBUG) { + e("Network error during update check", error) + } + Toast.makeText(this, "Failed to check for updates", Toast.LENGTH_SHORT).show() + } ) stringRequest.setShouldCache(false); queue.add(stringRequest) @@ -75,9 +89,13 @@ class MainActivity : Activity() { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) window.navigationBarColor = Color.TRANSPARENT val sPrefs = getSharedPreferences("settings", Context.MODE_PRIVATE) + val editor = sPrefs.edit() // https://developer.chrome.com/docs/devtools/remote-debugging/webviews/ WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG) setContentView(R.layout.activity_main) + if (sPrefs.getString("splash", "viggy") == "viggy") findViewById(R.id.viggy_gif).visibility = VISIBLE + else if (sPrefs.getString("splash", "viggy") == "shiggy") findViewById(R.id.shiggy_gif).visibility = VISIBLE + else if (sPrefs.getString("splash", "viggy") == "oneko") findViewById(R.id.oneko_gif).visibility = VISIBLE wv = findViewById(R.id.webview)!! explodeAndroid() wv!!.setWebViewClient(VWebviewClient()) @@ -86,11 +104,18 @@ class MainActivity : Activity() { s.javaScriptEnabled = true s.domStorageEnabled = true s.allowFileAccess = true - wv?.addJavascriptInterface(VencordNative(this, wv!!), "VencordMobileNative") - try { - fetchVencord(this) - } catch (ex: IOException) { + if(!sPrefs.getBoolean("safeMode", false)) { + wv?.addJavascriptInterface(VencordNative(this, wv!!), "VencordMobileNative") + try { + fetchVencord(this) + } catch (ex: IOException) { + } + } + else { + Toast.makeText(this, "Safe mode enabled, Vencord won't be loaded", Toast.LENGTH_SHORT).show() + editor.putBoolean("safeMode", false) + editor.apply() } val intent = intent if (intent.action == Intent.ACTION_VIEW) { @@ -117,36 +142,44 @@ class MainActivity : Activity() { return super.onKeyDown(keyCode, event) } - override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent) { - if (requestCode != FILECHOOSER_RESULTCODE || filePathCallback == null) return - if (resultCode != RESULT_OK || intent == null) { - filePathCallback!!.onReceiveValue(null) - } else { - var uris: Array? - try { - val clipData = intent.clipData - if (clipData != null) { // multiple items - uris = arrayOfNulls(clipData.itemCount) - for (i in 0 until clipData.itemCount) { - uris[i] = clipData.getItemAt(i).uri + override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { + super.onActivityResult(requestCode, resultCode, intent) + try { + if(resultCode != RESULT_CANCELED) { + if (requestCode != FILECHOOSER_RESULTCODE || filePathCallback == null) return + if (resultCode != RESULT_OK || intent == null) { + filePathCallback!!.onReceiveValue(null) + } else { + var uris: Array? + try { + val clipData = intent.clipData + if (clipData != null) { // multiple items + uris = arrayOfNulls(clipData.itemCount) + for (i in 0 until clipData.itemCount) { + uris[i] = clipData.getItemAt(i).uri + } + } else { // single item + uris = arrayOf(intent.data) + } + } catch (ex: Exception) { + e("Error during file upload", ex) + uris = null } - } else { // single item - uris = arrayOf(intent.data) + filePathCallback!!.onReceiveValue(uris) } - } catch (ex: Exception) { - e("Error during file upload", ex) - uris = null + filePathCallback = null } - filePathCallback!!.onReceiveValue(uris) } - filePathCallback = null + catch (ex: Exception) { + // it is well known that the best fix for the crash is to wrap the entire function in a try/catch block + } } private fun explodeAndroid() { StrictMode.setThreadPolicy( - ThreadPolicy.Builder() // trolley - .permitNetwork() - .build() + ThreadPolicy.Builder() // trolley + .permitNetwork() + .build() ) } diff --git a/app/src/main/java/com/nin0dev/vendroid/RecoveryActivity.kt b/app/src/main/java/com/nin0dev/vendroid/RecoveryActivity.kt new file mode 100644 index 0000000..45bc602 --- /dev/null +++ b/app/src/main/java/com/nin0dev/vendroid/RecoveryActivity.kt @@ -0,0 +1,51 @@ +package com.nin0dev.vendroid + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.view.WindowManager +import android.webkit.CookieManager +import android.webkit.CookieSyncManager +import android.webkit.WebView +import android.widget.Button +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import com.google.android.material.card.MaterialCardView +import com.google.android.material.snackbar.Snackbar + +class RecoveryActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + window.statusBarColor = Color.TRANSPARENT + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) + window.navigationBarColor = Color.TRANSPARENT + + setContentView(R.layout.activity_recovery) + + findViewById(R.id.start_normally).setOnClickListener { + finish() + startActivity(Intent(this, MainActivity::class.java)) + } + findViewById(R.id.safe_mode).setOnClickListener { + val sPrefs = getSharedPreferences("settings", Context.MODE_PRIVATE) + val e = sPrefs.edit() + e.putBoolean("safeMode", true) + e.apply() + finish() + startActivity(Intent(this, MainActivity::class.java)) + } + findViewById(R.id.settings).setOnClickListener { + finish() + startActivity(Intent(this, SettingsActivity::class.java)) + } + + } + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nin0dev/vendroid/SettingsActivity.kt b/app/src/main/java/com/nin0dev/vendroid/SettingsActivity.kt index a6470e2..54a6e15 100644 --- a/app/src/main/java/com/nin0dev/vendroid/SettingsActivity.kt +++ b/app/src/main/java/com/nin0dev/vendroid/SettingsActivity.kt @@ -37,6 +37,11 @@ class SettingsActivity : AppCompatActivity() { "ptb" -> findViewById(R.id.ptb).isChecked = true "canary" -> findViewById(R.id.canary).isChecked = true } + when (sPrefs.getString("splash", "viggy")) { + "viggy" -> findViewById(R.id.viggy).isChecked = true + "shiggy" -> findViewById(R.id.shiggy).isChecked = true + "oneko" -> findViewById(R.id.oneko).isChecked = true + } if(sPrefs.getString("vencordLocation", "")?.isNotBlank() == true) { findViewById(R.id.allow_custom_location).isChecked = true val devbuildField = findViewById(R.id.custom_location) @@ -71,6 +76,9 @@ class SettingsActivity : AppCompatActivity() { if (findViewById(R.id.stable).isChecked) editor.putString("discordBranch", "stable") if (findViewById(R.id.ptb).isChecked) editor.putString("discordBranch", "ptb") if (findViewById(R.id.canary).isChecked) editor.putString("discordBranch", "canary") + if (findViewById(R.id.viggy).isChecked) editor.putString("splash", "viggy") + if (findViewById(R.id.shiggy).isChecked) editor.putString("splash", "shiggy") + if (findViewById(R.id.oneko).isChecked) editor.putString("splash", "oneko") if (findViewById(R.id.allow_custom_location).isChecked && findViewById(R.id.custom_location).text.isNotBlank()) editor.putString("vencordLocation", findViewById(R.id.custom_location).text.toString()) editor.apply() diff --git a/app/src/main/java/com/nin0dev/vendroid/VWebviewClient.kt b/app/src/main/java/com/nin0dev/vendroid/VWebviewClient.kt index 7dc8566..999e489 100644 --- a/app/src/main/java/com/nin0dev/vendroid/VWebviewClient.kt +++ b/app/src/main/java/com/nin0dev/vendroid/VWebviewClient.kt @@ -8,9 +8,12 @@ import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebView import android.webkit.WebViewClient +import android.widget.Toast import androidx.annotation.RequiresApi import com.nin0dev.vendroid.Logger.e +import java.io.File import java.io.IOException +import java.lang.Exception import java.net.HttpURLConnection import java.net.URL @@ -26,8 +29,13 @@ class VWebviewClient : WebViewClient() { } override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - view.evaluateJavascript(HttpClient.VencordRuntime!!, null) - view.evaluateJavascript(HttpClient.VencordMobileRuntime!!, null) + try { + HttpClient.VencordRuntime?.let { view.evaluateJavascript(it, null) } + HttpClient.VencordMobileRuntime?.let { view.evaluateJavascript(it, null) } + } + catch (e: Exception) { + Toast.makeText(view.context, "Couldn't load Vencord, try restarting the app.", Toast.LENGTH_LONG).show() + } } override fun onPageFinished(view: WebView, url: String) { diff --git a/app/src/main/java/com/nin0dev/vendroid/WelcomeActivity.kt b/app/src/main/java/com/nin0dev/vendroid/WelcomeActivity.kt index 950772b..5cca6af 100644 --- a/app/src/main/java/com/nin0dev/vendroid/WelcomeActivity.kt +++ b/app/src/main/java/com/nin0dev/vendroid/WelcomeActivity.kt @@ -27,25 +27,6 @@ class WelcomeActivity : AppCompatActivity() { setContentView(R.layout.activity_welcome) - val devbuildCheckbox = findViewById(R.id.allow_custom_location) - devbuildCheckbox.setOnClickListener { - if (devbuildCheckbox.isChecked) { - MaterialAlertDialogBuilder(this) - .setTitle("Warning") - .setMessage("If you set a custom location, you will be loading and injecting Vencord from a different location. This feature is meant for developers ONLY. Never edit this setting if someone else asked you to, or if you don't know what you're doing! If you do set a custom location, you will not be able to ask for support in the Vencord support channel or in this project's issues. Are you sure you want to continue?") - .setNegativeButton(resources.getString(R.string.no)) { _, _ -> - devbuildCheckbox.isChecked = false - } - .setPositiveButton(resources.getString(R.string.yes)) { _, _ -> - findViewById(R.id.custom_location).visibility = VISIBLE - } - .show() - } - else { - findViewById(R.id.custom_location).visibility = GONE - } - } - findViewById(R.id.save_settings).setOnClickListener { val sPrefs = getSharedPreferences("settings", Context.MODE_PRIVATE) val editor = sPrefs.edit() @@ -54,7 +35,6 @@ class WelcomeActivity : AppCompatActivity() { if (findViewById(R.id.stable).isChecked) editor.putString("discordBranch", "stable") if (findViewById(R.id.ptb).isChecked) editor.putString("discordBranch", "ptb") if (findViewById(R.id.canary).isChecked) editor.putString("discordBranch", "canary") - if (findViewById(R.id.allow_custom_location).isChecked && findViewById(R.id.custom_location).text.isNotBlank()) editor.putString("vencordLocation", findViewById(R.id.custom_location).text.toString()) editor.apply() finish() diff --git a/app/src/main/res/drawable/oneko.gif b/app/src/main/res/drawable/oneko.gif new file mode 100644 index 0000000..5fb66d1 Binary files /dev/null and b/app/src/main/res/drawable/oneko.gif differ diff --git a/app/src/main/res/drawable/reset.xml b/app/src/main/res/drawable/reset.xml new file mode 100644 index 0000000..3016471 --- /dev/null +++ b/app/src/main/res/drawable/reset.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable/shiggy.gif b/app/src/main/res/drawable/shiggy.gif new file mode 100644 index 0000000..05e628d Binary files /dev/null and b/app/src/main/res/drawable/shiggy.gif differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 3172543..217b0ec 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,11 +13,31 @@ android:orientation="vertical"> + android:src="@drawable/viggy" + android:visibility="gone" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 38f6cd2..0863bb1 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -40,6 +40,38 @@ android:enabled="false" android:text="@string/autocheck_vencord" /> + + + + + + + + + + + + - - - - - + android:layout_height="?attr/actionBarSize" + android:elevation="0dp" + app:layout_collapseMode="pin" + app:title="Vendroid Settings" + app:titleTextColor="@color/text" /> diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml index 3905fe6..9187b9a 100644 --- a/app/src/main/res/layout/activity_welcome.xml +++ b/app/src/main/res/layout/activity_welcome.xml @@ -71,34 +71,6 @@ android:text="@string/canary" /> - - - - - - - - - - @@ -110,22 +82,13 @@ android:layout_height="wrap_content" android:layout_width="match_parent"> - - - - - + android:layout_height="?attr/actionBarSize" + android:elevation="0dp" + app:layout_collapseMode="pin" + app:title="Welcome to Vendroid" + app:titleTextColor="@color/text" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db3eb93..9e51c1b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,7 +15,19 @@ Custom location URL No Yes - Vendroid update available + VendroidEnhanced update available Update Later + Viggy, by shoritsu + Shiggy, by naga_U + Oneko + Splash screen + Recovery mode + Cleared all cookies + Start normally + Don\'t do anything and start the app normally. + Safe mode + Use this option to launch the app and load Discord, but without Vencord or any VendroidEnhanced tweak injected. + Open settings + Configure VendroidEnhanced. \ No newline at end of file diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml new file mode 100644 index 0000000..a69e9ae --- /dev/null +++ b/app/src/main/res/xml/shortcuts.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file