Skip to content

Commit

Permalink
add ktor for websocket, add live price implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
root14 committed Mar 31, 2024
1 parent 182aa39 commit 4a84c2e
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 16 deletions.
8 changes: 7 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ dependencies {
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.core:core-splashscreen:1.1.0-alpha02"

implementation libs.androidx.core.splashscreen

implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.websockets)

}

kapt {
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/root14/hoopoe/AssetDetailActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,30 @@ import android.graphics.Color
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.formatter.IFillFormatter
import com.root14.hoopoe.data.WebSocketHelper
import com.root14.hoopoe.data.entity.Favorite
import com.root14.hoopoe.data.model.Interval
import com.root14.hoopoe.databinding.ActivityAssetDetailBinding
import com.root14.hoopoe.viewmodel.DetailViewModel
import com.root14.hoopoe.viewmodel.FavoritesViewModel
import dagger.hilt.android.AndroidEntryPoint
import io.ktor.client.HttpClient
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.webSocket
import io.ktor.http.HttpMethod
import io.ktor.websocket.Frame
import io.ktor.websocket.readText
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch


@AndroidEntryPoint
Expand Down Expand Up @@ -45,6 +57,7 @@ class AssetDetailActivity() : AppCompatActivity() {
detailViewModel.getAssetById(assetName.toString()).observe(this) { assetById ->
binding.asset = assetById
}

detailViewModel.getIntervalData(assetName.toString()).observe(this) { changeRate ->
binding.changeRate = changeRate
}
Expand Down Expand Up @@ -81,6 +94,16 @@ class AssetDetailActivity() : AppCompatActivity() {
}
}

lifecycleScope.launch {
WebSocketHelper().subscribeWebSocket(
asset = assetName.toString(),
listener = object : WebSocketHelper.IWebSocketListener {
override fun observeSocket(data: String) {
binding.livePrice = data
}

})
}
}

private fun setData(interval: Interval) {
Expand Down
24 changes: 10 additions & 14 deletions app/src/main/java/com/root14/hoopoe/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
package com.root14.hoopoe

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.splashscreen.SplashScreen
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.root14.hoopoe.data.WebSocketHelper
import com.root14.hoopoe.databinding.ActivityMainBinding
import com.root14.hoopoe.utils.DataStoreUtil
import com.root14.hoopoe.view.adapter.CoinRecycleAdapter
import com.root14.hoopoe.view.adapter.MainPagerAdapter
import com.root14.hoopoe.view.bottomsheet.MainBottomSheet
import com.root14.hoopoe.viewmodel.MainViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import io.ktor.client.HttpClient
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.webSocket
import io.ktor.http.HttpMethod
import io.ktor.websocket.Frame
import io.ktor.websocket.readText
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
//It skips mainBottomSheet.dismiss() in the init phase and then closes the bottomSheet when recyclerview change.
private var initializer: Boolean = false

private lateinit var binding: ActivityMainBinding
private lateinit var adapter: MainPagerAdapter
Expand All @@ -36,7 +32,7 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
super.onCreate(savedInstanceState)
val splashScreen = installSplashScreen()
installSplashScreen()
//enableEdgeToEdge()
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Expand Down
45 changes: 45 additions & 0 deletions app/src/main/java/com/root14/hoopoe/data/WebSocketHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.root14.hoopoe.data

import io.ktor.client.HttpClient
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.webSocket
import io.ktor.http.HttpMethod
import io.ktor.websocket.Frame
import io.ktor.websocket.readText

/**
*@sample WebSocketHelper().subscribeWebSocket(object : WebSocketHelper.IWebSocketListener {
* override fun observeSocket(data: String) {
* println(data)
* }
* })
*/
class WebSocketHelper {
private val client = HttpClient {
install(WebSockets)
}

interface IWebSocketListener {
fun observeSocket(data: String)
}

//default listen bitcoin
suspend fun subscribeWebSocket(
listener: IWebSocketListener,
host: String = "ws.coincap.io",
asset: String = "bitcoin",
path: String = "/prices?assets=${asset}"
): IWebSocketListener {
client.webSocket(
method = HttpMethod.Get, host = host, path = path
) {
while (true) {
val othersMessage = incoming.receive() as? Frame.Text ?: continue
//println(othersMessage.readText())
listener.observeSocket(othersMessage.readText())
}
}
return listener
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fun setPriceChange(textView: TextView, priceChange: String) {
textView.text = priceChange.convertPriceChange()

val baseView = textView.rootView.resources
if (priceChange.isNotEmpty()) {
if (priceChange.isNotEmpty() and (priceChange != "null") and priceChange.isNotBlank()) {
val price = priceChange.toDouble()
if (price > 0) {
textView.setTextColor(baseView.getColor(R.color.positiveColor))
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/com/root14/hoopoe/view/binding/livePrice.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.root14.hoopoe.view.binding

import android.widget.TextView
import androidx.databinding.BindingAdapter
import com.root14.hoopoe.utils.convertPriceFormat

@BindingAdapter("setLivePrice")
fun setLivePrice(textView: TextView, data: String) {
if (data.isNotEmpty()) {
textView.text = data.convertPriceFormat()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.root14.hoopoe.data.WebSocketHelper
import com.root14.hoopoe.data.model.AssetById
import com.root14.hoopoe.data.model.AssetsData
import com.root14.hoopoe.data.model.ChangeRate
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/layout/activity_asset_detail.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<variable
name="changeRate"
type="com.root14.hoopoe.data.model.ChangeRate" />

<variable
name="livePrice"
type="String" />
</data>

<androidx.coordinatorlayout.widget.CoordinatorLayout
Expand Down Expand Up @@ -161,6 +165,7 @@

<TextView
android:id="@+id/tv_assetPrice"
app:setLivePrice='@{livePrice?? ""}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/alibaba_sans_regular"
Expand Down
6 changes: 6 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
activityKtx = "1.8.2"
agp = "8.3.0"
converterGson = "2.9.0"
coreSplashscreen = "1.1.0-alpha02"
datastorePreferences = "1.0.0"
fragmentKtx = "1.6.2"
glide = "4.16.0"
Expand All @@ -13,6 +14,7 @@ junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
appcompat = "1.6.1"
ktorClientCore = "2.3.9"
material = "1.11.0"
activity = "1.8.2"
constraintlayout = "2.1.4"
Expand All @@ -23,6 +25,7 @@ retrofit2KotlinCoroutinesAdapter = "0.9.2"
[libraries]
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" }
androidx-navigation-fragment-ktx = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
Expand All @@ -37,6 +40,9 @@ junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktorClientCore" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktorClientCore" }
ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktorClientCore" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
Expand Down

0 comments on commit 4a84c2e

Please sign in to comment.