Skip to content
Snippets Groups Projects
Verified Commit 53a762da authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

fix: improve post-connect experience

parent 40b06769
No related branches found
No related tags found
No related merge requests found
Pipeline #3000 passed
...@@ -28,7 +28,6 @@ import android.content.SharedPreferences ...@@ -28,7 +28,6 @@ import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.PersistableBundle
import android.system.ErrnoException import android.system.ErrnoException
import android.text.Html import android.text.Html
import android.view.ActionMode import android.view.ActionMode
...@@ -42,6 +41,7 @@ import androidx.appcompat.app.ActionBarDrawerToggle ...@@ -42,6 +41,7 @@ import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
...@@ -94,6 +94,7 @@ import de.kuschku.quasseldroid.util.backport.OsConstants ...@@ -94,6 +94,7 @@ import de.kuschku.quasseldroid.util.backport.OsConstants
import de.kuschku.quasseldroid.util.deceptive_networks.DeceptiveNetworkDialog import de.kuschku.quasseldroid.util.deceptive_networks.DeceptiveNetworkDialog
import de.kuschku.quasseldroid.util.helper.* import de.kuschku.quasseldroid.util.helper.*
import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer
import de.kuschku.quasseldroid.util.missingfeatures.MissingFeature
import de.kuschku.quasseldroid.util.missingfeatures.MissingFeaturesDialog import de.kuschku.quasseldroid.util.missingfeatures.MissingFeaturesDialog
import de.kuschku.quasseldroid.util.missingfeatures.RequiredFeatures import de.kuschku.quasseldroid.util.missingfeatures.RequiredFeatures
import de.kuschku.quasseldroid.util.service.ServiceBoundActivity import de.kuschku.quasseldroid.util.service.ServiceBoundActivity
...@@ -106,6 +107,9 @@ import de.kuschku.quasseldroid.viewmodel.ChatViewModel ...@@ -106,6 +107,9 @@ import de.kuschku.quasseldroid.viewmodel.ChatViewModel
import de.kuschku.quasseldroid.viewmodel.data.BufferData import de.kuschku.quasseldroid.viewmodel.data.BufferData
import de.kuschku.quasseldroid.viewmodel.helper.ChatViewModelHelper import de.kuschku.quasseldroid.viewmodel.helper.ChatViewModelHelper
import io.reactivex.BackpressureStrategy import io.reactivex.BackpressureStrategy
import io.reactivex.Observable
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.PublishSubject
import org.threeten.bp.Instant import org.threeten.bp.Instant
import org.threeten.bp.ZoneId import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter import org.threeten.bp.format.DateTimeFormatter
...@@ -162,6 +166,8 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -162,6 +166,8 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
private var restoredDrawerState = false private var restoredDrawerState = false
private val permissionGranted = BehaviorSubject.createDefault(false)
fun processIntent(intent: Intent) { fun processIntent(intent: Intent) {
when { when {
intent.type == "text/plain" -> { intent.type == "text/plain" -> {
...@@ -309,6 +315,20 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -309,6 +315,20 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissionGranted.onNext(
PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
applicationContext,
Manifest.permission.POST_NOTIFICATIONS
)
)
} else {
permissionGranted.onNext(true)
}
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
permissionGranted.onNext(isGranted)
}
chatlineFragment = chatlineFragment =
supportFragmentManager.findFragmentById(R.id.fragment_chatline) as? ChatlineFragment supportFragmentManager.findFragmentById(R.id.fragment_chatline) as? ChatlineFragment
...@@ -782,34 +802,46 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -782,34 +802,46 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
} }
}) })
// After initial connect, open the drawer val isConnected: Observable<Boolean> = modelHelper.connectionProgress.map { (state, _, _) ->
modelHelper.connectionProgress state == ConnectionState.CONNECTED
.filter { (it, _, _) -> it == ConnectionState.CONNECTED } }.filter { it }
.firstElement()
.toLiveData() val missingIdentity: Observable<Boolean> = modelHelper.connectedSession.map { session ->
.observe(this, Observer { session.orNull()?.identities.isNullOrEmpty()
if (connectedAccount != accountId) {
if (resources.getBoolean(R.bool.buffer_drawer_exists) &&
chatViewModel.bufferId.safeValue == BufferId.MAX_VALUE &&
!restoredDrawerState
) {
binding.drawerLayout.openDrawer(GravityCompat.START)
}
connectedAccount = accountId
modelHelper.connectedSession.value?.orNull()?.let { session ->
if (session.identities.isEmpty()) {
UserSetupActivity.launch(this)
} }
val missingFeatures = RequiredFeatures.features.filter {
val missingFeatures: Observable<List<MissingFeature>> =
modelHelper.connectedSession.mapMap { session ->
RequiredFeatures.features.filter {
it.feature !in session.features.core.enabledFeatures it.feature !in session.features.core.enabledFeatures
} }
if (missingFeatures.isNotEmpty()) { }.mapOrElse(emptyList())
val postConnectionState = combineLatest(
isConnected,
missingIdentity,
missingFeatures,
permissionGranted
).map { (connected, missingIdentity, missingFeatures, permissionGranted) ->
when {
!connected -> PostConnectionState.Connecting
missingIdentity -> PostConnectionState.SetupIdentity
missingFeatures.isNotEmpty() -> PostConnectionState.MissingFeatures(missingFeatures)
!permissionGranted -> PostConnectionState.RequestingPermissions
else -> PostConnectionState.Done
}
}
postConnectionState.toLiveData().observe(this) { state ->
if (state == PostConnectionState.SetupIdentity) {
UserSetupActivity.launch(this)
} else if (state is PostConnectionState.MissingFeatures) {
runInBackground { runInBackground {
val accounts = accountDatabase.accounts() val accounts = accountDatabase.accounts()
val account = accounts.findById(accountId) val account = accounts.findById(accountId)
if (account?.acceptedMissingFeatures == false) { if (account?.acceptedMissingFeatures == false) {
val dialog = MissingFeaturesDialog.Builder(this) val dialog = MissingFeaturesDialog.Builder(this)
.missingFeatures(missingFeatures) .missingFeatures(state.features)
.positiveListener(MaterialDialog.SingleButtonCallback { _, _ -> .positiveListener(MaterialDialog.SingleButtonCallback { _, _ ->
runInBackground { runInBackground {
accounts.save(account.copy(acceptedMissingFeatures = true)) accounts.save(account.copy(acceptedMissingFeatures = true))
...@@ -820,10 +852,32 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -820,10 +852,32 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
} }
} }
} }
} else if (state == PostConnectionState.RequestingPermissions &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
) {
if (ActivityCompat.checkSelfPermission(
applicationContext,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
1
)
}
} else {
if (connectedAccount != accountId) {
if (resources.getBoolean(R.bool.buffer_drawer_exists) &&
chatViewModel.bufferId.safeValue == BufferId.MAX_VALUE &&
!restoredDrawerState
) {
binding.drawerLayout.openDrawer(GravityCompat.START)
}
connectedAccount = accountId
} }
} }
} }
})
binding.layoutMain.connectionStatus.setOnClickListener { binding.layoutMain.connectionStatus.setOnClickListener {
if (modelHelper.connectionProgress.value?.first == ConnectionState.CONNECTED if (modelHelper.connectionProgress.value?.first == ConnectionState.CONNECTED
...@@ -950,28 +1004,6 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -950,28 +1004,6 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
launch(this, bufferId = info.bufferId) launch(this, bufferId = info.bufferId)
} }
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
if (modelHelper.connectionProgress.value?.first == ConnectionState.CONNECTED) {
notificationBackend.showConnectedNotifications()
}
}
}
if (ActivityCompat.checkSelfPermission(
applicationContext,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
1
)
}
}
} }
override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {
...@@ -1316,4 +1348,12 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -1316,4 +1348,12 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
} }
} }
} }
sealed class PostConnectionState {
object Connecting : PostConnectionState()
object SetupIdentity : PostConnectionState()
data class MissingFeatures(val features: List<MissingFeature>) : PostConnectionState()
object RequestingPermissions : PostConnectionState()
object Done : PostConnectionState()
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment