Skip to content

Commit 1d6b0f7

Browse files
authoredNov 10, 2023
Merge pull request #4 from DavideAG/fix/code_improvements
Release 1.0.0 🎉
2 parents f6b6a5e + f210eab commit 1d6b0f7

12 files changed

+121
-51
lines changed
 

‎.idea/deploymentTargetDropDown.xml

+17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.idea/misc.xml

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎CHANGELOG.md

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
## 1.0.0 (November, 10, 2023)
2+
3+
- add cpu core spinner support
4+
5+
## 0.6.0 (November, 7, 2023)
6+
7+
- update to JDK 17 and Gradle 7.5
8+
- fix bug about free disk space
9+
110
## 0.5.4 (April, 27, 2022)
211

312
- added a method to show free disk space in a more human friendly way
413

514
## 0.5.3 (April, 27, 2021)
615

7-
* Defined layout for settings page
8-
* created author ref to http://giorgiodavide.it with "Open on Phone" animation
9-
* added spinner for CPUs in order to compute the CPU usage in the correct way (default disabled)
10-
* added app version information in the setting page
16+
- Defined layout for settings page
17+
- created author ref to http://giorgiodavide.it with "Open on Phone" animation
18+
- added spinner for CPUs in order to compute the CPU usage in the correct way (default disabled)
19+
- added app version information in the setting page
1120

1221
## 0.5.2 (July, 14, 2020)
1322

‎README.md

