1+ package bruce.app
2+
3+ import android.annotation.SuppressLint
4+ import android.os.Bundle
5+ import android.webkit.WebView
6+ import android.webkit.WebViewClient
7+ import android.webkit.HttpAuthHandler
8+ import android.app.AlertDialog
9+ import android.widget.EditText
10+ import android.widget.LinearLayout
11+ import android.widget.TextView
12+ import android.widget.Toast
13+ import android.view.ViewGroup
14+ import android.text.InputType
15+ import android.graphics.Color
16+ import android.view.Gravity
17+ import androidx.activity.ComponentActivity
18+ import androidx.activity.compose.setContent
19+ import androidx.compose.material.*
20+ import androidx.compose.runtime.*
21+ import androidx.compose.ui.graphics.Color as ComposeColor
22+ import androidx.compose.ui.unit.dp
23+ import androidx.compose.ui.unit.sp
24+ import androidx.compose.ui.text.font.FontWeight
25+ import androidx.compose.foundation.layout.*
26+ import androidx.compose.ui.Alignment
27+ import androidx.compose.ui.Modifier
28+
29+ class AndroidWebViewActivity : ComponentActivity () {
30+ private val darkBackgroundColor = Color .parseColor(" #101010" )
31+ private val purpleColor = Color .parseColor(" #6200EE" )
32+ private val whiteColor = Color .parseColor(" #FFFFFF" )
33+ private var triedDefaultAuth = false
34+ private var webView: WebView ? = null
35+
36+ @SuppressLint(" SetJavaScriptEnabled" )
37+ override fun onCreate (savedInstanceState : Bundle ? ) {
38+ super .onCreate(savedInstanceState)
39+ setContent {
40+ WebViewScreen ()
41+ }
42+ }
43+
44+ @Composable
45+ fun WebViewScreen () {
46+ var showInstructionDialog by remember { mutableStateOf(true ) }
47+ var showCredentialDialog by remember { mutableStateOf(false ) }
48+ var username by remember { mutableStateOf(" admin" ) }
49+ var password by remember { mutableStateOf(" bruce" ) }
50+
51+ if (showInstructionDialog) {
52+ AlertDialog (
53+ onDismissRequest = { },
54+ title = {
55+ Text (
56+ " Bruce Device WebUI" ,
57+ color = ComposeColor (0xFF6200EE ),
58+ fontSize = 20 .sp,
59+ fontWeight = FontWeight .Bold
60+ )
61+ },
62+ text = {
63+ Text (
64+ " Go to Files > WebUI on your Bruce Device and Connect your phone to its WiFi." ,
65+ color = ComposeColor (0xFFFFFFFF ),
66+ fontSize = 16 .sp
67+ )
68+ },
69+ confirmButton = {
70+ Button (
71+ onClick = {
72+ showInstructionDialog = false
73+ showCredentialDialog = true
74+ },
75+ colors = ButtonDefaults .buttonColors(
76+ backgroundColor = ComposeColor (0xFF6200EE ),
77+ contentColor = ComposeColor (0xFFFFFFFF )
78+ )
79+ ) {
80+ Text (" Continue" )
81+ }
82+ },
83+ backgroundColor = ComposeColor (0xFF101010 ),
84+ contentColor = ComposeColor (0xFFFFFFFF )
85+ )
86+ }
87+
88+ if (showCredentialDialog) {
89+ var tempUsername by remember { mutableStateOf(username) }
90+ var tempPassword by remember { mutableStateOf(password) }
91+
92+ AlertDialog (
93+ onDismissRequest = { },
94+ title = {
95+ Text (
96+ " HTTP Basic Authentication" ,
97+ color = ComposeColor (0xFF6200EE ),
98+ fontSize = 20 .sp,
99+ fontWeight = FontWeight .Bold
100+ )
101+ },
102+ text = {
103+ Column {
104+ OutlinedTextField (
105+ value = tempUsername,
106+ onValueChange = { tempUsername = it },
107+ label = { Text (" Username" ) },
108+ colors = TextFieldDefaults .outlinedTextFieldColors(
109+ textColor = ComposeColor (0xFFFFFFFF ),
110+ cursorColor = ComposeColor (0xFFFFFFFF ),
111+ focusedBorderColor = ComposeColor (0xFF6200EE ),
112+ unfocusedBorderColor = ComposeColor (0xFF666666 ),
113+ focusedLabelColor = ComposeColor (0xFF6200EE ),
114+ unfocusedLabelColor = ComposeColor (0xFF666666 )
115+ )
116+ )
117+ Spacer (modifier = Modifier .height(8 .dp))
118+ OutlinedTextField (
119+ value = tempPassword,
120+ onValueChange = { tempPassword = it },
121+ label = { Text (" Password" ) },
122+ colors = TextFieldDefaults .outlinedTextFieldColors(
123+ textColor = ComposeColor (0xFFFFFFFF ),
124+ cursorColor = ComposeColor (0xFFFFFFFF ),
125+ focusedBorderColor = ComposeColor (0xFF6200EE ),
126+ unfocusedBorderColor = ComposeColor (0xFF666666 ),
127+ focusedLabelColor = ComposeColor (0xFF6200EE ),
128+ unfocusedLabelColor = ComposeColor (0xFF666666 )
129+ )
130+ )
131+ }
132+ },
133+ confirmButton = {
134+ Button (
135+ onClick = {
136+ if (tempUsername.isNotBlank() && tempPassword.isNotBlank()) {
137+ username = tempUsername
138+ password = tempPassword
139+ showCredentialDialog = false
140+ showWebViewWithUserAuth(username, password)
141+ }
142+ },
143+ colors = ButtonDefaults .buttonColors(
144+ backgroundColor = ComposeColor (0xFF6200EE ),
145+ contentColor = ComposeColor (0xFFFFFFFF )
146+ )
147+ ) {
148+ Text (" OK" )
149+ }
150+ },
151+ dismissButton = {
152+ Button (
153+ onClick = { finish() },
154+ colors = ButtonDefaults .buttonColors(
155+ backgroundColor = ComposeColor (0xFF6200EE ),
156+ contentColor = ComposeColor (0xFFFFFFFF )
157+ )
158+ ) {
159+ Text (" Cancel" )
160+ }
161+ },
162+ backgroundColor = ComposeColor (0xFF101010 ),
163+ contentColor = ComposeColor (0xFFFFFFFF )
164+ )
165+ }
166+ }
167+
168+ @SuppressLint(" SetJavaScriptEnabled" )
169+ private fun showWebViewWithUserAuth (username : String , password : String ) {
170+ triedDefaultAuth = false
171+ webView = WebView (this )
172+ webView?.webViewClient = object : WebViewClient () {
173+ override fun onReceivedHttpAuthRequest (
174+ view : WebView ,
175+ handler : HttpAuthHandler ,
176+ host : String ,
177+ realm : String
178+ ) {
179+ if (host == " bruce.local" ) {
180+ if (! triedDefaultAuth) {
181+ triedDefaultAuth = true
182+ handler.proceed(" admin" , " bruce" )
183+ } else {
184+ handler.cancel()
185+ // Show credential dialog again if needed
186+ setContent {
187+ WebViewScreen ()
188+ }
189+ }
190+ } else {
191+ handler.cancel()
192+ }
193+ }
194+ }
195+ webView?.settings?.javaScriptEnabled = true
196+ webView?.loadUrl(" http://bruce.local" )
197+ setContentView(webView)
198+ }
199+ }
0 commit comments