Skip to content

Commit

Permalink
feat(app): add dynamic app shortcuts for presets
Browse files Browse the repository at this point in the history
resolves #579
  • Loading branch information
ashutoshgngwr committed Apr 23, 2021
1 parent 6969004 commit 2248a50
Show file tree
Hide file tree
Showing 17 changed files with 127 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class PresetFragmentTest {
}

mockkObject(InAppReviewFlowManager, Preset.Companion, MediaPlayerService.Companion)
mockkStatic(ShortcutManagerCompat::class)
every { Preset.readAllFromUserPreferences(any()) } returns arrayOf(mockPreset)
fragmentScenario = launchFragmentInContainer(null, R.style.Theme_App)
}
Expand Down Expand Up @@ -136,6 +137,7 @@ class PresetFragmentTest {
onView(withText("test")).check(doesNotExist())
verify(exactly = 1) {
Preset.writeAllToUserPreferences(any(), emptyList())
ShortcutManagerCompat.removeDynamicShortcuts(any(), listOf("test-id"))
InAppReviewFlowManager.maybeAskForReview(any())
}
}
Expand Down Expand Up @@ -213,8 +215,6 @@ class PresetFragmentTest {

@Test
fun testRecyclerViewItem_AddToHomeScreenOption() {
mockkStatic(ShortcutManagerCompat::class)

val pinShortcutSupportedExpectations = arrayOf(false, true)
val expectedRequestPinShortcutCalls = arrayOf(0, 1)

Expand Down Expand Up @@ -260,13 +260,60 @@ class PresetFragmentTest {
)

onView(withId(com.google.android.material.R.id.snackbar_text))
.check(matches(withText(R.string.shortcuts_not_supported)))
.check(matches(withText(R.string.pinned_shortcuts_not_supported)))
}

clearStaticMockk(ShortcutManagerCompat::class)
}
}

@Test
fun testRecyclerViewItem_addToAppShortcuts() {
every { ShortcutManagerCompat.addDynamicShortcuts(any(), any()) } returns true
every { ShortcutManagerCompat.getDynamicShortcuts(any()) } returns mutableListOf()

// open context menu
onView(withId(R.id.preset_list)).perform(
RecyclerViewActions.actionOnItem<PresetFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickInItem(R.id.menu_button)
)
)

onView(withText(R.string.add_to_app_shortcuts)).perform(click())

val shortcutInfoSlot = slot<List<ShortcutInfoCompat>>()
verify(exactly = 1) {
ShortcutManagerCompat.addDynamicShortcuts(any(), capture(shortcutInfoSlot))
}

assertEquals(1, shortcutInfoSlot.captured.size)
assertEquals("test-id", shortcutInfoSlot.captured[0].id)
}

@Test
fun testRecyclerViewItem_removeFromAppShortcuts() {
every { ShortcutManagerCompat.getDynamicShortcuts(any()) } returns listOf(
mockk(relaxed = true) {
every { id } returns mockPreset.id
}
)

// open context menu
onView(withId(R.id.preset_list)).perform(
RecyclerViewActions.actionOnItem<PresetFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickInItem(R.id.menu_button)
)
)

onView(withText(R.string.remove_from_app_shortcuts)).perform(click())

verify(exactly = 1) {
ShortcutManagerCompat.removeDynamicShortcuts(any(), listOf("test-id"))
}
}

