Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new fct-ide installment #297

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
21 changes: 21 additions & 0 deletions efsity-ide/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
*.iml
.kotlin
.gradle
**/build/
xcuserdata
!src/**/build/
local.properties
.idea
.DS_Store
captures
.externalNativeBuild
.cxx
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
*.db
/composeApp/root/
/composeApp/private/
45 changes: 45 additions & 0 deletions efsity-ide/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## FCT (FHIRCore Tooling Application)
This document provides a step-by-step guide to set up and run the KMP Kotlin Multi-Platform desktop application.

### Prerequisites
Before you begin, ensure you have the following installed:

- Kotlin
- IntelliJ IDEA or Android Studio
- Android Debug Bridge (ADB)

### Setup Instructions
#### Verify ADB Configuration
1. Open your terminal or command prompt.
2. Type the following command to check if ADB is installed and properly configured:


```sh
adb --version
```
3. You should see the version information. If you encounter an error, ensure that ADB is included in your system's PATH variable.

### Connect Your Device
1. Connect your Android device to your computer via USB.
2. Ensure that USB debugging is enabled on your device. You can enable it by navigating to **Settings > Developer options > USB debugging.**
3. Verify that your device is properly connected and visible:

```sh
adb devices
```

4. You should see your device listed in the output. If it’s not listed, check your USB connection and permissions.

### Run the Application

1. To run the application, use the following command in your terminal:

```sh
./gradlew :composeApp:run
```
2. Alternatively, you can set up this command in your IDE's configurations for easier access.

### Select a Package from the Package Manager
1. Launch the application.
2. Open the **Package Manager** window within the application.
3. From the list of available packages, select the desired package you want to work with.
1 change: 1 addition & 0 deletions efsity-ide/adb/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
13 changes: 13 additions & 0 deletions efsity-ide/adb/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

plugins {
alias(libs.plugins.jetbrainsKotlinJvm)
alias(libs.plugins.jsonSerialization)
}

