Skip to content

Commit

Permalink
toolbar management (#4887)
Browse files Browse the repository at this point in the history
Toolbar management rework and toolbar style alignment
  • Loading branch information
fedrunov authored Jan 21, 2022
1 parent a085b4d commit f7aedff
Show file tree
Hide file tree
Showing 82 changed files with 275 additions and 744 deletions.
3 changes: 3 additions & 0 deletions changelog.d/4884.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Toolbar management rework. Toolbar title's and subtitle's text appearance now controlled by theme without local overrides. Helper class introduced to
help with toolbar configuration. Toolbar title, subtitle and navigation button widgets are removed where it is possible and replaced with built-in
toolbar widgets.
20 changes: 12 additions & 8 deletions library/ui-styles/src/main/res/values/styles_toolbar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
<item name="elevation">0dp</item>

<!-- main text -->
<item name="titleTextStyle">@style/Widget.Vector.TextView.ActionBarTitle</item>
<item name="titleTextAppearance">@style/TextAppearance.Vector.Widget.ActionBarTitle</item>

<!-- sub text -->
<item name="subtitleTextStyle">@style/Widget.Vector.TextView.ActionBarSubTitle</item>
<item name="subtitleTextAppearance">@style/TextAppearance.Vector.Widget.ActionBarSubTitle</item>

<item name="navigationIconTint">?vctr_content_secondary</item>
</style>

<!-- Default toolbar style -->
Expand All @@ -22,16 +24,18 @@

<!-- Toolbar text style -->
<!-- main text -->
<style name="Widget.Vector.TextView.ActionBarTitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
<style name="TextAppearance.Vector.Widget.ActionBarTitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
<item name="android:textColor">?vctr_content_primary</item>
<item name="android:fontFamily">"sans-serif-medium"</item>
<item name="android:textSize">20sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
<item name="fontFamily">sans-serif-medium</item>
<item name="android:textSize">18sp</item>
</style>

<!-- sub text -->
<style name="Widget.Vector.TextView.ActionBarSubTitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Subtitle">
<item name="android:textColor">?vctr_content_primary</item>
<item name="android:fontFamily">"sans-serif-medium"</item>
<style name="TextAppearance.Vector.Widget.ActionBarSubTitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Subtitle">
<item name="android:textColor">?vctr_content_secondary</item>
<item name="android:fontFamily">sans-serif</item>
<item name="fontFamily">sans-serif</item>
<item name="android:textSize">12sp</item>
</style>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ abstract class SimpleFragmentActivity : VectorBaseActivity<ActivityBinding>() {
final override fun getCoordinatorLayout() = views.coordinatorLayout

override fun initUiAndData() {
configureToolbar(views.toolbar)
setupToolbar(views.toolbar)
.allowBack(true)
waitingView = views.waitingView.waitingView
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import im.vector.app.core.extensions.restart
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.extensions.toMvRxBundle
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
Expand Down Expand Up @@ -126,6 +127,8 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
.launchIn(lifecycleScope)
}

var toolbar: ToolbarConfig? = null

/* ==========================================================================================
* Views
* ========================================================================================== */
Expand Down Expand Up @@ -508,18 +511,6 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
*/
protected fun isFirstCreation() = savedInstanceState == null

/**
* Configure the Toolbar, with default back button.
*/
protected fun configureToolbar(toolbar: MaterialToolbar, displayBack: Boolean = true) {
setSupportActionBar(toolbar)
supportActionBar?.let {
it.setDisplayShowHomeEnabled(displayBack)
it.setDisplayHomeAsUpEnabled(displayBack)
it.title = null
}
}

// ==============================================================================================
// Handle loading view (also called waiting view or spinner view)
// ==============================================================================================
Expand Down Expand Up @@ -629,4 +620,13 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
toast(getString(R.string.not_implemented))
}
}

