Feat no op (#81)

* feat: [ANDROID] no op lib

* feat: [ANDROID] no op lib

* renamed modules

* renamed modules

* renamed modules

* renamed modules

* updated publish yml

---------

Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
Florent CHAMPIGNY 2025-08-10 14:05:18 +02:00 committed by GitHub
parent 92fc478b12
commit ed07d7e674
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
106 changed files with 558 additions and 218 deletions

View file

@ -17,7 +17,7 @@ jobs:
distribution: 'zulu'
java-version: 21
- name: Publish to MavenCentral
run: ./gradlew :core:publishToMavenCentral :okhttp-interceptor:publishToMavenCentral :grpc-interceptor:publishToMavenCentral --no-configuration-cache
run: ./gradlew :flocon-base:publishToMavenCentral :flocon:publishToMavenCentral :flocon-no-op:publishToMavenCentral :okhttp-interceptor:publishToMavenCentral :grpc-interceptor:publishToMavenCentral --no-configuration-cache
working-directory: FloconAndroid
env:
PROJECT_VERSION_NAME: ${{ github.ref_name }}

View file

@ -11,7 +11,9 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/core" />
<option value="$PROJECT_DIR$/flocon" />
<option value="$PROJECT_DIR$/flocon-base" />
<option value="$PROJECT_DIR$/flocon-no-op" />
<option value="$PROJECT_DIR$/grpc-interceptor" />
<option value="$PROJECT_DIR$/okhttp-interceptor" />
</set>

View file

@ -46,12 +46,14 @@ android {
val useMaven = false
dependencies {
if(useMaven) {
val floconVersion = "1.0.3"
val floconVersion = "1.0.5"
implementation("io.github.openflocon:flocon:$floconVersion")
//implementation("io.github.openflocon:flocon-no-op:$floconVersion")
implementation("io.github.openflocon:flocon-grpc-interceptor:$floconVersion")
implementation("io.github.openflocon:flocon-okhttp-interceptor:$floconVersion")
} else {
implementation(project(":core"))
//implementation(project(":flocon"))
implementation(project(":flocon-no-op"))
implementation(project(":okhttp-interceptor"))
implementation(project(":grpc-interceptor"))
}

View file

@ -31,8 +31,6 @@ import io.github.openflocon.flocon.okhttp.FloconOkhttpInterceptor
import io.github.openflocon.flocon.plugins.analytics.analytics
import io.github.openflocon.flocon.plugins.analytics.model.AnalyticsEvent
import io.github.openflocon.flocon.plugins.analytics.model.analyticsProperty
import io.github.openflocon.flocon.plugins.deeplinks.deeplinks
import io.github.openflocon.flocon.plugins.deeplinks.model.Deeplink
import io.github.openflocon.flocon.plugins.tables.model.toParam
import io.github.openflocon.flocon.plugins.tables.table
import kotlinx.coroutines.GlobalScope

View file

@ -1,30 +0,0 @@
package io.github.openflocon.flocon.model
import io.github.openflocon.flocon.FloconLogger
import org.json.JSONObject
data class FloconMessageFromServer(
val plugin: String,
val method: String,
val body: String,
) {
companion object {
fun fromJson(
message: String,
): FloconMessageFromServer? {
return try {
val jsonObject = JSONObject(message)
FloconMessageFromServer(
plugin = jsonObject.getString("plugin"),
method = jsonObject.getString("method"),
body = jsonObject.getString("body"),
)
} catch (t: Throwable) {
FloconLogger.logError("parsing issue", t)
null
}
}
}
}

View file

@ -0,0 +1,82 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
id("com.vanniktech.maven.publish") version "0.34.0"
}
android {
namespace = "io.github.openflocon.flocon.base"
compileSdk = 36
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(platform(libs.kotlinx.coroutines.bom))
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.android)
}
mavenPublishing {
publishToMavenCentral(automaticRelease = true)
if (project.hasProperty("signing.required") && project.property("signing.required") == "false") {
// Skip signing
} else {
signAllPublications()
}
coordinates(
groupId = project.property("floconGroupId") as String,
artifactId = "flocon-base",
version = System.getenv("PROJECT_VERSION_NAME") ?: project.property("floconVersion") as String
)
pom {
name = "Flocon"
description = project.property("floconDescription") as String
inceptionYear = "2025"
url = "https://github.com/openflocon/Flocon"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
distribution = "https://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "openflocon"
name = "Open Flocon"
url = "https://github.com/openflocon"
}
}
scm {
url = "https://github.com/openflocon/Flocon"
connection = "scm:git:git://github.com/openflocon/Flocon.git"
developerConnection = "scm:git:ssh://git@github.com/openflocon/Flocon.git"
}
}
}

