diff --git a/app/src/main/java/io/xxlabs/messenger/search/FactSearchFragment.kt b/app/src/main/java/io/xxlabs/messenger/search/FactSearchFragment.kt index 2a2f1255dd3b144ead0f4f0cd7fd58f840c04ef7..6c4deddf4662f70dcafbc1853bec1cd56b400f55 100644 --- a/app/src/main/java/io/xxlabs/messenger/search/FactSearchFragment.kt +++ b/app/src/main/java/io/xxlabs/messenger/search/FactSearchFragment.kt @@ -121,6 +121,16 @@ class UsernameSearchFragment : FactSearchFragment() { } override fun getSearchTabUi(): FactSearchUi = searchViewModel.usernameSearchUi + + override fun onResume() { + super.onResume() + searchViewModel.invitationFrom.observe(viewLifecycleOwner) { username -> + username?.let { + onSearchClicked(it) + searchViewModel.onInvitationHandled() + } + } + } } class EmailSearchFragment : FactSearchFragment() { diff --git a/app/src/main/java/io/xxlabs/messenger/search/UserSearchFragment.kt b/app/src/main/java/io/xxlabs/messenger/search/UserSearchFragment.kt index eaebf5cda6a53a5a8630c6127f215de2aba2d8be..02beb4e7d823fdc168eda107d2d3b3edbaa37e69 100644 --- a/app/src/main/java/io/xxlabs/messenger/search/UserSearchFragment.kt +++ b/app/src/main/java/io/xxlabs/messenger/search/UserSearchFragment.kt @@ -52,6 +52,9 @@ class UserSearchFragment : RequestsFragment() { override val navController: NavController by lazy { findNavController() } + private val invitationUsername: String? by lazy { + UserSearchFragmentArgs.fromBundle(requireArguments()).username + } override fun onAttach(context: Context) { super.onAttach(context) @@ -161,9 +164,16 @@ class UserSearchFragment : RequestsFragment() { override fun onStart() { super.onStart() + handleInvitation() observeUi() } + private fun handleInvitation() { + invitationUsername?.let { + searchViewModel.onInvitationReceived(it) + } + } + private fun observeUi() { searchViewModel.udSearchUi.observe(viewLifecycleOwner) { state -> binding.ui = state diff --git a/app/src/main/java/io/xxlabs/messenger/search/UserSearchViewModel.kt b/app/src/main/java/io/xxlabs/messenger/search/UserSearchViewModel.kt index e5f40eaaf6edbe38ac692acc677c95f1ed6e669c..0937eb9b9d834c3b0dadadae79641eddf064aec4 100644 --- a/app/src/main/java/io/xxlabs/messenger/search/UserSearchViewModel.kt +++ b/app/src/main/java/io/xxlabs/messenger/search/UserSearchViewModel.kt @@ -206,6 +206,9 @@ class UserSearchViewModel @Inject constructor( private var searchJob: Job? = null + val invitationFrom: LiveData<String?> by ::_invitationFrom + private val _invitationFrom = MutableLiveData<String?>(null) + init { showNewUserPopups() } @@ -271,6 +274,14 @@ class UserSearchViewModel @Inject constructor( repo.enableDummyTraffic(enabled) } + fun onInvitationReceived(username: String) { + _invitationFrom.value = username + } + + fun onInvitationHandled() { + _invitationFrom.value = null + } + suspend fun onUsernameSearch(username: String?): Flow<List<RequestItem>> { _usernameResults.value = listOf() val factQuery = FactQuery.UsernameQuery(username) diff --git a/app/src/main/java/io/xxlabs/messenger/ui/intro/splash/SplashScreenPlaceholderActivity.kt b/app/src/main/java/io/xxlabs/messenger/ui/intro/splash/SplashScreenPlaceholderActivity.kt index 53913e0c92deaa41eaebe66a5e21fd8612dfcf6c..68bc86051046701fa28bb73cc400d609aed2159d 100644 --- a/app/src/main/java/io/xxlabs/messenger/ui/intro/splash/SplashScreenPlaceholderActivity.kt +++ b/app/src/main/java/io/xxlabs/messenger/ui/intro/splash/SplashScreenPlaceholderActivity.kt @@ -19,7 +19,9 @@ import io.xxlabs.messenger.support.isMockVersion import io.xxlabs.messenger.support.util.Utils import io.xxlabs.messenger.ui.base.BaseInjectorActivity import io.xxlabs.messenger.ui.main.MainActivity +import io.xxlabs.messenger.ui.main.MainActivity.Companion.INTENT_INVITATION import io.xxlabs.messenger.ui.main.MainActivity.Companion.INTENT_NOTIFICATION_CLICK +import timber.log.Timber import javax.inject.Inject class SplashScreenPlaceholderActivity : BaseInjectorActivity() { @@ -54,6 +56,26 @@ class SplashScreenPlaceholderActivity : BaseInjectorActivity() { } private fun handleIntent(intent: Intent) { + if (Intent.ACTION_VIEW == intent.action) { + // Implicit Intent from an invitation link + intent.data?.getQueryParameter("username")?.let { username -> + invitationIntent(username) + } + } else notificationIntent(intent) + } + + private fun invitationIntent(username: String) { + // Invitations can only be handled if the user has an account. + if (preferencesRepository.name.isNotEmpty()) { + val intent = Intent(this, MainActivity::class.java).apply { + putExtra(INTENT_INVITATION, username) + } + startActivity(intent) + finish() + } + } + + private fun notificationIntent(intent: Intent) { // Pass this intent on to MainActivity. mainIntent = intent.getBundleExtra(INTENT_NOTIFICATION_CLICK)?.let { Intent( diff --git a/app/src/main/java/io/xxlabs/messenger/ui/main/MainActivity.kt b/app/src/main/java/io/xxlabs/messenger/ui/main/MainActivity.kt index 01678bd8a3d751d765c9ca93e5c9b48bdaa4d0d8..66267999263db5e54e1eb3550a76fc1bb6931956 100755 --- a/app/src/main/java/io/xxlabs/messenger/ui/main/MainActivity.kt +++ b/app/src/main/java/io/xxlabs/messenger/ui/main/MainActivity.kt @@ -19,6 +19,7 @@ import androidx.lifecycle.* import androidx.lifecycle.Observer import androidx.navigation.NavController import androidx.navigation.Navigation +import androidx.navigation.findNavController import androidx.navigation.ui.onNavDestinationSelected import com.bumptech.glide.Glide import com.google.android.material.shape.CornerFamily @@ -164,8 +165,23 @@ class MainActivity : MediaProviderActivity(), SnackBarActivity, CustomToastActiv private fun handleIntent(intent: Intent) { intent.getBundleExtra(INTENT_NOTIFICATION_CLICK)?.let { + // PendingIntent from notifications handleNotification(it) + return } + + intent.getStringExtra(INTENT_INVITATION)?.let { username -> + // Implicit intent from an invitation link + invitationIntent(username) + return + } + } + + private fun invitationIntent(username: String) { + val userSearch = NavMainDirections.actionGlobalConnectionInvitation().apply { + this.username = username + } + mainNavController.navigateSafe(userSearch) } private fun handleNotification(bundle: Bundle) { @@ -811,6 +827,7 @@ class MainActivity : MediaProviderActivity(), SnackBarActivity, CustomToastActiv const val INTENT_PRIVATE_CHAT = "private_message" const val INTENT_GROUP_CHAT = "group_message" const val INTENT_REQUEST = "request" + const val INTENT_INVITATION = "invitation" private var activeInstances = 0 override fun activeInstancesCount(): Int { diff --git a/app/src/main/res/navigation/nav_main.xml b/app/src/main/res/navigation/nav_main.xml index 9953388f02e75a5d00c5d7fc4c878c425b4de5c6..b5e8db61fb5d600fffb25c7fa669dfd0c73cd4c4 100644 --- a/app/src/main/res/navigation/nav_main.xml +++ b/app/src/main/res/navigation/nav_main.xml @@ -320,6 +320,11 @@ app:exitAnim="@anim/slide_out_left" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" /> + <argument + android:name="username" + app:argType="string" + app:nullable="true" + android:defaultValue="@null" /> </fragment> <fragment @@ -354,6 +359,15 @@ android:label="UdProfileFragment" tools:layout="@layout/fragment_ud_profile" /> + <action + android:id="@+id/action_global_connection_invitation" + app:destination="@id/udPrivateSearchFragment" + app:enterAnim="@anim/slide_in_right" + app:exitAnim="@anim/slide_out_left" + app:popEnterAnim="@anim/slide_in_left" + app:popExitAnim="@anim/slide_out_right" /> + + <action android:id="@+id/action_global_contact_invitation" app:destination="@id/contactInvitationFragment"