diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5cfbb56..3839048 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -44,7 +44,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: cleanmeter
- path: target\server\build\compose\binaries\main\app
+ path: target\desktop\build\compose\binaries\main\app
dependency-submission:
diff --git a/README.md b/README.md
index 3e3226e..a7c5050 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,33 @@
-# Clean Meter
-
-> Did you like my work? Consider supporting me so I can keep putting hours in.
-> - [ko-fi](https://ko-fi.com/danil0v3s)
-> - [PayPal](https://www.paypal.com/donate/?hosted_button_id=W2GU6AHGQUND8)
-
-> [!IMPORTANT]
-> We are preparing our first major release 1.0.0. It's already available in [beta1](https://github.com/Danil0v3s/CleanMeter/releases/tag/1.0.0.beta-1) and it makes our app completely standalone, without the need of HWiNFO or MSI Afterburner anymore. Try it out and let us know!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
> [!IMPORTANT]
-> We released 0.0.4 which DROPPED the need of MSI Afterburner and rely entirely on HWInfo alone. We heard some of you dislike Afterburner so we opted to go the least friction route.
+> 🎉 We've released 1.0! Star this repo or keep an eye on it to follow along.
-## What is this?
+CleanMeter is the first gamer oriented clean statistics tracker, no fuss no muss, dead simple setup and good looking visuals.
-A small desktop companion app to display sleek graphs overlays from HWInfo. Designs were made by [/u/Violetmars](https://www.reddit.com/user/Violetmars/)
-
-
-
-
-## Getting started
-1. If you have HWiNFO installed already, make sure that `Enable Shared Memory Support` is **enabled** at the settings.
-
-> [!IMPORTANT]
-> If you chose to have HWiNFO installed, _**you**_ will have to manage the `Shared Memory Support` limitation of 12 hours. Every 12 hours of uptime you will need to re-enable the setting. It seems the timer resets if you shutdown your computer before 12h uptime.
-2. If you didn't have HWiNFO installed, there's no need to do any additional setup. (We manage a portable version of it ourselves)
-3. Download the latest release, run it
+### Benefits over traditional performance trackers
+- This looks good
+- No fluorescent numbers with Arial 12
+- Doesn't mess with your power profile or fan setup
-## Current Limitations
+### Current Limitations
- Doesn't work with exclusive fullscreen
+- Given our mission is to look _good_ and _clean_ at the same time, we might hold on to release new features because we need time to think how to accommodate our UI. We can't just enable every possible sensor, sorry.
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/PreferencesRepository.kt b/core/native/src/main/kotlin/app/cleanmeter/core/os/PreferencesRepository.kt
similarity index 63%
rename from target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/PreferencesRepository.kt
rename to core/native/src/main/kotlin/app/cleanmeter/core/os/PreferencesRepository.kt
index b9573f3..d6f8c67 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/PreferencesRepository.kt
+++ b/core/native/src/main/kotlin/app/cleanmeter/core/os/PreferencesRepository.kt
@@ -1,8 +1,5 @@
-package app.cleanmeter.target.desktop.data
+package app.cleanmeter.core.os
-import app.cleanmeter.target.desktop.model.OverlaySettings
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
import java.util.prefs.Preferences
const val OVERLAY_SETTINGS_PREFERENCE_KEY = "OVERLAY_SETTINGS_PREFERENCE_KEY"
@@ -26,18 +23,4 @@ object PreferencesRepository {
fun setPreference(key: String, value: String) = prefs.put(key, value)
fun setPreferenceBoolean(key: String, value: Boolean) = prefs.putBoolean(key, value)
fun clear() = prefs.clear()
-}
-
-fun PreferencesRepository.loadOverlaySettings(): OverlaySettings {
- val json = getPreferenceString(OVERLAY_SETTINGS_PREFERENCE_KEY)
- val settings = if (json != null) {
- try {
- Json.decodeFromString(json)
- } catch (e: Exception) {
- OverlaySettings()
- }
- } else {
- OverlaySettings()
- }
- return settings
}
\ No newline at end of file
diff --git a/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/HardwareMonitorProcessManager.kt b/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/HardwareMonitorProcessManager.kt
index 3d5bb6e..f788663 100644
--- a/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/HardwareMonitorProcessManager.kt
+++ b/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/HardwareMonitorProcessManager.kt
@@ -4,16 +4,53 @@ import app.cleanmeter.core.os.util.isDev
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
import java.nio.file.Path
import java.util.*
object HardwareMonitorProcessManager {
private var process: Process? = null
- fun checkRuntime() {
- ProcessBuilder().apply {
- command("dotnet --list-runtimes")
- }.start()
+ suspend fun checkRuntime(): Boolean {
+ return try {
+ val process = ProcessBuilder().apply {
+ command("cmd.exe", "/c", "dotnet", "--list-runtimes")
+ }.start()
+
+ val scannerIn = Scanner(process.inputStream)
+ val scannerErr = Scanner(process.errorStream)
+
+ val stdOutput = emptyList().toMutableList()
+ val errOutput = emptyList().toMutableList()
+
+ CoroutineScope(Dispatchers.IO).launch {
+ try {
+ while (scannerIn.hasNextLine()) {
+ stdOutput.add(scannerIn.nextLine())
+ }
+ } catch (e: Exception) {
+ return@launch
+ }
+
+ }
+ CoroutineScope(Dispatchers.IO).launch {
+ try {
+ while (scannerErr.hasNextLine()) {
+ errOutput.add(scannerIn.nextLine())
+ }
+ } catch (e: Exception) {
+ return@launch
+ }
+ }
+
+ return withContext(Dispatchers.IO) {
+ val exitCode = process.waitFor()
+ exitCode == 0 && errOutput.isEmpty()
+ }
+ } catch (ex: Exception) {
+ return false
+ }
}
fun start() {
@@ -32,12 +69,12 @@ object HardwareMonitorProcessManager {
val scannerErr = Scanner(process!!.errorStream)
CoroutineScope(Dispatchers.IO).launch {
- while(scannerIn.hasNextLine()) {
+ while (scannerIn.hasNextLine()) {
System.out.println(scannerIn.nextLine())
}
}
CoroutineScope(Dispatchers.IO).launch {
- while(scannerErr.hasNextLine()) {
+ while (scannerErr.hasNextLine()) {
System.err.println(scannerErr.nextLine())
}
}
@@ -57,7 +94,8 @@ object HardwareMonitorProcessManager {
val command = listOf(
"cmd.exe",
"/c",
- "sc create svcleanmeter displayname= \"CleanMeter Service\" binPath= $file start= auto group= LocalServiceNoNetworkFirewall")
+ "sc create svcleanmeter displayname= \"CleanMeter Service\" binPath= $file start= auto group= LocalServiceNoNetworkFirewall"
+ )
ProcessBuilder().apply {
command(command)
}.start()
diff --git a/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/SocketClient.kt b/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/SocketClient.kt
index b99f577..ab76fa4 100644
--- a/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/SocketClient.kt
+++ b/core/native/src/main/kotlin/app/cleanmeter/core/os/hardwaremonitor/SocketClient.kt
@@ -1,5 +1,7 @@
package app.cleanmeter.core.os.hardwaremonitor
+import app.cleanmeter.core.os.PREFERENCE_PERMISSION_CONSENT
+import app.cleanmeter.core.os.PreferencesRepository
import app.cleanmeter.core.os.util.getByteBuffer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -55,7 +57,9 @@ object SocketClient {
val packetFlow: Flow = packetChannel.receiveAsFlow()
init {
- connect()
+ if (PreferencesRepository.getPreferenceBoolean(PREFERENCE_PERMISSION_CONSENT, false)) {
+ connect()
+ }
}
private fun connect() = CoroutineScope(Dispatchers.IO).launch {
diff --git a/core/native/src/main/kotlin/app/cleanmeter/core/os/win32/WindowsService.kt b/core/native/src/main/kotlin/app/cleanmeter/core/os/win32/WindowsService.kt
index 960b98e..babf2af 100644
--- a/core/native/src/main/kotlin/app/cleanmeter/core/os/win32/WindowsService.kt
+++ b/core/native/src/main/kotlin/app/cleanmeter/core/os/win32/WindowsService.kt
@@ -78,10 +78,14 @@ class WindowsService {
fun tryElevateProcess(isAutostart: Boolean) {
if (isAutostart) return
if (!isDev() && !WindowsService.isProcessElevated()) {
- val currentDir = Path.of("").toAbsolutePath().toString()
- Shell32Impl.INSTANCE.ShellExecuteW(null, "runas", "$currentDir\\cleanmeter.exe", "", "", 10)
- exitProcess(0)
+ elevateProcess()
}
}
+
+ fun elevateProcess() {
+ val currentDir = Path.of("").toAbsolutePath().toString()
+ Shell32Impl.INSTANCE.ShellExecuteW(null, "runas", "$currentDir\\cleanmeter.exe", "", "", 10)
+ exitProcess(0)
+ }
}
}
diff --git a/images/Logo.png b/images/Logo.png
deleted file mode 100644
index c4a114c..0000000
Binary files a/images/Logo.png and /dev/null differ
diff --git a/images/compose-logo.svg b/images/compose-logo.svg
deleted file mode 100644
index 1aa3f8b..0000000
--- a/images/compose-logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/images/qa_clean_meter.png b/images/qa_clean_meter.png
deleted file mode 100644
index 16b5b7d..0000000
Binary files a/images/qa_clean_meter.png and /dev/null differ
diff --git a/images/qa_clean_meter2.png b/images/qa_clean_meter2.png
deleted file mode 100644
index 023a0ff..0000000
Binary files a/images/qa_clean_meter2.png and /dev/null differ
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/DesktopMain.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/DesktopMain.kt
index 966e887..a2808d2 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/DesktopMain.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/DesktopMain.kt
@@ -5,8 +5,8 @@ import app.cleanmeter.core.common.reporting.ApplicationParams
import app.cleanmeter.core.os.ProcessManager
import app.cleanmeter.core.os.util.isDev
import app.cleanmeter.core.os.win32.WindowsService
-import app.cleanmeter.target.desktop.data.PREFERENCE_PERMISSION_CONSENT
-import app.cleanmeter.target.desktop.data.PreferencesRepository
+import app.cleanmeter.core.os.PREFERENCE_PERMISSION_CONSENT
+import app.cleanmeter.core.os.PreferencesRepository
fun main(vararg args: String) = singleInstance(args) {
if (PreferencesRepository.getPreferenceBoolean(PREFERENCE_PERMISSION_CONSENT, false)) {
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/OverlaySettingsRepository.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/OverlaySettingsRepository.kt
index 25adcd8..7dda900 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/OverlaySettingsRepository.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/OverlaySettingsRepository.kt
@@ -1,5 +1,7 @@
package app.cleanmeter.target.desktop.data
+import app.cleanmeter.core.os.OVERLAY_SETTINGS_PREFERENCE_KEY
+import app.cleanmeter.core.os.PreferencesRepository
import app.cleanmeter.target.desktop.model.OverlaySettings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/PreferenceRepositoryExtensions.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/PreferenceRepositoryExtensions.kt
new file mode 100644
index 0000000..0f429d3
--- /dev/null
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/data/PreferenceRepositoryExtensions.kt
@@ -0,0 +1,21 @@
+package app.cleanmeter.target.desktop.data
+
+import app.cleanmeter.core.os.OVERLAY_SETTINGS_PREFERENCE_KEY
+import app.cleanmeter.core.os.PreferencesRepository
+import app.cleanmeter.target.desktop.model.OverlaySettings
+import kotlinx.serialization.decodeFromString
+import kotlinx.serialization.json.Json
+
+fun PreferencesRepository.loadOverlaySettings(): OverlaySettings {
+ val json = getPreferenceString(OVERLAY_SETTINGS_PREFERENCE_KEY)
+ val settings = if (json != null) {
+ try {
+ Json.decodeFromString(json)
+ } catch (e: Exception) {
+ OverlaySettings()
+ }
+ } else {
+ OverlaySettings()
+ }
+ return settings
+}
\ No newline at end of file
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/Progress.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/Progress.kt
index 25ec621..fc547d6 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/Progress.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/Progress.kt
@@ -38,7 +38,7 @@ fun Progress(
val color = when {
value in 0f..boundaries.low.div(100f) -> Green
value in boundaries.low.div(100f)..boundaries.medium.div(100f) -> Yellow
- value > boundaries.high.div(100f) -> Red
+ value > boundaries.medium.div(100f) -> Red
else -> White
}
@@ -87,43 +87,59 @@ fun Progress(
@Preview
@Composable
private fun ProgressPreview() {
+ Column {
+ ProgressRow(OverlaySettings.ProgressType.Bar)
+ ProgressRow(OverlaySettings.ProgressType.Circular)
+ }
+}
+
+@Composable
+private fun ProgressRow(progressType :OverlaySettings.ProgressType) {
Row(modifier = Modifier.background(Color.Black)) {
Progress(
- value = 0.5f,
- label = "05",
- progressType = OverlaySettings.ProgressType.Bar,
+ value = 0.12f,
+ label = "12",
+ progressType = progressType,
+ unit = "C",
+ boundaries = OverlaySettings.Sensor.GraphSensor.Boundaries()
+ )
+
+ Progress(
+ value = 0.53f,
+ label = "53",
+ progressType = progressType,
unit = "C",
boundaries = OverlaySettings.Sensor.GraphSensor.Boundaries()
)
Progress(
- value = 0.6f,
- label = "06",
- progressType = OverlaySettings.ProgressType.Bar,
+ value = 0.67f,
+ label = "67",
+ progressType = progressType,
unit = "C",
boundaries = OverlaySettings.Sensor.GraphSensor.Boundaries()
)
Progress(
- value = 0.7f,
- label = "07",
- progressType = OverlaySettings.ProgressType.Bar,
+ value = 0.72f,
+ label = "72",
+ progressType = progressType,
unit = "C",
boundaries = OverlaySettings.Sensor.GraphSensor.Boundaries()
)
Progress(
- value = 0.8f,
- label = "08",
- progressType = OverlaySettings.ProgressType.Bar,
+ value = 0.86f,
+ label = "86",
+ progressType = progressType,
unit = "C",
boundaries = OverlaySettings.Sensor.GraphSensor.Boundaries()
)
Progress(
- value = 0.9f,
- label = "09",
- progressType = OverlaySettings.ProgressType.Bar,
+ value = 0.99f,
+ label = "99",
+ progressType = progressType,
unit = "C",
boundaries = OverlaySettings.Sensor.GraphSensor.Boundaries()
)
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/RuntimeToast.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/RuntimeToast.kt
new file mode 100644
index 0000000..32f2960
--- /dev/null
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/RuntimeToast.kt
@@ -0,0 +1,135 @@
+package app.cleanmeter.target.desktop.ui.components
+
+import ClearButton
+import FilledButton
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
+import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Icon
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.Warning
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+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
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalUriHandler
+import androidx.compose.ui.unit.dp
+import app.cleanmeter.core.designsystem.LocalColorScheme
+import app.cleanmeter.core.designsystem.LocalTypography
+import app.cleanmeter.target.desktop.ui.AppTheme
+import kotlinx.coroutines.delay
+import kotlin.system.exitProcess
+
+@Composable
+internal fun BoxScope.RuntimeToast() {
+ val uriHandler = LocalUriHandler.current
+ val density = LocalDensity.current
+ var visible by remember {
+ mutableStateOf(false)
+ }
+
+ LaunchedEffect(Unit) {
+ delay(1000)
+ visible = true
+ }
+
+ AnimatedVisibility(
+ visible = visible,
+ enter = slideInVertically {
+ with(density) { 40.dp.roundToPx() }
+ },
+ exit = slideOutVertically {
+ with(density) { 40.dp.roundToPx() }
+ },
+ modifier = Modifier.align(Alignment.BottomCenter)
+ ) {
+ Row(
+ modifier = Modifier
+ .padding(bottom = 16.dp)
+ .fillMaxWidth(0.95f)
+ .background(LocalColorScheme.current.background.brand, RoundedCornerShape(100))
+ .padding(horizontal = 16.dp, vertical = 14.dp)
+ .align(Alignment.BottomCenter)
+ .animateContentSize(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ Box(modifier = Modifier.size(40.dp), contentAlignment = Alignment.Center) {
+ Icon(
+ imageVector = Icons.Rounded.Warning,
+ contentDescription = null,
+ tint = LocalColorScheme.current.icon.inverse,
+ modifier = Modifier.fillMaxSize().background(LocalColorScheme.current.background.brandSubtle, RoundedCornerShape(100)).padding(10.dp),
+ )
+ }
+ BodyText()
+ CallToAction(
+ onCloseClick = { exitProcess(0) },
+ onUpdateClick = {
+ uriHandler.openUri("https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.11-windows-x64-installer")
+ exitProcess(0)
+ },
+ )
+ }
+ }
+}
+
+@Composable
+private fun RowScope.BodyText() {
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = ".NET Core Runtime not available",
+ color = LocalColorScheme.current.text.inverse,
+ style = LocalTypography.current.labelLMedium,
+ modifier = Modifier.wrapContentHeight(),
+ )
+ Text(
+ text = "Please re-open CleanMeter after the installation.",
+ color = LocalColorScheme.current.text.disabled,
+ style = LocalTypography.current.labelLMedium,
+ modifier = Modifier.wrapContentHeight(),
+ )
+ }
+}
+
+
+
+@Composable
+private fun RowScope.CallToAction(
+ onCloseClick: () -> Unit,
+ onUpdateClick: () -> Unit,
+) {
+ ClearButton(label = "Later", onClick = onCloseClick)
+ FilledButton(label = "Install now", onClick = onUpdateClick)
+}
+
+@Preview
+@Composable
+private fun RuntimeToastPreview() {
+ AppTheme(false) {
+ Box(modifier = Modifier.fillMaxSize().padding(8.dp)) {
+ RuntimeToast()
+ }
+ }
+}
\ No newline at end of file
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/TopBar.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/TopBar.kt
index 3410698..a90e710 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/TopBar.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/TopBar.kt
@@ -51,7 +51,7 @@ internal fun TopBar(
) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
Image(
- painter = painterResource("imgs/favicon.ico"),
+ painter = painterResource("imgs/logo.svg"),
contentDescription = "logo",
modifier = Modifier.size(25.dp),
)
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/UpdateToast.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/UpdateToast.kt
index 4e254a0..afe011f 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/UpdateToast.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/components/UpdateToast.kt
@@ -166,14 +166,14 @@ private fun IconProgress(state: UpdateState) {
is UpdateState.Available -> Icon(
painter = painterResource("icons/cloud_download.svg"),
contentDescription = null,
- tint = LocalColorScheme.current.border.inverse,
+ tint = LocalColorScheme.current.icon.inverse,
modifier = Modifier.fillMaxSize().background(LocalColorScheme.current.background.brandSubtle, RoundedCornerShape(100)).padding(10.dp),
)
is UpdateState.Downloaded -> Icon(
painter = painterResource("icons/download_done.svg"),
contentDescription = null,
- tint = LocalColorScheme.current.border.inverse,
+ tint = LocalColorScheme.current.icon.inverse,
modifier = Modifier.fillMaxSize().background(LocalColorScheme.current.background.brandSubtle, RoundedCornerShape(100)).padding(10.dp),
)
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/Settings.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/Settings.kt
index 2da003f..a57f57b 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/Settings.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/Settings.kt
@@ -41,6 +41,7 @@ import app.cleanmeter.core.common.hardwaremonitor.networkReadings
import app.cleanmeter.core.designsystem.LocalColorScheme
import app.cleanmeter.core.designsystem.LocalTypography
import app.cleanmeter.target.desktop.ui.AppTheme
+import app.cleanmeter.target.desktop.ui.components.RuntimeToast
import app.cleanmeter.target.desktop.ui.components.SettingsTab
import app.cleanmeter.target.desktop.ui.components.TopBar
import app.cleanmeter.target.desktop.ui.components.UpdateToast
@@ -101,9 +102,12 @@ fun WindowScope.Settings(
)
}
- if (updaterState !is UpdateState.NotAvailable) {
+ if (updaterState !is UpdateState.NotAvailable && settingsState.isRuntimeAvailable) {
UpdateToast()
}
+ if (!settingsState.isRuntimeAvailable) {
+ RuntimeToast()
+ }
}
}
}
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsViewModel.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsViewModel.kt
index e9f302b..752481f 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsViewModel.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsViewModel.kt
@@ -3,7 +3,7 @@ package app.cleanmeter.target.desktop.ui.settings
import androidx.compose.ui.unit.IntOffset
import androidx.lifecycle.ViewModel
import app.cleanmeter.core.common.hardwaremonitor.HardwareMonitorData
-import app.cleanmeter.core.common.reporting.ApplicationParams
+import app.cleanmeter.core.os.hardwaremonitor.HardwareMonitorProcessManager
import app.cleanmeter.core.os.hardwaremonitor.HardwareMonitorReader
import app.cleanmeter.core.os.hardwaremonitor.Packet
import app.cleanmeter.core.os.hardwaremonitor.SocketClient
@@ -11,8 +11,8 @@ import app.cleanmeter.core.os.win32.WindowsService
import app.cleanmeter.target.desktop.KeyboardEvent
import app.cleanmeter.target.desktop.KeyboardManager
import app.cleanmeter.target.desktop.data.OverlaySettingsRepository
-import app.cleanmeter.target.desktop.data.PREFERENCE_PERMISSION_CONSENT
-import app.cleanmeter.target.desktop.data.PreferencesRepository
+import app.cleanmeter.core.os.PREFERENCE_PERMISSION_CONSENT
+import app.cleanmeter.core.os.PreferencesRepository
import app.cleanmeter.target.desktop.model.OverlaySettings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -31,6 +31,7 @@ data class SettingsState(
val hardwareData: HardwareMonitorData? = null,
val isRecording: Boolean = false,
val adminConsent: Boolean = false,
+ val isRuntimeAvailable: Boolean = false,
)
sealed class SettingsEvent {
@@ -65,6 +66,7 @@ class SettingsViewModel : ViewModel() {
observeRecordingHotkey()
observeRecordingState()
sendInitialPollingRate()
+ checkForNetCoreRuntime()
_state.update {
it.copy(
@@ -73,6 +75,13 @@ class SettingsViewModel : ViewModel() {
}
}
+ private fun checkForNetCoreRuntime() {
+ CoroutineScope(Dispatchers.IO).launch {
+ val isRuntimeAvailable = HardwareMonitorProcessManager.checkRuntime()
+ _state.update { it.copy(isRuntimeAvailable = isRuntimeAvailable) }
+ }
+ }
+
private fun observeOverlaySettings() {
CoroutineScope(Dispatchers.IO).launch {
OverlaySettingsRepository
@@ -174,7 +183,7 @@ class SettingsViewModel : ViewModel() {
private fun onConsentGiven() {
PreferencesRepository.setPreferenceBoolean(PREFERENCE_PERMISSION_CONSENT, true)
_state.update { it.copy(adminConsent = true) }
- WindowsService.tryElevateProcess(ApplicationParams.isAutostart)
+ WindowsService.elevateProcess()
}
private fun onBoundarySet(
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsWindow.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsWindow.kt
index 4380197..4e78241 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsWindow.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/SettingsWindow.kt
@@ -15,14 +15,12 @@ import androidx.compose.ui.window.ApplicationScope
import androidx.compose.ui.window.Tray
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.rememberWindowState
-import app.cleanmeter.target.desktop.data.PREFERENCE_START_MINIMIZED
-import app.cleanmeter.target.desktop.data.PreferencesRepository
+import app.cleanmeter.core.os.PREFERENCE_START_MINIMIZED
+import app.cleanmeter.core.os.PreferencesRepository
import com.github.kwhat.jnativehook.GlobalScreen
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import java.awt.GraphicsEnvironment
-import java.awt.event.ComponentAdapter
-import java.awt.event.ComponentEvent
import kotlin.math.min
@Composable
@@ -34,11 +32,7 @@ fun ApplicationScope.SettingsWindow(
val maximumWindowBounds = remember { GraphicsEnvironment.getLocalGraphicsEnvironment().maximumWindowBounds.height }
val minimumHeight = remember { min(800, maximumWindowBounds) }
var isVisible by remember {
- mutableStateOf(
- PreferencesRepository.getPreferenceBooleanNullable(
- PREFERENCE_START_MINIMIZED
- )?.not() ?: true
- )
+ mutableStateOf(!PreferencesRepository.getPreferenceBoolean(PREFERENCE_START_MINIMIZED, false))
}
val icon = painterResource("imgs/logo.png")
val state = rememberWindowState().apply {
diff --git a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/tabs/AppSettingsUi.kt b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/tabs/AppSettingsUi.kt
index a970bfe..32688fd 100644
--- a/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/tabs/AppSettingsUi.kt
+++ b/target/desktop/src/main/kotlin/app/cleanmeter/target/desktop/ui/settings/tabs/AppSettingsUi.kt
@@ -26,8 +26,8 @@ import androidx.compose.ui.unit.dp
import app.cleanmeter.core.designsystem.LocalColorScheme
import app.cleanmeter.core.designsystem.LocalTypography
import app.cleanmeter.core.os.win32.WinRegistry
-import app.cleanmeter.target.desktop.data.PREFERENCE_START_MINIMIZED
-import app.cleanmeter.target.desktop.data.PreferencesRepository
+import app.cleanmeter.core.os.PREFERENCE_START_MINIMIZED
+import app.cleanmeter.core.os.PreferencesRepository
import app.cleanmeter.target.desktop.model.OverlaySettings
import app.cleanmeter.target.desktop.ui.components.CheckboxWithLabel
import app.cleanmeter.target.desktop.ui.components.StyleCard
diff --git a/target/desktop/src/main/resources/imgs/favicon.ico b/target/desktop/src/main/resources/imgs/favicon.ico
index 71275e6..9d74369 100644
Binary files a/target/desktop/src/main/resources/imgs/favicon.ico and b/target/desktop/src/main/resources/imgs/favicon.ico differ
diff --git a/target/desktop/src/main/resources/imgs/logo.png b/target/desktop/src/main/resources/imgs/logo.png
index c4a114c..35c6e4b 100644
Binary files a/target/desktop/src/main/resources/imgs/logo.png and b/target/desktop/src/main/resources/imgs/logo.png differ
diff --git a/target/desktop/src/main/resources/imgs/logo.svg b/target/desktop/src/main/resources/imgs/logo.svg
new file mode 100644
index 0000000..752c9e3
--- /dev/null
+++ b/target/desktop/src/main/resources/imgs/logo.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+