Fix crash after resuming app
This commit is contained in:
parent
4f705ae074
commit
d365caf301
|
@ -301,14 +301,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
|
||||
fetchAnnouncements()
|
||||
|
||||
streamingManager.setup(lifecycleScope.coroutineContext.job) { active ->
|
||||
if (active) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise the tab adapter and set to viewpager. Fragments appear to be leaked if the
|
||||
// adapter changes over the life of the viewPager (the adapter, not its contents), so set
|
||||
// the initial list of tabs to empty, and set the full list later in setupTabs(). See
|
||||
|
@ -732,15 +724,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
super.onSaveInstanceState(binding.mainDrawer.saveInstanceState(outState))
|
||||
}
|
||||
|
||||
private fun tintCheckIcon(item: MenuItem) {
|
||||
if (item.isChecked) {
|
||||
@Suppress("DEPRECATION")
|
||||
item.icon?.setColorFilter(ContextCompat.getColor(this, R.color.tusky_green_light), PorterDuff.Mode.SRC_IN)
|
||||
} else {
|
||||
setDrawableTint(this, item.icon!!, android.R.attr.textColorTertiary)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTabs(selectNotificationTab: Boolean) {
|
||||
val activeTabLayout = if (preferences.getString(PrefKeys.MAIN_NAV_POSITION, "top") == "bottom") {
|
||||
val actionBarSize = getDimension(this, androidx.appcompat.R.attr.actionBarSize)
|
||||
|
@ -794,12 +777,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
if (data.id == LIST) {
|
||||
menuBuilder.findItem(R.id.tabEditList).isVisible = true
|
||||
}
|
||||
if (data.id in arrayOf(HOME, LOCAL, FEDERATED, LIST)) {
|
||||
menuBuilder.findItem(R.id.tabToggleStreaming).apply {
|
||||
isVisible = true
|
||||
isChecked = data.enableStreaming
|
||||
}
|
||||
}
|
||||
if (data.id == NOTIFICATIONS) {
|
||||
menuBuilder.findItem(R.id.tabToggleNotificationsFilter).isVisible = true
|
||||
}
|
||||
|
@ -813,7 +790,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
setDrawableTint(this, item.icon!!, android.R.attr.textColorPrimary)
|
||||
}
|
||||
}
|
||||
tintCheckIcon(menuBuilder.findItem(R.id.tabToggleStreaming))
|
||||
}
|
||||
|
||||
popup.setOnMenuItemClickListener { item ->
|
||||
|
@ -837,20 +813,6 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
data.arguments.getOrNull(1).orEmpty()
|
||||
).show(supportFragmentManager, null)
|
||||
}
|
||||
R.id.tabToggleStreaming -> {
|
||||
if (fragment is TimelineFragment) {
|
||||
val to = !item.isChecked
|
||||
fragment.setStreamingEnabled(to)
|
||||
item.isChecked = to
|
||||
tintCheckIcon(item)
|
||||
|
||||
tabs[position] = data.copy(enableStreaming = to)
|
||||
accountManager.activeAccount?.let {
|
||||
it.tabPreferences = tabs
|
||||
accountManager.saveAccount(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.tabToggleNotificationsFilter -> {
|
||||
if (fragment is NotificationsFragment) {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
@ -915,6 +877,17 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
}
|
||||
|
||||
updateProfiles()
|
||||
|
||||
streamingManager.setup(
|
||||
this,
|
||||
tabs.mapNotNull { it.subscription }.toSet(),
|
||||
) { active ->
|
||||
if (active) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshComposeButtonState(adapter: MainPagerAdapter, tabPosition: Int) {
|
||||
|
|
|
@ -24,6 +24,8 @@ import com.keylesspalace.tusky.components.notifications.NotificationsFragment
|
|||
import com.keylesspalace.tusky.components.timeline.TimelineFragment
|
||||
import com.keylesspalace.tusky.components.timeline.viewmodel.TimelineViewModel
|
||||
import com.keylesspalace.tusky.components.trending.TrendingFragment
|
||||
import net.accelf.yuito.streaming.StreamType
|
||||
import net.accelf.yuito.streaming.Subscription
|
||||
import java.util.Objects
|
||||
|
||||
/** this would be a good case for a sealed class, but that does not work nice with Room */
|
||||
|
@ -48,6 +50,20 @@ data class TabData(
|
|||
val title: (Context) -> String = { context -> context.getString(text) },
|
||||
val enableStreaming: Boolean = false,
|
||||
) {
|
||||
val subscription by lazy {
|
||||
if (enableStreaming) {
|
||||
when (id) {
|
||||
HOME -> Subscription(StreamType.USER)
|
||||
LOCAL -> Subscription(StreamType.LOCAL)
|
||||
FEDERATED -> Subscription(StreamType.PUBLIC)
|
||||
LIST -> Subscription(StreamType.LIST, arguments[0].toInt())
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
|
|
@ -212,6 +212,14 @@ class TabPreferenceActivity : BaseActivity(), Injectable, ItemInteractionListene
|
|||
currentTabsAdapter.notifyItemChanged(tabPosition)
|
||||
}
|
||||
|
||||
override fun onStreamingChanged(tab: TabData, tabPosition: Int, enabled: Boolean) {
|
||||
val newTab = tab.copy(enableStreaming = enabled)
|
||||
currentTabs[tabPosition] = newTab
|
||||
saveTabs()
|
||||
|
||||
currentTabsAdapter.notifyItemChanged(tabPosition)
|
||||
}
|
||||
|
||||
private fun toggleFab(expand: Boolean) {
|
||||
val transition = MaterialContainerTransform().apply {
|
||||
startView = if (expand) binding.actionButton else binding.sheet
|
||||
|
|
|
@ -18,12 +18,16 @@ package com.keylesspalace.tusky.adapter
|
|||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener
|
||||
import androidx.core.view.size
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.keylesspalace.tusky.FEDERATED
|
||||
import com.keylesspalace.tusky.HASHTAG
|
||||
import com.keylesspalace.tusky.HOME
|
||||
import com.keylesspalace.tusky.LIST
|
||||
import com.keylesspalace.tusky.LOCAL
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.TabData
|
||||
import com.keylesspalace.tusky.databinding.ItemTabPreferenceBinding
|
||||
|
@ -40,6 +44,7 @@ interface ItemInteractionListener {
|
|||
fun onStartDrag(viewHolder: RecyclerView.ViewHolder)
|
||||
fun onActionChipClicked(tab: TabData, tabPosition: Int)
|
||||
fun onChipClicked(tab: TabData, tabPosition: Int, chipPosition: Int)
|
||||
fun onStreamingChanged(tab: TabData, tabPosition: Int, enabled: Boolean)
|
||||
}
|
||||
|
||||
class TabAdapter(
|
||||
|
@ -146,6 +151,18 @@ class TabAdapter(
|
|||
} else {
|
||||
binding.chipGroup.hide()
|
||||
}
|
||||
|
||||
if (tab.id in arrayOf(HOME, LOCAL, FEDERATED, LIST)) {
|
||||
binding.switchStreaming.show()
|
||||
|
||||
binding.switchStreaming.isChecked = tab.enableStreaming
|
||||
binding.switchStreaming.setOnCheckedChangeListener { _, isChecked ->
|
||||
listener.onStreamingChanged(tab, holder.bindingAdapterPosition, isChecked)
|
||||
binding.switchStreaming.setOnCheckedChangeListener(null)
|
||||
}
|
||||
} else {
|
||||
binding.switchStreaming.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,4 +25,4 @@ data class DomainMuteEvent(val instance: String) : Event
|
|||
data class AnnouncementReadEvent(val announcementId: String) : Event
|
||||
data class PinEvent(val statusId: String, val pinned: Boolean) : Event
|
||||
data class QuickReplyEvent(val status: Status) : Event
|
||||
data class StreamUpdateEvent(val status: Status, val subscription: Subscription) : Event
|
||||
data class StreamUpdateEvent(val status: Status, val subscription: Subscription, val streamId: Int) : Event
|
||||
|
|
|
@ -82,7 +82,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
|||
import io.reactivex.rxjava3.core.Observable
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import net.accelf.yuito.streaming.StreamingManager
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
@ -103,9 +102,6 @@ class TimelineFragment :
|
|||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
@Inject
|
||||
lateinit var streamingManager: StreamingManager
|
||||
|
||||
private val viewModel: TimelineViewModel by unsafeLazy {
|
||||
if (kind == TimelineViewModel.Kind.HOME) {
|
||||
ViewModelProvider(this, viewModelFactory)[CachedTimelineViewModel::class.java]
|
||||
|
@ -180,10 +176,8 @@ class TimelineFragment :
|
|||
kind,
|
||||
id,
|
||||
tags,
|
||||
arguments.getBoolean(ARG_ENABLE_STREAMING),
|
||||
)
|
||||
if (arguments.getBoolean(ARG_ENABLE_STREAMING)) {
|
||||
setStreamingEnabled(true)
|
||||
}
|
||||
|
||||
isSwipeToRefreshEnabled = arguments.getBoolean(ARG_ENABLE_SWIPE_TO_REFRESH, true)
|
||||
|
||||
|
@ -428,23 +422,6 @@ class TimelineFragment :
|
|||
binding.recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
viewModel.isFirstOfStreaming = true
|
||||
}
|
||||
|
||||
fun setStreamingEnabled(to: Boolean) {
|
||||
viewModel.isStreamingEnabled = to
|
||||
|
||||
if (to) {
|
||||
streamingManager.subscribe(viewModel.subscription)
|
||||
viewModel.isFirstOfStreaming = true
|
||||
} else {
|
||||
streamingManager.unsubscribe(viewModel.subscription)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRefresh() {
|
||||
binding.statusView.hide()
|
||||
|
||||
|
|
|
@ -283,15 +283,15 @@ class CachedTimelineViewModel @Inject constructor(
|
|||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
override fun handleStreamUpdateEvent(status: Status) {
|
||||
override fun handleStreamUpdateEvent(status: Status, streamId: Int) {
|
||||
viewModelScope.launch {
|
||||
val timelineDao = db.timelineDao()
|
||||
val activeAccount = accountManager.activeAccount!!
|
||||
|
||||
db.withTransaction {
|
||||
if (isFirstOfStreaming) {
|
||||
if (streamId != currentStreamId) {
|
||||
timelineDao.insertStatus(Placeholder(status.id, loading = false).toEntity(activeAccount.id))
|
||||
isFirstOfStreaming = false
|
||||
currentStreamId = streamId
|
||||
return@withTransaction
|
||||
}
|
||||
|
||||
|
|
|
@ -243,13 +243,13 @@ class NetworkTimelineViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun handleStreamUpdateEvent(status: Status) {
|
||||
override fun handleStreamUpdateEvent(status: Status, streamId: Int) {
|
||||
viewModelScope.launch {
|
||||
val activeAccount = accountManager.activeAccount!!
|
||||
|
||||
if (isFirstOfStreaming) {
|
||||
if (streamId != currentStreamId) {
|
||||
statusData.add(0, StatusViewData.Placeholder(status.id, isLoading = false))
|
||||
isFirstOfStreaming = false
|
||||
currentStreamId = streamId
|
||||
} else {
|
||||
statusData.add(
|
||||
0,
|
||||
|
|
|
@ -73,6 +73,7 @@ abstract class TimelineViewModel(
|
|||
private set
|
||||
var tags: List<String> = emptyList()
|
||||
private set
|
||||
private var isStreamingEnabled = false
|
||||
|
||||
protected var alwaysShowSensitiveMedia = false
|
||||
private var alwaysOpenSpoilers = false
|
||||
|
@ -97,7 +98,7 @@ abstract class TimelineViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
var isFirstOfStreaming = false
|
||||
var currentStreamId: Int = 0
|
||||
val subscription by lazy {
|
||||
when (kind) {
|
||||
Kind.HOME -> Subscription(StreamType.USER)
|
||||
|
@ -115,16 +116,17 @@ abstract class TimelineViewModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
var isStreamingEnabled = false
|
||||
|
||||
fun init(
|
||||
kind: Kind,
|
||||
id: String?,
|
||||
tags: List<String>,
|
||||
isStreamingEnabled: Boolean,
|
||||
) {
|
||||
this.kind = kind
|
||||
this.id = id
|
||||
this.tags = tags
|
||||
this.isStreamingEnabled = isStreamingEnabled
|
||||
filterModel.kind = kind.toFilterKind()
|
||||
|
||||
if (kind == Kind.HOME) {
|
||||
|
@ -219,7 +221,7 @@ abstract class TimelineViewModel(
|
|||
|
||||
abstract fun handlePinEvent(pinEvent: PinEvent)
|
||||
|
||||
abstract fun handleStreamUpdateEvent(status: Status)
|
||||
abstract fun handleStreamUpdateEvent(status: Status, streamId: Int)
|
||||
|
||||
abstract fun fullReload()
|
||||
|
||||
|
@ -286,7 +288,7 @@ abstract class TimelineViewModel(
|
|||
is PinEvent -> handlePinEvent(event)
|
||||
is StreamUpdateEvent -> {
|
||||
if (isStreamingEnabled && event.subscription == subscription) {
|
||||
handleStreamUpdateEvent(event.status)
|
||||
handleStreamUpdateEvent(event.status, event.streamId)
|
||||
}
|
||||
}
|
||||
is MuteConversationEvent -> fullReload()
|
||||
|
|
|
@ -56,15 +56,12 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesBaseActivity(): BaseActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesMainActivity(): MainActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesAccountActivity(): AccountActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesListsActivity(): ListsActivity
|
||||
|
||||
|
@ -74,19 +71,15 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesEditProfileActivity(): EditProfileActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesAccountListActivity(): AccountListActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesViewThreadActivity(): ViewThreadActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesStatusListActivity(): StatusListActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesSearchActivity(): SearchActivity
|
||||
|
||||
|
@ -99,7 +92,6 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesLoginWebViewActivity(): LoginWebViewActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesPreferencesActivity(): PreferencesActivity
|
||||
|
||||
|
@ -118,11 +110,9 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesFollowedTagsActivity(): FollowedTagsActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesReportActivity(): ReportActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesInstanceListActivity(): InstanceListActivity
|
||||
|
||||
|
@ -138,7 +128,6 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesSplashActivity(): SplashActivity
|
||||
|
||||
@ActivityScope
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesTrendingActivity(): TrendingActivity
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package com.keylesspalace.tusky.di
|
||||
|
||||
import javax.inject.Scope
|
||||
|
||||
@Scope
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ActivityScope
|
|
@ -10,79 +10,36 @@ import com.keylesspalace.tusky.entity.Filter
|
|||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import net.accelf.yuito.streaming.SubscribeRequest.RequestType.SUBSCRIBE
|
||||
import net.accelf.yuito.streaming.SubscribeRequest.RequestType.UNSUBSCRIBE
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.WebSocket
|
||||
import okhttp3.WebSocketListener
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class MastodonStream(
|
||||
parent: Job,
|
||||
coroutineScope: CoroutineScope,
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val gson: Gson,
|
||||
private val eventHub: EventHub,
|
||||
private val onStatusChange: (Boolean) -> Unit,
|
||||
) : WebSocketListener(), CoroutineScope {
|
||||
) : WebSocketListener(), CoroutineScope by coroutineScope {
|
||||
|
||||
private var webSocket: WebSocket? = null
|
||||
private val subscribing = mutableSetOf<Subscription>()
|
||||
|
||||
private val job = SupervisorJob(parent).apply {
|
||||
invokeOnCompletion {
|
||||
webSocket?.let {
|
||||
closeSocket()
|
||||
}
|
||||
}
|
||||
}
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job
|
||||
|
||||
fun subscribe(subscription: Subscription) {
|
||||
if (!subscribing.add(subscription)) {
|
||||
// already subscribed
|
||||
return
|
||||
}
|
||||
|
||||
if (webSocket == null) {
|
||||
openSocket()
|
||||
}
|
||||
|
||||
send(SubscribeRequest.fromSubscription(SUBSCRIBE, subscription))
|
||||
Log.d(TAG, "Subscribed $subscription")
|
||||
}
|
||||
|
||||
fun unsubscribe(subscription: Subscription) {
|
||||
if (!subscribing.remove(subscription)) {
|
||||
// already unsubscribed
|
||||
return
|
||||
}
|
||||
|
||||
if (subscribing.isEmpty()) {
|
||||
closeSocket()
|
||||
return
|
||||
}
|
||||
|
||||
send(SubscribeRequest.fromSubscription(UNSUBSCRIBE, subscription))
|
||||
Log.d(TAG, "Unsubscribed $subscription")
|
||||
}
|
||||
|
||||
private fun openSocket() {
|
||||
fun openSocket(subscriptions: Set<Subscription>) {
|
||||
val request = Request.Builder().url(STREAMING_URL).build()
|
||||
webSocket = okHttpClient.newWebSocket(request, this)
|
||||
onStatusChange(true)
|
||||
subscriptions.forEach {
|
||||
send(SubscribeRequest.fromSubscription(SUBSCRIBE, it))
|
||||
Log.d(TAG, "Subscribed $it")
|
||||
}
|
||||
}
|
||||
|
||||
private fun closeSocket() {
|
||||
fun closeSocket() {
|
||||
webSocket!!.close(1000, null)
|
||||
webSocket = null
|
||||
onStatusChange(false)
|
||||
}
|
||||
|
||||
private fun send(subscribeRequest: SubscribeRequest) {
|
||||
|
@ -100,7 +57,7 @@ class MastodonStream(
|
|||
StreamEvent.EventType.UPDATE -> {
|
||||
val status = gson.fromJson(payload, Status::class.java)
|
||||
launch {
|
||||
eventHub.dispatch(StreamUpdateEvent(status, Subscription.fromStreamList(event.stream)))
|
||||
eventHub.dispatch(StreamUpdateEvent(status, Subscription.fromStreamList(event.stream), this.hashCode()))
|
||||
}
|
||||
}
|
||||
StreamEvent.EventType.DELETE -> launch {
|
||||
|
|
|
@ -1,30 +1,39 @@
|
|||
package net.accelf.yuito.streaming
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.gson.Gson
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.di.ActivityScope
|
||||
import kotlinx.coroutines.Job
|
||||
import okhttp3.OkHttpClient
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ActivityScope
|
||||
@Singleton
|
||||
class StreamingManager @Inject constructor(
|
||||
private val eventHub: EventHub,
|
||||
private val okHttpClient: OkHttpClient,
|
||||
private val gson: Gson,
|
||||
) {
|
||||
|
||||
private lateinit var stream: MastodonStream
|
||||
private var stream: MastodonStream? = null
|
||||
|
||||
fun setup(parent: Job, onStatusChange: (Boolean) -> Unit) {
|
||||
stream = MastodonStream(parent, okHttpClient, gson, eventHub, onStatusChange)
|
||||
}
|
||||
|
||||
fun subscribe(subscription: Subscription) {
|
||||
stream.subscribe(subscription)
|
||||
}
|
||||
|
||||
fun unsubscribe(subscription: Subscription) {
|
||||
stream.unsubscribe(subscription)
|
||||
fun setup(owner: LifecycleOwner, subscriptions: Set<Subscription>, onStatusChange: (Boolean) -> Unit) {
|
||||
owner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_RESUME -> {
|
||||
stream = MastodonStream(owner.lifecycleScope, okHttpClient, gson, eventHub)
|
||||
stream?.openSocket(subscriptions)
|
||||
onStatusChange(true)
|
||||
}
|
||||
Lifecycle.Event.ON_PAUSE -> {
|
||||
stream?.closeSocket()
|
||||
stream = null
|
||||
onStatusChange(false)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
app:layout_constraintBottom_toTopOf="@id/switchStreaming">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/actionChip"
|
||||
|
@ -73,4 +73,15 @@
|
|||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switchStreaming"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:text="@string/action_tab_toggle_streaming"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -15,11 +15,6 @@
|
|||
android:title="@string/action_tab_edit_list"
|
||||
android:visible="false" />
|
||||
|
||||
<item android:id="@+id/tabToggleStreaming"
|
||||
android:icon="@drawable/ic_check_24dp"
|
||||
android:title="@string/action_tab_toggle_streaming"
|
||||
android:visible="false" />
|
||||
|
||||
<item android:id="@+id/tabToggleNotificationsFilter"
|
||||
android:icon="@drawable/ic_notifications_24dp"
|
||||
android:title="@string/action_tab_toggle_notifications_filter"
|
||||
|
|
Loading…
Reference in New Issue