+12-10
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,36 @@ NcMonitor is a native [WearOS](https://wearos.google.com/#hands-free-help) appli
1515
</p>
1616

1717
## Displayed metrics :mag:
18-
Currently this application is still under development and the information that are displayed are:
18+
The goal of this application is to provide information about your NC instance:
1919

2020
- CPU usage (last-minute)
2121
- RAM usage
2222
- SWAP usage
2323
- Disk free space
2424

25-
The final goal is to provide to the user more information about the Nc instance. In the future more metrics will be added.
26-
27-
Data are retrived from [Nextcloud/serverinfo](https://github.com/nextcloud/serverinfo).
25+
Data are retrived from [Nextcloud/serverinfo](https://github.com/nextcloud/serverinfo) and we will provide more metrics when available.
2826

2927
## How to use it :question:
30-
To use the application you have to install the application (see Project status) and then you have to log-in in your Nc server using:
28+
The application requires basic authentication to communicate with the server and get back the metrics from [Nextcloud/serverinfo](https://github.com/nextcloud/serverinfo). During the first start it will require:
3129

3230
- select your HyperText Transfer Protocol (`http` or `https`)
33-
- server URL (e.g. myserver.com)
31+
- server URL (e.g. `myserver.com`)
3432
- Nextcloud username
3533
- Nextcloud password
3634

35+
### CPU Cores
36+
To calculate the app's total CPU load percentage, it requires information about the number of CPU cores in your NC instance, which is set to a default value of 4. You can modify this setting through the configuration panel.
37+
3738
## Changelog
3839
Changelog information are reported [here](https://github.com/DavideAG/NcMonitor/blob/master/CHANGELOG.md).
3940

40-
## Project status :hammer_and_wrench:
41-
This application is in `beta` phase and is working but it is not yet released in Google Play Store.
42-
If you want to use this application you can download the `apk` in the release section of this repository or you can manually build the project.
41+
## Project status
42+
The application has not been officially launched on the Google Play Store yet. To access and use the application, you can download the APK from the release section of this repository, or alternatively, you have the option to manually build the project. The initial release will soon be made available on the Google Play Store.
43+
44+
Please contact me if you have any problem with this installation process.
4345

4446
## License :scroll:
4547
This application is licensed under the `AGPLv3`
4648

4749
## Contact
48-
Any comment or idea about the project is appreciated. You can ping me at [davide@giorgiodavide.it](mailto:davide@giorgiodavide.it?subject=[GitHub]%20NcMonitor)
50+
Any comment or idea about the project is appreciated, feel free to ping me at [davide@giorgiodavide.it](mailto:davide@giorgiodavide.it?subject=[GitHub]%20NcMonitor) or open an issue on GitHub.

‎app/build.gradle

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ android {
1010
minSdkVersion 25
1111
targetSdkVersion 30
1212
versionCode 8
13-
versionName "0.5.4"
13+
versionName "1.0.0"
1414
}
1515

1616
buildTypes {
@@ -19,6 +19,7 @@ android {
1919
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
2020
}
2121
}
22+
namespace 'davideag.wearos.ncmonitor'
2223
}
2324

2425
dependencies {

‎app/src/main/AndroidManifest.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="davideag.wearos.ncmonitor">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
43

54
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
65
<uses-permission android:name="android.permission.WAKE_LOCK" />

‎app/src/main/java/davideag/wearos/ncmonitor/LoginActivity.kt

+5-4
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ import okhttp3.Response
4040
import org.json.JSONException
4141
import org.json.JSONObject
4242
import java.io.IOException
43+
import java.net.HttpURLConnection
44+
4345

4446

4547
const val SERVERINFO_API = "ocs/v2.php/apps/serverinfo/api/v1/info?format=json"
4648
const val PERMISSION_REQUEST = 10
4749
const val PREF_KEY = "profile"
4850
const val PREF_NAME = "USER"
49-
const val OK_200 = 200
5051

5152

5253
class LoginActivity : WearableActivity()
@@ -139,8 +140,8 @@ class LoginActivity : WearableActivity()
139140
}
140141

141142
/* This method is used to request the server status to your
142-
* NC instance. Then, if the result code is OK_200, results
143-
* are passed to the next activity.
143+
* NC instance. Then, if the return code is HttpURLConnection.HTTP_OK
144+
* results are passed to the next activity.
144145
*/
145146
private fun requestNcStatus(serverURL: String, username: String, password: String, domain: String, context: Context)
146147
{
@@ -157,7 +158,7 @@ class LoginActivity : WearableActivity()
157158
val metaObject = responseObject.getJSONObject("meta")
158159
val statusCode = metaObject.getInt("statuscode")
159160

160-
if (statusCode == OK_200) {
161+
if (statusCode == HttpURLConnection.HTTP_OK) {
161162
val userInfo = JSONObject()
162163
userInfo.put("serverURL", serverURL)
163164
userInfo.put("username", username)

‎app/src/main/java/davideag/wearos/ncmonitor/MainActivity.kt

+32-25
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ import android.view.View
2828
import kotlinx.android.synthetic.main.activity_main.*
2929
import org.json.JSONException
3030
import org.json.JSONObject
31-
import kotlin.math.roundToInt
31+
import java.net.HttpURLConnection
32+
3233

3334

3435
const val Byte = 1024
35-
const val N_CORES = 4 /* number of cores in your server. 4 for RPi4. */
36+
var N_CORES = 4 /* number of cores in your server. 4 for RPi4. */
37+
var CPU_LOAD = 0.0
3638

3739

3840
class MainActivity : WearableActivity()
@@ -63,6 +65,14 @@ class MainActivity : WearableActivity()
6365
}
6466
}
6567

68+
/* Refresh the cpu_load_placeholder with the new N_CORES.
69+
* We need to handle the new number of CPU cores to compute the CPU load
70+
*/
71+
override fun onRestart() {
72+
super.onRestart()
73+
cpu_load_placeholder.text = "%.2f".format((CPU_LOAD / N_CORES) * 100)
74+
}
75+
6676
/* This method shows the results retrieved from
6777
* the server. View are populated correctly.
6878
* In case of error a message is displayed
@@ -78,32 +88,32 @@ class MainActivity : WearableActivity()
7888

7989
val responseObject = json.getJSONObject("ocs")
8090
val metaObject = responseObject.getJSONObject("meta")
81-
8291
val statusCode = metaObject.getInt("statuscode")
8392

84-
if (statusCode == 200) {
93+
if (statusCode == HttpURLConnection.HTTP_OK) {
8594
status_code_response_layout.visibility = View.GONE
8695
status_message_response_layout.visibility = View.GONE
8796
server_name_url.visibility = View.VISIBLE
8897
server_name_url.text = serverURL
8998

90-
val dataObject = responseObject.getJSONObject("data")
91-
val nextcloudObject = dataObject.getJSONObject("nextcloud")
92-
val systemObject = nextcloudObject.getJSONObject("system")
99+
val dataObject = responseObject.getJSONObject("data")
100+
val nextcloudObject = dataObject.getJSONObject("nextcloud")
101+
val systemObject = nextcloudObject.getJSONObject("system")
93102

94103
// cpu load
95-
var cpuLoad = systemObject.getJSONArray("cpuload")[0]
96-
if (cpuLoad is Int) cpuLoad = cpuLoad.toDouble()
104+
CPU_LOAD = systemObject.getJSONArray("cpuload")[0] as Double
105+
//var cpuLoad = systemObject.getJSONArray("cpuload")[0]
106+
//if (CPU_LOAD is Int) CPU_LOAD = CPU_LOAD
97107
// ram
98108
val ramTotal = systemObject.getLong("mem_total")
99109
val ramFree = systemObject.getLong("mem_free")
100110
// swap
101111
val swapTotal = systemObject.getLong("swap_total")
102112
val swapFree = systemObject.getLong("swap_free")
103113
// disk
104-
val diskFree = systemObject.getDouble("freespace")
114+
val diskFree = systemObject.getLong("freespace")
105115

106-
updateViews(cpuLoad as Double, ramTotal-ramFree, ramTotal,
116+
updateViews(ramTotal-ramFree, ramTotal,
107117
swapTotal-swapFree, swapTotal, diskFree)
108118

109119
} else {
@@ -130,22 +140,18 @@ class MainActivity : WearableActivity()
130140
* using the information coming from the server.
131141
*/
132142
private fun updateViews(
133-
cpuLoad: Double,
134143
ramBusy: Long,
135144
ramTotal: Long,
136145
swapBusy: Long,
137146
swapTotal: Long,
138-
diskFree: Double)
147+
diskFree: Long)
139148
{
140149

141150
// Todo: to move as option and let this. We can't supposing the number of cpu cores
142151
// and it has to be specified by the final user using a specific option menu.
143-
// cpu_load_placeholder.text = cpuLoad.toString()
144-
145-
val cpuLoad3Digit = (((cpuLoad * 100) / N_CORES) * 1000.0).roundToInt() / 1000.0
146-
val cpuLoad2Digit = (cpuLoad3Digit * 100.0).roundToInt() / 100.0
152+
val cpuLoadPercentage = (CPU_LOAD / N_CORES) * 100
147153

148-
cpu_load_placeholder.text = cpuLoad2Digit.toString()
154+
cpu_load_placeholder.text = "%.2f".format(cpuLoadPercentage)
149155
ram_used_placeholder.text = (ramBusy / Byte).toString()
150156
ram_total_placeholder.text = (ramTotal / Byte).toString()
151157
swap_used_placeholder.text = (swapBusy / Byte).toString()
@@ -159,15 +165,16 @@ class MainActivity : WearableActivity()
159165
/* This function is used to convert the free disk
160166
* space in an human friendly measure
161167
*/
162-
private fun humanReadableByteCountBin(bytes: Double): Pair<String, String> {
168+
private fun humanReadableByteCountBin(bytes: Long): Pair<String, String> {
163169
return when {
164-
bytes == Double.MIN_VALUE || bytes < 0 -> Pair("N/A", "")
170+
bytes == Long.MIN_VALUE || bytes < 0 -> Pair("N/A", "")
165171
bytes < 1024L -> Pair("$bytes", "B")
166-
bytes <= 0xfffccccccccccccL shr 40 -> Pair("%.1f".format(bytes / (0x1 shl 10)), "KiB")
167-
bytes <= 0xfffccccccccccccL shr 30 -> Pair("%.1f".format(bytes / (0x1 shl 20)), "MiB")
168-
bytes <= 0xfffccccccccccccL shr 20 -> Pair("%.1f".format(bytes / (0x1 shl 30)), "GiB")
169-
bytes <= 0xfffccccccccccccL shr 10 -> Pair("%.1f".format(bytes / (0x1 shl 40)), "TiB")
170-
else -> Pair("N/A", "")
172+
bytes <= 0xfffccccccccccccL shr 40 -> Pair("%.1f".format(bytes.toDouble() / (0x1 shl 10)), "KiB")
173+
bytes <= 0xfffccccccccccccL shr 30 -> Pair("%.1f".format(bytes.toDouble() / (0x1 shl 20)), "MiB")
174+
bytes <= 0xfffccccccccccccL shr 20 -> Pair("%.1f".format(bytes.toDouble() / (0x1 shl 30)), "GiB")
175+
bytes <= 0xfffccccccccccccL shr 10 -> Pair("%.1f".format(bytes.toDouble() / (0x1 shl 40)), "TiB")
176+
bytes <= 0xfffccccccccccccL -> Pair("%.1f".format((bytes shr 10).toDouble() / (0x1 shl 40)), "PiB")
177+
else -> Pair("%.1f".format((bytes shr 20).toDouble() / (0x1 shl 40)), "EiB")
171178
}
172179
}
173180
}

‎app/src/main/java/davideag/wearos/ncmonitor/Settings.kt

+33-1
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,19 @@ import android.net.Uri
2525
import android.os.Bundle
2626
import android.support.wearable.activity.ConfirmationActivity
2727
import android.support.wearable.activity.WearableActivity
28+
import android.util.Log
29+
import android.view.View
30+
import android.widget.AdapterView
31+
import android.widget.ArrayAdapter
32+
import android.widget.SpinnerAdapter
2833
import com.google.android.wearable.intent.RemoteIntent
34+
import kotlinx.android.synthetic.main.activity_main.cpu_load_placeholder
2935
import kotlinx.android.synthetic.main.activity_settings.*
3036

3137

3238
const val VERSION = BuildConfig.VERSION_NAME
3339
const val AUTHOR_WEBSITE = "http://giorgiodavide.it"
40+
val CPU_CORES = (1..32).toList()
3441

3542

3643
class Settings : WearableActivity()
@@ -41,9 +48,34 @@ class Settings : WearableActivity()
4148
setContentView(R.layout.activity_settings)
4249

4350
version_number_placeholder.text = VERSION
51+
cpuSpinnerInit()
4452
creator_webpage.setOnClickListener{ launchBrowserOnPhone() }
4553
}
4654

55+
/* This method will configure the CPU spinner
56+
*/
57+
private fun cpuSpinnerInit()
58+
{
59+
// set the elements of the spinner (CPU_CORES
60+
val adapter: ArrayAdapter<Int> = ArrayAdapter<Int>(this, android.R.layout.simple_spinner_item, CPU_CORES)
61+
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
62+
cpu_spinner.adapter = adapter
63+
64+
// configure the selected N_CORES
65+
val selectedItemIndex = CPU_CORES.indexOf(N_CORES)
66+
cpu_spinner.setSelection(selectedItemIndex)
67+
68+
// handle the new N_CORES value
69+
cpu_spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
70+
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
71+
N_CORES = CPU_CORES[position]
72+
Log.d("selected cpu cores", "$N_CORES")
73+
}
74+
75+
override fun onNothingSelected(parent: AdapterView<*>?) {}
76+
}
77+
}
78+
4779
/* This method will launch the phone browser
4880
*/
4981
private fun launchBrowserOnPhone()
@@ -56,7 +88,7 @@ class Settings : WearableActivity()
5688
)
5789
startActivity(intentAnimation)
5890

59-
// launch the browser in the phone
91+
// launch the phone browser
6092
val intentBrowser = Intent(Intent.ACTION_VIEW)
6193
.addCategory(Intent.CATEGORY_BROWSABLE)
6294
.setData(Uri.parse(AUTHOR_WEBSITE))

‎build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
jcenter()
77
}
88
dependencies {
9-
classpath 'com.android.tools.build:gradle:7.4.2'
9+
classpath 'com.android.tools.build:gradle:8.1.2'
1010
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1111

1212
// NOTE: Do not place your application dependencies here; they belong

‎gradle.properties

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,7 @@ android.useAndroidX=true
1818
# Automatically convert third-party libraries to use AndroidX
1919
android.enableJetifier=true
2020
# Kotlin code style for this project: "official" or "obsolete":
21-
kotlin.code.style=official
21+
kotlin.code.style=official
22+
android.defaults.buildfeatures.buildconfig=true
23+
android.nonTransitiveRClass=false
24+
android.nonFinalResIds=false
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)