Merge pull request #5660 from vector-im/feature/ons/live_location_banner_visibility

Show a banner in timeline while location sharing service is running
This commit is contained in:
Onuray Sahin 2022-04-04 12:55:50 +03:00 committed by GitHub
commit ff34ed9eb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 3 deletions

1
changelog.d/5660.feature Normal file
View file

@ -0,0 +1 @@
Show a banner in timeline while location sharing service is running

View file

@ -82,4 +82,6 @@ sealed class RoomDetailViewEvents : VectorViewEvents {
data class StartChatEffect(val type: ChatEffect) : RoomDetailViewEvents()
object StopChatEffects : RoomDetailViewEvents()
object RoomReplacementStarted : RoomDetailViewEvents()
data class ChangeLocationIndicator(val isVisible: Boolean) : RoomDetailViewEvents()
}

View file

@ -482,6 +482,7 @@ class TimelineFragment @Inject constructor(
RoomDetailViewEvents.StopChatEffects -> handleStopChatEffects()
is RoomDetailViewEvents.DisplayAndAcceptCall -> acceptIncomingCall(it)
RoomDetailViewEvents.RoomReplacementStarted -> handleRoomReplacement()
is RoomDetailViewEvents.ChangeLocationIndicator -> handleChangeLocationIndicator(it)
}
}
@ -616,6 +617,10 @@ class TimelineFragment @Inject constructor(
)
}
private fun handleChangeLocationIndicator(event: RoomDetailViewEvents.ChangeLocationIndicator) {
views.locationLiveStatusIndicator.isVisible = event.isVisible
}
private fun displayErrorMessage(error: RoomDetailViewEvents.Failure) {
if (error.showInDialog) displayErrorDialog(error.throwable) else showErrorInSnackbar(error.throwable)
}

View file

@ -52,6 +52,7 @@ import im.vector.app.features.home.room.detail.sticker.StickerPickerActionHandle
import im.vector.app.features.home.room.detail.timeline.factory.TimelineFactory
import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever
import im.vector.app.features.home.room.typing.TypingHelper
import im.vector.app.features.location.LocationSharingServiceConnection
import im.vector.app.features.notifications.NotificationDrawerManager
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
import im.vector.app.features.session.coroutineScope
@ -124,10 +125,11 @@ class TimelineViewModel @AssistedInject constructor(
private val activeConferenceHolder: JitsiActiveConferenceHolder,
private val decryptionFailureTracker: DecryptionFailureTracker,
private val notificationDrawerManager: NotificationDrawerManager,
private val locationSharingServiceConnection: LocationSharingServiceConnection,
timelineFactory: TimelineFactory,
appStateHandler: AppStateHandler
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState),
Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener {
Timeline.Listener, ChatEffectManager.Delegate, CallProtocolsChecker.Listener, LocationSharingServiceConnection.Callback {
private val room = session.getRoom(initialState.roomId)!!
private val eventId = initialState.eventId
@ -219,6 +221,9 @@ class TimelineViewModel @AssistedInject constructor(
// Threads
initThreads()
// Observe location service lifecycle to be able to warn the user
locationSharingServiceConnection.bind(this)
}
/**
@ -1218,6 +1223,16 @@ class TimelineViewModel @AssistedInject constructor(
_viewEvents.post(RoomDetailViewEvents.OnNewTimelineEvents(eventIds))
}
override fun onLocationServiceRunning() {
_viewEvents.post(RoomDetailViewEvents.ChangeLocationIndicator(isVisible = true))
}
override fun onLocationServiceStopped() {
_viewEvents.post(RoomDetailViewEvents.ChangeLocationIndicator(isVisible = false))
// Bind again in case user decides to share live location without leaving the room
locationSharingServiceConnection.bind(this)
}
override fun onCleared() {
timeline.dispose()
timeline.removeAllListeners()
@ -1231,6 +1246,7 @@ class TimelineViewModel @AssistedInject constructor(
// we should also mark it as read here, for the scenario that the user
// is already in the thread timeline
markThreadTimelineAsReadLocal()
locationSharingServiceConnection.unbind()
super.onCleared()
}
}

View file

@ -17,6 +17,7 @@
package im.vector.app.features.location
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.os.Parcelable
import dagger.hilt.android.AndroidEntryPoint
@ -52,6 +53,8 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var clock: Clock
private val binder = LocalBinder()
private var roomArgsList = mutableListOf<RoomArgs>()
private var timers = mutableListOf<Timer>()
@ -160,8 +163,12 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
destroyMe()
}
override fun onBind(intent: Intent?): IBinder? {
return null
override fun onBind(intent: Intent?): IBinder {
return binder
}
inner class LocalBinder : Binder() {
fun getService(): LocationSharingService = this@LocationSharingService
}
companion object {

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.location
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import javax.inject.Inject
class LocationSharingServiceConnection @Inject constructor(
private val context: Context
) : ServiceConnection {
interface Callback {
fun onLocationServiceRunning()
fun onLocationServiceStopped()
}
private var callback: Callback? = null
private var isBound = false
fun bind(callback: Callback) {
this.callback = callback
if (isBound) {
callback.onLocationServiceRunning()
} else {
Intent(context, LocationSharingService::class.java).also { intent ->
context.bindService(intent, this, 0)
}
}
}
fun unbind() {
callback = null
}
override fun onServiceConnected(className: ComponentName, binder: IBinder) {
isBound = true
callback?.onLocationServiceRunning()
}
override fun onServiceDisconnected(className: ComponentName) {
isBound = false
callback?.onLocationServiceStopped()
}
}