Merge pull request #6655 from vector-im/feature/eric/app-layout-toolbar
New App Layout Toolbar
This commit is contained in:
		
						commit
						e2ed4b4ae1
					
				
							
								
								
									
										1
									
								
								changelog.d/6655.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								changelog.d/6655.feature
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Adds new app layout toolbar (feature flagged)
 | 
			
		||||
@ -0,0 +1,4 @@
 | 
			
		||||
<vector android:height="22dp" android:viewportHeight="22"
 | 
			
		||||
    android:viewportWidth="22" android:width="22dp" xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <path android:fillColor="#737D8C" android:fillType="evenOdd" android:pathData="M16.999,14.899C18.07,13.407 18.7,11.577 18.7,9.6C18.7,4.574 14.626,0.5 9.6,0.5C4.574,0.5 0.5,4.574 0.5,9.6C0.5,14.626 4.574,18.7 9.6,18.7C11.577,18.7 13.406,18.07 14.899,16.999C14.941,17.055 14.988,17.109 15.039,17.161L18.939,21.061C19.525,21.646 20.475,21.646 21.06,21.061C21.646,20.475 21.646,19.525 21.06,18.939L17.16,15.039C17.109,14.988 17.055,14.941 16.999,14.899ZM15.7,9.6C15.7,12.969 12.969,15.7 9.6,15.7C6.231,15.7 3.5,12.969 3.5,9.6C3.5,6.231 6.231,3.5 9.6,3.5C12.969,3.5 15.7,6.231 15.7,9.6Z"/>
 | 
			
		||||
</vector>
 | 
			
		||||
@ -71,4 +71,7 @@
 | 
			
		||||
    <dimen name="location_sharing_compass_button_margin_horizontal">8dp</dimen>
 | 
			
		||||
    <dimen name="location_sharing_live_duration_choice_margin_horizontal">12dp</dimen>
 | 
			
		||||
    <dimen name="location_sharing_live_duration_choice_margin_vertical">22dp</dimen>
 | 
			
		||||
 | 
			
		||||
    <!-- Material 3 -->
 | 
			
		||||
    <dimen name="collapsing_toolbar_layout_medium_size">112dp</dimen>
 | 
			
		||||
</resources>
 | 
			
		||||
 | 
			
		||||
@ -39,4 +39,14 @@
 | 
			
		||||
        <item name="android:textSize">12sp</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
    <!-- Material 3 -->
 | 
			
		||||
 | 
			
		||||
    <style name="Widget.Vector.Material3.Toolbar" parent="Widget.Material3.Toolbar" />
 | 
			
		||||
 | 
			
		||||
    <style name="Widget.Vector.Material3.CollapsingToolbar.Medium" parent="Widget.Material3.CollapsingToolbar.Medium">
 | 
			
		||||
        <item name="expandedTitleTextAppearance">@style/TextAppearance.Vector.Title.Medium</item>
 | 
			
		||||
        <item name="expandedTitleMarginBottom">20dp</item>
 | 
			
		||||
        <item name="collapsedTitleTextAppearance">@style/TextAppearance.Vector.Headline.Bold</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,15 @@
 | 
			
		||||
        <item name="android:textColor">?vctr_content_primary</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <style name="TextAppearance.Vector.Headline.Bold" parent="TextAppearance.MaterialComponents.Headline1">
 | 
			
		||||
        <item name="fontFamily">sans-serif</item>
 | 
			
		||||
        <item name="android:fontFamily">sans-serif</item>
 | 
			
		||||
        <item name="android:textStyle">bold</item>
 | 
			
		||||
        <item name="android:textSize">@dimen/text_size_headline</item>
 | 
			
		||||
        <item name="android:letterSpacing">0</item>
 | 
			
		||||
        <item name="android:textColor">?vctr_content_primary</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <style name="TextAppearance.Vector.Subtitle" parent="TextAppearance.MaterialComponents.Subtitle1">
 | 
			
		||||
        <item name="fontFamily">sans-serif</item>
 | 
			
		||||
        <item name="android:fontFamily">sans-serif</item>
 | 
			
		||||
 | 
			
		||||
@ -25,4 +25,4 @@
 | 
			
		||||
        <item name="android:backgroundDimEnabled">false</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
</resources>
 | 
			
		||||
 | 
			
		||||
@ -149,6 +149,9 @@
 | 
			
		||||
 | 
			
		||||
        <!-- Location sharing -->
 | 
			
		||||
        <item name="vctr_live_location">@color/vctr_live_location_dark</item>
 | 
			
		||||
 | 
			
		||||
        <!-- Material 3 -->
 | 
			
		||||
        <item name="collapsingToolbarLayoutMediumSize">@dimen/collapsing_toolbar_layout_medium_size</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />
 | 
			
		||||
 | 
			
		||||
@ -150,8 +150,12 @@
 | 
			
		||||
 | 
			
		||||
        <!-- Location sharing -->
 | 
			
		||||
        <item name="vctr_live_location">@color/vctr_live_location_light</item>
 | 
			
		||||
 | 
			
		||||
        <!-- Material 3 -->
 | 
			
		||||
        <item name="collapsingToolbarLayoutMediumSize">@dimen/collapsing_toolbar_layout_medium_size</item>
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
    <style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -57,6 +57,7 @@ import im.vector.app.features.discovery.change.SetIdentityServerFragment
 | 
			
		||||
import im.vector.app.features.home.HomeDetailFragment
 | 
			
		||||
import im.vector.app.features.home.HomeDrawerFragment
 | 
			
		||||
import im.vector.app.features.home.LoadingFragment
 | 
			
		||||
import im.vector.app.features.home.NewHomeDetailFragment
 | 
			
		||||
import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
 | 
			
		||||
import im.vector.app.features.home.room.detail.TimelineFragment
 | 
			
		||||
import im.vector.app.features.home.room.detail.search.SearchFragment
 | 
			
		||||
