Skip to content

Commit c554019

Browse files
committed
rich ui
1 parent 5927a32 commit c554019

File tree

3 files changed

+65
-171
lines changed

3 files changed

+65
-171
lines changed

android-app/app/build.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ dependencies {
4141
implementation("androidx.appcompat:appcompat:1.6.1")
4242
implementation("com.google.android.material:material:1.10.0")
4343
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
44+
45+
// Fragments
46+
implementation("androidx.fragment:fragment-ktx:1.6.2")
47+
48+
// Lifecycle & Coroutines
49+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
50+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
51+
52+
// JSON Parsing
53+
implementation("com.google.code.gson:gson:2.10.1")
54+
55+
// SwipeRefreshLayout
56+
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
4457
}
4558

4659
// Copy Rust JNI libraries from target directory to jniLibs
Lines changed: 36 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
package com.nervosnetwork.ckblightclient
22

3-
import android.content.Intent
43
import 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.*
114
import 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

1312
class 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
}
Lines changed: 16 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,23 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<LinearLayout
2+
<androidx.coordinatorlayout.widget.CoordinatorLayout
33
xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:app="http://schemas.android.com/apk/res-auto"
45
android:layout_width="match_parent"
5-
android:layout_height="match_parent"
6-
android:orientation="vertical"
7-
android:padding="16dp">
6+
android:layout_height="match_parent">
87

9-
<TextView
8+
<FrameLayout
9+
android:id="@+id/fragment_container"
1010
android:layout_width="match_parent"
11-
android:layout_height="wrap_content"
12-
android:text="CKB Light Client"
13-
android:textSize="24sp"
14-
android:textStyle="bold"
15-
android:gravity="center"
16-
android:paddingBottom="16dp"
17-
android:textColor="#000000"/>
11+
android:layout_height="match_parent"
12+
android:layout_marginBottom="56dp" />
1813

19-
<LinearLayout
14+
<com.google.android.material.bottomnavigation.BottomNavigationView
15+
android:id="@+id/bottom_navigation"
2016
android:layout_width="match_parent"
21-
android:layout_height="wrap_content"
22-
android:orientation="horizontal">
23-
24-
<Button
25-
android:id="@+id/startButton"
26-
android:layout_width="0dp"
27-
android:layout_height="wrap_content"
28-
android:layout_weight="1"
29-
android:text="Start"
30-
android:enabled="false"
31-
android:layout_marginEnd="8dp"/>
32-
33-
<Button
34-
android:id="@+id/stopButton"
35-
android:layout_width="0dp"
36-
android:layout_height="wrap_content"
37-
android:layout_weight="1"
38-
android:text="Stop"
39-
android:enabled="false"
40-
android:layout_marginStart="8dp"/>
41-
</LinearLayout>
42-
43-
<TextView
44-
android:layout_width="match_parent"
45-
android:layout_height="wrap_content"
46-
android:text="Logs:"
47-
android:textStyle="bold"
48-
android:paddingTop="8dp"
49-
android:paddingBottom="4dp"
50-
android:textColor="#000000"/>
51-
52-
<ScrollView
53-
android:id="@+id/scrollView"
54-
android:layout_width="match_parent"
55-
android:layout_height="0dp"
56-
android:layout_weight="1"
57-
android:background="#f0f0f0"
58-
android:padding="8dp">
59-
60-
<TextView
61-
android:id="@+id/logTextView"
62-
android:layout_width="match_parent"
63-
android:layout_height="wrap_content"
64-
android:textSize="11sp"
65-
android:fontFamily="monospace"
66-
android:textColor="#000000"
67-
android:lineSpacingMultiplier="1.1"/>
68-
</ScrollView>
69-
</LinearLayout>
17+
android:layout_height="56dp"
18+
android:layout_gravity="bottom"
19+
android:background="?attr/colorPrimary"
20+
app:itemIconTint="@android:color/white"
21+
app:itemTextColor="@android:color/white"
22+
app:menu="@menu/bottom_navigation_menu" />
23+
</androidx.coordinatorlayout.widget.CoordinatorLayout>

0 commit comments

Comments
 (0)