Files
apk/FastAdmin/app/src/main/java/MainActivity.kt
2025-12-09 11:35:41 +01:00

321 lines
12 KiB
Kotlin

package com.example.FastAdmin // Corrected package name
import android.os.Bundle
import android.webkit.HttpAuthHandler
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import android.app.AlertDialog
import android.content.Context
import android.content.SharedPreferences
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Button
import android.view.Gravity
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.graphics.Color
import android.util.TypedValue
import android.view.View
import android.graphics.drawable.GradientDrawable
class MainActivity : AppCompatActivity() {
// --- COLOR CONSTANTS DERIVED FROM styles.css AND colors.xml ---
private val COLOR_BG = 0xFF1A1B26.toInt()
private val COLOR_CARD = 0xFF24283B.toInt()
private val COLOR_PRIMARY_TEXT = 0xFFC0CAF5.toInt()
private val COLOR_ACCENT = 0xFF7AA2F7.toInt()
private val COLOR_ERROR = 0xFFF7768E.toInt()
private val COLOR_BORDER_DARK = 0xFF3A3C4D.toInt()
private lateinit var myWebView: WebView
private lateinit var sharedPrefs: SharedPreferences
// Key for SharedPreferences
private val PREFS_NAME = "AdminPrefs"
private val DOMAIN_KEY = "TargetDomain" // Currently selected domain
private val DOMAIN_LIST_KEY = "SavedDomains" // Key for the list of all domains
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize SharedPreferences
sharedPrefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
// Check if the domain is already saved
val savedDomain = sharedPrefs.getString(DOMAIN_KEY, null)
if (savedDomain.isNullOrEmpty()) {
// Domain not set: show the full manager menu
showDomainManagerDialog()
} else {
// Domain is set: proceed to load WebView
setupWebView(savedDomain)
}
}
// --- Core WebView Setup Function (NO CHANGE) ---
private fun setupWebView(baseUrl: String) {
myWebView = findViewById(R.id.webview)
val settings = myWebView.settings
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
myWebView.webViewClient = object : WebViewClient() {
override fun onReceivedHttpAuthRequest(
view: WebView?,
handler: HttpAuthHandler?,
host: String?,
realm: String?
) {
if (handler != null) {
showHttpAuthDialog(handler, host, realm)
}
}
}
val urlToLoad = if (baseUrl.startsWith("http")) baseUrl else "https://$baseUrl"
myWebView.loadUrl(urlToLoad)
}
// --- Domain Manager Menu (STYLED) ---
private fun showDomainManagerDialog() {
val savedDomains = sharedPrefs.getStringSet(DOMAIN_LIST_KEY, HashSet())?.toList() ?: emptyList()
val currentDomain = sharedPrefs.getString(DOMAIN_KEY, null)
val managerLayout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(dpToPx(20), dpToPx(10), dpToPx(20), dpToPx(10))
}
// 1. Add List of Domains
if (savedDomains.isEmpty()) {
managerLayout.addView(TextView(this).apply {
text = "No domains saved. Tap ADD NEW below."
setTextColor(COLOR_PRIMARY_TEXT)
setPadding(0, dpToPx(15), 0, dpToPx(15))
})
} else {
for (domain in savedDomains) {
val isSelected = domain == currentDomain
val domainItem = createDomainListItem(domain, isSelected)
managerLayout.addView(domainItem)
}
}
// 2. Add Buttons Layout
val buttonsLayout = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
gravity = Gravity.CENTER_HORIZONTAL
setPadding(0, dpToPx(20), 0, 0)
}
// Add Button
val addButton = createStyledButton("ADD NEW", COLOR_ACCENT, COLOR_BG).apply {
setOnClickListener {
showAddDomainDialog(savedDomains.toSet())
}
}
buttonsLayout.addView(addButton, LinearLayout.LayoutParams(0, WRAP_CONTENT, 1f).apply { rightMargin = dpToPx(10) })
// Delete Button
val deleteButton = createStyledButton("DELETE", COLOR_ERROR, COLOR_BG).apply {
isEnabled = savedDomains.isNotEmpty()
setOnClickListener {
showDeleteDomainDialog(savedDomains)
}
}
buttonsLayout.addView(deleteButton, LinearLayout.LayoutParams(0, WRAP_CONTENT, 1f))
managerLayout.addView(buttonsLayout)
// Show the styled AlertDialog
AlertDialog.Builder(this, R.style.Theme_App_DarkDialog) // Use the custom dialog theme
.setTitle("Manage Admin Boards")
.setMessage("Tap to select a board:")
.setView(managerLayout)
.setNegativeButton("EXIT") { _, _ ->
finish()
}
.show()
}
// --- Helper function to create a styled button ---
private fun createStyledButton(text: String, bgColor: Int, textColor: Int): Button {
return Button(this).apply {
this.text = text
setBackgroundColor(bgColor)
setTextColor(textColor)
setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f)
setPadding(dpToPx(15), dpToPx(10), dpToPx(15), dpToPx(10))
elevation = dpToPx(4).toFloat()
}
}
// --- Helper function to create a styled list item ---
private fun createDomainListItem(domain: String, isSelected: Boolean): View {
val container = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
setPadding(dpToPx(15), dpToPx(15), dpToPx(15), dpToPx(15))
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { bottomMargin = dpToPx(10) }
val drawable = GradientDrawable()
drawable.setColor(if (isSelected) COLOR_ACCENT else COLOR_CARD)
drawable.cornerRadius = dpToPx(8).toFloat()
background = drawable
setOnClickListener {
sharedPrefs.edit().putString(DOMAIN_KEY, domain).apply()
recreate()
}
}
val textView = TextView(this).apply {
text = domain
setTextColor(if (isSelected) COLOR_BG else COLOR_PRIMARY_TEXT)
setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
gravity = Gravity.CENTER_VERTICAL
}
container.addView(textView, LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f))
return container
}
// --- Add Domain Dialog (STYLED) ---
private fun showAddDomainDialog(existingDomains: Set<String>) {
val domainInput = EditText(this).apply {
hint = "e.g., admin.board.com/panel"
setTextColor(COLOR_PRIMARY_TEXT)
setHintTextColor(Color.GRAY)
setPadding(dpToPx(15), dpToPx(15), dpToPx(15), dpToPx(15))
val borderDrawable = GradientDrawable()
borderDrawable.setColor(COLOR_BG)
borderDrawable.setStroke(dpToPx(1), COLOR_BORDER_DARK)
borderDrawable.cornerRadius = dpToPx(8).toFloat()
background = borderDrawable
}
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(dpToPx(20), dpToPx(20), dpToPx(20), dpToPx(20))
addView(domainInput, LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
}
AlertDialog.Builder(this, R.style.Theme_App_DarkDialog)
.setTitle("Add New Domain")
.setView(layout)
.setPositiveButton("Save") { _, _ ->
val newDomain = domainInput.text.toString().trim()
if (newDomain.isNotEmpty() && !existingDomains.contains(newDomain)) {
val updatedSet = existingDomains.toMutableSet()
updatedSet.add(newDomain)
sharedPrefs.edit().putStringSet(DOMAIN_LIST_KEY, updatedSet).apply()
}
showDomainManagerDialog()
}
.setNegativeButton("Cancel") { _, _ ->
showDomainManagerDialog()
}
.show()
}
// --- Delete Domain Dialog (Styled) ---
private fun showDeleteDomainDialog(domainNames: List<String>) {
if (domainNames.isEmpty()) {
showDomainManagerDialog()
return
}
val items = domainNames.toTypedArray()
AlertDialog.Builder(this, R.style.Theme_App_DarkDialog)
.setTitle("Select Domain to DELETE")
.setItems(items) { dialog, which ->
val domainToDelete = domainNames[which]
val currentSet = sharedPrefs.getStringSet(DOMAIN_LIST_KEY, HashSet())?.toMutableSet()
if (currentSet != null) {
currentSet.remove(domainToDelete)
sharedPrefs.edit().putStringSet(DOMAIN_LIST_KEY, currentSet).apply()
if (sharedPrefs.getString(DOMAIN_KEY, null) == domainToDelete) {
sharedPrefs.edit().remove(DOMAIN_KEY).apply()
}
}
dialog.dismiss()
showDomainManagerDialog()
}
.setNegativeButton("Cancel") { _, _ ->
showDomainManagerDialog()
}
.show()
}
// --- Utility function for converting DP to PX ---
private fun dpToPx(dp: Int): Int {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp.toFloat(),
resources.displayMetrics
).toInt()
}
// --- HTTP Auth Dialog Function (EXISTING, uses custom theme) ---
private fun showHttpAuthDialog(handler: HttpAuthHandler, host: String?, realm: String?) {
val usernameInput = EditText(this).apply {
hint = "Username"
setTextColor(COLOR_PRIMARY_TEXT)
setHintTextColor(Color.GRAY)
}
val passwordInput = EditText(this).apply {
hint = "Password"
inputType = android.text.InputType.TYPE_CLASS_TEXT or android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD
setTextColor(COLOR_PRIMARY_TEXT)
setHintTextColor(Color.GRAY)
}
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(dpToPx(20), dpToPx(10), dpToPx(20), dpToPx(10))
addView(usernameInput, LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
addView(passwordInput, LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
}
AlertDialog.Builder(this, R.style.Theme_App_DarkDialog)
.setTitle("Authentication Required")
.setMessage("Please enter credentials for $realm on $host")
.setView(layout)
.setPositiveButton("Log In") { _, _ ->
val username = usernameInput.text.toString()
val password = passwordInput.text.toString()
handler.proceed(username, password)
}
.setNegativeButton("Cancel") { _, _ ->
handler.cancel()
}
.setCancelable(false)
.show()
}
// --- Back Button Logic (EXISTING) ---
override fun onBackPressed() {
if (::myWebView.isInitialized && myWebView.canGoBack()) {
myWebView.goBack()
} else {
if (sharedPrefs.getString(DOMAIN_KEY, null).isNullOrEmpty()) {
super.onBackPressed()
} else {
sharedPrefs.edit().remove(DOMAIN_KEY).apply()
setContentView(R.layout.activity_main)
showDomainManagerDialog()
}
}
}
}