@ -258,6 +259,11 @@ interface FragmentModule {
 | 
			
		||||
    @FragmentKey(HomeDetailFragment::class)
 | 
			
		||||
    fun bindHomeDetailFragment(fragment: HomeDetailFragment): Fragment
 | 
			
		||||
 | 
			
		||||
    @Binds
 | 
			
		||||
    @IntoMap
 | 
			
		||||
    @FragmentKey(NewHomeDetailFragment::class)
 | 
			
		||||
    fun bindNewHomeDetailFragment(fragment: NewHomeDetailFragment): Fragment
 | 
			
		||||
 | 
			
		||||
    @Binds
 | 
			
		||||
    @IntoMap
 | 
			
		||||
    @FragmentKey(EmojiSearchResultFragment::class)
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ import im.vector.app.R
 | 
			
		||||
import im.vector.app.core.platform.SimpleTextWatcher
 | 
			
		||||
 | 
			
		||||
fun EditText.setupAsSearch(
 | 
			
		||||
        @DrawableRes searchIconRes: Int = R.drawable.ic_search,
 | 
			
		||||
        @DrawableRes searchIconRes: Int = R.drawable.ic_home_search,
 | 
			
		||||
        @DrawableRes clearIconRes: Int = R.drawable.ic_x_gray
 | 
			
		||||
) {
 | 
			
		||||
    addTextChangedListener(object : SimpleTextWatcher() {
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,7 @@ import androidx.viewbinding.ViewBinding
 | 
			
		||||
import com.airbnb.mvrx.MavericksView
 | 
			
		||||
import com.bumptech.glide.util.Util
 | 
			
		||||
import com.google.android.material.appbar.MaterialToolbar
 | 
			
		||||
import com.google.android.material.color.MaterialColors
 | 
			
		||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
 | 
			
		||||
import com.google.android.material.snackbar.Snackbar
 | 
			
		||||
import dagger.hilt.android.EntryPointAccessors
 | 
			
		||||
@ -72,6 +73,7 @@ import im.vector.app.core.utils.ToolbarConfig
 | 
			
		||||
import im.vector.app.core.utils.toast
 | 
			
		||||
import im.vector.app.features.MainActivity
 | 
			
		||||
import im.vector.app.features.MainActivityArgs
 | 
			
		||||
import im.vector.app.features.VectorFeatures
 | 
			
		||||
import im.vector.app.features.analytics.AnalyticsTracker
 | 
			
		||||
import im.vector.app.features.analytics.plan.MobileScreen
 | 
			
		||||
import im.vector.app.features.configuration.VectorConfiguration
 | 
			
		||||
@ -161,6 +163,9 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
 | 
			
		||||
    @Inject
 | 
			
		||||
    lateinit var fontScalePreferences: FontScalePreferences
 | 
			
		||||
 | 
			
		||||
    @Inject
 | 
			
		||||
    lateinit var vectorFeatures: VectorFeatures
 | 
			
		||||
 | 
			
		||||
    lateinit var navigator: Navigator
 | 
			
		||||
        private set
 | 
			
		||||
    private lateinit var fragmentFactory: FragmentFactory
 | 
			
		||||
@ -253,6 +258,14 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
 | 
			
		||||
 | 
			
		||||
        initUiAndData()
 | 
			
		||||
 | 
			
		||||
        if (vectorFeatures.isNewAppLayoutEnabled()) {
 | 
			
		||||
            tryOrNull { // Add to XML theme when feature flag is removed
 | 
			
		||||
                val toolbarBackground = MaterialColors.getColor(views.root, R.attr.vctr_toolbar_background)
 | 
			
		||||
                window.statusBarColor = toolbarBackground
 | 
			
		||||
                window.navigationBarColor = toolbarBackground
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val titleRes = getTitleRes()
 | 
			
		||||
        if (titleRes != -1) {
 | 
			
		||||
            supportActionBar?.let {
 | 
			
		||||
 | 
			
		||||
@ -159,7 +159,7 @@ fun startInstallFromSourceIntent(context: Context, activityResultLauncher: Activ
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun startSharePlainTextIntent(
 | 
			
		||||
        fragment: Fragment,
 | 
			
		||||
        context: Context,
 | 
			
		||||
        activityResultLauncher: ActivityResultLauncher<Intent>?,
 | 
			
		||||
        chooserTitle: String?,
 | 
			
		||||
        text: String,
 | 
			
		||||
@ -182,10 +182,10 @@ fun startSharePlainTextIntent(
 | 
			
		||||
        if (activityResultLauncher != null) {
 | 
			
		||||
            activityResultLauncher.launch(intent)
 | 
			
		||||
        } else {
 | 
			
		||||
            fragment.startActivity(intent)
 | 
			
		||||
            context.startActivity(intent)
 | 
			
		||||
        }
 | 
			
		||||
    } catch (activityNotFoundException: ActivityNotFoundException) {
 | 
			
		||||
        fragment.activity?.toast(R.string.error_no_external_application_found)
 | 
			
		||||
        context.toast(R.string.error_no_external_application_found)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -142,7 +142,7 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment<Fr
 | 
			
		||||
 | 
			
		||||
        dialog.findViewById<View>(R.id.keys_backup_setup_share)?.debouncedClicks {
 | 
			
		||||
            startSharePlainTextIntent(
 | 
			
		||||
                    fragment = this,
 | 
			
		||||
                    context = requireContext(),
 | 
			
		||||
                    activityResultLauncher = null,
 | 
			
		||||
                    chooserTitle = context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
 | 
			
		||||
                    text = recoveryKey,
 | 
			
		||||
 | 
			
		||||
@ -104,7 +104,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
 | 
			
		||||
                ?: return@withState
 | 
			
		||||
 | 
			
		||||
        startSharePlainTextIntent(
 | 
			
		||||
                this,
 | 
			
		||||
                requireContext(),
 | 
			
		||||
                copyStartForActivityResult,
 | 
			
		||||
                context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
 | 
			
		||||
                recoveryKey,
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,7 @@ import im.vector.app.core.platform.VectorBaseActivity
 | 
			
		||||
import im.vector.app.core.platform.VectorMenuProvider
 | 
			
		||||
import im.vector.app.core.pushers.PushersManager
 | 
			
		||||
import im.vector.app.core.pushers.UnifiedPushHelper
 | 
			
		||||
import im.vector.app.core.utils.startSharePlainTextIntent
 | 
			
		||||
import im.vector.app.databinding.ActivityHomeBinding
 | 
			
		||||
import im.vector.app.features.MainActivity
 | 
			
		||||
import im.vector.app.features.MainActivityArgs
 | 
			
		||||
@ -203,11 +204,16 @@ class HomeActivity :
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
 | 
			
		||||
        sharedActionViewModel = viewModelProvider[HomeSharedActionViewModel::class.java]
 | 
			
		||||
        views.drawerLayout.addDrawerListener(drawerListener)
 | 
			
		||||
        if (isFirstCreation()) {
 | 
			
		||||
            replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
 | 
			
		||||
            replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
 | 
			
		||||
            if (vectorFeatures.isNewAppLayoutEnabled()) {
 | 
			
		||||
                views.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
 | 
			
		||||
                replaceFragment(views.homeDetailFragmentContainer, NewHomeDetailFragment::class.java)
 | 
			
		||||
            } else {
 | 
			
		||||
                replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
 | 
			
		||||
                replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sharedActionViewModel
 | 
			
		||||
@ -552,7 +558,7 @@ class HomeActivity :
 | 
			
		||||
        nightlyProxy.onHomeResumed()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getMenuRes() = R.menu.home
 | 
			
		||||
    override fun getMenuRes() = if (vectorFeatures.isNewAppLayoutEnabled()) R.menu.menu_new_home else R.menu.menu_home
 | 
			
		||||
 | 
			
		||||
    override fun handlePrepareMenu(menu: Menu) {
 | 
			
		||||
        menu.findItem(R.id.menu_home_init_sync_legacy).isVisible = vectorPreferences.developerMode()
 | 
			
		||||
@ -591,10 +597,29 @@ class HomeActivity :
 | 
			
		||||
                navigator.openSettings(this)
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
            R.id.menu_home_invite_friends -> {
 | 
			
		||||
                launchInviteFriends()
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
            else -> false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun launchInviteFriends() {
 | 
			
		||||
        activeSessionHolder.getSafeActiveSession()?.permalinkService()?.createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink ->
 | 
			
		||||
            analyticsTracker.screen(MobileScreen(screenName = MobileScreen.ScreenName.InviteFriends))
 | 
			
		||||
            val text = getString(R.string.invite_friends_text, permalink)
 | 
			
		||||
 | 
			
		||||
            startSharePlainTextIntent(
 | 
			
		||||
                    context = this,
 | 
			
		||||
                    activityResultLauncher = null,
 | 
			
		||||
                    chooserTitle = getString(R.string.invite_friends),
 | 
			
		||||
                    text = text,
 | 
			
		||||
                    extraTitle = getString(R.string.invite_friends_rich_title)
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBackPressed() {
 | 
			
		||||
        if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) {
 | 
			
		||||
            views.drawerLayout.closeDrawer(GravityCompat.START)
 | 
			
		||||
 | 
			
		||||
@ -102,7 +102,7 @@ class HomeDrawerFragment @Inject constructor(
 | 
			
		||||
                val text = getString(R.string.invite_friends_text, permalink)
 | 
			
		||||
 | 
			
		||||
                startSharePlainTextIntent(
 | 
			
		||||
                        fragment = this,
 | 
			
		||||
                        context = requireContext(),
 | 
			
		||||
                        activityResultLauncher = null,
 | 
			
		||||
                        chooserTitle = getString(R.string.invite_friends),
 | 
			
		||||
                        text = text,
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,462 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2019 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.home
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.Menu
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.lifecycle.lifecycleScope
 | 
			
		||||
import com.airbnb.mvrx.activityViewModel
 | 
			
		||||
import com.airbnb.mvrx.fragmentViewModel
 | 
			
		||||
import com.airbnb.mvrx.withState
 | 
			
		||||
import com.google.android.material.badge.BadgeDrawable
 | 
			
		||||
import im.vector.app.AppStateHandler
 | 
			
		||||
import im.vector.app.R
 | 
			
		||||
import im.vector.app.core.extensions.commitTransaction
 | 
			
		||||
import im.vector.app.core.extensions.toMvRxBundle
 | 
			
		||||
import im.vector.app.core.platform.OnBackPressed
 | 
			
		||||
import im.vector.app.core.platform.VectorBaseActivity
 | 
			
		||||
import im.vector.app.core.platform.VectorBaseFragment
 | 
			
		||||
import im.vector.app.core.platform.VectorMenuProvider
 | 
			
		||||
import im.vector.app.core.resources.ColorProvider
 | 
			
		||||
import im.vector.app.core.ui.views.CurrentCallsView
 | 
			
		||||
import im.vector.app.core.ui.views.CurrentCallsViewPresenter
 | 
			
		||||
import im.vector.app.core.ui.views.KeysBackupBanner
 | 
			
		||||
import im.vector.app.databinding.FragmentNewHomeDetailBinding
 | 
			
		||||
import im.vector.app.features.call.SharedKnownCallsViewModel
 | 
			
		||||
import im.vector.app.features.call.VectorCallActivity
 | 
			
		||||
import im.vector.app.features.call.dialpad.DialPadFragment
 | 
			
		||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
 | 
			
		||||
import im.vector.app.features.home.room.list.RoomListFragment
 | 
			
		||||
import im.vector.app.features.home.room.list.RoomListParams
 | 
			
		||||
import im.vector.app.features.popup.PopupAlertManager
 | 
			
		||||
import im.vector.app.features.popup.VerificationVectorAlert
 | 
			
		||||
import im.vector.app.features.settings.VectorLocale
 | 
			
		||||
import im.vector.app.features.settings.VectorPreferences
 | 
			
		||||
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
 | 
			
		||||
import im.vector.app.features.themes.ThemeUtils
 | 
			
		||||
import im.vector.app.features.workers.signout.BannerState
 | 
			
		||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import org.matrix.android.sdk.api.session.Session
 | 
			
		||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
 | 
			
		||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
 | 
			
		||||
import org.matrix.android.sdk.api.util.toMatrixItem
 | 
			
		||||
import javax.inject.Inject
 | 
			
		||||
 | 
			
		||||
class NewHomeDetailFragment @Inject constructor(
 | 
			
		||||
        private val avatarRenderer: AvatarRenderer,
 | 
			
		||||
        private val colorProvider: ColorProvider,
 | 
			
		||||
        private val alertManager: PopupAlertManager,
 | 
			
		||||
        private val callManager: WebRtcCallManager,
 | 
			
		||||
        private val vectorPreferences: VectorPreferences,
 | 
			
		||||
        private val appStateHandler: AppStateHandler,
 | 
			
		||||
        private val session: Session,
 | 
			
		||||
) : VectorBaseFragment<FragmentNewHomeDetailBinding>(),
 | 
			
		||||
        KeysBackupBanner.Delegate,
 | 
			
		||||
        CurrentCallsView.Callback,
 | 
			
		||||
        OnBackPressed,
 | 
			
		||||
        VectorMenuProvider {
 | 
			
		||||
 | 
			
		||||
    private val viewModel: HomeDetailViewModel by fragmentViewModel()
 | 
			
		||||
    private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
 | 
			
		||||
    private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel()
 | 
			
		||||
    private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel()
 | 
			
		||||
 | 
			
		||||
    private lateinit var sharedActionViewModel: HomeSharedActionViewModel
 | 
			
		||||
    private lateinit var sharedCallActionViewModel: SharedKnownCallsViewModel
 | 
			
		||||
 | 
			
		||||
    private var hasUnreadRooms = false
 | 
			
		||||
        set(value) {
 | 
			
		||||
            if (value != field) {
 | 
			
		||||
                field = value
 | 
			
		||||
                invalidateOptionsMenu()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun getMenuRes() = R.menu.room_list
 | 
			
		||||
 | 
			
		||||
    override fun handleMenuItemSelected(item: MenuItem): Boolean {
 | 
			
		||||
        return when (item.itemId) {
 | 
			
		||||
            R.id.menu_home_mark_all_as_read -> {
 | 
			
		||||
                viewModel.handle(HomeDetailAction.MarkAllRoomsRead)
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
            else -> false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun handlePrepareMenu(menu: Menu) {
 | 
			
		||||
        withState(viewModel) { state ->
 | 
			
		||||
            val isRoomList = state.currentTab is HomeTab.RoomList
 | 
			
		||||
            menu.findItem(R.id.menu_home_mark_all_as_read).isVisible = isRoomList && hasUnreadRooms
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentNewHomeDetailBinding {
 | 
			
		||||
        return FragmentNewHomeDetailBinding.inflate(inflater, container, false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val currentCallsViewPresenter = CurrentCallsViewPresenter()
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onViewCreated(view, savedInstanceState)
 | 
			
		||||
        sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
 | 
			
		||||
        sharedCallActionViewModel = activityViewModelProvider.get(SharedKnownCallsViewModel::class.java)
 | 
			
		||||
        setupBottomNavigationView()
 | 
			
		||||
        setupToolbar()
 | 
			
		||||
        setupKeysBackupBanner()
 | 
			
		||||
        setupActiveCallView()
 | 
			
		||||
 | 
			
		||||
        withState(viewModel) {
 | 
			
		||||
            // Update the navigation view if needed (for when we restore the tabs)
 | 
			
		||||
            views.bottomNavigationView.selectedItemId = it.currentTab.toMenuId()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.onEach(HomeDetailViewState::selectedSpace) { selectedSpace ->
 | 
			
		||||
            onSpaceChange(selectedSpace)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.onEach(HomeDetailViewState::currentTab) { currentTab ->
 | 
			
		||||
            updateUIForTab(currentTab)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.onEach(HomeDetailViewState::showDialPadTab) { showDialPadTab ->
 | 
			
		||||
            updateTabVisibilitySafely(R.id.bottom_action_dial_pad, showDialPadTab)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        viewModel.observeViewEvents { viewEvent ->
 | 
			
		||||
            when (viewEvent) {
 | 
			
		||||
                HomeDetailViewEvents.CallStarted -> handleCallStarted()
 | 
			
		||||
                is HomeDetailViewEvents.FailToCall -> showFailure(viewEvent.failure)
 | 
			
		||||
                HomeDetailViewEvents.Loading -> showLoadingDialog()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        unknownDeviceDetectorSharedViewModel.onEach { state ->
 | 
			
		||||
            state.unknownSessions.invoke()?.let { unknownDevices ->
 | 
			
		||||
                if (unknownDevices.firstOrNull()?.currentSessionTrust == true) {
 | 
			
		||||
                    val uid = "review_login"
 | 
			
		||||
                    alertManager.cancelAlert(uid)
 | 
			
		||||
                    val olderUnverified = unknownDevices.filter { !it.isNew }
 | 
			
		||||
                    val newest = unknownDevices.firstOrNull { it.isNew }?.deviceInfo
 | 
			
		||||
                    if (newest != null) {
 | 
			
		||||
                        promptForNewUnknownDevices(uid, state, newest)
 | 
			
		||||
                    } else if (olderUnverified.isNotEmpty()) {
 | 
			
		||||
                        // In this case we prompt to go to settings to review logins
 | 
			
		||||
                        promptToReviewChanges(uid, state, olderUnverified.map { it.deviceInfo })
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sharedCallActionViewModel
 | 
			
		||||
                .liveKnownCalls
 | 
			
		||||
                .observe(viewLifecycleOwner) {
 | 
			
		||||
                    currentCallsViewPresenter.updateCall(callManager.getCurrentCall(), callManager.getCalls())
 | 
			
		||||
                    invalidateOptionsMenu()
 | 
			
		||||
                }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun navigateBack() {
 | 
			
		||||
        val previousSpaceId = appStateHandler.getSpaceBackstack().removeLastOrNull()
 | 
			
		||||
        val parentSpaceId = appStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
 | 
			
		||||
        setCurrentSpace(previousSpaceId ?: parentSpaceId)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setCurrentSpace(spaceId: String?) {
 | 
			
		||||
        appStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false)
 | 
			
		||||
        sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun handleCallStarted() {
 | 
			
		||||
        dismissLoadingDialog()
 | 
			
		||||
        val fragmentTag = HomeTab.DialPad.toFragmentTag()
 | 
			
		||||
        (childFragmentManager.findFragmentByTag(fragmentTag) as? DialPadFragment)?.clear()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView() {
 | 
			
		||||
        currentCallsViewPresenter.unBind()
 | 
			
		||||
        super.onDestroyView()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
        super.onResume()
 | 
			
		||||
        updateTabVisibilitySafely(R.id.bottom_action_notification, vectorPreferences.labAddNotificationTab())
 | 
			
		||||
        callManager.checkForProtocolsSupportIfNeeded()
 | 
			
		||||
        refreshSpaceState()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun refreshSpaceState() {
 | 
			
		||||
        appStateHandler.getCurrentSpace()?.let {
 | 
			
		||||
            onSpaceChange(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun promptForNewUnknownDevices(uid: String, state: UnknownDevicesState, newest: DeviceInfo) {
 | 
			
		||||
        val user = state.myMatrixItem
 | 
			
		||||
        alertManager.postVectorAlert(
 | 
			
		||||
                VerificationVectorAlert(
 | 
			
		||||
                        uid = uid,
 | 
			
		||||
                        title = getString(R.string.new_session),
 | 
			
		||||
                        description = getString(R.string.verify_this_session, newest.displayName ?: newest.deviceId ?: ""),
 | 
			
		||||
                        iconId = R.drawable.ic_shield_warning
 | 
			
		||||
                ).apply {
 | 
			
		||||
                    viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer)
 | 
			
		||||
                    colorInt = colorProvider.getColorFromAttribute(R.attr.colorPrimary)
 | 
			
		||||
                    contentAction = Runnable {
 | 
			
		||||
                        (weakCurrentActivity?.get() as? VectorBaseActivity<*>)
 | 
			
		||||
                                ?.navigator
 | 
			
		||||
                                ?.requestSessionVerification(requireContext(), newest.deviceId ?: "")
 | 
			
		||||
                        unknownDeviceDetectorSharedViewModel.handle(
 | 
			
		||||
                                UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(newest.deviceId?.let { listOf(it) }.orEmpty())
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    dismissedAction = Runnable {
 | 
			
		||||
                        unknownDeviceDetectorSharedViewModel.handle(
 | 
			
		||||
                                UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(newest.deviceId?.let { listOf(it) }.orEmpty())
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun promptToReviewChanges(uid: String, state: UnknownDevicesState, oldUnverified: List<DeviceInfo>) {
 | 
			
		||||
        val user = state.myMatrixItem
 | 
			
		||||
        alertManager.postVectorAlert(
 | 
			
		||||
                VerificationVectorAlert(
 | 
			
		||||
                        uid = uid,
 | 
			
		||||
                        title = getString(R.string.review_logins),
 | 
			
		||||
                        description = getString(R.string.verify_other_sessions),
 | 
			
		||||
                        iconId = R.drawable.ic_shield_warning
 | 
			
		||||
                ).apply {
 | 
			
		||||
                    viewBinder = VerificationVectorAlert.ViewBinder(user, avatarRenderer)
 | 
			
		||||
                    colorInt = colorProvider.getColorFromAttribute(R.attr.colorPrimary)
 | 
			
		||||
                    contentAction = Runnable {
 | 
			
		||||
                        (weakCurrentActivity?.get() as? VectorBaseActivity<*>)?.let { activity ->
 | 
			
		||||
                            // mark as ignored to avoid showing it again
 | 
			
		||||
                            unknownDeviceDetectorSharedViewModel.handle(
 | 
			
		||||
                                    UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId })
 | 
			
		||||
                            )
 | 
			
		||||
                            activity.navigator.openSettings(activity, EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    dismissedAction = Runnable {
 | 
			
		||||
                        unknownDeviceDetectorSharedViewModel.handle(
 | 
			
		||||
                                UnknownDeviceDetectorSharedViewModel.Action.IgnoreDevice(oldUnverified.mapNotNull { it.deviceId })
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun onSpaceChange(spaceSummary: RoomSummary?) {
 | 
			
		||||
        // Reimplement in next PR
 | 
			
		||||
        println(spaceSummary)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupKeysBackupBanner() {
 | 
			
		||||
        serverBackupStatusViewModel
 | 
			
		||||
                .onEach {
 | 
			
		||||
                    when (val banState = it.bannerState.invoke()) {
 | 
			
		||||
                        is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false)
 | 
			
		||||
                        BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false)
 | 
			
		||||
                        null,
 | 
			
		||||
                        BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        views.homeKeysBackupBanner.delegate = this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupActiveCallView() {
 | 
			
		||||
        currentCallsViewPresenter.bind(views.currentCallsView, this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupToolbar() {
 | 
			
		||||
        setupToolbar(views.toolbar)
 | 
			
		||||
 | 
			
		||||
        lifecycleScope.launch(Dispatchers.IO) {
 | 
			
		||||
            session.userService().getUser(session.myUserId)?.let { user ->
 | 
			
		||||
                avatarRenderer.render(user.toMatrixItem(), views.avatar)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        views.avatar.debouncedClicks {
 | 
			
		||||
            navigator.openSettings(requireContext())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun setupBottomNavigationView() {
 | 
			
		||||
        views.bottomNavigationView.menu.findItem(R.id.bottom_action_notification).isVisible = vectorPreferences.labAddNotificationTab()
 | 
			
		||||
        views.bottomNavigationView.setOnItemSelectedListener {
 | 
			
		||||
            val tab = when (it.itemId) {
 | 
			
		||||
                R.id.bottom_action_people -> HomeTab.RoomList(RoomListDisplayMode.PEOPLE)
 | 
			
		||||
                R.id.bottom_action_rooms -> HomeTab.RoomList(RoomListDisplayMode.ROOMS)
 | 
			
		||||
                R.id.bottom_action_notification -> HomeTab.RoomList(RoomListDisplayMode.NOTIFICATIONS)
 | 
			
		||||
                else -> HomeTab.DialPad
 | 
			
		||||
            }
 | 
			
		||||
            viewModel.handle(HomeDetailAction.SwitchTab(tab))
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateUIForTab(tab: HomeTab) {
 | 
			
		||||
        views.bottomNavigationView.menu.findItem(tab.toMenuId()).isChecked = true
 | 
			
		||||
        updateSelectedFragment(tab)
 | 
			
		||||
        invalidateOptionsMenu()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun HomeTab.toFragmentTag() = "FRAGMENT_TAG_$this"
 | 
			
		||||
 | 
			
		||||
    private fun updateSelectedFragment(tab: HomeTab) {
 | 
			
		||||
        val fragmentTag = tab.toFragmentTag()
 | 
			
		||||
        val fragmentToShow = childFragmentManager.findFragmentByTag(fragmentTag)
 | 
			
		||||
        childFragmentManager.commitTransaction {
 | 
			
		||||
            childFragmentManager.fragments
 | 
			
		||||
                    .filter { it != fragmentToShow }
 | 
			
		||||
                    .forEach {
 | 
			
		||||
                        detach(it)
 | 
			
		||||
                    }
 | 
			
		||||
            if (fragmentToShow == null) {
 | 
			
		||||
                when (tab) {
 | 
			
		||||
                    is HomeTab.RoomList -> {
 | 
			
		||||
                        val params = RoomListParams(tab.displayMode)
 | 
			
		||||
                        add(R.id.roomListContainer, RoomListFragment::class.java, params.toMvRxBundle(), fragmentTag)
 | 
			
		||||
                    }
 | 
			
		||||
                    is HomeTab.DialPad -> {
 | 
			
		||||
                        add(R.id.roomListContainer, createDialPadFragment(), fragmentTag)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if (tab is HomeTab.DialPad) {
 | 
			
		||||
                    (fragmentToShow as? DialPadFragment)?.applyCallback()
 | 
			
		||||
                }
 | 
			
		||||
                attach(fragmentToShow)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun createDialPadFragment(): Fragment {
 | 
			
		||||
        val fragment = childFragmentManager.fragmentFactory.instantiate(vectorBaseActivity.classLoader, DialPadFragment::class.java.name)
 | 
			
		||||
        return (fragment as DialPadFragment).apply {
 | 
			
		||||
            arguments = Bundle().apply {
 | 
			
		||||
                putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true)
 | 
			
		||||
                putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true)
 | 
			
		||||
                putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country)
 | 
			
		||||
            }
 | 
			
		||||
            applyCallback()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateTabVisibilitySafely(tabId: Int, isVisible: Boolean) {
 | 
			
		||||
        val wasVisible = views.bottomNavigationView.menu.findItem(tabId).isVisible
 | 
			
		||||
        views.bottomNavigationView.menu.findItem(tabId).isVisible = isVisible
 | 
			
		||||
        if (wasVisible && !isVisible) {
 | 
			
		||||
            // As we hide it check if it's not the current item!
 | 
			
		||||
            withState(viewModel) {
 | 
			
		||||
                if (it.currentTab.toMenuId() == tabId) {
 | 
			
		||||
                    viewModel.handle(HomeDetailAction.SwitchTab(HomeTab.RoomList(RoomListDisplayMode.PEOPLE)))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* ==========================================================================================
 | 
			
		||||
     * KeysBackupBanner Listener
 | 
			
		||||
     * ========================================================================================== */
 | 
			
		||||
 | 
			
		||||
    override fun setupKeysBackup() {
 | 
			
		||||
        navigator.openKeysBackupSetup(requireActivity(), false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun recoverKeysBackup() {
 | 
			
		||||
        navigator.openKeysBackupManager(requireActivity())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun invalidate() = withState(viewModel) {
 | 
			
		||||
        views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_people).render(it.notificationCountPeople, it.notificationHighlightPeople)
 | 
			
		||||
        views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_rooms).render(it.notificationCountRooms, it.notificationHighlightRooms)
 | 
			
		||||
        views.bottomNavigationView.getOrCreateBadge(R.id.bottom_action_notification).render(it.notificationCountCatchup, it.notificationHighlightCatchup)
 | 
			
		||||
        views.syncStateView.render(
 | 
			
		||||
                it.syncState,
 | 
			
		||||
                it.incrementalSyncRequestState,
 | 
			
		||||
                it.pushCounter,
 | 
			
		||||
                vectorPreferences.developerShowDebugInfo()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        hasUnreadRooms = it.hasUnreadMessages
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun BadgeDrawable.render(count: Int, highlight: Boolean) {
 | 
			
		||||
        isVisible = count > 0
 | 
			
		||||
        number = count
 | 
			
		||||
        maxCharacterCount = 3
 | 
			
		||||
        badgeTextColor = ThemeUtils.getColor(requireContext(), R.attr.colorOnPrimary)
 | 
			
		||||
        backgroundColor = if (highlight) {
 | 
			
		||||
            ThemeUtils.getColor(requireContext(), R.attr.colorError)
 | 
			
		||||
        } else {
 | 
			
		||||
            ThemeUtils.getColor(requireContext(), R.attr.vctr_unread_background)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun HomeTab.toMenuId() = when (this) {
 | 
			
		||||
        is HomeTab.DialPad -> R.id.bottom_action_dial_pad
 | 
			
		||||
        is HomeTab.RoomList -> when (displayMode) {
 | 
			
		||||
            RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people
 | 
			
		||||
            RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
 | 
			
		||||
            else -> R.id.bottom_action_notification
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onTapToReturnToCall() {
 | 
			
		||||
        callManager.getCurrentCall()?.let { call ->
 | 
			
		||||
            VectorCallActivity.newIntent(
 | 
			
		||||
                    context = requireContext(),
 | 
			
		||||
                    callId = call.callId,
 | 
			
		||||
                    signalingRoomId = call.signalingRoomId,
 | 
			
		||||
                    otherUserId = call.mxCall.opponentUserId,
 | 
			
		||||
                    isIncomingCall = !call.mxCall.isOutgoing,
 | 
			
		||||
                    isVideoCall = call.mxCall.isVideoCall,
 | 
			
		||||
                    mode = null
 | 
			
		||||
            ).let {
 | 
			
		||||
                startActivity(it)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun DialPadFragment.applyCallback(): DialPadFragment {
 | 
			
		||||
        callback = object : DialPadFragment.Callback {
 | 
			
		||||
            override fun onOkClicked(formatted: String?, raw: String?) {
 | 
			
		||||
                if (raw.isNullOrEmpty()) return
 | 
			
		||||
                viewModel.handle(HomeDetailAction.StartCallWithPhoneNumber(raw))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onBackPressed(toolbarButton: Boolean) = if (appStateHandler.getCurrentSpace() != null) {
 | 
			
		||||
        navigateBack()
 | 
			
		||||
        true
 | 
			
		||||
    } else {
 | 
			
		||||
        false
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -334,7 +334,7 @@ class RoomMemberProfileFragment @Inject constructor(
 | 
			
		||||
                .setNeutralButton(R.string.ok, null)
 | 
			
		||||
                .setPositiveButton(R.string.share_by_text) { _, _ ->
 | 
			
		||||
                    startSharePlainTextIntent(
 | 
			
		||||
                            fragment = this,
 | 
			
		||||
                            context = requireContext(),
 | 
			
		||||
                            activityResultLauncher = null,
 | 
			
		||||
                            chooserTitle = null,
 | 
			
		||||
                            text = permalink
 | 
			
		||||
 | 
			
		||||
@ -337,7 +337,7 @@ class RoomProfileFragment @Inject constructor(
 | 
			
		||||
 | 
			
		||||
    private fun onShareRoomProfile(permalink: String) {
 | 
			
		||||
        startSharePlainTextIntent(
 | 
			
		||||
                fragment = this,
 | 
			
		||||
                context = requireContext(),
 | 
			
		||||
                activityResultLauncher = null,
 | 
			
		||||
                chooserTitle = null,
 | 
			
		||||
                text = permalink
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ class ShareSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpa
 | 
			
		||||
                }
 | 
			
		||||
                is ShareSpaceViewEvents.ShowInviteByLink -> {
 | 
			
		||||
                    startSharePlainTextIntent(
 | 
			
		||||
                            fragment = this,
 | 
			
		||||
                            context = requireContext(),
 | 
			
		||||
                            activityResultLauncher = null,
 | 
			
		||||
                            chooserTitle = getString(R.string.share_by_text),
 | 
			
		||||
                            text = getString(R.string.share_space_link_message, event.spaceName, event.permalink),
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@ class ShowUserCodeFragment @Inject constructor(
 | 
			
		||||
        sharedViewModel.observeViewEvents {
 | 
			
		||||
            if (it is UserCodeShareViewEvents.SharePlainText) {
 | 
			
		||||
                startSharePlainTextIntent(
 | 
			
		||||
                        fragment = this,
 | 
			
		||||
                        context = requireContext(),
 | 
			
		||||
                        activityResultLauncher = null,
 | 
			
		||||
                        chooserTitle = it.title,
 | 
			
		||||
                        text = it.text,
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ class UserListFragment @Inject constructor(
 | 
			
		||||
                is UserListViewEvents.OpenShareMatrixToLink -> {
 | 
			
		||||
                    val text = getString(R.string.invite_friends_text, it.link)
 | 
			
		||||
                    startSharePlainTextIntent(
 | 
			
		||||
                            fragment = this,
 | 
			
		||||
                            context = requireContext(),
 | 
			
		||||
                            activityResultLauncher = null,
 | 
			
		||||
                            chooserTitle = getString(R.string.invite_friends),
 | 
			
		||||
                            text = text,
 | 
			
		||||
 | 
			
		||||
@ -17,4 +17,4 @@
 | 
			
		||||
        android:left="14dp"
 | 
			
		||||
        android:right="14dp"
 | 
			
		||||
        android:top="14dp" />
 | 
			
		||||
</layer-list>
 | 
			
		||||
</layer-list>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										103
									
								
								vector/src/main/res/layout/fragment_new_home_detail.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vector/src/main/res/layout/fragment_new_home_detail.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <im.vector.app.core.ui.views.KeysBackupBanner
 | 
			
		||||
        android:id="@+id/homeKeysBackupBanner"
 | 
			
		||||
        android:layout_width="0dp"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:background="?vctr_keys_backup_banner_accent_color"
 | 
			
		||||
        android:minHeight="67dp"
 | 
			
		||||
        android:visibility="gone"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
        tools:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
    <im.vector.app.core.ui.views.CurrentCallsView
 | 
			
		||||
        android:id="@+id/currentCallsView"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:minHeight="48dp"
 | 
			
		||||
        android:visibility="gone"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner"
 | 
			
		||||
        tools:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
    <im.vector.app.features.sync.widget.SyncStateView
 | 
			
		||||
        android:id="@+id/syncStateView"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
        app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@id/currentCallsView"
 | 
			
		||||
        tools:visibility="gone" />
 | 
			
		||||
 | 
			
		||||
    <androidx.coordinatorlayout.widget.CoordinatorLayout
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="0dp"
 | 
			
		||||
        app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
        app:layout_constraintTop_toBottomOf="@id/currentCallsView">
 | 
			
		||||
 | 
			
		||||
        <com.google.android.material.appbar.AppBarLayout
 | 
			
		||||
            android:id="@+id/appBarLayout"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:fitsSystemWindows="true"
 | 
			
		||||
            app:layout_constraintTop_toBottomOf="@id/syncStateView">
 | 
			
		||||
 | 
			
		||||
            <com.google.android.material.appbar.CollapsingToolbarLayout
 | 
			
		||||
                style="@style/Widget.Vector.Material3.CollapsingToolbar.Medium"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
 | 
			
		||||
                app:layout_scrollFlags="scroll|exitUntilCollapsed">
 | 
			
		||||
 | 
			
		||||
                <com.google.android.material.appbar.MaterialToolbar
 | 
			
		||||
                    android:id="@+id/toolbar"
 | 
			
		||||
                    style="@style/Widget.Vector.Material3.Toolbar"
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="?attr/actionBarSize"
 | 
			
		||||
                    android:elevation="0dp"
 | 
			
		||||
                    app:layout_collapseMode="pin"
 | 
			
		||||
                    app:title="@string/all_chats">
 | 
			
		||||
 | 
			
		||||
                    <ImageView
 | 
			
		||||
                        android:id="@+id/avatar"
 | 
			
		||||
                        android:layout_width="36dp"
 | 
			
		||||
                        android:layout_height="36dp"
 | 
			
		||||
                        android:padding="6dp"
 | 
			
		||||
                        android:contentDescription="@string/a11y_open_settings"
 | 
			
		||||
                        tools:src="@sample/user_round_avatars" />
 | 
			
		||||
 | 
			
		||||
                </com.google.android.material.appbar.MaterialToolbar>
 | 
			
		||||
 | 
			
		||||
            </com.google.android.material.appbar.CollapsingToolbarLayout>
 | 
			
		||||
 | 
			
		||||
        </com.google.android.material.appbar.AppBarLayout>
 | 
			
		||||
 | 
			
		||||
        <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent"
 | 
			
		||||
            app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
 | 
			
		||||
 | 
			
		||||
            <androidx.fragment.app.FragmentContainerView
 | 
			
		||||
                android:id="@+id/roomListContainer"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="0dp"
 | 
			
		||||
                app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent" />
 | 
			
		||||
 | 
			
		||||
            <com.google.android.material.bottomnavigation.BottomNavigationView
 | 
			
		||||
                android:id="@+id/bottomNavigationView"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                app:layout_constraintBottom_toBottomOf="parent"
 | 
			
		||||
                app:menu="@menu/home_bottom_navigation" />
 | 
			
		||||
 | 
			
		||||
        </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
 | 
			
		||||
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
 | 
			
		||||
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
    xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/search"
 | 
			
		||||
        android:icon="@drawable/ic_search"
 | 
			
		||||
        android:icon="@drawable/ic_home_search"
 | 
			
		||||
        app:iconTint="?vctr_content_primary"
 | 
			
		||||
        android:title="@string/search"
 | 
			
		||||
        app:actionViewClass="android.widget.SearchView"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								vector/src/main/res/menu/menu_new_home.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vector/src/main/res/menu/menu_new_home.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools">
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/menu_home_invite_friends"
 | 
			
		||||
        android:title="@string/invite_friends"
 | 
			
		||||
        app:showAsAction="never" />
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/menu_home_suggestion"
 | 
			
		||||
        android:icon="@drawable/ic_material_bug_report"
 | 
			
		||||
        android:title="@string/send_suggestion"
 | 
			
		||||
        app:showAsAction="never" />
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/menu_home_report_bug"
 | 
			
		||||
        android:icon="@drawable/ic_material_bug_report"
 | 
			
		||||
        android:title="@string/send_bug_report"
 | 
			
		||||
        app:showAsAction="never" />
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/menu_home_init_sync_legacy"
 | 
			
		||||
        android:title="Do a legacy init sync"
 | 
			
		||||
        tools:ignore="HardcodedText"
 | 
			
		||||
        app:showAsAction="never" />
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/menu_home_init_sync_optimized"
 | 
			
		||||
        android:title="Do an optimized init sync"
 | 
			
		||||
        tools:ignore="HardcodedText"
 | 
			
		||||
        app:showAsAction="never" />
 | 
			
		||||
 | 
			
		||||
    <item
 | 
			
		||||
        android:id="@+id/menu_home_filter"
 | 
			
		||||
        android:icon="@drawable/ic_home_search"
 | 
			
		||||
        android:title="@string/home_filter_placeholder_home"
 | 
			
		||||
        app:iconTint="?vctr_content_secondary"
 | 
			
		||||
        app:showAsAction="always" />
 | 
			
		||||
 | 
			
		||||
</menu>
 | 
			
		||||
@ -136,6 +136,7 @@
 | 
			
		||||
    <string name="matrix_error">Matrix error</string>
 | 
			
		||||
 | 
			
		||||
    <!-- Home Screen -->
 | 
			
		||||
    <string name="all_chats">All Chats</string>
 | 
			
		||||
 | 
			
		||||
    <!-- Last seen time -->
 | 
			
		||||
 | 
			
		||||
@ -2808,6 +2809,7 @@
 | 
			
		||||
 | 
			
		||||
    <string name="a11y_screenshot">Screenshot</string>
 | 
			
		||||
    <string name="a11y_open_widget">Open widgets</string>
 | 
			
		||||
    <string name="a11y_open_settings">Open settings</string>
 | 
			
		||||
    <string name="a11y_import_key_from_file">Import key from file</string>
 | 
			
		||||
    <string name="a11y_image">Image</string>
 | 
			
		||||
    <string name="a11y_change_avatar">Change avatar</string>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user