View file

@ -0,0 +1,41 @@
package io.github.openflocon.flocon
import android.content.Context
import io.github.openflocon.flocon.core.FloconMessageSender
import io.github.openflocon.flocon.plugins.analytics.FloconAnalyticsPlugin
import io.github.openflocon.flocon.plugins.dashboard.FloconDashboardPlugin
import io.github.openflocon.flocon.plugins.deeplinks.FloconDeeplinksPlugin
import io.github.openflocon.flocon.plugins.network.FloconNetworkPlugin
import io.github.openflocon.flocon.plugins.tables.FloconTablePlugin
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
abstract class FloconApp {
companion object {
var instance: FloconApp? = null
private set
}
interface Client : FloconMessageSender {
@Throws(Throwable::class)
suspend fun connect(onClosed: () -> Unit)
fun disconnect()
val dashboardPlugin: FloconDashboardPlugin
val tablePlugin: FloconTablePlugin
val deeplinksPlugin: FloconDeeplinksPlugin
val analyticsPlugin: FloconAnalyticsPlugin
val networkPlugin: FloconNetworkPlugin
}
open val client: FloconApp.Client? = null
abstract val isInitialized : StateFlow<Boolean>
open fun initialize(context: Context) {
instance = this
}
}

View file

@ -0,0 +1,7 @@
package io.github.openflocon.flocon.model
data class FloconMessageFromServer(
val plugin: String,
val method: String,
val body: String,
)

View file

@ -0,0 +1,17 @@
package io.github.openflocon.flocon.plugins.analytics
import io.github.openflocon.flocon.FloconApp
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.plugins.analytics.builder.AnalyticsBuilder
import io.github.openflocon.flocon.plugins.analytics.model.AnalyticsItem
fun FloconApp.analytics(analyticsName: String): AnalyticsBuilder {
return AnalyticsBuilder(
analyticsTableId = analyticsName,
analyticsPlugin = this.client?.analyticsPlugin,
)
}
interface FloconAnalyticsPlugin : FloconPlugin {
fun registerAnalytics(analyticsItems: List<AnalyticsItem>)
}

View file

@ -0,0 +1,9 @@
package io.github.openflocon.flocon.plugins.analytics.model
data class AnalyticsItem(
val id: String,
val analyticsTableId: String,
val eventName: String,
val createdAt: Long,
val properties: List<AnalyticsPropertiesConfig>,
)

View file

@ -0,0 +1,20 @@
package io.github.openflocon.flocon.plugins.dashboard
import io.github.openflocon.flocon.FloconApp
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.plugins.dashboard.dsl.DashboardBuilder
import io.github.openflocon.flocon.plugins.dashboard.dsl.dashboardConfig
import io.github.openflocon.flocon.plugins.dashboard.model.DashboardConfig
fun FloconApp.dashboard(id: String, block: DashboardBuilder.() -> Unit) {
this.client?.dashboardPlugin?.let {
// on no op, this callback is never called
val dashboardConfig = dashboardConfig(id = id, block)
it.registerDashboard(dashboardConfig)
}
}
interface FloconDashboardPlugin : FloconPlugin {
fun registerDashboard(dashboardConfig: DashboardConfig)
}

View file

@ -0,0 +1,6 @@
package io.github.openflocon.flocon.plugins.database
import io.github.openflocon.flocon.core.FloconPlugin
interface FloconDatabasePlugin : FloconPlugin

View file

@ -0,0 +1,13 @@
package io.github.openflocon.flocon.plugins.deeplinks
import io.github.openflocon.flocon.FloconApp
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.plugins.deeplinks.model.Deeplink
fun FloconApp.deeplinks(deeplinks: List<Deeplink>) {
this.client?.deeplinksPlugin?.registerDeeplinks(deeplinks)
}
interface FloconDeeplinksPlugin : FloconPlugin {
fun registerDeeplinks(deeplinks: List<Deeplink>)
}

