Skip to content

Commit

Permalink
Dump Flo from internal repository
Browse files Browse the repository at this point in the history
The private artifact is not included in the dump and, like the app, will be
updated to depend on this artifact once it's published.

The demo app has seen slight changes as it connected to our internal backend.
  • Loading branch information
stoyicker committed Dec 5, 2024
1 parent 84171dd commit 42ffff0
Show file tree
Hide file tree
Showing 48 changed files with 1,705 additions and 0 deletions.
10 changes: 10 additions & 0 deletions flo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- Initial dump from internal repo
49 changes: 49 additions & 0 deletions flo/apps/demo/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
plugins {
alias(libs.plugins.tidal.android.application)
}

android {
namespace = "com.tidal.sdk.flo.demo"

buildFeatures {
compose = false
}

defaultConfig {
applicationId = "com.tidal.sdk.flo.demo"
versionCode = 1
versionName = "0.1.0"
}

flavorDimensions += "api"
productFlavors {
create("core") {
dimension = "api"
applicationIdSuffix = ".core"
}
create("kotlincoroutines") {
dimension = "api"
applicationIdSuffix = ".kotlincoroutines"
}
create("rxjava3") {
dimension = "api"
applicationIdSuffix = ".rxjava3"
}
create("rxjava2") {
dimension = "api"
applicationIdSuffix = ".rxjava2"
}
create("rxjava") {
dimension = "api"
applicationIdSuffix = ".rxjava"
}
}
}