/**
* Sets toolbar as actionBar
*
* @return Instance of [ToolbarConfig] with set of helper methods to configure toolbar
* */
fun setupToolbar(toolbar: MaterialToolbar) = ToolbarConfig(this, toolbar).also {
this.toolbar = it.setup()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.extensions.singletonEntryPoint
import im.vector.app.core.extensions.toMvRxBundle
import im.vector.app.core.utils.ToolbarConfig
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.plan.Screen
import im.vector.app.features.analytics.screen.ScreenEvent
Expand Down Expand Up @@ -80,6 +81,12 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView

private var progress: AlertDialog? = null

/**
* [ToolbarConfig] instance from host activity
* */
protected var toolbar: ToolbarConfig? = null
get() = (activity as? VectorBaseActivity<*>)?.toolbar
private set
/* ==========================================================================================
* View model
* ========================================================================================== */
Expand Down Expand Up @@ -228,13 +235,12 @@ abstract class VectorBaseFragment<VB : ViewBinding> : Fragment(), MavericksView
* ========================================================================================== */

/**
* Configure the Toolbar.
*/
protected fun setupToolbar(toolbar: MaterialToolbar) {
val parentActivity = vectorBaseActivity
if (parentActivity is ToolbarConfigurable) {
parentActivity.configure(toolbar)
}
* Sets toolbar as actionBar for current activity
*
* @return Instance of [ToolbarConfig] with set of helper methods to configure toolbar
* */
protected fun setupToolbar(toolbar: MaterialToolbar): ToolbarConfig {
return vectorBaseActivity.setupToolbar(toolbar)
}

/* ==========================================================================================
Expand Down
82 changes: 82 additions & 0 deletions vector/src/main/java/im/vector/app/core/utils/ToolbarConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2022 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.core.utils

import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import com.google.android.material.appbar.MaterialToolbar
import im.vector.app.R

/**
* Helper class to configure toolbar.
* Wraps [MaterialToolbar] providing set of methods to configure it
*/
class ToolbarConfig(val activity: AppCompatActivity, val toolbar: MaterialToolbar) {
private var customBackResId: Int? = null

fun setup() = apply {
activity.setSupportActionBar(toolbar)
}

/**
* Delegating property for [toolbar.title]
* */
var title: CharSequence? by toolbar::title

/**
* Delegating property for [toolbar.subtitle]
* */
var subtitle: CharSequence? by toolbar::subtitle

/**
* Sets toolbar's title text
* */
fun setTitle(title: CharSequence?) = apply { toolbar.title = title }

/**
* Sets toolbar's title text using provided string resource
* */
fun setTitle(@StringRes titleRes: Int) = apply { toolbar.setTitle(titleRes) }

/**
* Sets toolbar's subtitle text
* */
fun setSubtitle(subtitle: String?) = apply { toolbar.subtitle = subtitle }

/**
* Sets toolbar's title text using provided string resource
* */
fun setSubtitle(@StringRes subtitleRes: Int) = apply { toolbar.subtitle = activity.getString(subtitleRes) }

/**
* Enables/disables navigate back button
*
* @param isAllowed defines if back button is enabled. Default [true]
* @param useCross defines if cross icon should be used instead of arrow. Default [false]
* */
fun allowBack(isAllowed: Boolean = true, useCross: Boolean = false) = apply {
activity.supportActionBar?.let {
it.setDisplayShowHomeEnabled(isAllowed)
it.setDisplayHomeAsUpEnabled(isAllowed)
if (isAllowed && useCross) {
val navResId = customBackResId ?: R.drawable.ic_x_18dp
toolbar.navigationIcon = AppCompatResources.getDrawable(activity, navResId)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,15 @@ package im.vector.app.features.attachments.preview

import android.content.Context
import android.content.Intent
import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.ToolbarConfigurable
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.themes.ActivityOtherThemes
import org.matrix.android.sdk.api.session.content.ContentAttachmentData

@AndroidEntryPoint
class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarConfigurable {
class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {

companion object {
private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
Expand Down Expand Up @@ -72,8 +70,4 @@ class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>(),
setResult(RESULT_OK, resultIntent)
finish()
}

override fun configure(toolbar: MaterialToolbar) {
configureToolbar(toolbar)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
if (savedInstanceState != null) {
(supportFragmentManager.findFragmentByTag(FRAGMENT_DIAL_PAD_TAG) as? CallDialPadBottomSheet)?.callback = dialPadCallback
}
setSupportActionBar(views.callToolbar)
setupToolbar(views.callToolbar)
configureCallViews()

callViewModel.onEach {
Expand Down Expand Up @@ -257,18 +257,18 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.fullscreenRenderer.isVisible = false
views.pipRendererWrapper.isVisible = false
views.callInfoGroup.isVisible = true
views.callToolbar.setSubtitle(R.string.call_ringing)
toolbar?.setSubtitle(R.string.call_ringing)
configureCallInfo(state)
}
is CallState.Answering -> {
views.fullscreenRenderer.isVisible = false
views.pipRendererWrapper.isVisible = false
views.callInfoGroup.isVisible = true
views.callToolbar.setSubtitle(R.string.call_connecting)
toolbar?.setSubtitle(R.string.call_connecting)
configureCallInfo(state)
}
is CallState.Connected -> {
views.callToolbar.subtitle = state.formattedDuration
toolbar?.subtitle = state.formattedDuration
if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
if (state.isLocalOnHold || state.isRemoteOnHold) {
views.smallIsHeldIcon.isVisible = true
Expand All @@ -280,11 +280,11 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.callActionText.setText(R.string.call_resume_action)
views.callActionText.isVisible = true
views.callActionText.setOnClickListener { callViewModel.handle(VectorCallViewActions.ToggleHoldResume) }
views.callToolbar.setSubtitle(R.string.call_held_by_you)
toolbar?.setSubtitle(R.string.call_held_by_you)
} else {
views.callActionText.isInvisible = true
state.callInfo?.opponentUserItem?.let {
views.callToolbar.subtitle = getString(R.string.call_held_by_user, it.getBestName())
toolbar?.subtitle = getString(R.string.call_held_by_user, it.getBestName())
}
}
} else if (state.transferee !is VectorCallViewState.TransfereeState.NoTransferee) {
Expand Down Expand Up @@ -316,14 +316,14 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.pipRendererWrapper.isVisible = false
views.callInfoGroup.isVisible = true
configureCallInfo(state)
views.callToolbar.setSubtitle(R.string.call_connecting)
toolbar?.setSubtitle(R.string.call_connecting)
}
}
is CallState.Ended -> {
views.fullscreenRenderer.isVisible = false
views.pipRendererWrapper.isVisible = false
views.callInfoGroup.isVisible = true
views.callToolbar.setSubtitle(R.string.call_ended)
toolbar?.setSubtitle(R.string.call_ended)
configureCallInfo(state)
}
else -> {
Expand Down Expand Up @@ -410,7 +410,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
avatarRenderer.renderBlur(it, views.bgCallView, sampling = 20, rounded = false, colorFilter = colorFilter, addPlaceholder = false)
if (state.transferee is VectorCallViewState.TransfereeState.NoTransferee) {
views.participantNameText.setTextOrHide(null)
views.callToolbar.title = if (state.isVideoCall) {
toolbar?.title = if (state.isVideoCall) {
getString(R.string.video_call_with_participant, it.getBestName())
} else {
getString(R.string.audio_call_with_participant, it.getBestName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>() {
CallTransferPagerAdapter.DIAL_PAD_INDEX -> tab.text = getString(R.string.call_dial_pad_title)
}
}.attach()
configureToolbar(views.callTransferToolbar)
setupToolbar(views.callTransferToolbar)
.allowBack()
views.callTransferToolbar.title = getString(R.string.call_transfer_title)
setupConnectAction()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class ContactsBookFragment @Inject constructor(
setupFilterView()
setupConsentView()
setupOnlyBoundContactsView()
setupCloseView()
setupToolbar(views.phoneBookToolbar)
.allowBack(useCross = true)
contactsBookViewModel.observeViewEvents {
when (it) {
is ContactsBookViewEvents.Failure -> showFailure(it.throwable)
Expand Down Expand Up @@ -119,12 +120,6 @@ class ContactsBookFragment @Inject constructor(
views.phoneBookRecyclerView.configureWith(contactsBookController)
}

private fun setupCloseView() {
views.phoneBookClose.debouncedClicks {
sharedActionViewModel.post(UserListSharedAction.GoBack)
}
}

override fun invalidate() = withState(contactsBookViewModel) { state ->
views.phoneBookSearchForMatrixContacts.isVisible = state.filteredMappedContacts.isNotEmpty() && state.identityServerUrl != null && !state.userConsent
views.phoneBookOnlyBoundContacts.isVisible = state.isBoundRetrieved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,8 @@ class CreateDirectRoomByQrCodeFragment @Inject constructor() : VectorBaseFragmen
super.onViewCreated(view, savedInstanceState)

setupToolbar(views.qrScannerToolbar)

views.qrScannerClose.debouncedClicks {
requireActivity().onBackPressed()
}
views.qrScannerTitle.text = getString(R.string.add_by_qr_code)
.setTitle(R.string.add_by_qr_code)
.allowBack(useCross = true)
}

override fun onResume() {
Expand Down
Loading

0 comments on commit f7aedff

Please sign in to comment.