-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update mobile connect flow and UI #1008
Changes from all commits
bb0708d
9508b28
53ae79c
dfa3603
73c075c
2e0da3b
67b9c8a
e6a77e1
d5536e9
e0aa548
3d1af37
b0c2275
6b03334
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
package com.babylon.wallet.android.data.dapp | ||
|
||
import com.babylon.wallet.android.domain.model.IncomingMessage.IncomingRequest | ||
import com.babylon.wallet.android.utils.AppEvent | ||
import com.babylon.wallet.android.utils.AppEventBus | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.asSharedFlow | ||
|
@@ -17,24 +19,31 @@ interface IncomingRequestRepository { | |
|
||
suspend fun add(incomingRequest: IncomingRequest) | ||
|
||
suspend fun addPriorityRequest(incomingRequest: IncomingRequest) | ||
|
||
suspend fun requestHandled(requestId: String) | ||
|
||
suspend fun pauseIncomingRequests() | ||
|
||
suspend fun resumeIncomingRequests() | ||
|
||
fun getUnauthorizedRequest(requestId: String): IncomingRequest.UnauthorizedRequest? | ||
|
||
fun getTransactionWriteRequest(requestId: String): IncomingRequest.TransactionRequest? | ||
|
||
fun getAuthorizedRequest(requestId: String): IncomingRequest.AuthorizedRequest? | ||
Comment on lines
-26
to
-30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice that you removed those 👍 |
||
fun getRequest(requestId: String): IncomingRequest? | ||
|
||
fun removeAll() | ||
|
||
fun getAmountOfRequests(): Int | ||
|
||
suspend fun requestDeferred(requestId: String) | ||
|
||
fun consumeBufferedRequest(): IncomingRequest? | ||
|
||
fun setBufferedRequest(request: IncomingRequest) | ||
} | ||
|
||
class IncomingRequestRepositoryImpl @Inject constructor() : IncomingRequestRepository { | ||
@Suppress("TooManyFunctions") | ||
class IncomingRequestRepositoryImpl @Inject constructor( | ||
private val appEventBus: AppEventBus | ||
) : IncomingRequestRepository { | ||
|
||
private val requestQueue = LinkedList<QueueItem>() | ||
|
||
|
@@ -52,6 +61,19 @@ class IncomingRequestRepositoryImpl @Inject constructor() : IncomingRequestRepos | |
|
||
private val mutex = Mutex() | ||
|
||
/** | ||
* Request that can come in via deep link before wallet is setup. | ||
*/ | ||
Comment on lines
+64
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👌🏽 |
||
private var bufferedRequest: IncomingRequest? = null | ||
|
||
override fun setBufferedRequest(request: IncomingRequest) { | ||
bufferedRequest = request | ||
} | ||
|
||
override fun consumeBufferedRequest(): IncomingRequest? { | ||
return bufferedRequest?.also { bufferedRequest = null } | ||
} | ||
|
||
override suspend fun add(incomingRequest: IncomingRequest) { | ||
mutex.withLock { | ||
val requestItem = QueueItem.RequestItem(incomingRequest) | ||
|
@@ -68,25 +90,71 @@ class IncomingRequestRepositoryImpl @Inject constructor() : IncomingRequestRepos | |
} | ||
} | ||
|
||
/** | ||
* There are two path of execution when using this method: | ||
* - there is high priority screen in the queue, so the incoming request is added below it, | ||
* taking priority over requests currently in the queue | ||
* - there is no high priority screen: request is added at the top of queue and if there other request currently handled, | ||
* we send a defer event for it so that UI can react and defer handling, without removing it from the queue. | ||
* Deferred request will be handled again when top priority one handling completes | ||
*/ | ||
override suspend fun addPriorityRequest(incomingRequest: IncomingRequest) { | ||
mutex.withLock { | ||
requestQueue.addFirst(QueueItem.RequestItem(incomingRequest)) | ||
val currentRequest = _currentRequestToHandle.value | ||
val handlingPaused = requestQueue.contains(QueueItem.HighPriorityScreen) | ||
when { | ||
currentRequest != null -> { | ||
Timber.d("🗂 Deferring request with id ${currentRequest.interactionId}") | ||
appEventBus.sendEvent(AppEvent.DeferRequestHandling(currentRequest.interactionId)) | ||
} | ||
|
||
else -> { | ||
if (!handlingPaused) { | ||
handleNextRequest() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
override suspend fun requestHandled(requestId: String) { | ||
mutex.withLock { | ||
requestQueue.removeIf { it is QueueItem.RequestItem && it.incomingRequest.interactionId.toString() == requestId } | ||
requestQueue.removeIf { it is QueueItem.RequestItem && it.incomingRequest.interactionId == requestId } | ||
clearCurrent(requestId) | ||
handleNextRequest() | ||
Timber.d("🗂 request $requestId handled so size of list is now: ${getAmountOfRequests()}") | ||
} | ||
} | ||
|
||
override suspend fun requestDeferred(requestId: String) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not actually deferred here? This is like a yield action right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is deferred, but this method works in tandem with |
||
mutex.withLock { | ||
clearCurrent(requestId) | ||
handleNextRequest() | ||
Timber.d("🗂 request $requestId handled so size of list is now: ${getAmountOfRequests()}") | ||
} | ||
} | ||
|
||
private suspend fun clearCurrent(requestId: String) { | ||
if (_currentRequestToHandle.value?.interactionId == requestId) { | ||
_currentRequestToHandle.emit(null) | ||
} | ||
} | ||
|
||
override suspend fun pauseIncomingRequests() { | ||
mutex.withLock { | ||
// If the queue knows about any high priority item, no need to add it again | ||
if (requestQueue.contains(QueueItem.HighPriorityScreen)) { | ||
return | ||
} | ||
|
||
// Put high priority item below any internal request | ||
val topQueueItem = requestQueue.peekFirst() | ||
if (topQueueItem is QueueItem.RequestItem && topQueueItem.incomingRequest.isInternal) { | ||
requestQueue.add(1, QueueItem.HighPriorityScreen) | ||
// Put high priority item below any internal request and mobile connect requests | ||
val index = requestQueue.indexOfFirst { | ||
val item = it as? QueueItem.RequestItem | ||
item != null && !item.incomingRequest.isInternal && !item.incomingRequest.isMobileConnectRequest | ||
} | ||
if (index != -1) { | ||
requestQueue.add(index, QueueItem.HighPriorityScreen) | ||
} else { | ||
requestQueue.addFirst(QueueItem.HighPriorityScreen) | ||
} | ||
|
@@ -104,37 +172,14 @@ class IncomingRequestRepositoryImpl @Inject constructor() : IncomingRequestRepos | |
} | ||
} | ||
|
||
override fun getUnauthorizedRequest(requestId: String): IncomingRequest.UnauthorizedRequest? { | ||
override fun getRequest(requestId: String): IncomingRequest? { | ||
val queueItem = requestQueue.find { | ||
it is QueueItem.RequestItem && it.incomingRequest.interactionId.toString() == requestId && | ||
it.incomingRequest is IncomingRequest.UnauthorizedRequest | ||
it is QueueItem.RequestItem && it.incomingRequest.interactionId == requestId | ||
} | ||
if (queueItem == null) { | ||
Timber.w("Unauthorized request with id $requestId is null") | ||
Timber.w("Request with id $requestId is null") | ||
} | ||
return (queueItem as? QueueItem.RequestItem)?.incomingRequest as? IncomingRequest.UnauthorizedRequest | ||
} | ||
|
||
override fun getTransactionWriteRequest(requestId: String): IncomingRequest.TransactionRequest? { | ||
val queueItem = requestQueue.find { | ||
it is QueueItem.RequestItem && it.incomingRequest.interactionId.toString() == requestId && | ||
it.incomingRequest is IncomingRequest.TransactionRequest | ||
} | ||
if (queueItem == null) { | ||
Timber.w("Transaction request with id $requestId is null") | ||
} | ||
return (queueItem as? QueueItem.RequestItem)?.incomingRequest as? IncomingRequest.TransactionRequest | ||
} | ||
|
||
override fun getAuthorizedRequest(requestId: String): IncomingRequest.AuthorizedRequest? { | ||
val queueItem = requestQueue.find { | ||
it is QueueItem.RequestItem && it.incomingRequest.interactionId.toString() == requestId && | ||
it.incomingRequest is IncomingRequest.AuthorizedRequest | ||
} | ||
if (queueItem == null) { | ||
Timber.w("Authorized request with id $requestId is null") | ||
} | ||
return (queueItem as? QueueItem.RequestItem)?.incomingRequest as? IncomingRequest.AuthorizedRequest | ||
return (queueItem as? QueueItem.RequestItem)?.incomingRequest | ||
} | ||
|
||
override fun removeAll() { | ||
|
@@ -149,14 +194,13 @@ class IncomingRequestRepositoryImpl @Inject constructor() : IncomingRequestRepos | |
// In order to emit an incoming request, the topmost item should be | ||
// a. An incoming request | ||
// b. It should not be the same as the one being handled already | ||
if (nextRequest is QueueItem.RequestItem && _currentRequestToHandle.value != nextRequest) { | ||
if (nextRequest is QueueItem.RequestItem && _currentRequestToHandle.value != nextRequest.incomingRequest) { | ||
_currentRequestToHandle.emit(nextRequest.incomingRequest) | ||
} | ||
} | ||
|
||
private sealed interface QueueItem { | ||
data object HighPriorityScreen : QueueItem | ||
|
||
data class RequestItem(val incomingRequest: IncomingRequest) : QueueItem | ||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice that you added this here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually can someone explain me what does this line do? Because I see it in the line 103, too.
Does it "clear" the intent with an empty bundle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it removes
data
from an intent, so deep link is not delivered 2nd time if you move app to background and open from recentThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the app is moved to background and re-opened from recent neither
onCreate
noronNewIntent
should get called in normal circumstances, unless the app task has been closed by the OS? Is that the case or there are simple repro steps for the issue that this line fixes? I'm really curious about what is happening.