Skip to content

Commit

Permalink
Merge pull request #111 from getditto/rr/tool-entry-point
Browse files Browse the repository at this point in the history
Tools Entry Point
  • Loading branch information
rajramsaroop authored Aug 21, 2024
2 parents d6b9373 + 5f9d438 commit ef5ff72
Show file tree
Hide file tree
Showing 22 changed files with 597 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@ import live.ditto.dittodiskusage.TOTAL_SIZE
import live.ditto.dittodiskusage.FIVE_HUNDRED_MEGABYTES_IN_BYTES
import live.ditto.healthmetrics.HealthMetric

class GetDiskUsageMetrics() {
class GetDiskUsageMetrics {
val metricName: String = METRIC_NAME
var unhealthySizeInBytes: Int = FIVE_HUNDRED_MEGABYTES_IN_BYTES

fun execute(currentState: DiskUsageState): HealthMetric {

val dittoStoreSize: Int = currentState.children.first { shortRelativePath(it.relativePath) == DITTO_STORE}.sizeInBytes
val dittoReplicationSize: Int = currentState.children.first { shortRelativePath(it.relativePath) == DITTO_REPLICATION}.sizeInBytes
val dittoStoreSize: Int =
currentState.children.first { shortRelativePath(it.relativePath) == DITTO_STORE }.sizeInBytes
val dittoReplicationSize: Int = currentState.children.firstOrNull {
shortRelativePath(it.relativePath) == DITTO_REPLICATION }?.sizeInBytes ?: 0

val isHealthy = healthCheckSize(dittoStoreSize, dittoReplicationSize)

val details = mutableMapOf<String, String>().apply {
for(child in currentState.children) {
for (child in currentState.children) {
this[shortRelativePath(child.relativePath)] = child.size
}
this[ROOT_PATH] = currentState.rootPath
Expand Down
1 change: 1 addition & 0 deletions DittoToolsViewer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
50 changes: 50 additions & 0 deletions DittoToolsViewer/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// libs. will show an IDE error. This is a bug with Android Studio/IntelliJ. This issue is
// is tracked here: https://youtrack.jetbrains.com/issue/KTIJ-19369
// Workaround is to suppress the error until the issue linked above is fixed
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.com.android.library)
alias(libs.plugins.org.jetbrains.kotlin.android)
}

extra["libraryGroupId"] = "live.ditto"
extra["libraryArtifactId"] = "dittotoolsviewer"
extra["libraryVersion"] = "1.0.0"

apply {
from("${rootProject.projectDir}/gradle/deploy.gradle")
from("${rootProject.projectDir}/gradle/android-common.gradle")
}

android {
namespace = "live.ditto.dittotoolsviewer"
}

dependencies {

implementation(libs.core.ktx)
implementation(libs.androidx.appcompat.appcompat)
implementation(libs.material)

implementation(platform(libs.androidx.compose.composeBom))
implementation(libs.androidx.compose.ui.ui)
implementation(libs.androidx.compose.ui.uiToolingPreview)
implementation(libs.androidx.navigation.navigationCompose)
implementation(libs.androidx.compose.material3.material3)

implementation(libs.live.ditto.ditto)
implementation(libs.live.ditto.databrowser)
implementation(libs.live.ditto.exportlogs)
implementation(libs.live.ditto.presenceviewer)
implementation(libs.live.ditto.diskusage)
implementation(libs.live.ditto.health)
implementation(libs.live.ditto.heartbeat)
implementation(libs.live.ditto.presencedegradationreporter)
implementation(libs.live.ditto.healthmetrics)
implementation(libs.live.ditto.exporter)

testImplementation(libs.junit.junit)

androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
}
Empty file.
21 changes: 21 additions & 0 deletions DittoToolsViewer/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions DittoToolsViewer/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package live.ditto.dittotoolsviewer.presentation

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Build
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import ditto.live.dittopresenceviewer.DittoPresenceViewer
import live.ditto.Ditto
import live.ditto.dittodatabrowser.DittoDataBrowser
import live.ditto.dittodiskusage.DittoDiskUsage
import live.ditto.dittoexportlogs.ExportLogs
import live.ditto.dittotoolsviewer.R
import live.ditto.dittotoolsviewer.presentation.navigation.Screens
import live.ditto.dittotoolsviewer.presentation.viewmodel.ToolsViewerViewModel
import live.ditto.health.HealthScreen
import live.ditto.presencedegradationreporter.PresenceDegradationReporterScreen

/**
* A Composable that you can include in your app that will give a single entry point for all Ditto
* Tools.
*
* @param modifier an optional modifier if you need to adjust the layout to fit the view
* @param ditto your instance of [Ditto] that is required
* @param onExitTools an optional lambda function that will be called whenever a user taps the
* "Exit Tools" button. Use this to do any back navigation or dismissal/hiding of the Tools Viewer
*/
@Composable
fun DittoToolsViewer(
modifier: Modifier = Modifier,
ditto: Ditto,
onExitTools: () -> Unit = { }
) {
DittoToolsViewerScaffold(
modifier = modifier,
ditto = ditto,
onExitTools = onExitTools
)
}

@Composable
private fun DittoToolsViewerScaffold(
modifier: Modifier,
ditto: Ditto,
onExitTools: () -> Unit,
viewModel: ToolsViewerViewModel = ToolsViewerViewModel()
) {

val navController = rememberNavController()

Scaffold(
modifier = modifier,
bottomBar = {
BottomAppBar(
actions = {
Button(onClick = { onExitTools() }) {
Text(text = "Exit Tools")
}
},
floatingActionButton = {
MenuFloatingActionButton {
if (navController.currentDestination?.route != Screens.MainScreen.route) {
navController.popBackStack()
}
}
}
)
}
) { contentPadding ->
ToolsViewerContent(
navController = navController,
viewModel = viewModel,
contentPadding = contentPadding,
ditto = ditto
)
}
}

@Composable
private fun ToolsViewerContent(
navController: NavHostController,
viewModel: ToolsViewerViewModel,
contentPadding: PaddingValues,
ditto: Ditto,
) {
ToolsViewerNavHost(
navController = navController,
contentPadding = contentPadding,
ditto = ditto,
toolMenuItems = viewModel.toolsMenuItems()
)
}

@Composable
private fun ToolsViewerNavHost(
navController: NavHostController,
contentPadding: PaddingValues,
ditto: Ditto,
toolMenuItems: List<ToolMenuItem>
) {
NavHost(
modifier = Modifier.padding(contentPadding),
navController = navController,
startDestination = Screens.MainScreen.route,
) {
composable(Screens.MainScreen.route) {
ToolsMenu(
navController = navController,
menuItems = toolMenuItems,
)
}
composable(Screens.PresenceViewerScreen.route) {
DittoPresenceViewer(ditto = ditto)
}
composable(Screens.DataBrowserScreen.route) {
DittoDataBrowser(ditto = ditto)
}
composable(Screens.ExportLogsScreen.route) {
ExportLogs(
onDismiss = {
navController.popBackStack()
}
)
}
composable(Screens.DiskUsageScreen.route) {
DittoDiskUsage(ditto = ditto)
}
composable(Screens.HealthScreen.route) {
HealthScreen()
}
composable(Screens.HeartbeatScreen.route) {
HeartbeatScreen(ditto = ditto)
}
composable(Screens.PresenceDegradationReporterScreen.route) {
PresenceDegradationReporterScreen(ditto = ditto)
}
}
}

@Composable
private fun MenuFloatingActionButton(onClick: () -> Unit) {
ExtendedFloatingActionButton(
onClick = { onClick() },
icon = { Icon(Icons.Filled.Build, stringResource(R.string.tools_menu_content_description)) },
text = { Text(text = stringResource(R.string.tools_menu)) }
)
}

@Preview
@Composable
private fun MenuFloatingActionButtonPreview() {
MenuFloatingActionButton(
onClick = { }
)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package live.ditto.dittotoolsapp
package live.ditto.dittotoolsviewer.presentation

import android.os.Build
import androidx.annotation.RequiresApi
Expand All @@ -9,6 +9,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -19,12 +20,13 @@ import live.ditto.healthmetrics.HealthMetricProvider
import live.ditto.dittoheartbeat.DittoHeartbeatConfig
import live.ditto.dittoheartbeat.DittoHeartbeatInfo
import live.ditto.dittoheartbeat.startHeartbeat
import live.ditto.dittotoolsviewer.R
import java.util.*


@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun ShowHeartbeatData(ditto: Ditto) {
fun HeartbeatScreen(ditto: Ditto) {

var heartbeatInfo by remember { mutableStateOf<DittoHeartbeatInfo?>(null) }
val healthMetricProviders: MutableList<HealthMetricProvider> = mutableListOf()
Expand Down Expand Up @@ -85,7 +87,8 @@ fun HeartbeatInfoCard(heartbeatInfo: DittoHeartbeatInfo) {
val connection = entry.value
if (connection is Map<*, *>) { // Check if connection is a Map
@Suppress("UNCHECKED_CAST")
val typedConnection = connection as Map<String, Any> // Type cast connection to Map<String, Any>
val typedConnection =
connection as Map<String, Any> // Type cast connection to Map<String, Any>
ConnectionInfo(connection = typedConnection)
}
}
Expand All @@ -97,23 +100,34 @@ fun HeartbeatInfoCard(heartbeatInfo: DittoHeartbeatInfo) {
@Composable
fun HeartbeatHeader(heartbeatInfo: DittoHeartbeatInfo) {
Column {
Text("ID: ${heartbeatInfo.id}")
Text("SDK: ${heartbeatInfo.sdk}")
Text("Last Updated: ${heartbeatInfo.lastUpdated}")
Text("remotePeersCount: ${heartbeatInfo.presenceSnapshotDirectlyConnectedPeersCount}", color = Color.Black)
Text("Peer key: ${heartbeatInfo.peerKey}")
Text(stringResource(R.string.heartbeat_id_label, heartbeatInfo.id))
Text(stringResource(R.string.heartbeat_sdk_label, heartbeatInfo.sdk))
Text(stringResource(R.string.heartbeat_last_updated_label, heartbeatInfo.lastUpdated))
Text(
text = stringResource(
R.string.heartbeat_remotepeerscount_label,
heartbeatInfo.presenceSnapshotDirectlyConnectedPeersCount
),
color = Color.Black
)
Text(stringResource(R.string.heartbeat_peer_key_label, heartbeatInfo.peerKey))
}
}

@Composable
fun ConnectionInfo(connection: Map<String, Any>) {
Column {
Text("\nConnection: ${connection["deviceName"]}")
Text("SDK: ${connection["sdk"]}")
Text(text = if (connection["isConnectedToDittoCloud"] as Boolean) "Online" else "Offline")
Text("BT: ${connection["bluetooth"]}")
Text("P2PWifi: ${connection["p2pWifi"]}")
Text("LAN: ${connection["lan"]}")
Text(stringResource(R.string.connection_info_connection, connection["deviceName"] ?: ""))
Text(stringResource(R.string.connection_info_sdk, connection["sdk"] ?: ""))
val isConnectedToDittoCloudString = if (connection["isConnectedToDittoCloud"] as Boolean) {
stringResource(R.string.connection_info_online)
} else stringResource(
R.string.connection_info_offline
)
Text(isConnectedToDittoCloudString)
Text(stringResource(R.string.connection_info_bt, connection["bluetooth"] ?: ""))
Text(stringResource(R.string.connection_info_p2pwifi, connection["p2pWifi"] ?: ""))
Text(stringResource(R.string.connection_info_lan, connection["lan"] ?: ""))
}
}

Expand Down
Loading

0 comments on commit ef5ff72

Please sign in to comment.