View file

@ -0,0 +1,5 @@
package io.github.openflocon.flocon.plugins.files
import io.github.openflocon.flocon.core.FloconPlugin
interface FloconFilesPlugin : FloconPlugin

View file

@ -0,0 +1,8 @@
package io.github.openflocon.flocon.plugins.network
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.plugins.network.model.FloconNetworkRequest
interface FloconNetworkPlugin : FloconPlugin {
fun log(call: FloconNetworkRequest)
}

View file

@ -0,0 +1,26 @@
package io.github.openflocon.flocon.plugins.network.model
data class FloconNetworkRequest(
val request: Request,
val response: Response,
val durationMs: Double,
val floconNetworkType: String,
) {
data class Request(
val url: String,
val method: String,
val startTime: Long,
val headers: Map<String, String>,
val body: String?,
val size: Long?,
)
data class Response(
val httpCode: Int?,
val grpcStatus: String?,
val contentType: String?,
val body: String?,
val size: Long?,
val headers: Map<String, String>,
)
}

View file

@ -0,0 +1,5 @@
package io.github.openflocon.flocon.plugins.SharedPreferences
import io.github.openflocon.flocon.core.FloconPlugin
interface FloconSharedPreferencesPlugin : FloconPlugin

View file

@ -0,0 +1,17 @@
package io.github.openflocon.flocon.plugins.tables
import io.github.openflocon.flocon.FloconApp
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.plugins.tables.builder.TableBuilder
import io.github.openflocon.flocon.plugins.tables.model.TableItem
fun FloconApp.table(tableName: String): TableBuilder {
return TableBuilder(
tableName = tableName,
tablePlugin = this.client?.tablePlugin,
)
}
interface FloconTablePlugin : FloconPlugin {
fun registerTable(tableItem: TableItem)
}

View file

@ -0,0 +1,8 @@
package io.github.openflocon.flocon.plugins.tables.model
data class TableItem(
val id: String,
val name: String,
val createdAt: Long,
val columns: List<TableColumnConfig>,
)

