From 5d7695aa154f294defa17e151d88df0b12c60098 Mon Sep 17 00:00:00 2001 From: Minteck Date: Tue, 3 Jan 2023 22:01:57 +0100 Subject: Initial commit --- .gitignore | 16 + .idea/.gitignore | 3 + .idea/.name | 1 + .idea/compiler.xml | 6 + .idea/deploymentTargetDropDown.xml | 17 + .idea/gradle.xml | 19 + .idea/jarRepositories.xml | 25 + .idea/kotlinc.xml | 6 + .idea/misc.xml | 10 + TODO.md | 3 + app/.gitignore | 1 + app/build.gradle.kts | 61 +++ app/proguard-rules.pro | 21 + app/release/app-release.apk | Bin 0 -> 5274500 bytes app/release/app-release.apk.zip | Bin 0 -> 4719976 bytes app/release/output-metadata.json | 20 + app/src/main/AndroidManifest.xml | 42 ++ app/src/main/ic_launcher-playstore.png | Bin 0 -> 11606 bytes .../main/java/dev/equestria/delta/HTTPRequest.kt | 61 +++ .../main/java/dev/equestria/delta/MainActivity.kt | 510 +++++++++++++++++++++ app/src/main/res/drawable-anydpi/ic_stat_name.xml | 16 + app/src/main/res/drawable-hdpi/ic_stat_name.png | Bin 0 -> 369 bytes app/src/main/res/drawable-mdpi/ic_stat_name.png | Bin 0 -> 312 bytes app/src/main/res/drawable-xhdpi/ic_stat_name.png | Bin 0 -> 430 bytes app/src/main/res/drawable-xxhdpi/ic_stat_name.png | Bin 0 -> 976 bytes app/src/main/res/drawable/baseline_home_24.xml | 10 + app/src/main/res/drawable/baseline_person_24.xml | 10 + app/src/main/res/drawable/baseline_search_24.xml | 10 + .../main/res/drawable/baseline_text_snippet_24.xml | 11 + app/src/main/res/drawable/defaultuser.xml | 46 ++ .../main/res/drawable/ic_launcher_foreground.xml | 33 ++ app/src/main/res/drawable/outline_home_24.xml | 10 + app/src/main/res/drawable/outline_person_24.xml | 10 + app/src/main/res/drawable/outline_search_24.xml | 10 + .../main/res/drawable/outline_text_snippet_24.xml | 11 + app/src/main/res/layout/activity_main.xml | 77 ++++ app/src/main/res/menu/action_bar.xml | 30 ++ app/src/main/res/menu/navigation_bar.xml | 29 ++ app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../res/mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3593 bytes app/src/main/res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 3593 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2278 bytes app/src/main/res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2278 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5255 bytes .../main/res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 5255 bytes app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 8377 bytes .../main/res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 8377 bytes app/src/main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 12020 bytes .../main/res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 12020 bytes app/src/main/res/values-fr/strings.xml | 26 ++ app/src/main/res/values-night/themes.xml | 3 + app/src/main/res/values/dimens.xml | 4 + app/src/main/res/values/ic_launcher_background.xml | 4 + app/src/main/res/values/strings.xml | 26 ++ app/src/main/res/values/themes.xml | 3 + app/src/main/res/values/values.xml | 5 + app/src/main/res/xml/backup_rules.xml | 1 + app/src/main/res/xml/data_extraction_rules.xml | 3 + app/src/main/res/xml/locales_config.xml | 4 + build.gradle.kts | 31 ++ gradle.properties | 23 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 ++++++++ gradlew.bat | 89 ++++ settings.gradle.kts | 9 + 67 files changed, 1567 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/kotlinc.xml create mode 100644 .idea/misc.xml create mode 100644 TODO.md create mode 100644 app/.gitignore create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/release/app-release.apk create mode 100644 app/release/app-release.apk.zip create mode 100644 app/release/output-metadata.json create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/ic_launcher-playstore.png create mode 100644 app/src/main/java/dev/equestria/delta/HTTPRequest.kt create mode 100644 app/src/main/java/dev/equestria/delta/MainActivity.kt create mode 100644 app/src/main/res/drawable-anydpi/ic_stat_name.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_name.png create mode 100644 app/src/main/res/drawable-mdpi/ic_stat_name.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_name.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_stat_name.png create mode 100644 app/src/main/res/drawable/baseline_home_24.xml create mode 100644 app/src/main/res/drawable/baseline_person_24.xml create mode 100644 app/src/main/res/drawable/baseline_search_24.xml create mode 100644 app/src/main/res/drawable/baseline_text_snippet_24.xml create mode 100644 app/src/main/res/drawable/defaultuser.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/outline_home_24.xml create mode 100644 app/src/main/res/drawable/outline_person_24.xml create mode 100644 app/src/main/res/drawable/outline_search_24.xml create mode 100644 app/src/main/res/drawable/outline_text_snippet_24.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/menu/action_bar.xml create mode 100644 app/src/main/res/menu/navigation_bar.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values-fr/strings.xml create mode 100644 app/src/main/res/values-night/themes.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/ic_launcher_background.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 app/src/main/res/values/values.xml create mode 100644 app/src/main/res/xml/backup_rules.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/main/res/xml/locales_config.xml create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93bfc47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties +app/google-services.json diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..dd4648f --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Delta \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..ab2c519 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..d58262b --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..d2ce72d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..0e65cea --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..1896758 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..dcd7589 --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +# TODO + +- About dialog diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..669068d --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,61 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("com.google.gms.google-services") +} + +android { + namespace = "dev.equestria.delta" + compileSdk = 33 + + defaultConfig { + applicationId = "dev.equestria.delta" + minSdk = 27 + targetSdk = 33 + versionCode = 2 + versionName = "5.0-8" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + resConfigs("en", "fr") + } + + buildFeatures { + buildConfig = true + } + + buildTypes { + getByName("release") { + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + implementation("com.android.volley:volley:1.2.1") + implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.appcompat:appcompat:1.5.1") + implementation("com.google.android.material:material:1.7.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.1") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1") + implementation("androidx.navigation:navigation-fragment-ktx:2.5.3") + implementation("androidx.navigation:navigation-ui-ktx:2.5.3") + implementation("androidx.core:core-ktx:1.9.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.4") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") + implementation("com.squareup.picasso:picasso:2.8") + implementation(platform("com.google.firebase:firebase-bom:31.1.1")) + implementation("com.google.firebase:firebase-analytics-ktx") + implementation("com.google.firebase:firebase-messaging-ktx") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..ff59496 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle.kts. +# +# 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 + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/release/app-release.apk b/app/release/app-release.apk new file mode 100644 index 0000000..b53f9dc Binary files /dev/null and b/app/release/app-release.apk differ diff --git a/app/release/app-release.apk.zip b/app/release/app-release.apk.zip new file mode 100644 index 0000000..7cdcd1a Binary files /dev/null and b/app/release/app-release.apk.zip differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json new file mode 100644 index 0000000..b6a0617 --- /dev/null +++ b/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "dev.equestria.delta", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 2, + "versionName": "5.0-8", + "outputFile": "app-release.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..297d49c --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..118d501 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/dev/equestria/delta/HTTPRequest.kt b/app/src/main/java/dev/equestria/delta/HTTPRequest.kt new file mode 100644 index 0000000..1bebbc0 --- /dev/null +++ b/app/src/main/java/dev/equestria/delta/HTTPRequest.kt @@ -0,0 +1,61 @@ +package dev.equestria.delta + +import android.content.Context +import android.content.res.Resources +import android.util.Log +import com.android.volley.Request +import com.android.volley.toolbox.JsonObjectRequest +import com.android.volley.toolbox.Volley +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dev.equestria.delta.databinding.ActivityMainBinding +import org.json.JSONObject +import kotlin.system.exitProcess + +class HTTPRequest { + companion object { + fun request( + url: String, + session: String?, + context: Context, + resources: Resources, + activity: MainActivity, + initial: Boolean, + binding: ActivityMainBinding, + positiveCallback: (JSONObject) -> Unit = { }, + negativeCallback: (Unit) -> Unit = { } + ) { + val volleyQueue = Volley.newRequestQueue(context) + + val data = JSONObject() + data.put("session", session) + + val jsonObjectRequest = JsonObjectRequest(Request.Method.POST, url, data, + + { response -> + Log.i("HTTPRequest", response.toString()) + positiveCallback(response) + }, + + { error -> + MaterialAlertDialogBuilder(context).setCancelable(false) + .setTitle(resources.getString(R.string.offline_title)) + .setMessage(resources.getString(R.string.offline_message)) + .setPositiveButton(resources.getString(R.string.offline_retry)) { _, _ -> + if (initial) { + activity.initialCheck() + } else { + binding.webView.reload() + } + }.setNegativeButton(resources.getString(R.string.offline_close)) { _, _ -> + activity.moveTaskToBack(true) + exitProcess(0) + }.setNeutralButton(resources.getString(R.string.offline_status)) { _, _ -> + negativeCallback(Unit) + }.show() + Log.e("HTTPRequest", "Request error: ${error.localizedMessage}") + }) + + volleyQueue.add(jsonObjectRequest) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/equestria/delta/MainActivity.kt b/app/src/main/java/dev/equestria/delta/MainActivity.kt new file mode 100644 index 0000000..7e239c6 --- /dev/null +++ b/app/src/main/java/dev/equestria/delta/MainActivity.kt @@ -0,0 +1,510 @@ +package dev.equestria.delta + +import android.Manifest +import android.annotation.SuppressLint +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Intent +import android.content.res.Resources.getSystem +import android.graphics.Bitmap +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.webkit.CookieManager +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import com.google.android.gms.tasks.OnCompleteListener +import com.google.android.material.color.DynamicColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.elevation.SurfaceColors +import com.google.firebase.messaging.FirebaseMessaging +import com.squareup.picasso.Picasso +import com.squareup.picasso.Target +import dev.equestria.delta.databinding.ActivityMainBinding +import org.json.JSONObject +import java.net.URL +import kotlin.system.exitProcess + +val Int.dp: Int get() = (this / getSystem().displayMetrics.density).toInt() + +class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + private lateinit var appMenu: Menu + private lateinit var navigationMenu: Menu + private var changedNavItem: Boolean = false + private var deltaInformation: JSONObject? = null + private var lastRequestLoggedIn: Boolean = false + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + val inflater = menuInflater + inflater.inflate(R.menu.action_bar, menu) + if (menu != null) { + appMenu = menu + } + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.user -> { + binding.webView.loadUrl("${getString(R.string.delta_root)}/profile") + return true + } + + R.id.btn_forward -> { + if (binding.webView.canGoForward()) binding.webView.goForward() + return true + } + + R.id.btn_reload -> { + binding.webView.reload() + return true + } + + R.id.btn_user_logout -> { + binding.webView.loadUrl("${getString(R.string.delta_root)}/logout") + return true + } + + R.id.btn_about -> { + MaterialAlertDialogBuilder(binding.root.context).setTitle( + getString( + R.string.about_title, + getString(R.string.app_launch_name) + ) + ).setMessage( + getString( + R.string.about_message, + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ", " + BuildConfig.BUILD_TYPE + ")", + deltaInformation?.get("version") ?: "-", + Build.VERSION.RELEASE + " " + Build.VERSION.CODENAME + " (" + Build.VERSION.SDK_INT + ")", + System.getProperty("os.version"), + Build.DEVICE + "/" + Build.MODEL, + Build.VERSION.SECURITY_PATCH, + Build.BOARD, + Build.BOOTLOADER + ) + ).setPositiveButton(getString(R.string.about_close)) { _, _ -> }.show() + + return true + } + + else -> return false + } + } + + fun getCookie(siteName: String?, CookieName: String?): String? { + var cookieValue: String? = null + val cookieManager: CookieManager = CookieManager.getInstance() + val cookies: String? = cookieManager.getCookie(siteName) + + return if (cookies != null) { + val temp = cookies.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + for (ar1 in temp) { + if (ar1.contains(CookieName!!)) { + val temp1 = + ar1.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + cookieValue = temp1[1] + } + } + cookieValue + } else { + "" + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + DynamicColors.applyToActivitiesIfAvailable(application) + + val name = getString(R.string.channel_name) + val descriptionText = getString(R.string.channel_description) + val importance = NotificationManager.IMPORTANCE_DEFAULT + val mChannel = NotificationChannel("default", name, importance) + mChannel.description = descriptionText + val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(mChannel) + + if (Build.VERSION.SDK_INT >= 33) { + ActivityCompat.requestPermissions( + this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1 + ) + } + + FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task -> + if (!task.isSuccessful) { + Log.w("Firebase", "Fetching FCM registration token failed", task.exception) + return@OnCompleteListener + } + + val token = task.result + + Log.d("Firebase", token) + + HTTPRequest.request( + "${getString(R.string.delta_root)}/handoff/fcm/", + getCookie(getString(R.string.delta_root), "DeltaSession") + "||||" + token, + binding.root.context, + resources, + this, + true, + binding + ) { + val openURL = Intent(Intent.ACTION_VIEW) + openURL.data = Uri.parse("https://status.equestria.dev/") + startActivity(openURL) + } + }) + + val color = SurfaceColors.SURFACE_2.getColor(this) + window.statusBarColor = color + window.navigationBarColor = color + + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + navigationMenu = binding.navigationBar.menu + + initialCheck() + } + + fun initialCheck() { + HTTPRequest.request("${getString(R.string.delta_root)}/handoff/version/", + getCookie(getString(R.string.delta_root), "DeltaSession"), + binding.root.context, + resources, + this, + true, + binding, + { + deltaInformation = it + appMenu.getItem(3).isEnabled = deltaInformation!!.get("loggedIn") as Boolean + initialise() + }) { + val openURL = Intent(Intent.ACTION_VIEW) + openURL.data = Uri.parse("https://status.equestria.dev/") + startActivity(openURL) + } + } + + fun routineCheck() { + HTTPRequest.request("${getString(R.string.delta_root)}/handoff/version/", + getCookie(getString(R.string.delta_root), "DeltaSession"), + binding.root.context, + resources, + this, + false, + binding, + { + deltaInformation = it + appMenu.getItem(3).isEnabled = deltaInformation!!.get("loggedIn") as Boolean + + if (deltaInformation!!.get("loggedIn") as Boolean || lastRequestLoggedIn) { + refreshAvatar(deltaInformation!!) + lastRequestLoggedIn = deltaInformation!!.get("loggedIn") as Boolean + + if (lastRequestLoggedIn) { + appMenu.getItem(0).title = deltaInformation!!.get("name") as CharSequence? + } else { + appMenu.getItem(0).title = getString(R.string.navigation_profile) + } + } + }) { + val openURL = Intent(Intent.ACTION_VIEW) + openURL.data = Uri.parse("https://status.equestria.dev/") + startActivity(openURL) + } + } + + fun refreshAvatar(deltaInformation: JSONObject) { + val target = object : Target { + override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) { + try { + if (bitmap != null) { + appMenu.getItem(0).icon = BitmapDrawable(resources, bitmap) + } + } catch (ex: IllegalArgumentException) { + Log.e("Picasso", ex.toString()) + } + } + + override fun onBitmapFailed(e: Exception?, errorDrawable: Drawable?) { + Log.e("Picasso", e.toString()) + } + + override fun onPrepareLoad(placeHolderDrawable: Drawable?) {} + } + + Picasso.get().load( + "${getString(R.string.delta_root)}/handoff/avatar/?token=" + deltaInformation.get("session") + ).into(target) + } + + @SuppressLint("SetJavaScriptEnabled") + fun initialise() { + binding.webView.webViewClient = object : WebViewClient() { + override fun onPageFinished(view: WebView?, url: String?) { + appMenu.getItem(2).isEnabled = true + binding.progressBar.visibility = View.INVISIBLE + binding.webView.visibility = View.VISIBLE + + val pageTitle = binding.webView.title?.split("·")?.get(0)?.trim() ?: "" + + if (pageTitle.startsWith("(") && pageTitle.split(") ").count() > 1) { + title = pageTitle.split(")")[1].trim() + binding.navigationBar.getOrCreateBadge(R.id.navigation_profile).isVisible = true + } else { + title = pageTitle + binding.navigationBar.getOrCreateBadge(R.id.navigation_profile).isVisible = + false + } + + if (URL(url).path.startsWith("/login")) { + binding.navigationBar.visibility = View.GONE + val params = binding.webView.layoutParams as ViewGroup.MarginLayoutParams + params.setMargins(0, 0, 0, 80.dp) + supportActionBar?.hide() + + val color = SurfaceColors.SURFACE_0.getColor(binding.root.context) + window.statusBarColor = color + window.navigationBarColor = color + } else { + val params = binding.webView.layoutParams as ViewGroup.MarginLayoutParams + params.setMargins(0, 0, 0, 0) + binding.navigationBar.visibility = View.VISIBLE + supportActionBar?.show() + + val color = SurfaceColors.SURFACE_2.getColor(binding.root.context) + window.statusBarColor = color + window.navigationBarColor = color + } + + routineCheck() + appMenu.getItem(1).isEnabled = binding.webView.canGoForward() + } + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { + appMenu.getItem(2).isEnabled = false + binding.progressBar.visibility = View.VISIBLE + + if (!changedNavItem) { + if (URL(url).path.startsWith("/articles/") || URL(url).path === "/articles" || URL( + url + ).path.startsWith("/edit/") || URL(url).path === "/edit" || URL(url).path.startsWith( + "/request/" + ) || URL(url).path === "/request" || URL(url).path.startsWith("/people/") || URL( + url + ).path === "/people" || URL(url).path.startsWith("/gallery/") || URL(url).path === "/gallery" + ) { + changedNavItem = true + binding.navigationBar.selectedItemId = R.id.navigation_content + } else if (URL(url).path.startsWith("/search/") || URL(url).path === "/search") { + changedNavItem = true + binding.navigationBar.selectedItemId = R.id.navigation_search + } else if (URL(url).path.startsWith("/admin/") || URL(url).path === "/admin" || URL( + url + ).path.startsWith("/profile/") || URL(url).path === "/profile" || URL(url).path.startsWith( + "/requests/" + ) || URL(url).path === "/requests" || URL(url).path.startsWith("/plus/") || URL( + url + ).path === "/plus" || URL(url).path.startsWith("/alerts/") || URL(url).path === "/alerts" || URL( + url + ).path.startsWith("/support/") || URL(url).path === "/support" || URL(url).path.startsWith( + "/mobile_profile/" + ) || URL(url).path === "/mobile_profile" + ) { + changedNavItem = true + binding.navigationBar.selectedItemId = R.id.navigation_profile + } else { + changedNavItem = true + binding.navigationBar.selectedItemId = R.id.navigation_dashboard + } + } + + appMenu.getItem(1).isEnabled = binding.webView.canGoForward() + changedNavItem = false + } + + override fun shouldInterceptRequest( + view: WebView, request: WebResourceRequest + ): WebResourceResponse? { + request.url.host?.let { Log.i("MainActivity", '"' + it + '"') } + + if (request.url.host != getString(R.string.delta_root).split("/")[2]) { + val openURL = Intent(Intent.ACTION_VIEW) + openURL.data = request.url + startActivity(openURL) + + return WebResourceResponse("text/javascript", "UTF-8", null) + } + + return null + } + } + + binding.navigationBar.setOnItemSelectedListener { item -> + when (item.itemId) { + R.id.navigation_dashboard -> { + setNavigationBarSelected(item.itemId) + + if (!changedNavItem) { + changedNavItem = true + binding.webView.loadUrl("${getString(R.string.delta_root)}/") + } + + true + } + + R.id.navigation_search -> { + setNavigationBarSelected(item.itemId) + + if (!changedNavItem) { + changedNavItem = true + binding.webView.loadUrl("${getString(R.string.delta_root)}/search") + } + + true + } + + R.id.navigation_content -> { + setNavigationBarSelected(item.itemId) + + if (!changedNavItem) { + changedNavItem = true + binding.webView.loadUrl("${getString(R.string.delta_root)}/content") + } + + true + } + + R.id.navigation_profile -> { + setNavigationBarSelected(item.itemId) + + if (!changedNavItem) { + changedNavItem = true + binding.webView.loadUrl("${getString(R.string.delta_root)}/profile") + } + + true + } + + else -> false + } + } + + binding.navigationBar.menu.findItem(R.id.navigation_profile).iconTintList = null + + binding.webView.settings.javaScriptEnabled = true + + handoffApi31() + } + + fun setNavigationBarSelected(id: Int) { + binding.navigationBar.menu.findItem(R.id.navigation_dashboard) + .setIcon(R.drawable.outline_home_24) + binding.navigationBar.menu.findItem(R.id.navigation_content) + .setIcon(R.drawable.outline_text_snippet_24) + binding.navigationBar.menu.findItem(R.id.navigation_search) + .setIcon(R.drawable.outline_search_24) + binding.navigationBar.menu.findItem(R.id.navigation_profile) + .setIcon(R.drawable.outline_person_24) + + when (id) { + R.id.navigation_dashboard -> { + binding.navigationBar.menu.findItem(R.id.navigation_dashboard) + .setIcon(R.drawable.baseline_home_24) + } + + R.id.navigation_content -> { + binding.navigationBar.menu.findItem(R.id.navigation_content) + .setIcon(R.drawable.baseline_text_snippet_24) + } + + R.id.navigation_search -> { + binding.navigationBar.menu.findItem(R.id.navigation_search) + .setIcon(R.drawable.baseline_search_24) + } + + R.id.navigation_profile -> { + binding.navigationBar.menu.findItem(R.id.navigation_profile) + .setIcon(R.drawable.baseline_person_24) + } + + else -> {} + } + } + + fun handoffApi31() { + val colors: ArrayList = arrayListOf( + SurfaceColors.SURFACE_0.getColor(this), + SurfaceColors.SURFACE_1.getColor(this), + SurfaceColors.SURFACE_2.getColor(this), + SurfaceColors.SURFACE_3.getColor(this), + SurfaceColors.SURFACE_4.getColor(this), + SurfaceColors.SURFACE_5.getColor(this), + binding.textView.currentTextColor, + binding.textView.currentHintTextColor, + binding.button.currentTextColor, + binding.button.highlightColor + ) + + val appLinkAction = intent.action + val appLinkData: Uri? = intent.data + if (Intent.ACTION_VIEW == appLinkAction) { + if (appLinkData != null) { + binding.webView.loadUrl( + "${getString(R.string.delta_root)}/handoff/?version=" + BuildConfig.VERSION_CODE + "&colors=" + colors.joinToString( + "," + ) + "&return=" + java.net.URLEncoder.encode(appLinkData.path, "utf-8") + ) + } else { + binding.webView.loadUrl( + "${getString(R.string.delta_root)}/handoff/?version=" + BuildConfig.VERSION_CODE + "&colors=" + colors.joinToString( + "," + ) + "&return=/" + ) + } + } else { + binding.webView.loadUrl( + "${getString(R.string.delta_root)}/handoff/?version=" + BuildConfig.VERSION_CODE + "&colors=" + colors.joinToString( + "," + ) + "&return=/" + ) + } + } + + @Deprecated("Deprecated in Java") + override fun onBackPressed() { + if (binding.webView.canGoBack()) { + binding.webView.goBack() + } else { + moveTaskToBack(true) + exitProcess(0) + } + } + + override fun onSupportNavigateUp(): Boolean { + if (binding.webView.canGoBack()) { + binding.webView.goBack() + } else { + moveTaskToBack(true) + exitProcess(0) + } + + return true + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi/ic_stat_name.xml b/app/src/main/res/drawable-anydpi/ic_stat_name.xml new file mode 100644 index 0000000..e34aed3 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_stat_name.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/drawable-hdpi/ic_stat_name.png b/app/src/main/res/drawable-hdpi/ic_stat_name.png new file mode 100644 index 0000000..ac129b5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_stat_name.png b/app/src/main/res/drawable-mdpi/ic_stat_name.png new file mode 100644 index 0000000..9e11a41 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/app/src/main/res/drawable-xhdpi/ic_stat_name.png new file mode 100644 index 0000000..a3bb50b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/app/src/main/res/drawable-xxhdpi/ic_stat_name.png new file mode 100644 index 0000000..e2cf94d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ diff --git a/app/src/main/res/drawable/baseline_home_24.xml b/app/src/main/res/drawable/baseline_home_24.xml new file mode 100644 index 0000000..993f3ab --- /dev/null +++ b/app/src/main/res/drawable/baseline_home_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_person_24.xml b/app/src/main/res/drawable/baseline_person_24.xml new file mode 100644 index 0000000..9a48b63 --- /dev/null +++ b/app/src/main/res/drawable/baseline_person_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_search_24.xml b/app/src/main/res/drawable/baseline_search_24.xml new file mode 100644 index 0000000..d3b13cf --- /dev/null +++ b/app/src/main/res/drawable/baseline_search_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/baseline_text_snippet_24.xml b/app/src/main/res/drawable/baseline_text_snippet_24.xml new file mode 100644 index 0000000..99ed06c --- /dev/null +++ b/app/src/main/res/drawable/baseline_text_snippet_24.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable/defaultuser.xml b/app/src/main/res/drawable/defaultuser.xml new file mode 100644 index 0000000..c6ee512 --- /dev/null +++ b/app/src/main/res/drawable/defaultuser.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + 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..bf017fc --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/outline_home_24.xml b/app/src/main/res/drawable/outline_home_24.xml new file mode 100644 index 0000000..dcfedda --- /dev/null +++ b/app/src/main/res/drawable/outline_home_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/outline_person_24.xml b/app/src/main/res/drawable/outline_person_24.xml new file mode 100644 index 0000000..e1c804c --- /dev/null +++ b/app/src/main/res/drawable/outline_person_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/outline_search_24.xml b/app/src/main/res/drawable/outline_search_24.xml new file mode 100644 index 0000000..d3b13cf --- /dev/null +++ b/app/src/main/res/drawable/outline_search_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/outline_text_snippet_24.xml b/app/src/main/res/drawable/outline_text_snippet_24.xml new file mode 100644 index 0000000..c52bfc5 --- /dev/null +++ b/app/src/main/res/drawable/outline_text_snippet_24.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..96d5235 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,77 @@ + + + + + +