summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/.gitignore1
-rw-r--r--app/build.gradle.kts61
-rw-r--r--app/proguard-rules.pro21
-rw-r--r--app/release/app-release.apkbin0 -> 5274500 bytes
-rw-r--r--app/release/app-release.apk.zipbin0 -> 4719976 bytes
-rw-r--r--app/release/output-metadata.json20
-rw-r--r--app/src/main/AndroidManifest.xml42
-rw-r--r--app/src/main/ic_launcher-playstore.pngbin0 -> 11606 bytes
-rw-r--r--app/src/main/java/dev/equestria/delta/HTTPRequest.kt61
-rw-r--r--app/src/main/java/dev/equestria/delta/MainActivity.kt510
-rw-r--r--app/src/main/res/drawable-anydpi/ic_stat_name.xml16
-rw-r--r--app/src/main/res/drawable-hdpi/ic_stat_name.pngbin0 -> 369 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_stat_name.pngbin0 -> 312 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_stat_name.pngbin0 -> 430 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/ic_stat_name.pngbin0 -> 976 bytes
-rw-r--r--app/src/main/res/drawable/baseline_home_24.xml10
-rw-r--r--app/src/main/res/drawable/baseline_person_24.xml10
-rw-r--r--app/src/main/res/drawable/baseline_search_24.xml10
-rw-r--r--app/src/main/res/drawable/baseline_text_snippet_24.xml11
-rw-r--r--app/src/main/res/drawable/defaultuser.xml46
-rw-r--r--app/src/main/res/drawable/ic_launcher_foreground.xml33
-rw-r--r--app/src/main/res/drawable/outline_home_24.xml10
-rw-r--r--app/src/main/res/drawable/outline_person_24.xml10
-rw-r--r--app/src/main/res/drawable/outline_search_24.xml10
-rw-r--r--app/src/main/res/drawable/outline_text_snippet_24.xml11
-rw-r--r--app/src/main/res/layout/activity_main.xml77
-rw-r--r--app/src/main/res/menu/action_bar.xml30
-rw-r--r--app/src/main/res/menu/navigation_bar.xml29
-rw-r--r--app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml5
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3593 bytes
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 3593 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2278 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2278 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 5255 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 5255 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 8377 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 8377 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 12020 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 12020 bytes
-rw-r--r--app/src/main/res/values-fr/strings.xml26
-rw-r--r--app/src/main/res/values-night/themes.xml3
-rw-r--r--app/src/main/res/values/dimens.xml4
-rw-r--r--app/src/main/res/values/ic_launcher_background.xml4
-rw-r--r--app/src/main/res/values/strings.xml26
-rw-r--r--app/src/main/res/values/themes.xml3
-rw-r--r--app/src/main/res/values/values.xml5
-rw-r--r--app/src/main/res/xml/backup_rules.xml1
-rw-r--r--app/src/main/res/xml/data_extraction_rules.xml3
-rw-r--r--app/src/main/res/xml/locales_config.xml4
50 files changed, 1118 insertions, 0 deletions
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
--- /dev/null
+++ b/app/release/app-release.apk
Binary files differ
diff --git a/app/release/app-release.apk.zip b/app/release/app-release.apk.zip
new file mode 100644
index 0000000..7cdcd1a
--- /dev/null
+++ b/app/release/app-release.apk.zip
Binary files 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="dev.equestria.delta">
+
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:allowBackup="true"
+ android:dataExtractionRules="@xml/data_extraction_rules"
+ android:fullBackupContent="@xml/backup_rules"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:localeConfig="@xml/locales_config"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.Delta"
+ tools:targetApi="33">
+ <activity
+ android:name=".MainActivity"
+ android:exported="true"
+ android:label="@string/app_launch_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter android:autoVerify="true">
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:host="delta.equestria.dev" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ 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
--- /dev/null
+++ b/app/src/main/ic_launcher-playstore.png
Binary files 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<Int> = 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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#FFFFFF"
+ android:viewportWidth="512"
+ android:viewportHeight="512">
+ <group
+ android:scaleX="0.92"
+ android:scaleY="0.92"
+ android:translateX="20.48"
+ android:translateY="20.48">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M255.6,100.4l175,350.6H80.5L255.6,100.4M255.6,13.3c-7.1,0 -14.2,3.7 -17.9,11L14.1,472.1C7.5,485.4 17.2,501 32,501h447.1c14.9,0 24.5,-15.6 17.9,-28.9L273.5,24.3C269.8,16.9 262.7,13.3 255.6,13.3L255.6,13.3z" />
+ </group>
+</vector>
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
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_stat_name.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_stat_name.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_stat_name.png
Binary files 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
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
Binary files 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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:autoMirrored="true"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20.41,8.41l-4.83,-4.83C15.21,3.21 14.7,3 14.17,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V9.83C21,9.3 20.79,8.79 20.41,8.41zM7,7h7v2H7V7zM17,17H7v-2h10V17zM17,13H7v-2h10V13z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:width="512dp"
+ android:height="512dp"
+ android:viewportWidth="512"
+ android:viewportHeight="512"
+ tools:ignore="VectorRaster">
+ <path android:pathData="M256,256m-256,0a256,256 0,1 1,512 0a256,256 0,1 1,-512 0">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="437.02"
+ android:endY="74.98"
+ android:startX="74.98"
+ android:startY="437.02"
+ android:type="linear">
+ <item
+ android:color="#FFE6E6E6"
+ android:offset="0" />
+ <item
+ android:color="#FFF2F2F2"
+ android:offset="1" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path android:pathData="M373.4,296.6c25.4,0 46,20.6 46,45.9c0,0 0,0 0,0v18.8c0,11.7 -3.7,23.1 -10.5,32.7c-31.6,44.2 -83.2,66.1 -153,66.1c-69.9,0 -121.5,-21.9 -153,-66.1c-6.8,-9.5 -10.4,-20.9 -10.4,-32.6v-18.8c0,-25.4 20.6,-46 45.9,-46c0,0 0,0 0,0L373.4,296.6L373.4,296.6zM255.8,51.5c56.4,0 102.2,45.7 102.2,102.1c0,56.4 -45.7,102.2 -102.1,102.2c0,0 0,0 0,0c-56.4,0 -102.2,-45.7 -102.2,-102.2S199.4,51.5 255.8,51.5z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="391"
+ android:endY="414.61"
+ android:startX="120.67"
+ android:startY="144.28"
+ android:type="linear">
+ <item
+ android:color="#E3E3E3"
+ android:offset="0" />
+ <item
+ android:color="#E0E0E0"
+ android:offset="0.5" />
+ <item
+ android:color="#FFFFFF"
+ android:offset="1" />
+ </gradient>
+ </aapt:attr>
+ </path>
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="512"
+ android:viewportHeight="512">
+ <group
+ android:scaleX="0.34"
+ android:scaleY="0.34"
+ android:translateX="168.96"
+ android:translateY="168.96">
+ <path android:pathData="M237.7,24.3L14.1,472.1C7.5,485.4 17.2,501 32,501h447.1c14.9,0 24.5,-15.6 17.9,-28.9L273.5,24.3C266.1,9.6 245.1,9.6 237.7,24.3z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="437.58"
+ android:endY="550.88"
+ android:startX="73.62"
+ android:startY="186.92"
+ android:type="linear">
+ <item
+ android:color="#FFE44857"
+ android:offset="0" />
+ <item
+ android:color="#FFC711E1"
+ android:offset="0.5" />
+ <item
+ android:color="#FF7F52FF"
+ android:offset="1" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ </group>
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,5.69l5,4.5V18h-2v-6H9v6H7v-7.81l5,-4.5M12,3L2,12h3v8h6v-6h2v6h6v-8h3L12,3z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,6c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2m0,10c2.7,0 5.8,1.29 6,2L6,18c0.23,-0.72 3.31,-2 6,-2m0,-12C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
+</vector>
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 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:autoMirrored="true"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M14.17,5L19,9.83V19H5V5L14.17,5L14.17,5M14.17,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V9.83c0,-0.53 -0.21,-1.04 -0.59,-1.41l-4.83,-4.83C15.21,3.21 14.7,3 14.17,3L14.17,3zM7,15h10v2H7V15zM7,11h10v2H7V11zM7,7h7v2H7V7z" />
+</vector>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/progressBar" />
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@+id/webView"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="e" />
+
+ <com.google.android.material.bottomnavigation.BottomNavigationView
+ android:id="@+id/navigationBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hapticFeedbackEnabled="true"
+ android:soundEffectsEnabled="true"
+ app:labelVisibilityMode="labeled"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:menu="@menu/navigation_bar" />
+
+ <WebView
+ android:id="@+id/webView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="80dp"
+ android:saveEnabled="true"
+ android:visibility="invisible"
+ app:layout_constraintBottom_toTopOf="@id/navigationBar"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/progressBar">
+
+ </WebView>
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="20dp"
+ android:layout_marginTop="-8dp"
+ android:indeterminate="true"
+ android:padding="0dp"
+ android:paddingHorizontal="0dp"
+ android:paddingVertical="0dp"
+ android:paddingStart="0dp"
+ android:paddingLeft="0dp"
+ android:paddingTop="0dp"
+ android:paddingEnd="0dp"
+ android:paddingRight="0dp"
+ android:paddingBottom="0dp"
+ app:barrierMargin="0dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/app/src/main/res/menu/action_bar.xml b/app/src/main/res/menu/action_bar.xml
new file mode 100644
index 0000000..d25a24c
--- /dev/null
+++ b/app/src/main/res/menu/action_bar.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/user"
+ android:icon="@drawable/defaultuser"
+ android:title="@string/navigation_profile"
+ app:showAsAction="ifRoom" />
+ <item
+ android:id="@+id/btn_forward"
+ android:title="@string/navigation_forward"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/btn_reload"
+ android:title="@string/navigation_reload"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/btn_user_logout"
+ android:enabled="false"
+ android:title="@string/navigation_user_logout"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/btn_about"
+ android:enabled="true"
+ android:title="@string/navigation_user_about"
+ app:showAsAction="never" />
+</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/navigation_bar.xml b/app/src/main/res/menu/navigation_bar.xml
new file mode 100644
index 0000000..acaeb0e
--- /dev/null
+++ b/app/src/main/res/menu/navigation_bar.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/navigation_dashboard"
+ android:icon="@drawable/baseline_home_24"
+ android:title="@string/pages_dashboard"
+ app:showAsAction="ifRoom" />
+
+ <item
+ android:id="@+id/navigation_content"
+ android:icon="@drawable/outline_text_snippet_24"
+ android:title="@string/pages_content"
+ app:showAsAction="ifRoom" />
+
+ <item
+ android:id="@+id/navigation_search"
+ android:icon="@drawable/outline_search_24"
+ android:title="@string/pages_search"
+ app:showAsAction="ifRoom" />
+
+ <item
+ android:id="@+id/navigation_profile"
+ android:icon="@drawable/baseline_person_24"
+ android:title="@string/pages_profile"
+ app:showAsAction="ifRoom" />
+
+</menu> \ No newline at end of file
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..ac94b34
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ 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..ac94b34
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@color/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ 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..d7273d4
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files 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..d7273d4
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files 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..128dfb8
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files 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..128dfb8
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files 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..10fc1e0
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files 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..10fc1e0
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files 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..9e654bf
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files 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..9e654bf
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files 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..649f939
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files 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..649f939
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..3d882d1
--- /dev/null
+++ b/app/src/main/res/values-fr/strings.xml
@@ -0,0 +1,26 @@
+<resources>
+ <string name="navigation_forward">Aller en avant</string>
+ <string name="navigation_search">Recherche</string>
+ <string name="navigation_profile">Utilisateur</string>
+ <string name="navigation_reload">Recharger</string>
+ <string name="navigation_user_profile">Profil</string>
+ <string name="navigation_user_logout">Se déconnecter</string>
+ <string name="navigation_user_about">À propos</string>
+ <string name="about_title">À propos de %1$s</string>
+ <string name="about_message">Une application Android pour la plate-forme Delta.\n\nApplication : %1$s\nServeur : %2$s\nAndroid : %3$s\nMàJ : %6$s\nNoyau : %4$s\nAppareil : %5$s\nCarte : %7$s\nAmorceur : %8$s</string>
+ <string name="about_close">Fermer</string>
+ <string name="pages_dashboard">Accueil</string>
+ <string name="pages_search">Recherche</string>
+ <string name="pages_profile">Profil</string>
+ <string name="pages_alerts">Alertes</string>
+ <string name="pages_content">Contenu</string>
+ <string name="offline_title">Impossible de se connecter à Delta</string>
+ <string name="offline_message">Nous ne parvenons pas à joindre les serveurs de Delta. Vérifiez votre connexion Internet et réessayez.</string>
+ <string name="offline_close">Quitter</string>
+ <string name="offline_retry">Réessayer</string>
+ <string name="channel_name">Alertes Delta</string>
+ <string name="channel_description">Pour les utilisateurs Delta Ultra uniquement. Alertes qui apparaissent sur votre profil.</string>
+ <string name="about_copy">Copier</string>
+ <string name="about_copy_done">Informations copiées dans le presse-papiers</string>
+ <string name="offline_status">Ouvrir l\'état des services</string>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..33d0ef5
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,3 @@
+<resources>
+ <style name="Theme.Delta" parent="Theme.Material3.DynamicColors.DayNight" />
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..51c43ef
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,4 @@
+<resources>
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources> \ No newline at end of file
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..746b9f4
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="ic_launcher_background">#E3E3E3</color>
+</resources> \ 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..0cbeecc
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,26 @@
+<resources>
+ <string name="navigation_forward">Navigate down</string>
+ <string name="navigation_search">Search</string>
+ <string name="navigation_profile">User</string>
+ <string name="navigation_reload">Reload</string>
+ <string name="navigation_user_profile">Profile</string>
+ <string name="navigation_user_logout">Log out</string>
+ <string name="navigation_user_about">About</string>
+ <string name="about_title">About %1$s</string>
+ <string name="about_message">An Android app for the Delta platform.\n\nApp: %1$s\nServer: %2$s\nAndroid: %3$s\nSecurity: %6$s\nKernel: %4$s\nDevice: %5$s\nBoard: %7$s\nBootloader: %8$s</string>
+ <string name="about_close">Close</string>
+ <string name="about_copy">Copy</string>
+ <string name="about_copy_done">Copied info to clipboard</string>
+ <string name="pages_dashboard">Home</string>
+ <string name="pages_search">Search</string>
+ <string name="pages_profile">Profile</string>
+ <string name="pages_alerts">Alerts</string>
+ <string name="pages_content">Content</string>
+ <string name="offline_title">Unable to connect to Delta</string>
+ <string name="offline_message">We are currently unable to connect to Delta\'s servers. Check your network connection and try again later.</string>
+ <string name="offline_close">Quit</string>
+ <string name="offline_status">Open status page</string>
+ <string name="offline_retry">Retry</string>
+ <string name="channel_name">Delta alerts</string>
+ <string name="channel_description">For Delta Ultra users only. Alerts that appear on your Delta profile.</string>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..33d0ef5
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,3 @@
+<resources>
+ <style name="Theme.Delta" parent="Theme.Material3.DynamicColors.DayNight" />
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml
new file mode 100644
index 0000000..ee1eb49
--- /dev/null
+++ b/app/src/main/res/values/values.xml
@@ -0,0 +1,5 @@
+<resources>
+ <string name="app_name" translatable="false">Equestria.dev Delta</string>
+ <string name="app_launch_name" translatable="false">Delta</string>
+ <string name="delta_root" translatable="false">https://delta.equestria.dev</string>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..c981ec0
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1 @@
+<full-backup-content></full-backup-content> \ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..11dba30
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,3 @@
+<data-extraction-rules>
+ <cloud-backup></cloud-backup>
+</data-extraction-rules> \ No newline at end of file
diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml
new file mode 100644
index 0000000..da6451b
--- /dev/null
+++ b/app/src/main/res/xml/locales_config.xml
@@ -0,0 +1,4 @@
+<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+ <locale android:name="en" />
+ <locale android:name="fr" />
+</locale-config> \ No newline at end of file