11package com.nervosnetwork.ckblightclient
22
3- import android.content.Intent
43import android.os.Bundle
5- import android.widget.TextView
6- import android.widget.Button
7- import android.widget.ScrollView
8- import androidx.appcompat.app.AppCompatActivity
9- import androidx.core.content.ContextCompat
10- import java.io.*
114import android.util.Log
5+ import androidx.appcompat.app.AppCompatActivity
6+ import androidx.fragment.app.Fragment
7+ import com.google.android.material.bottomnavigation.BottomNavigationView
8+ import com.nervosnetwork.ckblightclient.fragments.LogsFragment
9+ import com.nervosnetwork.ckblightclient.fragments.StatusFragment
10+ import java.io.File
1211
1312class MainActivity : AppCompatActivity () {
14- private lateinit var logTextView: TextView
15- private lateinit var scrollView: ScrollView
16- private lateinit var startButton: Button
17- private lateinit var stopButton: Button
18-
19- private var isRunning = false
13+ private lateinit var bottomNavigation: BottomNavigationView
2014 private val TAG = " CKBLightClient"
2115
2216 companion object {
@@ -27,50 +21,48 @@ class MainActivity : AppCompatActivity() {
2721 super .onCreate(savedInstanceState)
2822 setContentView(R .layout.activity_main)
2923
30- logTextView = findViewById(R .id.logTextView)
31- scrollView = findViewById(R .id.scrollView)
32- startButton = findViewById(R .id.startButton)
33- stopButton = findViewById(R .id.stopButton)
34-
35- // Set up log callback from service
36- LightClientService .logCallback = { message ->
37- runOnUiThread { appendLog(message) }
38- }
24+ bottomNavigation = findViewById(R .id.bottom_navigation)
3925
40- startButton.setOnClickListener { startLightClient() }
41- stopButton.setOnClickListener { stopLightClient() }
26+ // Setup binary and config
27+ setupBinaryAndConfig()
4228
43- appendLog(" CKB Light Client Android v0.5.3" )
44- appendLog(" Checking binary and config..." )
29+ // Load default fragment
30+ if (savedInstanceState == null ) {
31+ loadFragment(LogsFragment ())
32+ }
4533
46- if (setupBinaryAndConfig()) {
47- appendLog(" Ready to start." )
48- startButton.isEnabled = true
49- } else {
50- appendLog(" ERROR: Setup failed!" )
34+ // Setup bottom navigation
35+ bottomNavigation.setOnItemSelectedListener { item ->
36+ when (item.itemId) {
37+ R .id.nav_logs -> {
38+ loadFragment(LogsFragment ())
39+ true
40+ }
41+ R .id.nav_status -> {
42+ loadFragment(StatusFragment ())
43+ true
44+ }
45+ else -> false
46+ }
5147 }
5248 }
5349
54- private fun setupBinaryAndConfig (): Boolean {
50+ private fun loadFragment (fragment : Fragment ) {
51+ supportFragmentManager.beginTransaction()
52+ .replace(R .id.fragment_container, fragment)
53+ .commit()
54+ }
55+
56+ private fun setupBinaryAndConfig () {
5557 try {
5658 // JNI mode: no need to extract binary, only setup config
57- val configPath = setupConfig()
58- val libcPath = copySharedLibrary(" libc++_shared.so" )
59-
60- appendLog(" Config: ${configPath.absolutePath} " )
61- appendLog(" libc++: ${libcPath.absolutePath} " )
62- appendLog(" Using JNI native library" )
63-
64- return configPath.exists() && libcPath.exists()
59+ setupConfig()
60+ copySharedLibrary(" libc++_shared.so" )
6561 } catch (e: Exception ) {
66- appendLog(" ERROR: ${e.message} " )
6762 Log .e(TAG , " Setup error" , e)
68- return false
6963 }
7064 }
7165
72- // extractBinary() and ensureExecutable() removed - JNI mode doesn't need them
73-
7466 private fun copySharedLibrary (libName : String ): File {
7567 val nativeLibDir = applicationInfo.nativeLibraryDir
7668 val sourceLib = File (nativeLibDir, libName)
@@ -79,9 +71,6 @@ class MainActivity : AppCompatActivity() {
7971 if (! destLib.exists() || sourceLib.lastModified() > destLib.lastModified()) {
8072 sourceLib.copyTo(destLib, overwrite = true )
8173 destLib.setReadable(true , false )
82- appendLog(" $libName copied" )
83- } else {
84- appendLog(" $libName already exists" )
8574 }
8675
8776 return destLib
@@ -93,13 +82,11 @@ class MainActivity : AppCompatActivity() {
9382 if (configFile.exists()) {
9483 val existing = runCatching { configFile.readText() }.getOrNull()
9584 if (existing != null && existing.contains(" logger" , ignoreCase = true )) {
96- appendLog(" Existing config has deprecated 'logger'; regenerating from template" )
9785 runCatching {
9886 configFile.copyTo(File (configFile.parentFile, " $CONFIG_NAME .bak" ), overwrite = true )
9987 }
10088 configFile.delete()
10189 } else {
102- appendLog(" Config already exists" )
10390 return configFile
10491 }
10592 }
@@ -113,67 +100,7 @@ class MainActivity : AppCompatActivity() {
113100 .replace(" path = \" data/network\" " , " path = \" ${File (dataDir, " network" ).absolutePath} \" " )
114101
115102 configFile.writeText(modifiedConfig)
116- appendLog(" Config created" )
117103
118104 return configFile
119105 }
120-
121- private fun startLightClient () {
122- if (isRunning) {
123- appendLog(" Already running!" )
124- return
125- }
126-
127- try {
128- val intent = Intent (this , LightClientService ::class .java).apply {
129- action = LightClientService .ACTION_START
130- }
131- ContextCompat .startForegroundService(this , intent)
132-
133- isRunning = true
134- startButton.isEnabled = false
135- stopButton.isEnabled = true
136-
137- } catch (e: Exception ) {
138- appendLog(" ERROR: ${e.message} " )
139- Log .e(TAG , " Start error" , e)
140- isRunning = false
141- startButton.isEnabled = true
142- stopButton.isEnabled = false
143- }
144- }
145-
146- private fun stopLightClient () {
147- if (! isRunning) {
148- appendLog(" Not running!" )
149- return
150- }
151-
152- try {
153- val intent = Intent (this , LightClientService ::class .java).apply {
154- action = LightClientService .ACTION_STOP
155- }
156- startService(intent)
157-
158- isRunning = false
159- startButton.isEnabled = true
160- stopButton.isEnabled = false
161-
162- } catch (e: Exception ) {
163- appendLog(" ERROR: ${e.message} " )
164- Log .e(TAG , " Stop error" , e)
165- }
166- }
167-
168- private fun appendLog (message : String ) {
169- logTextView.append(" $message \n " )
170- scrollView.post { scrollView.fullScroll(ScrollView .FOCUS_DOWN ) }
171- }
172-
173- override fun onDestroy () {
174- super .onDestroy()
175- // Don't stop the service when activity is destroyed
176- // The service will continue running in background
177- LightClientService .logCallback = null
178- }
179106}
0 commit comments