1
FloconAndroid/flocon-no-op/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,84 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
id("com.vanniktech.maven.publish") version "0.34.0"
}
android {
namespace = "io.github.openflocon.flocon"
compileSdk = 36
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(platform(libs.kotlinx.coroutines.bom))
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.android)
api(project(":flocon-base"))
}
mavenPublishing {
publishToMavenCentral(automaticRelease = true)
if (project.hasProperty("signing.required") && project.property("signing.required") == "false") {
// Skip signing
} else {
signAllPublications()
}
coordinates(
groupId = project.property("floconGroupId") as String,
artifactId = "flocon-no-op",
version = System.getenv("PROJECT_VERSION_NAME") ?: project.property("floconVersion") as String
)
pom {
name = "Flocon"
description = project.property("floconDescription") as String
inceptionYear = "2025"
url = "https://github.com/openflocon/Flocon"
licenses {
license {
name = "The Apache License, Version 2.0"
url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
distribution = "https://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
developers {
developer {
id = "openflocon"
name = "Open Flocon"
url = "https://github.com/openflocon"
}
}
scm {
url = "https://github.com/openflocon/Flocon"
connection = "scm:git:git://github.com/openflocon/Flocon.git"
developerConnection = "scm:git:ssh://git@github.com/openflocon/Flocon.git"
}
}
}

View file

@ -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

View file

@ -0,0 +1,7 @@
package io.github.openflocon.flocon
import kotlinx.coroutines.flow.MutableStateFlow
object Flocon : FloconApp() {
override val isInitialized = MutableStateFlow(false)
}

1
FloconAndroid/flocon/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -40,6 +40,7 @@ dependencies {
implementation(platform(libs.okhttp.bom))
implementation(libs.okhttp)
api(project(":flocon-base"))
}
mavenPublishing {

View file

21
FloconAndroid/flocon/proguard-rules.pro vendored Normal file
View file

@ -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

View file

@ -11,35 +11,34 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
object Flocon {
object Flocon : FloconApp() {
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
interface Client : FloconMessageSender {
private var _client: FloconApp.Client? = null
@Throws(Throwable::class)
suspend fun connect(onClosed: () -> Unit)
fun disconnect()
override val client: FloconApp.Client?
get() {
return _client
}
val dashboardPlugin: FloconDashboardPlugin
val tablePlugin: FloconTablePlugin
val deeplinksPlugin: FloconDeeplinksPlugin
val analyticsPlugin: FloconAnalyticsPlugin
}
override val isInitialized = MutableStateFlow(false)
var client: Flocon.Client? = null
private set
fun initialize(context: Context) {
override fun initialize(context: Context) {
val app = context.applicationContext
val newClient = FloconClientImpl(app)
client = newClient
_client = newClient
isInitialized.value = true
scope.launch {
start(newClient)
}
super.initialize(context)
}
private suspend fun start(client: FloconClientImpl) {

View file

@ -3,10 +3,11 @@ package io.github.openflocon.flocon.client
import android.content.Context
import android.os.Build
import android.provider.Settings
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.FloconApp
import io.github.openflocon.flocon.Protocol
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.model.FloconMessageFromServer
import io.github.openflocon.flocon.model.floconMessageFromServerFromJson
import io.github.openflocon.flocon.model.toFloconMessageToServer
import io.github.openflocon.flocon.plugins.SharedPreferences.FloconSharedPreferencesPluginImpl
import io.github.openflocon.flocon.plugins.analytics.FloconAnalyticsPluginImpl
@ -14,6 +15,7 @@ import io.github.openflocon.flocon.plugins.dashboard.FloconDashboardPluginImpl
import io.github.openflocon.flocon.plugins.database.FloconDatabasePluginImpl
import io.github.openflocon.flocon.plugins.deeplinks.FloconDeeplinksPluginImpl
import io.github.openflocon.flocon.plugins.files.FloconFilesPluginImpl
import io.github.openflocon.flocon.plugins.network.FloconNetworkPluginImpl
import io.github.openflocon.flocon.plugins.tables.FloconTablePluginImpl
import io.github.openflocon.flocon.utils.AppUtils
import io.github.openflocon.flocon.utils.NetUtils
@ -26,7 +28,7 @@ import kotlinx.coroutines.launch
internal class FloconClientImpl(
appContext: Context,
) : Flocon.Client {
) : FloconApp.Client {
private val FLOCON_PORT = 9023
@ -47,6 +49,7 @@ internal class FloconClientImpl(
override val tablePlugin = FloconTablePluginImpl(sender = this)
override val deeplinksPlugin = FloconDeeplinksPluginImpl(sender = this)
override val analyticsPlugin = FloconAnalyticsPluginImpl(sender = this)
override val networkPlugin = FloconNetworkPluginImpl(sender = this)
private val allPlugins = listOf<FloconPlugin>(
databasePlugin,
@ -56,6 +59,7 @@ internal class FloconClientImpl(
tablePlugin,
deeplinksPlugin,
analyticsPlugin,
networkPlugin,
)
@Throws(Throwable::class)
@ -79,7 +83,7 @@ internal class FloconClientImpl(
private fun onMessageReceived(message: String) {
coroutineScope.launch(Dispatchers.IO) {
FloconMessageFromServer.fromJson(message)?.let { messageFromServer ->
floconMessageFromServerFromJson(message)?.let { messageFromServer ->
when (messageFromServer.plugin) {
Protocol.ToDevice.Database.Plugin -> {
databasePlugin.onMessageReceived(

View file

@ -0,0 +1,21 @@
package io.github.openflocon.flocon.model
import io.github.openflocon.flocon.FloconLogger
import org.json.JSONObject
fun floconMessageFromServerFromJson(
message: String,
): FloconMessageFromServer? {
return try {
val jsonObject = JSONObject(message)
FloconMessageFromServer(
plugin = jsonObject.getString("plugin"),
method = jsonObject.getString("method"),
body = jsonObject.getString("body"),
)
} catch (t: Throwable) {
FloconLogger.logError("parsing issue", t)
null
}
}

View file

@ -1,26 +1,13 @@
package io.github.openflocon.flocon.plugins.analytics
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.Protocol
import io.github.openflocon.flocon.core.FloconMessageSender
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.model.FloconMessageFromServer
import io.github.openflocon.flocon.plugins.analytics.builder.AnalyticsBuilder
import io.github.openflocon.flocon.plugins.analytics.model.AnalyticsItem
import io.github.openflocon.flocon.plugins.analytics.model.analyticsItemsToJson
import org.json.JSONArray
import java.util.concurrent.ConcurrentLinkedQueue
fun Flocon.analytics(analyticsName: String): AnalyticsBuilder {
return AnalyticsBuilder(
analyticsTableId = analyticsName,
analyticsPlugin = this.client?.analyticsPlugin,
)
}
interface FloconAnalyticsPlugin : FloconPlugin {
fun registerAnalytics(analyticsItems: List<AnalyticsItem>)
}
class FloconAnalyticsPluginImpl(
private val sender: FloconMessageSender,
) : FloconAnalyticsPlugin {
@ -31,17 +18,17 @@ class FloconAnalyticsPluginImpl(
messageFromServer: FloconMessageFromServer,
sender: FloconMessageSender,
) {
when(messageFromServer.method) {
Protocol.ToDevice.Analytics.Method.ClearItems-> {
when (messageFromServer.method) {
Protocol.ToDevice.Analytics.Method.ClearItems -> {
val items = readIds(messageFromServer.body)
if(items.isNotEmpty()) {
if (items.isNotEmpty()) {
clearItems(items.toSet())
}
}
}
}
private fun readIds(body: String) : List<String> {
private fun readIds(body: String): List<String> {
return try {
val array = JSONArray(body)
val items = mutableListOf<String>()
@ -69,7 +56,7 @@ class FloconAnalyticsPluginImpl(
sender.send(
plugin = Protocol.FromDevice.Analytics.Plugin,
method = Protocol.FromDevice.Analytics.Method.AddItems,
body = AnalyticsItem.listToJson(toSend).toString()
body = analyticsItemsToJson(toSend).toString()
)
}
}

View file

@ -3,24 +3,14 @@ package io.github.openflocon.flocon.plugins.analytics.model
import org.json.JSONArray
import org.json.JSONObject
data class AnalyticsItem(
val id: String,
val analyticsTableId: String,
val eventName: String,
val createdAt: Long,
val properties: List<AnalyticsPropertiesConfig>,
) {
companion object {
fun listToJson(items: Collection<AnalyticsItem>) : JSONArray {
val array = JSONArray()
fun analyticsItemsToJson(items: Collection<AnalyticsItem>) : JSONArray {
val array = JSONArray()
items.forEach {
array.put(it.toJson())
}
return array
}
items.forEach {
array.put(it.toJson())
}
return array
}
private fun AnalyticsItem.toJson() : JSONObject {

View file

@ -1,12 +1,8 @@
package io.github.openflocon.flocon.plugins.dashboard
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.Protocol
import io.github.openflocon.flocon.core.FloconMessageSender
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.model.FloconMessageFromServer
import io.github.openflocon.flocon.plugins.dashboard.dsl.DashboardBuilder
import io.github.openflocon.flocon.plugins.dashboard.dsl.dashboardConfig
import io.github.openflocon.flocon.plugins.dashboard.mapper.toJson
import io.github.openflocon.flocon.plugins.dashboard.model.DashboardCallback
import io.github.openflocon.flocon.plugins.dashboard.model.DashboardConfig
@ -14,16 +10,6 @@ import io.github.openflocon.flocon.plugins.dashboard.model.todevice.ToDeviceChec
import io.github.openflocon.flocon.plugins.dashboard.model.todevice.ToDeviceSubmittedTextFieldMessage
import java.util.concurrent.ConcurrentHashMap
fun Flocon.dashboard(id: String, block: DashboardBuilder.() -> Unit) {
val dashboardConfig = dashboardConfig(id = id, block)
this.client?.dashboardPlugin?.registerDashboard(dashboardConfig)
}
interface FloconDashboardPlugin : FloconPlugin {
fun registerDashboard(dashboardConfig: DashboardConfig)
}
class FloconDashboardPluginImpl(
private val sender: FloconMessageSender,
) : FloconDashboardPlugin {
@ -41,14 +27,20 @@ class FloconDashboardPluginImpl(
callbackMap[id]?.let { it as? DashboardCallback.ButtonCallback }?.action?.invoke()
}
Protocol.ToDevice.Dashboard.Method.OnTextFieldSubmitted -> {
ToDeviceSubmittedTextFieldMessage.fromJson(messageFromServer.body)?.let {
callbackMap[it.id]?.let { it as? DashboardCallback.TextFieldCallback }?.action?.invoke(it.value)
callbackMap[it.id]?.let { it as? DashboardCallback.TextFieldCallback }?.action?.invoke(
it.value
)
}
}
Protocol.ToDevice.Dashboard.Method.OnCheckBoxValueChanged -> {
ToDeviceCheckBoxValueChangedMessage.fromJson(messageFromServer.body)?.let {
callbackMap[it.id]?.let { it as? DashboardCallback.CheckBoxCallback }?.action?.invoke(it.value)
callbackMap[it.id]?.let { it as? DashboardCallback.CheckBoxCallback }?.action?.invoke(
it.value
)
}
}
}

View file

@ -16,9 +16,6 @@ import io.github.openflocon.flocon.plugins.database.model.todevice.DatabaseQuery
import java.io.File
import java.util.Locale
interface FloconDatabasePlugin : FloconPlugin
class FloconDatabasePluginImpl(
private val context: Context,
) : FloconDatabasePlugin {

View file

@ -1,23 +1,12 @@
package io.github.openflocon.flocon.plugins.deeplinks
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.Protocol
import io.github.openflocon.flocon.core.FloconMessageSender
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.model.FloconMessageFromServer
import io.github.openflocon.flocon.plugins.deeplinks.model.Deeplink
import org.json.JSONArray
import org.json.JSONObject
fun Flocon.deeplinks(deeplinks: List<Deeplink>) {
this.client?.deeplinksPlugin?.registerDeeplinks(deeplinks)
}
interface FloconDeeplinksPlugin : FloconPlugin {
fun registerDeeplinks(deeplinks: List<Deeplink>)
}
class FloconDeeplinksPluginImpl(
private val sender: FloconMessageSender,
) : FloconDeeplinksPlugin {

View file

@ -13,10 +13,6 @@ import io.github.openflocon.flocon.plugins.files.model.todevice.ToDeviceDeleteFo
import io.github.openflocon.flocon.plugins.files.model.todevice.ToDeviceGetFilesMessage
import java.io.File
interface FloconFilesPlugin : FloconPlugin {
}
class FloconFilesPluginImpl(
private val context: Context,
) : FloconFilesPlugin {

View file

@ -0,0 +1,32 @@
package io.github.openflocon.flocon.plugins.network
import io.github.openflocon.flocon.Protocol
import io.github.openflocon.flocon.core.FloconMessageSender
import io.github.openflocon.flocon.model.FloconMessageFromServer
import io.github.openflocon.flocon.plugins.network.model.FloconNetworkRequest
import io.github.openflocon.flocon.plugins.network.model.floconNetworkRequestToJson
class FloconNetworkPluginImpl(
private var sender: FloconMessageSender,
) : FloconNetworkPlugin {
override fun log(call: FloconNetworkRequest) {
sender.send(
plugin = Protocol.FromDevice.Network.Plugin,
method = Protocol.FromDevice.Network.Method.LogNetworkCall,
body = floconNetworkRequestToJson(call).toString(),
)
}
override fun onMessageReceived(
messageFromServer: FloconMessageFromServer,
sender: FloconMessageSender
) {
// no op
}
override fun onConnectedToServer(sender: FloconMessageSender) {
// no op
}
}

View file

@ -2,33 +2,11 @@ package io.github.openflocon.flocon.plugins.network.model
import org.json.JSONObject
data class FloconNetworkRequest(
val request: Request,
val response: Response,
val durationMs: Double,
val floconNetworkType: String,
) {
data class Request(
val url: String,
val method: String,
val startTime: Long,
val headers: Map<String, String>,
val body: String?,
val size: Long?,
)
data class Response(
val httpCode: Int?,
val grpcStatus: String?,
val contentType: String?,
val body: String?,
val size: Long?,
val headers: Map<String, String>,
)
fun toJson(): JSONObject {
val json = JSONObject()
fun floconNetworkRequestToJson(network: FloconNetworkRequest): JSONObject {
val json = JSONObject()
with(network) {
json.put("floconNetworkType", floconNetworkType)
json.put("url", request.url)
@ -42,11 +20,11 @@ data class FloconNetworkRequest(
response.httpCode?.let { json.put("responseHttpCode", it) }
response.grpcStatus?.let { json.put("responseGrpcStatus", it) }
response.contentType?.let { json.put("responseContentType", it) }
response.contentType?.let { json.put("responseContentType", it) }
response.body?.let { json.put("responseBody", it) }
json.put("responseHeaders", JSONObject(response.headers))
json.put("responseSize", response.size)
return json
}
return json
}

View file

@ -19,9 +19,6 @@ import io.github.openflocon.flocon.plugins.sharedprefs.model.todevice.ToDeviceGe
// Got some code from Flipper client
// https://github.com/facebook/flipper/blob/main/android/src/main/java/com/facebook/flipper/plugins/sharedpreferences/SharedPreferencesFlipperPlugin.java
interface FloconSharedPreferencesPlugin : FloconPlugin {
}
class FloconSharedPreferencesPluginImpl(
private val context: Context,
) : FloconSharedPreferencesPlugin {

View file

@ -1,27 +1,13 @@
package io.github.openflocon.flocon.plugins.tables
import io.github.openflocon.flocon.Flocon
import io.github.openflocon.flocon.Protocol
import io.github.openflocon.flocon.core.FloconMessageSender
import io.github.openflocon.flocon.core.FloconPlugin
import io.github.openflocon.flocon.model.FloconMessageFromServer
import io.github.openflocon.flocon.plugins.tables.builder.TableBuilder
import io.github.openflocon.flocon.plugins.tables.model.TableItem
import io.github.openflocon.flocon.plugins.tables.model.tableItemListToJson
import org.json.JSONArray
import java.util.concurrent.ConcurrentLinkedQueue
fun Flocon.table(tableName: String): TableBuilder {
return TableBuilder(
tableName = tableName,
tablePlugin = this.client?.tablePlugin,
)
}
interface FloconTablePlugin : FloconPlugin {
fun registerTable(tableItem: TableItem)
}
class FloconTablePluginImpl(
private val sender: FloconMessageSender,
) : FloconTablePlugin {
@ -32,17 +18,17 @@ class FloconTablePluginImpl(
messageFromServer: FloconMessageFromServer,
sender: FloconMessageSender,
) {
when(messageFromServer.method) {
Protocol.ToDevice.Table.Method.ClearItems-> {
when (messageFromServer.method) {
Protocol.ToDevice.Table.Method.ClearItems -> {
val items = readIds(messageFromServer.body)
if(items.isNotEmpty()) {
if (items.isNotEmpty()) {
clearItems(items.toSet())
}
}
}
}
private fun readIds(body: String) : List<String> {
private fun readIds(body: String): List<String> {
return try {
val array = JSONArray(body)
val items = mutableListOf<String>()
@ -70,7 +56,7 @@ class FloconTablePluginImpl(
sender.send(
plugin = Protocol.FromDevice.Table.Plugin,
method = Protocol.FromDevice.Table.Method.AddItems,
body = TableItem.listToJson(tableMessages).toString()
body = tableItemListToJson(tableMessages).toString()
)
}
}

View file

@ -3,26 +3,17 @@ package io.github.openflocon.flocon.plugins.tables.model
import org.json.JSONArray
import org.json.JSONObject
data class TableItem(
val id: String,
val name: String,
val createdAt: Long,
val columns: List<TableColumnConfig>,
) {
companion object {
fun listToJson(items: Collection<TableItem>) : JSONArray {
val array = JSONArray()
fun tableItemListToJson(items: Collection<TableItem>): JSONArray {
val array = JSONArray()
items.forEach {
array.put(it.toJson())
}
return array
}
items.forEach {
array.put(it.toJson())
}
return array
}
private fun TableItem.toJson() : JSONObject {
private fun TableItem.toJson(): JSONObject {
val tableItemJson = JSONObject()
tableItemJson.put("id", this.id)

View file

@ -35,7 +35,7 @@ android {
}
dependencies {
implementation(project(":core"))
implementation(project(":flocon-base"))
implementation(libs.gson)
implementation(libs.grpc.android)

Some files were not shown because too many files have changed in this diff Show more