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_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_horizontal">12dp</dimen>
|
||||||
<dimen name="location_sharing_live_duration_choice_margin_vertical">22dp</dimen>
|
<dimen name="location_sharing_live_duration_choice_margin_vertical">22dp</dimen>
|
||||||
|
|
||||||
|
<!-- Material 3 -->
|
||||||
|
<dimen name="collapsing_toolbar_layout_medium_size">112dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -39,4 +39,14 @@
|
|||||||
<item name="android:textSize">12sp</item>
|
<item name="android:textSize">12sp</item>
|
||||||
</style>
|
</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>
|
<item name="android:textColor">?vctr_content_primary</item>
|
||||||
</style>
|
</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">
|
<style name="TextAppearance.Vector.Subtitle" parent="TextAppearance.MaterialComponents.Subtitle1">
|
||||||
<item name="fontFamily">sans-serif</item>
|
<item name="fontFamily">sans-serif</item>
|
||||||
<item name="android:fontFamily">sans-serif</item>
|
<item name="android:fontFamily">sans-serif</item>
|
||||||
|
@ -25,4 +25,4 @@
|
|||||||
<item name="android:backgroundDimEnabled">false</item>
|
<item name="android:backgroundDimEnabled">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -149,6 +149,9 @@
|
|||||||
|
|
||||||
<!-- Location sharing -->
|
<!-- Location sharing -->
|
||||||
<item name="vctr_live_location">@color/vctr_live_location_dark</item>
|
<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>
|
||||||
|
|
||||||
<style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />
|
<style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />
|
||||||
|
@ -150,8 +150,12 @@
|
|||||||
|
|
||||||
<!-- Location sharing -->
|
<!-- Location sharing -->
|
||||||
<item name="vctr_live_location">@color/vctr_live_location_light</item>
|
<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>
|
||||||
|
|
||||||
<style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />
|
<style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />
|
||||||
|
|
||||||
</resources>
|
</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.HomeDetailFragment
|
||||||
import im.vector.app.features.home.HomeDrawerFragment
|
import im.vector.app.features.home.HomeDrawerFragment
|
||||||
import im.vector.app.features.home.LoadingFragment
|
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.breadcrumbs.BreadcrumbsFragment
|
||||||
import im.vector.app.features.home.room.detail.TimelineFragment
|
import im.vector.app.features.home.room.detail.TimelineFragment
|
||||||
import im.vector.app.features.home.room.detail.search.SearchFragment
|
import im.vector.app.features.home.room.detail.search.SearchFragment
|
||||||
@ -258,6 +259,11 @@ interface FragmentModule {
|
|||||||
@FragmentKey(HomeDetailFragment::class)
|
@FragmentKey(HomeDetailFragment::class)
|
||||||
fun bindHomeDetailFragment(fragment: HomeDetailFragment): Fragment
|
fun bindHomeDetailFragment(fragment: HomeDetailFragment): Fragment
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FragmentKey(NewHomeDetailFragment::class)
|
||||||
|
fun bindNewHomeDetailFragment(fragment: NewHomeDetailFragment): Fragment
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(EmojiSearchResultFragment::class)
|
@FragmentKey(EmojiSearchResultFragment::class)
|
||||||
|
@ -28,7 +28,7 @@ import im.vector.app.R
|
|||||||
import im.vector.app.core.platform.SimpleTextWatcher
|
import im.vector.app.core.platform.SimpleTextWatcher
|
||||||
|
|
||||||
fun EditText.setupAsSearch(
|
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
|
@DrawableRes clearIconRes: Int = R.drawable.ic_x_gray
|
||||||
) {
|
) {
|
||||||
addTextChangedListener(object : SimpleTextWatcher() {
|
addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
|
@ -50,6 +50,7 @@ import androidx.viewbinding.ViewBinding
|
|||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.bumptech.glide.util.Util
|
import com.bumptech.glide.util.Util
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
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.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.EntryPointAccessors
|
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.core.utils.toast
|
||||||
import im.vector.app.features.MainActivity
|
import im.vector.app.features.MainActivity
|
||||||
import im.vector.app.features.MainActivityArgs
|
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.AnalyticsTracker
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import im.vector.app.features.configuration.VectorConfiguration
|
import im.vector.app.features.configuration.VectorConfiguration
|
||||||
@ -161,6 +163,9 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var fontScalePreferences: FontScalePreferences
|
lateinit var fontScalePreferences: FontScalePreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var vectorFeatures: VectorFeatures
|
||||||
|
|
||||||
lateinit var navigator: Navigator
|
lateinit var navigator: Navigator
|
||||||
private set
|
private set
|
||||||
private lateinit var fragmentFactory: FragmentFactory
|
private lateinit var fragmentFactory: FragmentFactory
|
||||||
@ -253,6 +258,14 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||||||
|
|
||||||
initUiAndData()
|
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()
|
val titleRes = getTitleRes()
|
||||||
if (titleRes != -1) {
|
if (titleRes != -1) {
|
||||||
supportActionBar?.let {
|
supportActionBar?.let {
|
||||||
|
@ -159,7 +159,7 @@ fun startInstallFromSourceIntent(context: Context, activityResultLauncher: Activ
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startSharePlainTextIntent(
|
fun startSharePlainTextIntent(
|
||||||
fragment: Fragment,
|
context: Context,
|
||||||
activityResultLauncher: ActivityResultLauncher<Intent>?,
|
activityResultLauncher: ActivityResultLauncher<Intent>?,
|
||||||
chooserTitle: String?,
|
chooserTitle: String?,
|
||||||
text: String,
|
text: String,
|
||||||
@ -182,10 +182,10 @@ fun startSharePlainTextIntent(
|
|||||||
if (activityResultLauncher != null) {
|
if (activityResultLauncher != null) {
|
||||||
activityResultLauncher.launch(intent)
|
activityResultLauncher.launch(intent)
|
||||||
} else {
|
} else {
|
||||||
fragment.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
} 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 {
|
dialog.findViewById<View>(R.id.keys_backup_setup_share)?.debouncedClicks {
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
chooserTitle = context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
||||||
text = recoveryKey,
|
text = recoveryKey,
|
||||||
|
@ -104,7 +104,7 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
|
|||||||
?: return@withState
|
?: return@withState
|
||||||
|
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
this,
|
requireContext(),
|
||||||
copyStartForActivityResult,
|
copyStartForActivityResult,
|
||||||
context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
|
||||||
recoveryKey,
|
recoveryKey,
|
||||||
|
@ -46,6 +46,7 @@ import im.vector.app.core.platform.VectorBaseActivity
|
|||||||
import im.vector.app.core.platform.VectorMenuProvider
|
import im.vector.app.core.platform.VectorMenuProvider
|
||||||
import im.vector.app.core.pushers.PushersManager
|
import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.pushers.UnifiedPushHelper
|
import im.vector.app.core.pushers.UnifiedPushHelper
|
||||||
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
import im.vector.app.databinding.ActivityHomeBinding
|
import im.vector.app.databinding.ActivityHomeBinding
|
||||||
import im.vector.app.features.MainActivity
|
import im.vector.app.features.MainActivity
|
||||||
import im.vector.app.features.MainActivityArgs
|
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)
|
views.drawerLayout.addDrawerListener(drawerListener)
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
replaceFragment(views.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
if (vectorFeatures.isNewAppLayoutEnabled()) {
|
||||||
replaceFragment(views.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
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
|
sharedActionViewModel
|
||||||
@ -552,7 +558,7 @@ class HomeActivity :
|
|||||||
nightlyProxy.onHomeResumed()
|
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) {
|
override fun handlePrepareMenu(menu: Menu) {
|
||||||
menu.findItem(R.id.menu_home_init_sync_legacy).isVisible = vectorPreferences.developerMode()
|
menu.findItem(R.id.menu_home_init_sync_legacy).isVisible = vectorPreferences.developerMode()
|
||||||
@ -591,10 +597,29 @@ class HomeActivity :
|
|||||||
navigator.openSettings(this)
|
navigator.openSettings(this)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
R.id.menu_home_invite_friends -> {
|
||||||
|
launchInviteFriends()
|
||||||
|
true
|
||||||
|
}
|
||||||
else -> false
|
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() {
|
override fun onBackPressed() {
|
||||||
if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
if (views.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
@ -102,7 +102,7 @@ class HomeDrawerFragment @Inject constructor(
|
|||||||
val text = getString(R.string.invite_friends_text, permalink)
|
val text = getString(R.string.invite_friends_text, permalink)
|
||||||
|
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = getString(R.string.invite_friends),
|
chooserTitle = getString(R.string.invite_friends),
|
||||||
text = text,
|
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)
|
.setNeutralButton(R.string.ok, null)
|
||||||
.setPositiveButton(R.string.share_by_text) { _, _ ->
|
.setPositiveButton(R.string.share_by_text) { _, _ ->
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = null,
|
chooserTitle = null,
|
||||||
text = permalink
|
text = permalink
|
||||||
|
@ -337,7 +337,7 @@ class RoomProfileFragment @Inject constructor(
|
|||||||
|
|
||||||
private fun onShareRoomProfile(permalink: String) {
|
private fun onShareRoomProfile(permalink: String) {
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = null,
|
chooserTitle = null,
|
||||||
text = permalink
|
text = permalink
|
||||||
|
@ -89,7 +89,7 @@ class ShareSpaceBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpa
|
|||||||
}
|
}
|
||||||
is ShareSpaceViewEvents.ShowInviteByLink -> {
|
is ShareSpaceViewEvents.ShowInviteByLink -> {
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = getString(R.string.share_by_text),
|
chooserTitle = getString(R.string.share_by_text),
|
||||||
text = getString(R.string.share_space_link_message, event.spaceName, event.permalink),
|
text = getString(R.string.share_space_link_message, event.spaceName, event.permalink),
|
||||||
|
@ -67,7 +67,7 @@ class ShowUserCodeFragment @Inject constructor(
|
|||||||
sharedViewModel.observeViewEvents {
|
sharedViewModel.observeViewEvents {
|
||||||
if (it is UserCodeShareViewEvents.SharePlainText) {
|
if (it is UserCodeShareViewEvents.SharePlainText) {
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = it.title,
|
chooserTitle = it.title,
|
||||||
text = it.text,
|
text = it.text,
|
||||||
|
@ -96,7 +96,7 @@ class UserListFragment @Inject constructor(
|
|||||||
is UserListViewEvents.OpenShareMatrixToLink -> {
|
is UserListViewEvents.OpenShareMatrixToLink -> {
|
||||||
val text = getString(R.string.invite_friends_text, it.link)
|
val text = getString(R.string.invite_friends_text, it.link)
|
||||||
startSharePlainTextIntent(
|
startSharePlainTextIntent(
|
||||||
fragment = this,
|
context = requireContext(),
|
||||||
activityResultLauncher = null,
|
activityResultLauncher = null,
|
||||||
chooserTitle = getString(R.string.invite_friends),
|
chooserTitle = getString(R.string.invite_friends),
|
||||||
text = text,
|
text = text,
|
||||||
|
@ -17,4 +17,4 @@
|
|||||||
android:left="14dp"
|
android:left="14dp"
|
||||||
android:right="14dp"
|
android:right="14dp"
|
||||||
android:top="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">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/search"
|
android:id="@+id/search"
|
||||||
android:icon="@drawable/ic_search"
|
android:icon="@drawable/ic_home_search"
|
||||||
app:iconTint="?vctr_content_primary"
|
app:iconTint="?vctr_content_primary"
|
||||||
android:title="@string/search"
|
android:title="@string/search"
|
||||||
app:actionViewClass="android.widget.SearchView"
|
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>
|
<string name="matrix_error">Matrix error</string>
|
||||||
|
|
||||||
<!-- Home Screen -->
|
<!-- Home Screen -->
|
||||||
|
<string name="all_chats">All Chats</string>
|
||||||
|
|
||||||
<!-- Last seen time -->
|
<!-- Last seen time -->
|
||||||
|
|
||||||
@ -2808,6 +2809,7 @@
|
|||||||
|
|
||||||
<string name="a11y_screenshot">Screenshot</string>
|
<string name="a11y_screenshot">Screenshot</string>
|
||||||
<string name="a11y_open_widget">Open widgets</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_import_key_from_file">Import key from file</string>
|
||||||
<string name="a11y_image">Image</string>
|
<string name="a11y_image">Image</string>
|
||||||
<string name="a11y_change_avatar">Change avatar</string>
|
<string name="a11y_change_avatar">Change avatar</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user