dependencies {
implementation(project(":flo"))
"kotlincoroutinesImplementation"(project(":flo:extensions:kotlincoroutines"))
"rxjava3Implementation"(project(":flo:extensions:rxjava3"))
"rxjava2Implementation"(project(":flo:extensions:rxjava2"))
"rxjavaImplementation"(project(":flo:extensions:rxjava"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.tidal.sdk.flo.demo

import com.tidal.sdk.flo.core.FloClient
import com.tidal.sdk.flo.core.SubscriptionHandle

internal typealias SelectedApiSubscriptionManager = CoreApiSubscriptionManager

internal class CoreApiSubscriptionManager(
floClient: FloClient,
name: String,
) : SubscriptionManager(floClient, name) {

private val topicToSubscriptionHandle = mutableMapOf<String, SubscriptionHandle>()

override fun subscribeInternal(
topic: String,
onMessage: (String) -> Unit,
onError: (Throwable) -> Unit,
tail: Int,
) {
topicToSubscriptionHandle[topic] = floClient.subscribe(topic, onMessage, onError, tail)
}

override fun unsubscribeInternal(topic: String) {
topicToSubscriptionHandle[topic]?.unsubscribe()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.tidal.sdk.flo.demo

import com.tidal.sdk.flo.core.FloClient
import com.tidal.sdk.flo.core.FloException
import com.tidal.sdk.flo.extensions.kotlincoroutines.topicAsFlow
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

internal typealias SelectedApiSubscriptionManager = KotlinCoroutineApiSubscriptionManager

internal class KotlinCoroutineApiSubscriptionManager(
floClient: FloClient,
name: String,
) : SubscriptionManager(floClient, name) {

private val topicToJob = mutableMapOf<String, Job>()

@Suppress("TooGenericExceptionCaught") // We don't want singled-out behavior
override fun subscribeInternal(
topic: String,
onMessage: (String) -> Unit,
onError: (Throwable) -> Unit,
tail: Int,
) {
topicToJob[topic] = GlobalScope.launch {
floClient.topicAsFlow(topic, tail).collect {
try {
onMessage(it)
} catch (throwable: Throwable) {
when (throwable) {
is FloException -> onError(throwable)
else -> throw throwable
}
}
}
}
}

override fun unsubscribeInternal(topic: String) {
topicToJob[topic]?.cancel(RequestedCancellationException())
}
}

private class RequestedCancellationException : CancellationException()
16 changes: 16 additions & 0 deletions flo/apps/demo/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:name=".MainApplication"
android:icon="@android:mipmap/sym_def_app_icon">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
129 changes: 129 additions & 0 deletions flo/apps/demo/src/main/kotlin/com/tidal/sdk/flo/demo/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.tidal.sdk.flo.demo

import android.annotation.SuppressLint
import android.app.Activity
import android.os.Bundle
import android.text.InputType
import android.util.Log
import android.view.Gravity
import android.widget.Button
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView

internal class MainActivity : Activity() {

@Suppress("LongMethod")
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
title = "API: ${BuildConfig.FLAVOR}"
val topicView = EditText(this).apply {
gravity = Gravity.CENTER
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
)
}
val tailView = EditText(this).apply {
gravity = Gravity.CENTER
inputType = InputType.TYPE_CLASS_NUMBER
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
)
}
val subscriptionView = TextView(this).apply {
gravity = Gravity.CENTER
}
val subscriptionManager = SelectedApiSubscriptionManager(
(applicationContext as MainApplication).demoFloClient,
"Demo FloClient",
)
val updateSubscriptionView = {
subscriptionView.text = subscriptionManager.subscribedTopics
.joinToString(separator = "\n", postfix = "\n") {
"topic=$it (${subscriptionManager.name})"
}
}
setContentView(
LinearLayout(this).apply {
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
orientation = LinearLayout.VERTICAL
addView(
LinearLayout(this@MainActivity).apply {
gravity = Gravity.CENTER
addView(
Button(this@MainActivity).apply {
text = "Subscribe"
setOnClickListener {
val topic = topicView.text.toString()
subscriptionManager.unsubscribe(topic)
subscriptionManager
.subscribe(
topic,
{ msg: String ->
Log.d(
"HOLA",
"topic $topic - MSG: $msg",
)
},
{ e: Throwable ->
Log.d(
"HOLA",
"topic $topic - ERROR",
e,
)
},
tailView.text.toString().ifBlank { "0" }.toInt(),
)
updateSubscriptionView()
}
},
)
addView(
Button(this@MainActivity).apply {
text = "Unsubscribe"
setOnClickListener {
val topic = topicView.text.toString()
subscriptionManager.unsubscribe(topic)
updateSubscriptionView()
}
},
)
},
)
addView(
LinearLayout(this@MainActivity).apply {
gravity = Gravity.CENTER
orientation = LinearLayout.HORIZONTAL
addView(
TextView(this@MainActivity).apply {
text = "Topic:"
},
)
addView(topicView)
},
)
addView(
LinearLayout(this@MainActivity).apply {
gravity = Gravity.CENTER
orientation = LinearLayout.HORIZONTAL
addView(
TextView(this@MainActivity).apply {
text = "Tail (for subscribing only):"
},
)
addView(tailView)
},
)
addView(subscriptionView).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT,
)
}
},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.tidal.sdk.flo.demo

import android.app.Application
import android.net.ConnectivityManager
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import com.tidal.sdk.flo.core.FloClient

internal class MainApplication : Application() {

val demoFloClient by lazy {
FloClient(
getSystemService(ConnectivityManager::class.java),
{ "atoken" },
{ false },
TODO("URL to your Flo backend here"),
HandlerThread("DemoFloClient::Operations")
.also {
it.start()
}.looper.run {
Handler(this)
},
Handler(Looper.getMainLooper()),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.tidal.sdk.flo.demo

import com.tidal.sdk.flo.core.FloClient

abstract class SubscriptionManager(
protected val floClient: FloClient,
val name: String,
) {

var subscribedTopics = listOf<String>()
private set

fun subscribe(
topic: String,
onMessage: (String) -> Unit,
onError: (Throwable) -> Unit,
tail: Int = 0,
) = synchronized(this) {
subscribedTopics = subscribedTopics + topic
subscribeInternal(topic, onMessage, onError, tail)
}

fun unsubscribe(topic: String) = synchronized(this) {
subscribedTopics = subscribedTopics - topic
unsubscribeInternal(topic)
}

protected abstract fun subscribeInternal(
topic: String,
onMessage: (String) -> Unit,
onError: (Throwable) -> Unit,
tail: Int = 0,
)

protected abstract fun unsubscribeInternal(topic: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.tidal.sdk.flo.demo

import com.tidal.sdk.flo.core.FloClient
import com.tidal.sdk.flo.extensions.rxjava.topicAsObservable
import rx.Emitter
import rx.Subscription

internal typealias SelectedApiSubscriptionManager = RxJavaApiSubscriptionManager

internal class RxJavaApiSubscriptionManager(
floClient: FloClient,
name: String,
) : SubscriptionManager(floClient, name) {

private val topicToSubscription = mutableMapOf<String, Subscription>()

override fun subscribeInternal(
topic: String,
onMessage: (String) -> Unit,
onError: (Throwable) -> Unit,
tail: Int,
) {
topicToSubscription[topic] = floClient.topicAsObservable(
topic,
tail,
Emitter.BackpressureMode.LATEST,
)
.subscribe(
onMessage,
onError,
)
}

override fun unsubscribeInternal(topic: String) {
topicToSubscription[topic]?.unsubscribe()
}
}
Loading

0 comments on commit 42ffff0

Please sign in to comment.