mirror of
https://github.com/M4TH1EU/DJI-FCC-HACK.git
synced 2025-07-02 18:03:09 +00:00
fix dark mode, improved icons and status reports, readded disclaimer and instructions
This commit is contained in:
parent
3513b5ab0b
commit
0942019869
@ -14,6 +14,7 @@ import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -27,6 +28,8 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Build
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.Clear
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.Refresh
|
||||
import androidx.compose.material3.Button
|
||||
@ -42,6 +45,7 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -54,11 +58,16 @@ import com.hoho.android.usbserial.driver.CdcAcmSerialDriver
|
||||
import com.hoho.android.usbserial.driver.ProbeTable
|
||||
import com.hoho.android.usbserial.driver.UsbSerialPort
|
||||
import com.hoho.android.usbserial.driver.UsbSerialProber
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private lateinit var usbManager: UsbManager
|
||||
private var usbConnection by mutableStateOf(null as UsbDeviceConnection?)
|
||||
private var isPatching by mutableStateOf(false)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -82,7 +91,9 @@ class MainActivity : ComponentActivity() {
|
||||
refreshUsbConnection()
|
||||
|
||||
setContent {
|
||||
MainScreen(usbConnection != null, ::refreshUsbConnection, ::sendPatch)
|
||||
DJI_FCC_HACK_Theme {
|
||||
MainScreen(usbConnection != null, ::refreshUsbConnection, ::sendPatch, isPatching)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,8 +131,11 @@ class MainActivity : ComponentActivity() {
|
||||
* Handles sending the patch via USB communication
|
||||
*/
|
||||
private fun sendPatch() {
|
||||
isPatching = true
|
||||
|
||||
if (usbConnection == null) {
|
||||
Toast.makeText(this, "No USB device connected!", Toast.LENGTH_SHORT).show()
|
||||
isPatching = false
|
||||
return
|
||||
}
|
||||
|
||||
@ -156,6 +170,8 @@ class MainActivity : ComponentActivity() {
|
||||
Toast.makeText(this, "Patch failed: ${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
isPatching = false
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,13 +218,21 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MainScreen(usbConnected: Boolean, onRefresh: () -> Unit, onSendPatch: () -> Unit) {
|
||||
fun MainScreen(
|
||||
usbConnected: Boolean,
|
||||
onRefresh: () -> Unit,
|
||||
onSendPatch: () -> Unit,
|
||||
isPatching: Boolean = false
|
||||
) {
|
||||
var buttonText by remember { mutableStateOf("Send FCC Patch") }
|
||||
var buttonEnabled by remember { mutableStateOf(true) }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("DJI FCC Hack") },
|
||||
actions = {
|
||||
IconButton(onClick = onRefresh) {
|
||||
IconButton(onClick = onRefresh, enabled = !isPatching) {
|
||||
Icon(Icons.Default.Refresh, contentDescription = "Refresh USB Connection")
|
||||
}
|
||||
IconButton(onClick = { /* Open Settings */ }) {
|
||||
@ -228,9 +252,9 @@ fun MainScreen(usbConnected: Boolean, onRefresh: () -> Unit, onSendPatch: () ->
|
||||
) {
|
||||
// App Logo
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.dji_innovations_logo),
|
||||
painter = painterResource(id = isSystemInDarkTheme().let { if (it) R.drawable.dji_light else R.drawable.dji_dark }),
|
||||
contentDescription = "DJI Logo",
|
||||
modifier = Modifier.size(100.dp)
|
||||
modifier = Modifier.size(75.dp),
|
||||
)
|
||||
|
||||
// USB Connection Status
|
||||
@ -246,10 +270,9 @@ fun MainScreen(usbConnected: Boolean, onRefresh: () -> Unit, onSendPatch: () ->
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.usb_c_port),
|
||||
contentDescription = "USB Status",
|
||||
modifier = Modifier.size(24.dp),
|
||||
Icon(
|
||||
if (usbConnected) Icons.Default.CheckCircle else Icons.Default.Clear,
|
||||
contentDescription = "USB Status"
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
@ -261,16 +284,65 @@ fun MainScreen(usbConnected: Boolean, onRefresh: () -> Unit, onSendPatch: () ->
|
||||
|
||||
// Send Patch Button
|
||||
Button(
|
||||
onClick = onSendPatch,
|
||||
onClick = {
|
||||
buttonText = "Successfully patched"
|
||||
buttonEnabled = false
|
||||
onSendPatch()
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
delay(5000)
|
||||
buttonText = "Send FCC Patch"
|
||||
buttonEnabled = true
|
||||
}
|
||||
},
|
||||
shape = RoundedCornerShape(24.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp),
|
||||
enabled = usbConnected
|
||||
enabled = usbConnected && !isPatching && buttonEnabled
|
||||
) {
|
||||
Icon(Icons.Default.Build, contentDescription = "Patch")
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text("Send FCC Patch")
|
||||
Text(buttonText)
|
||||
}
|
||||
|
||||
// Instructions Section
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = "Instructions",
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "1. Connect your phone to the bottom port of the RC remote.\n" +
|
||||
"2. Tap 'Send FCC Patch'.\n" +
|
||||
"3. Disconnect from the bottom port and connect to the top port.",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Disclaimer Section
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.errorContainer)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = "Disclaimer",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "This app is provided as-is and is not affiliated with DJI. Use at your own risk.",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -281,6 +353,6 @@ fun MainScreen(usbConnected: Boolean, onRefresh: () -> Unit, onSendPatch: () ->
|
||||
@Composable
|
||||
fun PreviewMainScreen() {
|
||||
DJI_FCC_HACK_Theme {
|
||||
MainScreen(usbConnected = true, onRefresh = {}, onSendPatch = {})
|
||||
MainScreen(usbConnected = true, onRefresh = {}, onSendPatch = {}, isPatching = false)
|
||||
}
|
||||
}
|
@ -5,11 +5,11 @@
|
||||
android:viewportHeight="95.2">
|
||||
<path
|
||||
android:pathData="m120.64,69.13 l12.16,-50.5l-26.1,-0l-11.12,45.29c-1.61,8.83 -11.1,12.96 -17.84,13.06l-18.49,-0l-6.27,18.2l38.86,-0c9.59,-0 23.74,-4.91 28.81,-26.06"
|
||||
android:fillColor="#ffffff"/>
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="m65.86,51.32 l12.27,-51.33l26.86,-0l-13.96,58.39c-2.69,11.27 -11.07,13.98 -18.81,13.98l-61.91,-0c-6.82,-0 -12.54,-2.9 -9.44,-15.92l5.57,-23.29c2.83,-11.81 11.61,-14.51 17.96,-14.51l43.21,-0l-3.48,14.55l-22.06,-0c-3.24,-0 -5.02,0.7 -5.93,4.49l-3.56,14.87c-1.27,5.34 0.59,5.71 4.5,5.71l20.21,-0c3.7,-0 6.95,-0.23 8.56,-6.94"
|
||||
android:fillColor="#ffffff"/>
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="m138.69,18.63 l-12.64,53.73l26.09,-0l12.64,-53.73l-26.09,-0z"
|
||||
android:fillColor="#ffffff"/>
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
15
app/src/main/res/drawable/dji_light.xml
Normal file
15
app/src/main/res/drawable/dji_light.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="46.51dp"
|
||||
android:height="26.87dp"
|
||||
android:viewportWidth="164.78"
|
||||
android:viewportHeight="95.2">
|
||||
<path
|
||||
android:pathData="m120.64,69.13 l12.16,-50.5l-26.1,-0l-11.12,45.29c-1.61,8.83 -11.1,12.96 -17.84,13.06l-18.49,-0l-6.27,18.2l38.86,-0c9.59,-0 23.74,-4.91 28.81,-26.06"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m65.86,51.32 l12.27,-51.33l26.86,-0l-13.96,58.39c-2.69,11.27 -11.07,13.98 -18.81,13.98l-61.91,-0c-6.82,-0 -12.54,-2.9 -9.44,-15.92l5.57,-23.29c2.83,-11.81 11.61,-14.51 17.96,-14.51l43.21,-0l-3.48,14.55l-22.06,-0c-3.24,-0 -5.02,0.7 -5.93,4.49l-3.56,14.87c-1.27,5.34 0.59,5.71 4.5,5.71l20.21,-0c3.7,-0 6.95,-0.23 8.56,-6.94"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m138.69,18.63 l-12.64,53.73l26.09,-0l12.64,-53.73l-26.09,-0z"
|
||||
android:fillColor="#fff"/>
|
||||
</vector>
|
Loading…
x
Reference in New Issue
Block a user