@Test
fun testShouldShowAsHomeScreenSwitch_whenInitiallyUnchecked() {
val mockPrefsEditor = mockk<SharedPreferences.Editor>(relaxed = true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ class PresetFragment : Fragment() {

val onMenuItemClickListener = PopupMenu.OnMenuItemClickListener {
when (it.itemId) {
R.id.action_create_shortcut -> createShortcut()
R.id.action_create_pinned_shortcut -> createPinnedShortcut()
R.id.action_create_app_shortcut -> createAppShortcut()
R.id.action_remove_app_shortcut -> removeAppShortcut()
R.id.action_delete -> showDeletePresetConfirmation()
R.id.action_rename -> showRenamePresetInput()
}
Expand All @@ -142,32 +144,68 @@ class PresetFragment : Fragment() {
binding.menuButton.setOnClickListener {
PopupMenu(requireContext(), binding.menuButton).let {
it.inflate(R.menu.preset)
val hasAppShortcut = hasAppShortcut()
it.menu.findItem(R.id.action_create_app_shortcut).isVisible = !hasAppShortcut
it.menu.findItem(R.id.action_remove_app_shortcut).isVisible = hasAppShortcut
it.setOnMenuItemClickListener(onMenuItemClickListener)
it.show()
}
}
}

private fun createShortcut() {
private fun createPinnedShortcut() {
if (!ShortcutManagerCompat.isRequestPinShortcutSupported(requireContext())) {
Snackbar.make(requireView(), R.string.shortcuts_not_supported, Snackbar.LENGTH_LONG).show()
Snackbar.make(requireView(), R.string.pinned_shortcuts_not_supported, Snackbar.LENGTH_LONG)
.show()
return
}

val shortcutID = UUID.randomUUID().toString()
val info = buildShortcutInfo(UUID.randomUUID().toString())
ShortcutManagerCompat.requestPinShortcut(requireContext(), info, null)
}

private fun createAppShortcut() {
val list = ShortcutManagerCompat.getDynamicShortcuts(requireContext())
val presetID = dataSet[adapterPosition].id
list.add(buildShortcutInfo(presetID))

var message = R.string.app_shortcut_creation_failed
if (ShortcutManagerCompat.addDynamicShortcuts(requireContext(), list)) {
message = R.string.app_shortcut_created
}

Snackbar.make(requireView(), message, Snackbar.LENGTH_LONG).show()
}

private fun removeAppShortcut() {
val presetID = dataSet[adapterPosition].id
ShortcutInfoCompat.Builder(requireContext(), shortcutID).also {
it.setShortLabel(dataSet[adapterPosition].name)
it.setIcon(IconCompat.createWithResource(requireContext(), R.mipmap.ic_preset_shortcut))
it.setIntent(
ShortcutManagerCompat.removeDynamicShortcuts(requireContext(), listOf(presetID))
Snackbar.make(requireView(), R.string.app_shortcut_removed, Snackbar.LENGTH_LONG).show()
}

private fun hasAppShortcut(): Boolean {
ShortcutManagerCompat.getDynamicShortcuts(requireContext()).forEach {
if (it.id == dataSet[adapterPosition].id) {
return true
}
}

return false
}

private fun buildShortcutInfo(shortcutID: String): ShortcutInfoCompat {
return with(ShortcutInfoCompat.Builder(requireContext(), shortcutID)) {
setShortLabel(dataSet[adapterPosition].name)
setIcon(IconCompat.createWithResource(requireContext(), R.mipmap.ic_preset_shortcut))
setIntent(
Intent(requireContext(), ShortcutHandlerActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
.putExtra(ShortcutHandlerActivity.EXTRA_SHORTCUT_ID, shortcutID)
.putExtra(ShortcutHandlerActivity.EXTRA_PRESET_ID, presetID)
.putExtra(ShortcutHandlerActivity.EXTRA_PRESET_ID, dataSet[adapterPosition].id)
)

ShortcutManagerCompat.requestPinShortcut(requireContext(), it.build(), null)
build()
}
}

Expand Down Expand Up @@ -218,6 +256,7 @@ class PresetFragment : Fragment() {
}

cancelWakeUpTimerIfScheduled(preset.id)
ShortcutManagerCompat.removeDynamicShortcuts(requireContext(), listOf(preset.id))
adapter?.notifyItemRemoved(adapterPosition)
updateEmptyListIndicatorVisibility()
Snackbar.make(requireView(), R.string.preset_deleted, Snackbar.LENGTH_LONG)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:tint="@color/primary"
android:tint="@color/woodsmoke"
android:viewportWidth="108"
android:viewportHeight="108">
<group
Expand Down
10 changes: 9 additions & 1 deletion app/src/main/res/menu/preset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item
android:id="@+id/action_create_shortcut"
android:id="@+id/action_create_pinned_shortcut"
android:title="@string/add_to_home_screen" />

<item
android:id="@+id/action_create_app_shortcut"
android:title="@string/add_to_app_shortcuts" />

<item
android:id="@+id/action_remove_app_shortcut"
android:title="@string/remove_from_app_shortcuts" />

<item
android:id="@+id/action_rename"
android:title="@string/rename" />
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
unteren Ecke des Bildschirms anklicken.
</string>
<string name="rename">Umbenennen</string>
<string name="shortcuts_not_supported">Ihr Standard-Launcher unterstützt das Hinzufügen von Verknüpfungen nicht.</string>
<string name="pinned_shortcuts_not_supported">Ihr Standard-Launcher unterstützt das Hinzufügen von Verknüpfungen nicht.</string>
<string name="show_saved_preset_on_startup">Gespeicherte Voreinstellungen beim Start der App anzeigen</string>
<string name="auto_sleep_schedule_cancelled">Automatischer Schlaftimer abgebrochen!</string>
<string name="reset">Zurücksetzen</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-el/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<string name="reset">Επαναφορά</string>
<string name="auto_sleep_schedule_cancelled">Ο χρονοδιακόπτης ύπνου ακυρώθηκε!</string>
<string name="show_saved_preset_on_startup">Εμφάνιση των συνθέσεων με την έναρξη</string>
<string name="shortcuts_not_supported">Η εφαρμογή αρχικής οθόνης σας δεν υποστηρίζει την προσθήκη συντομεύσεων.</string>
<string name="pinned_shortcuts_not_supported">Η εφαρμογή αρχικής οθόνης σας δεν υποστηρίζει την προσθήκη συντομεύσεων.</string>
<string name="rename">Μετονομασία</string>
<string name="preset_info__description">Δεν έχετε δημιουργήσει ακόμα συνθέσεις. Για να δημιουργήσετε, πηγαίνετε στη Βιβλιοθήκη και αναπαράγετε κάποιους ήχους. Κατόπιν πατήστε το κουμπί Αποθήκευση στην κάτω δεξιά γωνία της οθόνης.</string>
<string name="preset_does_not_exist">Η σύνθεση δεν υπάρχει. Μπορεί να έχει διαγραφεί!</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-es-rES/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
<string name="preset_does_not_exist">El preajuste no existe. ¡Puede haber sido borrada!</string>
<string name="add_to_home_screen">Añadir a la pantalla de inicio</string>
<string name="okay">Vale</string>
<string name="shortcuts_not_supported">Su aplicación de inicio predeterminada no admite añadir accesos directos.</string>
<string name="pinned_shortcuts_not_supported">Su aplicación de inicio predeterminada no admite añadir accesos directos.</string>
<string name="random_preset_description">Los preajustes generados aleatoriamente contendrán sonidos correspondientes al ambiente elegido. Además, los preajustes densos intentarán reproducir más sonidos simultáneamente.</string>
<string name="should_update_media_volume">Actualice el volumen del dispositivo multimedia antes de que comience el preajuste</string>
<string name="device_media_volume">Volumen del dispositivo multimedia</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-fr-rFR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
<string name="use_24h_format">Utiliser le format 24 heures</string>
<string name="wake_up_timer_cancelled">Minuterie du réveil annulée !</string>
<string name="show_saved_preset_on_startup">Afficher les configurations sauvegardées au lancement de l\'application</string>
<string name="shortcuts_not_supported">Votre lanceur par défaut ne supporte pas l\'ajout de raccourcis.</string>
<string name="pinned_shortcuts_not_supported">Votre lanceur par défaut ne supporte pas l\'ajout de raccourcis.</string>
<string name="never">Jamais</string>
<string name="later">Plus tard</string>
<string name="in_app_feedback__title">Soumettre une évaluation</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-hi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
<string name="cast_media">किसी अन्य डिवाइस पर मीडिया कास्ट करें</string>
<string name="notification_channel_default__description">मीडिया प्लेबैक नियंत्रण</string>
<string name="notification_channel_default__name">मीडिया प्लेबैक</string>
<string name="shortcuts_not_supported">आपका डिफ़ॉल्ट लॉन्चर शॉर्टकट जोड़ने का समर्थन नहीं करता है।</string>
<string name="pinned_shortcuts_not_supported">आपका डिफ़ॉल्ट लॉन्चर शॉर्टकट जोड़ने का समर्थन नहीं करता है।</string>
<string name="never">कभी नहीं</string>
<string name="later">बाद में</string>
<string name="in_app_feedback__title">समीक्षा जमा करें</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-in/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@
<string name="never">Tidak pernah</string>
<string name="notification_channel_default__description">Kontrol pemutaran media</string>
<string name="notification_channel_default__name">Pemutaran Media</string>
<string name="shortcuts_not_supported">Launcher default anda tidak mendukung untuk menambahkan shortcuts.</string>
<string name="pinned_shortcuts_not_supported">Launcher default anda tidak mendukung untuk menambahkan shortcuts.</string>
<string name="preset_does_not_exist">Preset tidak tersedia. Mungkin sudah dihapus!</string>
<string name="add_to_home_screen">Tambahkan di layar utama</string>
<string name="relax">Rileks</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-it-rIT/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
<string name="wake_up_timer">Timer risveglio</string>
<string name="sleep_timer_description">Noice si riavvierà allo scadere del tempo. Usa i pulsanti sotto per aggiungere del tempo e avviare il timer.</string>
<string name="show_saved_preset_on_startup">Mostra i preset salvati all\'avvio dell\'app</string>
<string name="shortcuts_not_supported">Il tuo launcher di default non supporta l\'aggiunta di scorciatoie.</string>
<string name="pinned_shortcuts_not_supported">Il tuo launcher di default non supporta l\'aggiunta di scorciatoie.</string>
<string name="wake_up_timer_description">Noice eseguirà il preset selezionato allo scadere del tempo. Usa i pulsanti sotto per selezionare un preset e impostare il tempo desiderato per il timer di risveglio.</string>
<string name="wake_up_timer_cancelled">Timer di risveglio annullato!</string>
<string name="schedule">Programma</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-ja/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<string name="reset">リセット</string>
<string name="auto_sleep_schedule_cancelled">自動スリープタイマーがキャンセルされました!</string>
<string name="show_saved_preset_on_startup">アプリ起動時に保存されたプリセットを表示する</string>
<string name="shortcuts_not_supported">あなたが利用しているデフォルトのランチャーは、ショートカットの追加をサポートしていません。</string>
<string name="pinned_shortcuts_not_supported">あなたが利用しているデフォルトのランチャーは、ショートカットの追加をサポートしていません。</string>
<string name="rename">名前を変更</string>
<string name="preset_info__description">プリセットが作成されていません。プレイリストを作成するには,ライブラリに移動してサウンドを再生します。その後、画面の下隅に表示される保存ボタンをクリックします。</string>
<string name="preset_does_not_exist">プリセットが存在しません。削除された可能性があります!</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-pl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
<string name="appintro__chromecast_title">Chromecast aktywny</string>
<string name="use_24h_format">Uzyj 24-godzinnego formatu</string>
<string name="schedule">Zaplanuj</string>
<string name="shortcuts_not_supported">Twój domyślny ekran startowy nie wspiera dodawania skrótów.</string>
<string name="pinned_shortcuts_not_supported">Twój domyślny ekran startowy nie wspiera dodawania skrótów.</string>
<string name="add_to_home_screen">Dodaj do ekranu głównego</string>
<string name="walking_through_the_snow">Chodzenie przez śnieg</string>
<string name="quiet_conversation">Cicha Konwersacja</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
<string name="should_update_media_volume">Обновить громкость звуков устройства перед запуском предустановок</string>
<string name="device_media_volume">Громкость звука устройства</string>
<string name="wake_up_timer_cancelled">Таймер пробуждения отменён!</string>
<string name="shortcuts_not_supported">Ваш лаунчер по умолчанию не поддерживает добавление ярлыков.</string>
<string name="pinned_shortcuts_not_supported">Ваш лаунчер по умолчанию не поддерживает добавление ярлыков.</string>
<string name="focus">Фокус</string>
<plurals name="time_minutes">
<item quantity="one">%1$d минуту</item>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
ve birkaç ses oynatın. Sonra da ekranın alt köşesindeki Kaydet tuşuna basın.
</string>
<string name="rename">Yeniden adlandır</string>
<string name="shortcuts_not_supported">Başlatıcınız kısa yol eklemeyi desteklemiyor.</string>
<string name="pinned_shortcuts_not_supported">Başlatıcınız kısa yol eklemeyi desteklemiyor.</string>
<string name="auto_sleep_schedule_cancelled">Otomatik uyku zamanlayıcısı iptal edildi!</string>
<string name="reset">Sıfırla</string>
<string name="sleep_timer_description">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<string name="reset">重置</string>
<string name="auto_sleep_schedule_cancelled">自动睡眠定时器已取消!</string>
<string name="show_saved_preset_on_startup">在应用启动时显示已保存的预设</string>
<string name="shortcuts_not_supported">你的默认启动器不支持添加快捷方式。</string>
<string name="pinned_shortcuts_not_supported">你的默认启动器不支持添加快捷方式。</string>
<string name="rename">重命名</string>
<string name="preset_info__description">你还没有创建任何预设。要创建预设,请进入库并播放声音。然后点击屏幕下角出现的 \"保存 \"按钮。</string>
<string name="preset_does_not_exist">预设不存在。它可能已被删除!</string>
Expand Down
7 changes: 6 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
Then click on the Save button that appears on the bottom corner of the screen.
</string>
<string name="rename">Rename</string>
<string name="shortcuts_not_supported">Your default launcher does not support adding shortcuts.</string>
<string name="pinned_shortcuts_not_supported">Your default launcher does not support adding shortcuts.</string>
<string name="show_saved_preset_on_startup">Show saved presets on app startup</string>
<string name="auto_sleep_schedule_cancelled">Auto sleep timer cancelled!</string>
<string name="reset">Reset</string>
Expand Down Expand Up @@ -187,4 +187,9 @@
<string name="notification_channel_default__description">Media playback controls</string>
<string name="notification_channel_default__name">Media Playback</string>
<string name="app_authors">View list of the Noice Authors</string>
<string name="add_to_app_shortcuts">Add to app shortcuts</string>
<string name="remove_from_app_shortcuts">Remove from app shortcuts</string>
<string name="app_shortcut_removed">Preset removed from app shortcuts!</string>
<string name="app_shortcut_created">Preset added to app shortcuts!</string>
<string name="app_shortcut_creation_failed">Failed to add the preset to app shortcuts!</string>
</resources>

0 comments on commit 2248a50

Please sign in to comment.