Skip to content

Commit 42ffff0

Browse files
committed
Dump Flo from internal repository
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.
1 parent 84171dd commit 42ffff0

File tree

48 files changed

+1705
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1705
-0
lines changed

flo/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
- Initial dump from internal repo

flo/apps/demo/build.gradle.kts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
plugins {
2+
alias(libs.plugins.tidal.android.application)
3+
}
4+
5+
android {
6+
namespace = "com.tidal.sdk.flo.demo"
7+
8+
buildFeatures {
9+
compose = false
10+
}
11+
12+
defaultConfig {
13+
applicationId = "com.tidal.sdk.flo.demo"
14+
versionCode = 1
15+
versionName = "0.1.0"
16+
}
17+
18+
flavorDimensions += "api"
19+
productFlavors {
20+
create("core") {
21+
dimension = "api"
22+
applicationIdSuffix = ".core"
23+
}
24+
create("kotlincoroutines") {
25+
dimension = "api"
26+
applicationIdSuffix = ".kotlincoroutines"
27+
}
28+
create("rxjava3") {
29+
dimension = "api"
30+
applicationIdSuffix = ".rxjava3"
31+
}
32+
create("rxjava2") {
33+
dimension = "api"
34+
applicationIdSuffix = ".rxjava2"
35+
}
36+
create("rxjava") {
37+
dimension = "api"
38+
applicationIdSuffix = ".rxjava"
39+
}
40+
}
41+
}
42+
43+
dependencies {
44+
implementation(project(":flo"))
45+
"kotlincoroutinesImplementation"(project(":flo:extensions:kotlincoroutines"))
46+
"rxjava3Implementation"(project(":flo:extensions:rxjava3"))
47+
"rxjava2Implementation"(project(":flo:extensions:rxjava2"))
48+
"rxjavaImplementation"(project(":flo:extensions:rxjava"))
49+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.tidal.sdk.flo.demo
2+
3+
import com.tidal.sdk.flo.core.FloClient
4+
import com.tidal.sdk.flo.core.SubscriptionHandle
5+
6+
internal typealias SelectedApiSubscriptionManager = CoreApiSubscriptionManager
7+
8+
internal class CoreApiSubscriptionManager(
9+
floClient: FloClient,
10+
name: String,
11+
) : SubscriptionManager(floClient, name) {
12+
13+
private val topicToSubscriptionHandle = mutableMapOf<String, SubscriptionHandle>()
14+
15+
override fun subscribeInternal(
16+
topic: String,
17+
onMessage: (String) -> Unit,
18+
onError: (Throwable) -> Unit,
19+
tail: Int,
20+
) {
21+
topicToSubscriptionHandle[topic] = floClient.subscribe(topic, onMessage, onError, tail)
22+
}
23+
24+
override fun unsubscribeInternal(topic: String) {
25+
topicToSubscriptionHandle[topic]?.unsubscribe()
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.tidal.sdk.flo.demo
2+
3+
import com.tidal.sdk.flo.core.FloClient
4+
import com.tidal.sdk.flo.core.FloException
5+
import com.tidal.sdk.flo.extensions.kotlincoroutines.topicAsFlow
6+
import kotlinx.coroutines.CancellationException
7+
import kotlinx.coroutines.GlobalScope
8+
import kotlinx.coroutines.Job
9+
import kotlinx.coroutines.launch
10+
11+
internal typealias SelectedApiSubscriptionManager = KotlinCoroutineApiSubscriptionManager
12+
13+
internal class KotlinCoroutineApiSubscriptionManager(
14+
floClient: FloClient,
15+
name: String,
16+
) : SubscriptionManager(floClient, name) {
17+
18+
private val topicToJob = mutableMapOf<String, Job>()
19+
20+
@Suppress("TooGenericExceptionCaught") // We don't want singled-out behavior
21+
override fun subscribeInternal(
22+
topic: String,
23+
onMessage: (String) -> Unit,
24+
onError: (Throwable) -> Unit,
25+
tail: Int,
26+
) {
27+
topicToJob[topic] = GlobalScope.launch {
28+
floClient.topicAsFlow(topic, tail).collect {
29+
try {
30+
onMessage(it)
31+
} catch (throwable: Throwable) {
32+
when (throwable) {
33+
is FloException -> onError(throwable)
34+
else -> throw throwable
35+
}
36+
}
37+
}
38+
}
39+
}
40+
41+
override fun unsubscribeInternal(topic: String) {
42+
topicToJob[topic]?.cancel(RequestedCancellationException())
43+
}
44+
}
45+
46+
private class RequestedCancellationException : CancellationException()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
<application
5+
android:name=".MainApplication"
6+
android:icon="@android:mipmap/sym_def_app_icon">
7+
<activity
8+
android:name=".MainActivity"
9+
android:exported="true">
10+
<intent-filter>
11+
<action android:name="android.intent.action.MAIN" />
12+
<category android:name="android.intent.category.LAUNCHER" />
13+
</intent-filter>
14+
</activity>
15+
</application>
16+
</manifest>
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.tidal.sdk.flo.demo
2+
3+
import android.annotation.SuppressLint
4+
import android.app.Activity
5+
import android.os.Bundle
6+
import android.text.InputType
7+
import android.util.Log
8+
import android.view.Gravity
9+
import android.widget.Button
10+
import android.widget.EditText
11+
import android.widget.LinearLayout
12+
import android.widget.TextView
13+
14+
internal class MainActivity : Activity() {
15+
16+
@Suppress("LongMethod")
17+
@SuppressLint("SetTextI18n")
18+
override fun onCreate(savedInstanceState: Bundle?) {
19+
super.onCreate(savedInstanceState)
20+
title = "API: ${BuildConfig.FLAVOR}"
21+
val topicView = EditText(this).apply {
22+
gravity = Gravity.CENTER
23+
layoutParams = LinearLayout.LayoutParams(
24+
LinearLayout.LayoutParams.MATCH_PARENT,
25+
LinearLayout.LayoutParams.WRAP_CONTENT,
26+
)
27+
}
28+
val tailView = EditText(this).apply {
29+
gravity = Gravity.CENTER
30+
inputType = InputType.TYPE_CLASS_NUMBER
31+
layoutParams = LinearLayout.LayoutParams(
32+
LinearLayout.LayoutParams.MATCH_PARENT,
33+
LinearLayout.LayoutParams.WRAP_CONTENT,
34+
)
35+
}
36+
val subscriptionView = TextView(this).apply {
37+
gravity = Gravity.CENTER
38+
}
39+
val subscriptionManager = SelectedApiSubscriptionManager(
40+
(applicationContext as MainApplication).demoFloClient,
41+
"Demo FloClient",
42+
)
43+
val updateSubscriptionView = {
44+
subscriptionView.text = subscriptionManager.subscribedTopics
45+
.joinToString(separator = "\n", postfix = "\n") {
46+
"topic=$it (${subscriptionManager.name})"
47+
}
48+
}
49+
setContentView(
50+
LinearLayout(this).apply {
51+
gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
52+
orientation = LinearLayout.VERTICAL
53+
addView(
54+
LinearLayout(this@MainActivity).apply {
55+
gravity = Gravity.CENTER
56+
addView(
57+
Button(this@MainActivity).apply {
58+
text = "Subscribe"
59+
setOnClickListener {
60+
val topic = topicView.text.toString()
61+
subscriptionManager.unsubscribe(topic)
62+
subscriptionManager
63+
.subscribe(
64+
topic,
65+
{ msg: String ->
66+
Log.d(
67+
"HOLA",
68+
"topic $topic - MSG: $msg",
69+
)
70+
},
71+
{ e: Throwable ->
72+
Log.d(
73+
"HOLA",
74+
"topic $topic - ERROR",
75+
e,
76+
)
77+
},
78+
tailView.text.toString().ifBlank { "0" }.toInt(),
79+
)
80+
updateSubscriptionView()
81+
}
82+
},
83+
)
84+
addView(
85+
Button(this@MainActivity).apply {
86+
text = "Unsubscribe"
87+
setOnClickListener {
88+
val topic = topicView.text.toString()
89+
subscriptionManager.unsubscribe(topic)
90+
updateSubscriptionView()
91+
}
92+
},
93+
)
94+
},
95+
)
96+
addView(
97+
LinearLayout(this@MainActivity).apply {
98+
gravity = Gravity.CENTER
99+
orientation = LinearLayout.HORIZONTAL
100+
addView(
101+
TextView(this@MainActivity).apply {
102+
text = "Topic:"
103+
},
104+
)
105+
addView(topicView)
106+
},
107+
)
108+
addView(
109+
LinearLayout(this@MainActivity).apply {
110+
gravity = Gravity.CENTER
111+
orientation = LinearLayout.HORIZONTAL
112+
addView(
113+
TextView(this@MainActivity).apply {
114+
text = "Tail (for subscribing only):"
115+
},
116+
)
117+
addView(tailView)
118+
},
119+
)
120+
addView(subscriptionView).apply {
121+
layoutParams = LinearLayout.LayoutParams(
122+
LinearLayout.LayoutParams.MATCH_PARENT,
123+
LinearLayout.LayoutParams.MATCH_PARENT,
124+
)
125+
}
126+
},
127+
)
128+
}
129+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.tidal.sdk.flo.demo
2+
3+
import android.app.Application
4+
import android.net.ConnectivityManager
5+
import android.os.Handler
6+
import android.os.HandlerThread
7+
import android.os.Looper
8+
import com.tidal.sdk.flo.core.FloClient
9+
10+
internal class MainApplication : Application() {
11+
12+
val demoFloClient by lazy {
13+
FloClient(
14+
getSystemService(ConnectivityManager::class.java),
15+
{ "atoken" },
16+
{ false },
17+
TODO("URL to your Flo backend here"),
18+
HandlerThread("DemoFloClient::Operations")
19+
.also {
20+
it.start()
21+
}.looper.run {
22+
Handler(this)
23+
},
24+
Handler(Looper.getMainLooper()),
25+
)
26+
}
27+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.tidal.sdk.flo.demo
2+
3+
import com.tidal.sdk.flo.core.FloClient
4+
5+
abstract class SubscriptionManager(
6+
protected val floClient: FloClient,
7+
val name: String,
8+
) {
9+
10+
var subscribedTopics = listOf<String>()
11+
private set
12+
13+
fun subscribe(
14+
topic: String,
15+
onMessage: (String) -> Unit,
16+
onError: (Throwable) -> Unit,
17+
tail: Int = 0,
18+
) = synchronized(this) {
19+
subscribedTopics = subscribedTopics + topic
20+
subscribeInternal(topic, onMessage, onError, tail)
21+
}
22+
23+
fun unsubscribe(topic: String) = synchronized(this) {
24+
subscribedTopics = subscribedTopics - topic
25+
unsubscribeInternal(topic)
26+
}
27+
28+
protected abstract fun subscribeInternal(
29+
topic: String,
30+
onMessage: (String) -> Unit,
31+
onError: (Throwable) -> Unit,
32+
tail: Int = 0,
33+
)
34+
35+
protected abstract fun unsubscribeInternal(topic: String)
36+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.tidal.sdk.flo.demo
2+
3+
import com.tidal.sdk.flo.core.FloClient
4+
import com.tidal.sdk.flo.extensions.rxjava.topicAsObservable
5+
import rx.Emitter
6+
import rx.Subscription
7+
8+
internal typealias SelectedApiSubscriptionManager = RxJavaApiSubscriptionManager
9+
10+
internal class RxJavaApiSubscriptionManager(
11+
floClient: FloClient,
12+
name: String,
13+
) : SubscriptionManager(floClient, name) {
14+
15+
private val topicToSubscription = mutableMapOf<String, Subscription>()
16+
17+
override fun subscribeInternal(
18+
topic: String,
19+
onMessage: (String) -> Unit,
20+
onError: (Throwable) -> Unit,
21+
tail: Int,
22+
) {
23+
topicToSubscription[topic] = floClient.topicAsObservable(
24+
topic,
25+
tail,
26+
Emitter.BackpressureMode.LATEST,
27+
)
28+
.subscribe(
29+
onMessage,
30+
onError,
31+
)
32+
}
33+
34+
override fun unsubscribeInternal(topic: String) {
35+
topicToSubscription[topic]?.unsubscribe()
36+
}
37+
}

0 commit comments

Comments
 (0)