Skip to content

Commit

Permalink
refactor(type): improve type class
Browse files Browse the repository at this point in the history
  • Loading branch information
Irineu333 committed Nov 17, 2023
1 parent 72df8fb commit 04be3c6
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import android.content.Context
import android.speech.tts.TextToSpeech
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import com.neo.speaktouch.utils.Reader
import com.neo.speaktouch.model.UiText
import com.neo.speaktouch.model.Text
import com.neo.speaktouch.utils.extension.getLog
import timber.log.Timber

Expand All @@ -45,7 +45,7 @@ class SpeechController(
)
}

fun speak(text: UiText) {
fun speak(text: Text) {
Timber.i("speak: $text")

speak(text.resolved(context))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import com.neo.speaktouch.controller.Controllers
import com.neo.speaktouch.controller.SpeechController
import com.neo.speaktouch.controller.VibratorController
import com.neo.speaktouch.utils.Reader
import com.neo.speaktouch.model.UiText
import com.neo.speaktouch.model.Text
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand Down Expand Up @@ -63,7 +63,7 @@ object ControllerModule {
val textToSpeech = TextToSpeech(context) { status ->
if (status == TextToSpeech.SUCCESS) {
Controllers.speech.speak(
UiText(R.string.speak_touch_activated)
Text(R.string.speak_touch_activated)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ package com.neo.speaktouch.model
import android.content.Context
import androidx.annotation.StringRes

sealed interface UiText {
sealed interface Text {

val args: List<Any>

data class Raw(
val text: String,
override val args: List<Any>
) : UiText
) : Text

data class Res(
@StringRes val res: Int,
override val args: List<Any>
) : UiText
) : Text

fun resolved(context: Context): String {
val text = when (this) {
Expand All @@ -45,16 +45,15 @@ sealed interface UiText {
return text
}

val args = resolvedArgs(context)
.toTypedArray()
val args = resolvedArgs(context).toTypedArray()

return String.format(text, *args)
}

fun resolvedArgs(context: Context): List<Any> {
return args.map { arg ->
when (arg) {
is UiText -> {
is Text -> {
arg.resolved(context)
}

Expand Down
110 changes: 69 additions & 41 deletions app/src/main/java/com/neo/speaktouch/model/Type.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

package com.neo.speaktouch.model

import android.os.Build
import android.widget.AbsListView
import android.widget.AbsSpinner
import android.widget.Button
import android.widget.CheckBox
import android.widget.CheckedTextView
import android.widget.EditText
Expand All @@ -30,76 +30,104 @@ import android.widget.RadioButton
import android.widget.Switch
import android.widget.ToggleButton
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import com.neo.speaktouch.R
import com.neo.speaktouch.utils.extension.`is`

enum class Type {
NONE,
IMAGE,
SWITCH,
TOGGLE,
RADIO,
CHECKBOX,
BUTTON,
EDITFIELD,
OPTIONS,
LIST,
TITLE,
CHECKEDTEXT;
sealed class Type {

object Image : Type()

sealed class Checkable : Type() {
object Switch : Checkable()

object Toggle : Checkable()

object Radio : Checkable()

object Checkbox : Checkable()

object TextView : Checkable()
}

object Button : Type()

object EditField : Type()

object DropdownList : Type()

object List : Type()

object Title : Type()

companion object {
fun get(node: AccessibilityNodeInfoCompat): Type {
val className = node.className ?: return NONE
fun get(node: AccessibilityNodeInfoCompat): Type? {

val className = node.className ?: return null

/* ImageView */

// View->ImageView->ImageButton
if (className `is` ImageButton::class.java) return BUTTON
// View -> ImageView -> ImageButton
if (className `is` ImageButton::class.java) return Button

// View->ImageView
// View -> ImageView
if (className `is` ImageView::class.java) {
return if (node.isClickable) BUTTON else IMAGE
return if (node.isClickable) Button else Image
}

/* TextView */

// View->TextView->EditText
if (className `is` EditText::class.java) return EDITFIELD
// View -> TextView -> EditText
if (className `is` EditText::class.java) return EditField

// View->TextView->CheckedTextView
if (className `is` CheckedTextView::class.java) return CHECKEDTEXT
// View -> TextView -> CheckedTextView
if (className `is` CheckedTextView::class.java) return Checkable.TextView

/* Button */

// View->TextView->Button->CompoundButton->Switch
if (className `is` Switch::class.java) return SWITCH
// View -> TextView -> Button -> CompoundButton -> Switch
if (className `is` Switch::class.java) return Checkable.Switch

// View->TextView->Button->CompoundButton->ToggleButton
if (className `is` ToggleButton::class.java) return TOGGLE
// View -> TextView -> Button -> CompoundButton -> ToggleButton
if (className `is` ToggleButton::class.java) return Checkable.Toggle

// View->TextView->Button->CompoundButton->RadioButton
if (className `is` RadioButton::class.java) return RADIO
// View -> TextView -> Button -> CompoundButton -> RadioButton
if (className `is` RadioButton::class.java) return Checkable.Radio

// View->TextView->Button->CompoundButton->CheckBox
if (className `is` CheckBox::class.java) return CHECKBOX
// View -> TextView -> Button -> CompoundButton -> CheckBox
if (className `is` CheckBox::class.java) return Checkable.Checkbox

// View->TextView->Button
if (className `is` Button::class.java) return BUTTON
// View -> TextView -> Button
if (className `is` android.widget.Button::class.java) return Button

/* AdapterView */

// View->ViewGroup->AdapterView->AbsListView
if (className `is` AbsListView::class.java) return LIST
// View -> ViewGroup -> AdapterView -> AbsListView
if (className `is` AbsListView::class.java) return List

// View->ViewGroup->AdapterView->AbsSpinner
if (className `is` AbsSpinner::class.java) return OPTIONS
// View -> ViewGroup -> AdapterView -> AbsSpinner
if (className `is` AbsSpinner::class.java) return DropdownList

/* Independent of inheritance */

if (node.collectionInfo != null) return LIST
if (node.collectionInfo != null) return List

if (node.isHeading) return TITLE
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && node.isHeading) return Title

return NONE
return null
}
}
}

fun Type.toTypeText() = when (this) {
Type.Button -> Text(R.string.text_button_type)
Type.DropdownList -> Text(R.string.text_options_type)
Type.EditField -> Text(R.string.text_editfield_type)
Type.Image -> Text(R.string.text_image_type)
Type.List -> Text(R.string.text_list_type)
Type.Title -> Text(R.string.text_title_type)
Type.Checkable.Checkbox -> Text(R.string.text_checkbox_type)
Type.Checkable.Radio -> Text(R.string.text_radio_type)
Type.Checkable.Switch -> Text(R.string.text_switch_type)
Type.Checkable.Toggle -> Text(R.string.text_toggle_type)
Type.Checkable.TextView -> null /* don't speak type */
}
63 changes: 6 additions & 57 deletions app/src/main/java/com/neo/speaktouch/utils/Reader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.neo.speaktouch.utils.extension.filterNotNullOrEmpty
import com.neo.speaktouch.utils.extension.getLog
import com.neo.speaktouch.utils.extension.ifEmptyOrNull
import com.neo.speaktouch.utils.extension.iterator
import com.neo.speaktouch.utils.extension.toText
import timber.log.Timber
import javax.inject.Inject

Expand Down Expand Up @@ -84,10 +85,10 @@ class Reader @Inject constructor(
Level.Text(
mustReadSelection = false,
mustReadType = listOf(
Type.SWITCH,
Type.TOGGLE,
Type.RADIO,
Type.CHECKBOX
Type.Checkable.Switch,
Type.Checkable.Toggle,
Type.Checkable.Radio,
Type.Checkable.Checkbox
).any { it == Type.get(child) }
)
)
Expand All @@ -104,59 +105,7 @@ class Reader @Inject constructor(

if (!mustRead) return null

return when (Type.get(node)) {
Type.NONE -> null
Type.IMAGE -> context.getString(R.string.text_image_type)
Type.SWITCH -> {
val switchType = context.getString(R.string.text_switch_type)
val selectionStatus = if (node.isChecked) {
node.stateDescription?.toString() ?: context.getString(R.string.text_enabled)
} else {
node.stateDescription?.toString() ?: context.getString(R.string.text_disabled)
}
"$switchType, $selectionStatus"
}
Type.TOGGLE -> {
val toggleType = context.getString(R.string.text_toggle_type)
val selectionStatus = if (node.isChecked) {
node.stateDescription?.toString() ?: context.getString(R.string.text_pressed)
} else {
node.stateDescription?.toString() ?: context.getString(R.string.text_not_pressed)
}
"$toggleType, $selectionStatus"
}
Type.RADIO -> {
val radioButtonType = context.getString(R.string.text_radio_type)
val selectionStatus = if (node.isChecked) {
node.stateDescription?.toString() ?: context.getString(R.string.text_selected)
} else {
node.stateDescription?.toString() ?: context.getString(R.string.text_not_selected)
}
"$radioButtonType, $selectionStatus"
}
Type.CHECKBOX -> {
val checkboxType = context.getString(R.string.text_checkbox_type)
val selectionStatus = if (node.isChecked) {
node.stateDescription?.toString() ?: context.getString(R.string.text_checked)
} else {
node.stateDescription?.toString() ?: context.getString(R.string.text_not_checked)
}
"$checkboxType, $selectionStatus"
}
Type.BUTTON -> context.getString(R.string.text_button_type)
Type.EDITFIELD -> context.getString(R.string.text_editfield_type)
Type.OPTIONS -> context.getString(R.string.text_options_type)
Type.LIST -> context.getString(R.string.text_list_type)
Type.TITLE -> context.getString(R.string.text_title_type)
Type.CHECKEDTEXT -> {
val selectionStatus = if (node.isChecked) {
node.stateDescription?.toString() ?: context.getString(R.string.text_selected)
} else {
""
}
"$selectionStatus"
}
}
return node.toText()?.resolved(context)
}

private fun getSelection(
Expand Down
Loading

0 comments on commit 04be3c6

Please sign in to comment.