From a401f49bce14ffe59e2b6b1b18a163739eba80c2 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 3 Feb 2021 23:19:45 +0100 Subject: [PATCH] OmnipodOverviewFragment -> jetpack --- omnipod/build.gradle | 3 + .../omnipod/ui/OmnipodOverviewFragment.kt | 179 +- .../src/main/res/layout/omnipod_overview.xml | 1641 +++++++++-------- 3 files changed, 921 insertions(+), 902 deletions(-) diff --git a/omnipod/build.gradle b/omnipod/build.gradle index 8fb1b2d51f..19eacc0d1d 100644 --- a/omnipod/build.gradle +++ b/omnipod/build.gradle @@ -19,6 +19,9 @@ android { kotlinOptions { jvmTarget = '1.8' } + buildFeatures { + viewBinding true + } buildTypes { release { diff --git a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt index 6ad44e9ea1..15582f7e6b 100644 --- a/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt +++ b/omnipod/src/main/java/info/nightscout/androidaps/plugins/pump/omnipod/ui/OmnipodOverviewFragment.kt @@ -24,6 +24,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLin import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData import info.nightscout.androidaps.plugins.pump.omnipod.OmnipodPumpPlugin import info.nightscout.androidaps.plugins.pump.omnipod.R +import info.nightscout.androidaps.plugins.pump.omnipod.databinding.OmnipodOverviewBinding import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.ActivationProgress import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.OmnipodConstants import info.nightscout.androidaps.plugins.pump.omnipod.driver.definition.PodProgressStatus @@ -50,7 +51,6 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.ui.UIRunnable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable -import kotlinx.android.synthetic.main.omnipod_overview.* import org.apache.commons.lang3.StringUtils import org.joda.time.DateTime import org.joda.time.Duration @@ -61,8 +61,8 @@ import kotlin.collections.ArrayList class OmnipodOverviewFragment : DaggerFragment() { companion object { - private val REFRESH_INTERVAL_MILLIS = 15 * 1000L // 15 seconds - private val PLACEHOLDER = "-" // 15 seconds + private const val REFRESH_INTERVAL_MILLIS = 15 * 1000L // 15 seconds + private const val PLACEHOLDER = "-" // 15 seconds } @Inject lateinit var fabricPrivacy: FabricPrivacy @@ -92,14 +92,19 @@ class OmnipodOverviewFragment : DaggerFragment() { } } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.omnipod_overview, container, false) - } + private var _binding: OmnipodOverviewBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = + OmnipodOverviewBinding.inflate(inflater, container, false).also { _binding = it }.root override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - omnipod_overview_button_pod_management.setOnClickListener { + binding.buttonPodManagement.setOnClickListener { if (omnipodPumpPlugin.rileyLinkService?.verifyConfiguration() == true) { activity?.let { activity -> context?.let { context -> @@ -114,19 +119,19 @@ class OmnipodOverviewFragment : DaggerFragment() { } } - omnipod_overview_button_resume_delivery.setOnClickListener { + binding.buttonResumeDelivery.setOnClickListener { disablePodActionButtons() commandQueue.customCommand(CommandResumeDelivery(), DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_resume_delivery), true).messageOnSuccess(resourceHelper.gs(R.string.omnipod_confirmation_delivery_resumed))) } - omnipod_overview_button_refresh_status.setOnClickListener { + binding.buttonRefreshStatus.setOnClickListener { disablePodActionButtons() commandQueue.customCommand(CommandGetPodStatus(), DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_refresh_status), false)) } - omnipod_overview_button_acknowledge_active_alerts.setOnClickListener { + binding.buttonAcknowledgeActiveAlerts.setOnClickListener { disablePodActionButtons() commandQueue.customCommand(CommandAcknowledgeAlerts(), DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_acknowledge_alerts), false) @@ -134,14 +139,14 @@ class OmnipodOverviewFragment : DaggerFragment() { .actionOnSuccess { rxBus.send(EventDismissNotification(Notification.OMNIPOD_POD_ALERTS)) }) } - omnipod_overview_button_suspend_delivery.setOnClickListener { + binding.buttonSuspendDelivery.setOnClickListener { disablePodActionButtons() commandQueue.customCommand(CommandSuspendDelivery(), DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_suspend_delivery), true) .messageOnSuccess(resourceHelper.gs(R.string.omnipod_confirmation_suspended_delivery))) } - omnipod_overview_button_set_time.setOnClickListener { + binding.buttonSetTime.setOnClickListener { disablePodActionButtons() commandQueue.customCommand(CommandHandleTimeChange(true), DisplayResultDialogCallback(resourceHelper.gs(R.string.omnipod_error_failed_to_set_time), true) @@ -188,6 +193,12 @@ class OmnipodOverviewFragment : DaggerFragment() { loopHandler.removeCallbacks(refreshLoop) } + @Synchronized + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + private fun updateUi() { updateRileyLinkStatus() updateOmnipodStatus() @@ -202,7 +213,7 @@ class OmnipodOverviewFragment : DaggerFragment() { val resourceId = rileyLinkServiceState.resourceId val rileyLinkError = rileyLinkServiceData.rileyLinkError - omnipod_overview_riley_link_status.text = + binding.rileyLinkStatus.text = when { rileyLinkServiceState == RileyLinkServiceState.NotStarted -> resourceHelper.gs(resourceId) rileyLinkServiceState.isConnecting -> "{fa-bluetooth-b spin} " + resourceHelper.gs(resourceId) @@ -210,7 +221,7 @@ class OmnipodOverviewFragment : DaggerFragment() { rileyLinkServiceState.isError && rileyLinkError != null -> "{fa-bluetooth-b} " + resourceHelper.gs(rileyLinkError.getResourceId(RileyLinkTargetDevice.Omnipod)) else -> "{fa-bluetooth-b} " + resourceHelper.gs(resourceId) } - omnipod_overview_riley_link_status.setTextColor(if (rileyLinkServiceState.isError || rileyLinkError != null) Color.RED else Color.WHITE) + binding.rileyLinkStatus.setTextColor(if (rileyLinkServiceState.isError || rileyLinkError != null) Color.RED else Color.WHITE) } private fun updateOmnipodStatus() { @@ -228,41 +239,41 @@ class OmnipodOverviewFragment : DaggerFragment() { } if (!podStateManager.hasPodState() || !podStateManager.isPodInitialized) { - omnipod_overview_pod_address.text = if (podStateManager.hasPodState()) { + binding.podAddress.text = if (podStateManager.hasPodState()) { podStateManager.address.toString() } else { PLACEHOLDER } - omnipod_overview_pod_lot.text = PLACEHOLDER - omnipod_overview_pod_tid.text = PLACEHOLDER - omnipod_overview_firmware_version.text = PLACEHOLDER - omnipod_overview_time_on_pod.text = PLACEHOLDER - omnipod_overview_pod_expiry_date.text = PLACEHOLDER - omnipod_overview_pod_expiry_date.setTextColor(Color.WHITE) - omnipod_overview_base_basal_rate.text = PLACEHOLDER - omnipod_overview_total_delivered.text = PLACEHOLDER - omnipod_overview_reservoir.text = PLACEHOLDER - omnipod_overview_reservoir.setTextColor(Color.WHITE) - omnipod_overview_pod_active_alerts.text = PLACEHOLDER + binding.podLot.text = PLACEHOLDER + binding.podTid.text = PLACEHOLDER + binding.firmwareVersion.text = PLACEHOLDER + binding.timeOnPod.text = PLACEHOLDER + binding.podExpiryDate.text = PLACEHOLDER + binding.podExpiryDate.setTextColor(Color.WHITE) + binding.baseBasalRate.text = PLACEHOLDER + binding.totalDelivered.text = PLACEHOLDER + binding.reservoir.text = PLACEHOLDER + binding.reservoir.setTextColor(Color.WHITE) + binding.podActiveAlerts.text = PLACEHOLDER } else { - omnipod_overview_pod_address.text = podStateManager.address.toString() - omnipod_overview_pod_lot.text = podStateManager.lot.toString() - omnipod_overview_pod_tid.text = podStateManager.tid.toString() - omnipod_overview_firmware_version.text = resourceHelper.gs(R.string.omnipod_firmware_version_value, podStateManager.pmVersion.toString(), podStateManager.piVersion.toString()) + binding.podAddress.text = podStateManager.address.toString() + binding.podLot.text = podStateManager.lot.toString() + binding.podTid.text = podStateManager.tid.toString() + binding.firmwareVersion.text = resourceHelper.gs(R.string.omnipod_firmware_version_value, podStateManager.pmVersion.toString(), podStateManager.piVersion.toString()) - omnipod_overview_time_on_pod.text = readableZonedTime(podStateManager.time) - omnipod_overview_time_on_pod.setTextColor(if (podStateManager.timeDeviatesMoreThan(OmnipodConstants.TIME_DEVIATION_THRESHOLD)) { + binding.timeOnPod.text = readableZonedTime(podStateManager.time) + binding.timeOnPod.setTextColor(if (podStateManager.timeDeviatesMoreThan(OmnipodConstants.TIME_DEVIATION_THRESHOLD)) { Color.RED } else { Color.WHITE }) val expiresAt = podStateManager.expiresAt if (expiresAt == null) { - omnipod_overview_pod_expiry_date.text = PLACEHOLDER - omnipod_overview_pod_expiry_date.setTextColor(Color.WHITE) + binding.podExpiryDate.text = PLACEHOLDER + binding.podExpiryDate.setTextColor(Color.WHITE) } else { - omnipod_overview_pod_expiry_date.text = readableZonedTime(expiresAt) - omnipod_overview_pod_expiry_date.setTextColor(if (DateTime.now().isAfter(expiresAt)) { + binding.podExpiryDate.text = readableZonedTime(expiresAt) + binding.podExpiryDate.setTextColor(if (DateTime.now().isAfter(expiresAt)) { Color.RED } else { Color.WHITE @@ -275,14 +286,14 @@ class OmnipodOverviewFragment : DaggerFragment() { } // base basal rate - omnipod_overview_base_basal_rate.text = if (podStateManager.isPodActivationCompleted) { + binding.baseBasalRate.text = if (podStateManager.isPodActivationCompleted) { resourceHelper.gs(R.string.pump_basebasalrate, omnipodPumpPlugin.model().determineCorrectBasalSize(podStateManager.basalSchedule.rateAt(TimeUtil.toDuration(DateTime.now())))) } else { PLACEHOLDER } // total delivered - omnipod_overview_total_delivered.text = if (podStateManager.isPodActivationCompleted && podStateManager.totalInsulinDelivered != null) { + binding.totalDelivered.text = if (podStateManager.isPodActivationCompleted && podStateManager.totalInsulinDelivered != null) { resourceHelper.gs(R.string.omnipod_overview_total_delivered_value, podStateManager.totalInsulinDelivered - OmnipodConstants.POD_SETUP_UNITS) } else { PLACEHOLDER @@ -290,21 +301,21 @@ class OmnipodOverviewFragment : DaggerFragment() { // reservoir if (podStateManager.reservoirLevel == null) { - omnipod_overview_reservoir.text = resourceHelper.gs(R.string.omnipod_overview_reservoir_value_over50) - omnipod_overview_reservoir.setTextColor(Color.WHITE) + binding.reservoir.text = resourceHelper.gs(R.string.omnipod_overview_reservoir_value_over50) + binding.reservoir.setTextColor(Color.WHITE) } else { val lowReservoirThreshold = (omnipodAlertUtil.lowReservoirAlertUnits ?: OmnipodConstants.DEFAULT_MAX_RESERVOIR_ALERT_THRESHOLD).toDouble() - omnipod_overview_reservoir.text = resourceHelper.gs(R.string.omnipod_overview_reservoir_value, podStateManager.reservoirLevel) - omnipod_overview_reservoir.setTextColor(if (podStateManager.reservoirLevel < lowReservoirThreshold) { + binding.reservoir.text = resourceHelper.gs(R.string.omnipod_overview_reservoir_value, podStateManager.reservoirLevel) + binding.reservoir.setTextColor(if (podStateManager.reservoirLevel < lowReservoirThreshold) { Color.RED } else { Color.WHITE }) } - omnipod_overview_pod_active_alerts.text = if (podStateManager.hasActiveAlerts()) { + binding.podActiveAlerts.text = if (podStateManager.hasActiveAlerts()) { TextUtils.join(System.lineSeparator(), omnipodUtil.getTranslatedActiveAlerts(podStateManager)) } else { PLACEHOLDER @@ -312,27 +323,27 @@ class OmnipodOverviewFragment : DaggerFragment() { } if (errors.size == 0) { - omnipod_overview_errors.text = PLACEHOLDER - omnipod_overview_errors.setTextColor(Color.WHITE) + binding.errors.text = PLACEHOLDER + binding.errors.setTextColor(Color.WHITE) } else { - omnipod_overview_errors.text = StringUtils.join(errors, System.lineSeparator()) - omnipod_overview_errors.setTextColor(Color.RED) + binding.errors.text = StringUtils.join(errors, System.lineSeparator()) + binding.errors.setTextColor(Color.RED) } } private fun updateLastConnection() { if (podStateManager.isPodInitialized && podStateManager.lastSuccessfulCommunication != null) { - omnipod_overview_last_connection.text = readableDuration(podStateManager.lastSuccessfulCommunication) + binding.lastConnection.text = readableDuration(podStateManager.lastSuccessfulCommunication) val lastConnectionColor = if (omnipodPumpPlugin.isUnreachableAlertTimeoutExceeded(getPumpUnreachableTimeout().millis)) { Color.RED } else { Color.WHITE } - omnipod_overview_last_connection.setTextColor(lastConnectionColor) + binding.lastConnection.setTextColor(lastConnectionColor) } else { - omnipod_overview_last_connection.setTextColor(Color.WHITE) - omnipod_overview_last_connection.text = if (podStateManager.hasPodState() && podStateManager.lastSuccessfulCommunication != null) { + binding.lastConnection.setTextColor(Color.WHITE) + binding.lastConnection.text = if (podStateManager.hasPodState() && podStateManager.lastSuccessfulCommunication != null) { readableDuration(podStateManager.lastSuccessfulCommunication) } else { PLACEHOLDER @@ -341,7 +352,7 @@ class OmnipodOverviewFragment : DaggerFragment() { } private fun updatePodStatus() { - omnipod_overview_pod_status.text = if (!podStateManager.hasPodState()) { + binding.podStatus.text = if (!podStateManager.hasPodState()) { resourceHelper.gs(R.string.omnipod_pod_status_no_active_pod) } else if (!podStateManager.isPodActivationCompleted) { if (!podStateManager.isPodInitialized) { @@ -380,7 +391,7 @@ class OmnipodOverviewFragment : DaggerFragment() { } else { Color.WHITE } - omnipod_overview_pod_status.setTextColor(podStatusColor) + binding.podStatus.setTextColor(podStatusColor) } private fun updateLastBolus() { @@ -395,20 +406,20 @@ class OmnipodOverviewFragment : DaggerFragment() { text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")" } - omnipod_overview_last_bolus.text = text - omnipod_overview_last_bolus.setTextColor(textColor) + binding.lastBolus.text = text + binding.lastBolus.setTextColor(textColor) } else { - omnipod_overview_last_bolus.text = PLACEHOLDER - omnipod_overview_last_bolus.setTextColor(Color.WHITE) + binding.lastBolus.text = PLACEHOLDER + binding.lastBolus.setTextColor(Color.WHITE) } } private fun updateTempBasal() { if (podStateManager.isPodActivationCompleted && podStateManager.isTempBasalRunning) { if (!podStateManager.hasTempBasal()) { - omnipod_overview_temp_basal.text = "???" - omnipod_overview_temp_basal.setTextColor(Color.RED) + binding.tempBasal.text = "???" + binding.tempBasal.setTextColor(Color.RED) } else { val now = DateTime.now() @@ -428,8 +439,8 @@ class OmnipodOverviewFragment : DaggerFragment() { text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")" } - omnipod_overview_temp_basal.text = text - omnipod_overview_temp_basal.setTextColor(textColor) + binding.tempBasal.text = text + binding.tempBasal.setTextColor(textColor) } } else { var text = PLACEHOLDER @@ -442,17 +453,17 @@ class OmnipodOverviewFragment : DaggerFragment() { text += " (" + resourceHelper.gs(R.string.omnipod_uncertain) + ")" } - omnipod_overview_temp_basal.text = text - omnipod_overview_temp_basal.setTextColor(textColor) + binding.tempBasal.text = text + binding.tempBasal.setTextColor(textColor) } } private fun updateQueueStatus() { if (isQueueEmpty()) { - omnipod_overview_queue.visibility = View.GONE + binding.queue.visibility = View.GONE } else { - omnipod_overview_queue.visibility = View.VISIBLE - omnipod_overview_queue.text = commandQueue.spannedStatus().toString() + binding.queue.visibility = View.VISIBLE + binding.queue.text = commandQueue.spannedStatus().toString() } } @@ -465,52 +476,52 @@ class OmnipodOverviewFragment : DaggerFragment() { } private fun disablePodActionButtons() { - omnipod_overview_button_acknowledge_active_alerts.isEnabled = false - omnipod_overview_button_resume_delivery.isEnabled = false - omnipod_overview_button_suspend_delivery.isEnabled = false - omnipod_overview_button_set_time.isEnabled = false - omnipod_overview_button_refresh_status.isEnabled = false + binding.buttonAcknowledgeActiveAlerts.isEnabled = false + binding.buttonResumeDelivery.isEnabled = false + binding.buttonSuspendDelivery.isEnabled = false + binding.buttonSetTime.isEnabled = false + binding.buttonRefreshStatus.isEnabled = false } private fun updateRefreshStatusButton() { - omnipod_overview_button_refresh_status.isEnabled = podStateManager.isPodInitialized && podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED) + binding.buttonRefreshStatus.isEnabled = podStateManager.isPodInitialized && podStateManager.activationProgress.isAtLeast(ActivationProgress.PAIRING_COMPLETED) && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } private fun updateResumeDeliveryButton() { if (podStateManager.isPodRunning && (podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandResumeDelivery::class.java))) { - omnipod_overview_button_resume_delivery.visibility = View.VISIBLE - omnipod_overview_button_resume_delivery.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + binding.buttonResumeDelivery.visibility = View.VISIBLE + binding.buttonResumeDelivery.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_overview_button_resume_delivery.visibility = View.GONE + binding.buttonResumeDelivery.visibility = View.GONE } } private fun updateAcknowledgeAlertsButton() { if (!omnipodManager.isAutomaticallyAcknowledgeAlertsEnabled && podStateManager.isPodRunning && (podStateManager.hasActiveAlerts() || commandQueue.isCustomCommandInQueue(CommandAcknowledgeAlerts::class.java))) { - omnipod_overview_button_acknowledge_active_alerts.visibility = View.VISIBLE - omnipod_overview_button_acknowledge_active_alerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + binding.buttonAcknowledgeActiveAlerts.visibility = View.VISIBLE + binding.buttonAcknowledgeActiveAlerts.isEnabled = rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_overview_button_acknowledge_active_alerts.visibility = View.GONE + binding.buttonAcknowledgeActiveAlerts.visibility = View.GONE } } private fun updateSuspendDeliveryButton() { // If the Pod is currently suspended, we show the Resume delivery button instead. if (omnipodManager.isSuspendDeliveryButtonEnabled && podStateManager.isPodRunning && (!podStateManager.isSuspended || commandQueue.isCustomCommandInQueue(CommandSuspendDelivery::class.java))) { - omnipod_overview_button_suspend_delivery.visibility = View.VISIBLE - omnipod_overview_button_suspend_delivery.isEnabled = podStateManager.isPodRunning && !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + binding.buttonSuspendDelivery.visibility = View.VISIBLE + binding.buttonSuspendDelivery.isEnabled = podStateManager.isPodRunning && !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_overview_button_suspend_delivery.visibility = View.GONE + binding.buttonSuspendDelivery.visibility = View.GONE } } private fun updateSetTimeButton() { if (podStateManager.isPodRunning && (podStateManager.timeDeviatesMoreThan(Duration.standardMinutes(5)) || commandQueue.isCustomCommandInQueue(CommandHandleTimeChange::class.java))) { - omnipod_overview_button_set_time.visibility = View.VISIBLE - omnipod_overview_button_set_time.isEnabled = !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() + binding.buttonSetTime.visibility = View.VISIBLE + binding.buttonSetTime.isEnabled = !podStateManager.isSuspended && rileyLinkServiceData.rileyLinkServiceState.isReady && isQueueEmpty() } else { - omnipod_overview_button_set_time.visibility = View.GONE + binding.buttonSetTime.visibility = View.GONE } } diff --git a/omnipod/src/main/res/layout/omnipod_overview.xml b/omnipod/src/main/res/layout/omnipod_overview.xml index 46ee486de3..f646296e90 100644 --- a/omnipod/src/main/res/layout/omnipod_overview.xml +++ b/omnipod/src/main/res/layout/omnipod_overview.xml @@ -1,853 +1,858 @@ - - + android:layout_height="match_parent" + android:layout_above="@+id/buttons" + android:fillViewport="true"> - + android:layout_height="wrap_content" + android:orientation="vertical"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:orientation="horizontal" + android:paddingTop="2dp" + android:paddingBottom="5dp" + android:visibility="gone"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_marginLeft="5dp" + android:layout_marginRight="5dp" + android:gravity="center_vertical|center_horizontal" + android:text="@string/initializing" + android:textAppearance="?android:attr/textAppearanceSmall" /> - - - + -