Skip to content

Commit b028af5

Browse files
authored
Merge pull request #11 from algolia/feat/customization
Feat/customization
2 parents 5c9418d + cddc6f5 commit b028af5

File tree

4 files changed

+59
-41
lines changed

4 files changed

+59
-41
lines changed

app/src/main/kotlin/com/algolia/instantsearch/voice/demo/MainActivity.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import android.support.v7.app.AppCompatActivity
55
import android.view.View
66
import com.algolia.instantsearch.voice.VoiceSpeechRecognizer
77
import com.algolia.instantsearch.voice.ui.Voice
8+
import com.algolia.instantsearch.voice.ui.Voice.isRecordAudioPermissionGranted
9+
import com.algolia.instantsearch.voice.ui.Voice.shouldExplainPermission
10+
import com.algolia.instantsearch.voice.ui.Voice.showPermissionRationale
811
import com.algolia.instantsearch.voice.ui.VoiceInputDialogFragment
912
import com.algolia.instantsearch.voice.ui.VoicePermissionDialogFragment
1013
import kotlinx.android.synthetic.main.main.*
@@ -23,7 +26,7 @@ class MainActivity : AppCompatActivity(), VoiceSpeechRecognizer.ResultsListener
2326
setContentView(R.layout.main)
2427

2528
main.buttonVoice.setOnClickListener { _ ->
26-
if (!Voice.isRecordAudioPermissionGranted(this)) {
29+
if (!isRecordAudioPermissionGranted()) {
2730
VoicePermissionDialogFragment().show(supportFragmentManager, Tag.Permission.name)
2831
} else {
2932
showVoiceDialog()
@@ -44,7 +47,7 @@ class MainActivity : AppCompatActivity(), VoiceSpeechRecognizer.ResultsListener
4447
if (Voice.isRecordPermissionWithResults(requestCode, grantResults)) {
4548
when {
4649
Voice.isPermissionGranted(grantResults) -> showVoiceDialog()
47-
Voice.shouldExplainPermission(this) -> Voice.showPermissionRationale(getPermissionView(), this)
50+
shouldExplainPermission() -> showPermissionRationale(getPermissionView())
4851
else -> Voice.showPermissionManualInstructions(getPermissionView())
4952
}
5053
}
@@ -53,8 +56,7 @@ class MainActivity : AppCompatActivity(), VoiceSpeechRecognizer.ResultsListener
5356
private fun showVoiceDialog() {
5457
getPermissionDialog()?.dismiss()
5558
(getVoiceDialog() ?: VoiceInputDialogFragment()).let {
56-
it.setArguments(
57-
"Hey, I just met you",
59+
it.setSuggestions("Hey, I just met you",
5860
"And this is crazy",
5961
"But here's my number",
6062
"So call me maybe"

ui/src/main/kotlin/com/algolia/instantsearch/voice/ui/Voice.kt

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,46 +39,45 @@ object Voice {
3939
* Gets whether your application was granted the [recording permission][RECORD_AUDIO].
4040
*/
4141
@JvmStatic
42-
fun isRecordAudioPermissionGranted(context: Context) =
43-
ContextCompat.checkSelfPermission(context, RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
42+
fun Context.isRecordAudioPermissionGranted() =
43+
ContextCompat.checkSelfPermission(this, RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
4444

4545
/**
46-
* Gets whether your [activity] should show UI with rationale for requesting the [recording permission][RECORD_AUDIO].
46+
* Gets whether your activity should show UI with rationale for requesting the [recording permission][RECORD_AUDIO].
4747
*/
4848
@JvmStatic
49-
fun shouldExplainPermission(activity: Activity) =
50-
ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.RECORD_AUDIO)
49+
fun Activity.shouldExplainPermission() =
50+
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)
5151

5252
/**
53-
* Requests the [recording permission][RECORD_AUDIO] from your [activity].*/
53+
* Requests the [recording permission][RECORD_AUDIO] from your activity.*/
5454
@JvmStatic
55-
fun requestPermission(activity: Activity) {
56-
ActivityCompat.requestPermissions(activity, arrayOf(RECORD_AUDIO), PermissionRequestRecordAudio)
55+
fun Activity.requestRecordingPermission() {
56+
ActivityCompat.requestPermissions(this, arrayOf(RECORD_AUDIO), PermissionRequestRecordAudio)
5757
}
5858

59-
/** Opens the application's settings from a given [context], so the user can enable recording permission.*/
59+
/** Opens the application's settings from a given context, so the user can enable the recording permission.*/
6060
@JvmStatic
61-
fun openAppSettings(context: Context) {
62-
context.startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
63-
.setData(Uri.fromParts("package", context.packageName, null)))
61+
fun Context.openAppSettings() {
62+
startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
63+
.setData(Uri.fromParts("package", packageName, null)))
6464
}
6565

6666
/** Displays the rationale behind requesting the recording permission via a [Snackbar].
6767
* @param anchor the view on which the SnackBar will be anchored.
68-
* @param activity the activity which would request the permission.
6968
* @param whyAllow a description of why the permission should be granted.
7069
* @param buttonAllow a call to action for granting the permission.
7170
* */
7271
@JvmStatic
73-
fun showPermissionRationale(
72+
@JvmOverloads
73+
fun Activity.showPermissionRationale(
7474
anchor: View,
75-
activity: Activity,
7675
whyAllow: CharSequence? = null,
7776
buttonAllow: CharSequence? = null
7877
) {
79-
val whyText = whyAllow ?: activity.getString(R.string.permission_rationale)
80-
val buttonText = (buttonAllow ?: activity.getString(R.string.permission_button_again))
81-
Snackbar.make(anchor, whyText, Snackbar.LENGTH_LONG).setAction(buttonText) { requestPermission(activity) }.show()
78+
val whyText = whyAllow ?: getString(R.string.permission_rationale)
79+
val buttonText = (buttonAllow ?: getString(R.string.permission_button_again))
80+
Snackbar.make(anchor, whyText, Snackbar.LENGTH_LONG).setAction(buttonText) { requestRecordingPermission() }.show()
8281
}
8382

8483
/** Guides the user to manually enable recording permission in the app's settings.
@@ -88,6 +87,7 @@ object Voice {
8887
* @param howEnable instructions to manually enable the permission in settings.
8988
* */
9089
@JvmStatic
90+
@JvmOverloads
9191
fun showPermissionManualInstructions(
9292
anchor: View,
9393
whyEnable: CharSequence? = null,
@@ -102,12 +102,10 @@ object Voice {
102102
val snackbar = Snackbar.make(anchor, whyText, Snackbar.LENGTH_LONG).setAction(buttonText) {
103103
Snackbar.make(anchor, howText, Snackbar.LENGTH_SHORT)
104104
.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
105-
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) = openAppSettings(context)
105+
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) = context.openAppSettings()
106106
}).show()
107107
}
108108
(snackbar.view.findViewById(android.support.design.R.id.snackbar_text) as TextView).maxLines = 2
109109
snackbar.show()
110110
}
111-
}
112-
113-
//TODO: Expose Activity extension methods instead?
111+
}

ui/src/main/kotlin/com/algolia/instantsearch/voice/ui/VoiceAndroidView.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ class VoiceAndroidView(
4242
view.voiceInput.subtitle.text = subtitle
4343
}
4444

45-
override fun setSubtitle(subtitle: VoiceUI.Subtitle) {
46-
view.voiceInput.subtitle.setText(subtitle.resource)
47-
}
45+
override fun setSubtitle(subtitle: VoiceUI.Subtitle) = view.voiceInput.subtitle.setText(subtitle.resource)
4846

4947
override fun setSuggestionVisibility(isVisible: Boolean) {
5048
view.voiceInput.suggestions.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
@@ -54,9 +52,8 @@ class VoiceAndroidView(
5452
view.voiceInput.hint.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
5553
}
5654

57-
override fun setRippleActivity(isActive: Boolean) {
55+
override fun setRippleActivity(isActive: Boolean) =
5856
if (isActive) view.voiceInput.ripple.start() else view.voiceInput.ripple.cancel()
59-
}
6057

6158
override fun setMicrophoneState(state: VoiceMicrophone.State) {
6259
view.voiceInput.microphone.state = state

ui/src/main/kotlin/com/algolia/instantsearch/voice/ui/VoiceInputDialogFragment.kt

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,50 @@ import kotlinx.android.synthetic.main.voice_input.*
1212
class VoiceInputDialogFragment : DialogFragment() {
1313

1414
private enum class Field {
15-
Suggestions
15+
Suggestions,
16+
AutoStart
1617
}
1718

1819
private lateinit var speechRecognizer: VoiceSpeechRecognizer
1920

20-
private var suggestions: Array<out String>? = null
21+
/** suggestions to display to the user before they speak. */
22+
var suggestions: Array<out String>? = null
23+
@JvmName("setSuggestionsArray")
24+
set(value) {
25+
if (arguments == null) {
26+
arguments = Bundle()
27+
}
28+
arguments?.putStringArray(Field.Suggestions.name, value)
29+
field = value
30+
}
2131

22-
/** Defines suggestions to display to the user before they speak. */
23-
fun setArguments(vararg suggestions: String) {
24-
arguments = Bundle().also {
25-
it.putStringArray(Field.Suggestions.name, suggestions)
32+
/** set to `false` if you want to manually [start] the voice recognition. */
33+
var autoStart: Boolean = true
34+
set(value) {
35+
if (arguments == null) arguments = Bundle()
36+
arguments?.putBoolean(Field.AutoStart.name, value)
37+
field = value
2638
}
39+
40+
/** Sets [suggestions] to display to the user before they speak. */
41+
@Suppress("unused") // Java DX: Expose vararg setter
42+
fun setSuggestions(vararg suggestions: String) {
43+
this.suggestions = suggestions
2744
}
2845

46+
/** Starts listening to user input, in case you disabled [autoStart]. */
47+
fun start() = speechRecognizer.start()
48+
49+
// region Lifecycle
2950
override fun onCreate(savedInstanceState: Bundle?) {
3051
super.onCreate(savedInstanceState)
3152
setStyle(DialogFragment.STYLE_NORMAL, R.style.VoiceDialogTheme)
3253
speechRecognizer = VoiceSpeechRecognizer(requireContext())
3354
suggestions = arguments?.getStringArray(Field.Suggestions.name)
3455
}
3556

36-
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
37-
return inflater.inflate(R.layout.voice_input, container, false)
38-
}
57+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
58+
inflater.inflate(R.layout.voice_input, container, false)
3959

4060
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
4161
super.onViewCreated(view, savedInstanceState)
@@ -60,7 +80,7 @@ class VoiceInputDialogFragment : DialogFragment() {
6080

6181
override fun onResume() {
6282
super.onResume()
63-
speechRecognizer.start()
83+
if (autoStart) start()
6484
}
6585

6686
override fun onPause() {
@@ -72,4 +92,5 @@ class VoiceInputDialogFragment : DialogFragment() {
7292
super.onDestroy()
7393
speechRecognizer.destroy()
7494
}
95+
//endregion
7596
}

0 commit comments

Comments
 (0)