321 lines
12 KiB
Kotlin
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()
|
|
}
|
|
}
|
|
}
|
|
}
|