dependencies {
implementation(Dependencies.json)
implementation(Dependencies.KotlinX.coroutine)
implementation(Dependencies.KotlinX.serializationJson)
implementation(project(":common"))
implementation(project(":shell"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.smartregister.fct.adb

import org.koin.core.context.GlobalContext
import org.koin.dsl.module
import org.smartregister.fct.adb.data.commands.GetAllDevicesCommand
import org.smartregister.fct.adb.data.commands.GetBatteryAndOtherInfoCommand
import org.smartregister.fct.adb.data.commands.GetDeviceInfoCommand
import org.smartregister.fct.adb.data.controller.ADBController
import org.smartregister.fct.shell.program.KScriptShellProgram
import org.smartregister.fct.shell.program.ShellProgram
import org.smartregister.fct.engine.setup.ModuleSetup
import org.smartregister.fct.logger.FCTLogger
import org.smartregister.fct.logger.model.Log
import org.smartregister.fct.logger.model.LogFilter

class ADBModuleSetup : ModuleSetup {

private val adbModule = module(createdAtStart = true) {
single<ShellProgram> { KScriptShellProgram() }
single<ADBController> { ADBController(get()) }
}

override suspend fun setup() {
FCTLogger.d("Loading... ADB Module")
GlobalContext.get().loadModules(listOf(adbModule))
FCTLogger.addFilter(this, ADBCommandFilter())
FCTLogger.d("ADB Module Loaded")
}

private class ADBCommandFilter : LogFilter {

override fun isLoggable(log: Log): Boolean {
return log.tag.let {
it != GetAllDevicesCommand::class.java.simpleName &&
it != GetDeviceInfoCommand::class.java.simpleName &&
it != GetBatteryAndOtherInfoCommand::class.java.simpleName
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.smartregister.fct.adb.data.commands

internal class AppDatabaseQueryCommand(packageId: String, arg: String) : ContentCommand(packageId, arg) {

override fun getMethodName(): String {
return "db_operation"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.smartregister.fct.adb.data.commands

import org.json.JSONObject
import org.smartregister.fct.adb.domain.model.CommandResult
import org.smartregister.fct.adb.domain.program.ADBCommand
import org.smartregister.fct.engine.util.compress
import org.smartregister.fct.engine.util.decompress
import org.smartregister.fct.engine.util.replaceLast
import org.smartregister.fct.logger.FCTLogger

internal abstract class ContentCommand(
private val packageId: String,
private val arg: String
) : ADBCommand<JSONObject> {

override fun process(response: String, dependentResult: List<CommandResult<*>>): Result<JSONObject> {
return try {
val sanitizeResponse = response.replace("Result: Bundle[{data=", "").replaceLast("}]", "")
val jsonObject = JSONObject(sanitizeResponse.decompress())
return process(jsonObject)
} catch (ex: Exception) {
FCTLogger.e(ex)
Result.failure(ex)
}
}

open fun process(jsonObject: JSONObject) : Result<JSONObject> {
return if (jsonObject.getBoolean("success")) {
Result.success(jsonObject)
} else {
Result.failure(RuntimeException(jsonObject.getString("error")))
}
}

override fun build(): List<String> {
return listOf("content call --uri 'content://${packageId}.fct' --method '${getMethodName()}' --arg '${getCompressedArgument()}'")
}

private fun getCompressedArgument(): String {
FCTLogger.d("Content Request: $arg")
if (arg.trim().isEmpty()) return arg
return arg.compress()
}

abstract fun getMethodName(): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.smartregister.fct.adb.data.commands

import org.json.JSONObject

internal class ExecuteRulesCommand(packageId: String, arg: String) : ContentCommand(packageId, arg) {

override fun getMethodName(): String {
return "execute_rules"
}

override fun process(jsonObject: JSONObject): Result<JSONObject> {
return Result.success(jsonObject)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.smartregister.fct.adb.data.commands

import org.json.JSONObject

internal class ExecuteWorkflowCommand(packageId: String, arg: String) : ContentCommand(packageId, arg) {

override fun getMethodName(): String {
return "execute_workflow"
}

override fun process(jsonObject: JSONObject): Result<JSONObject> {
return Result.success(jsonObject)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.smartregister.fct.adb.data.commands

import org.smartregister.fct.adb.domain.model.CommandResult
import org.smartregister.fct.adb.domain.model.Device
import org.smartregister.fct.adb.domain.program.ADBCommand
import org.smartregister.fct.adb.utils.CommandConstants
import org.smartregister.fct.adb.utils.resultAsCommandException

internal class GetAllDevicesCommand : ADBCommand<List<Device>> {

override fun process(response: String, dependentResult: List<CommandResult<*>>): Result<List<Device>> {
return response
.takeIf { it.contains("\t") }
?.split("\n")
?.filter { it.contains("\t") }
?.filterNot { it.contains("offline") }
?.map {
Device(
deviceId = it.split("\t")[0]
)
}
?.toList()
?.let { Result.success(it) }
?: response.resultAsCommandException()
}

override fun build(): List<String> {
return listOf(CommandConstants.DEVICES)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.smartregister.fct.adb.data.commands

import org.smartregister.fct.adb.domain.model.CommandResult
import org.smartregister.fct.adb.domain.program.ADBCommand
import org.smartregister.fct.adb.utils.resultAsCommandException
import org.smartregister.fct.adb.utils.takeIfNotError
import org.smartregister.fct.engine.domain.model.PackageInfo

internal class GetAllPackagesCommand(private val packageFilterList: List<String>) :
ADBCommand<List<PackageInfo>> {

override fun process(
response: String,
dependentResult: List<CommandResult<*>>
): Result<List<PackageInfo>> {
return response
.takeIfNotError()
?.split("\n")
?.map { PackageInfo(packageId = it.replace("package:", "")) }
?.let { Result.success(it) }
?: response.resultAsCommandException()

}

override fun build(): List<String> {

return listOf(
(listOf(
"pm",
"list",
"packages",
) + packageFilterList).joinToString(" ")
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.smartregister.fct.adb.data.commands

import org.smartregister.fct.adb.domain.model.CommandResult
import org.smartregister.fct.adb.domain.program.ADBCommand
import org.smartregister.fct.adb.utils.CommandConstants
import org.smartregister.fct.adb.utils.resultAsCommandException
import org.smartregister.fct.adb.utils.takeIfNotError
import org.smartregister.fct.engine.util.Platform
import org.smartregister.fct.engine.util.PlatformType

internal class GetBatteryAndOtherInfoCommand : ADBCommand<Map<String, String>> {

override fun process(
response: String,
dependentResult: List<CommandResult<*>>
): Result<Map<String, String>> {
return response
.takeIfNotError()
?.split("\n")
?.filter { it.contains(":") || it.contains("=") }
?.associate {
val row = it
.takeIf { it.contains(":") }
?.replace(": ", ":")
?.split(":") ?: it.split("=")
row[0].trim() to row[1].trim()
}?.let {
Result.success(it)
} ?: response.resultAsCommandException()
}

override fun build(): List<String> {
val platform = Platform.getPlatform()

val searchCommand = if (platform == PlatformType.Windows) {
"findstr"
} else {
"grep"
}

return listOf(
"dumpsys battery",
"dumpsys display | $searchCommand \"${CommandConstants.DEVICE_RESOLUTION}\""
)
}
}
Loading