Skip to content

Commit

Permalink
Merge pull request #311 from ashutoshgngwr/chore/general-maintenance
Browse files Browse the repository at this point in the history
General Maintenance
  • Loading branch information
ashutoshgngwr authored Sep 1, 2020
2 parents 9f6ef52 + 7c99dd0 commit a4c08db
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.github.ashutoshgngwr.noice

import android.view.View
import android.widget.SeekBar
import androidx.annotation.IdRes
import androidx.annotation.StringRes
import androidx.test.espresso.Espresso.onView
Expand All @@ -13,6 +12,7 @@ import androidx.test.espresso.action.MotionEvents
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.espresso.util.TreeIterables
import com.github.ashutoshgngwr.noice.widget.DurationPicker
import com.google.android.material.slider.Slider
import com.google.android.material.textfield.TextInputLayout
import org.hamcrest.Description
import org.hamcrest.Matcher
Expand All @@ -26,9 +26,10 @@ import org.hamcrest.TypeSafeMatcher
object EspressoX {

/**
* [clickOn] performs a click action on item with the given [viewId].
* [clickInItem] performs a click action on item with the given [viewId] inside currently
* matched view.
*/
fun clickOn(@IdRes viewId: Int): ViewAction {
fun clickInItem(@IdRes viewId: Int): ViewAction {
return object : ViewAction {
override fun getDescription() = "Click on view with specified id"
override fun getConstraints() = hasDescendant(withId(viewId))
Expand All @@ -40,28 +41,28 @@ object EspressoX {
}

/**
* [seekProgress] performs a seek action on a [SeekBar] with given [seekBarId] inside currently
* [slideInItem] performs a slide action on a [Slider] with given [sliderID] inside currently
* matched view.
*/
fun seekProgress(@IdRes seekBarId: Int, progress: Int): ViewAction {
fun slideInItem(@IdRes sliderID: Int, value: Float): ViewAction {
return object : ViewAction {
override fun getDescription() = "Emulate user input on a seek bar"
override fun getConstraints() =
hasDescendant(allOf(withId(seekBarId), instanceOf(SeekBar::class.java)))
hasDescendant(allOf(withId(sliderID), instanceOf(Slider::class.java)))

override fun perform(uiController: UiController, view: View) {
val seekBar = view.findViewById<SeekBar>(seekBarId)
val width = seekBar.width - seekBar.paddingStart - seekBar.paddingEnd
val height = seekBar.height - seekBar.paddingTop - seekBar.paddingBottom
val slider = view.findViewById<Slider>(sliderID)
val height = slider.height - slider.paddingTop - slider.paddingBottom

val location = intArrayOf(0, 0)
seekBar.getLocationOnScreen(location)
slider.getLocationOnScreen(location)

val xOffset = location[0].toFloat() + seekBar.paddingStart
val xStart = ((seekBar.progress.toFloat() / seekBar.max) * width) + xOffset
val xOffset = location[0].toFloat() + slider.paddingStart + slider.trackSidePadding
val range = slider.valueTo - slider.valueFrom
val xStart = (((slider.value - slider.valueFrom) / range) * slider.trackWidth) + xOffset

val x = ((progress.toFloat() / seekBar.max) * width) + xOffset
val y = location[1] + seekBar.paddingTop + (height.toFloat() / 2)
val x = (((value - slider.valueFrom) / range) * slider.trackWidth) + xOffset
val y = location[1] + slider.paddingTop + (height.toFloat() / 2)

val startCoordinates = floatArrayOf(xStart, y)
val endCoordinates = floatArrayOf(x, y)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class PresetFragmentTest {
onView(withId(R.id.list_presets)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

Expand All @@ -109,7 +109,7 @@ class PresetFragmentTest {
onView(withId(R.id.list_presets)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

Expand All @@ -122,7 +122,7 @@ class PresetFragmentTest {
onView(withId(R.id.list_presets)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickOn(R.id.button_menu)
EspressoX.clickInItem(R.id.button_menu)
)
)

Expand Down Expand Up @@ -150,7 +150,7 @@ class PresetFragmentTest {
onView(withId(R.id.list_presets)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickOn(R.id.button_menu)
EspressoX.clickInItem(R.id.button_menu)
)
)

Expand All @@ -174,7 +174,7 @@ class PresetFragmentTest {
onView(withId(R.id.list_presets)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText("test"))),
EspressoX.clickOn(R.id.button_menu)
EspressoX.clickInItem(R.id.button_menu)
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class SoundLibraryFragmentTest {
onView(withId(R.id.list_sound)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText(R.string.birds))),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

Expand All @@ -73,15 +73,15 @@ class SoundLibraryFragmentTest {
onView(withId(R.id.list_sound)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText(R.string.birds))),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

verify(exactly = 1) { eventBus.post(MediaPlayerService.StopPlayerEvent("birds")) }
}

@Test
fun testRecyclerViewItem_volumeSeekBar() {
fun testRecyclerViewItem_volumeSlider() {
val mockPlayer = mockk<Player>(relaxed = true) {
every { volume } returns Player.DEFAULT_VOLUME
}
Expand All @@ -96,7 +96,7 @@ class SoundLibraryFragmentTest {
onView(withId(R.id.list_sound)).perform(
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText(R.string.birds))),
EspressoX.seekProgress(R.id.seekbar_volume, expectedVolume)
EspressoX.slideInItem(R.id.slider_volume, expectedVolume.toFloat())
)
)

Expand All @@ -105,7 +105,7 @@ class SoundLibraryFragmentTest {
}

@Test
fun testRecyclerViewItem_timePeriodSeekBar() {
fun testRecyclerViewItem_timePeriodSlider() {
val mockPlayer = mockk<Player>(relaxed = true) {
every { timePeriod } returns Player.DEFAULT_TIME_PERIOD
}
Expand All @@ -118,7 +118,8 @@ class SoundLibraryFragmentTest {
val expectedTimePeriods = arrayOf(
Player.MIN_TIME_PERIOD,
Player.MAX_TIME_PERIOD,
Random.nextInt(Player.MIN_TIME_PERIOD, Player.MAX_TIME_PERIOD)
// following because step size of the slider is 10s
Random.nextInt(Player.MIN_TIME_PERIOD / 10, Player.MAX_TIME_PERIOD / 10) * 10
)

for (expectedTimePeriod in expectedTimePeriods) {
Expand All @@ -129,9 +130,7 @@ class SoundLibraryFragmentTest {
),
RecyclerViewActions.actionOnItem<SoundLibraryFragment.ViewHolder>(
hasDescendant(allOf(withId(R.id.title), withText(R.string.rolling_thunder))),
EspressoX.seekProgress(
R.id.seekbar_time_period, expectedTimePeriod - Player.MIN_TIME_PERIOD
)
EspressoX.slideInItem(R.id.slider_time_period, expectedTimePeriod.toFloat())
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ class WakeUpTimerFragmentTest {
.check(matches(not(isEnabled())))
}

@Test
fun testSelectPreset_withoutSavedPresets() {
every { Preset.readAllFromUserPreferences(any()) } returns arrayOf()
onView(withId(R.id.button_select_preset))
.check(matches(withText(R.string.select_preset)))
.perform(click())

EspressoX.waitForView(withText(R.string.preset_info__description), 100, 5)
.check(matches(isDisplayed()))
}

@Test
fun testSetTimer() {
every { Preset.readAllFromUserPreferences(any()) } returns arrayOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,17 @@ class GenerateScreenshots {
onView(withId(R.id.list_sound)).perform(
actionOnItem<SoundLibraryFragment.ViewHolder>(
ViewMatchers.hasDescendant(allOf(withId(R.id.title), withText(R.string.airplane_inflight))),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

onView(withId(R.id.list_sound)).perform(
actionOnItem<SoundLibraryFragment.ViewHolder>(
ViewMatchers.hasDescendant(allOf(withId(R.id.title), withText(R.string.airplane_inflight))),
EspressoX.seekProgress(R.id.seekbar_volume, Player.MAX_VOLUME - Player.DEFAULT_VOLUME)
EspressoX.slideInItem(
R.id.slider_volume,
Player.MAX_VOLUME.toFloat() - Player.DEFAULT_VOLUME
)
)
)

Expand All @@ -170,7 +173,7 @@ class GenerateScreenshots {
ViewMatchers.hasDescendant(
allOf(withId(R.id.title), withText(R.string.airplane_seatbelt_beeps))
),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

Expand All @@ -179,7 +182,7 @@ class GenerateScreenshots {
ViewMatchers.hasDescendant(
allOf(withId(R.id.title), withText(R.string.airplane_seatbelt_beeps))
),
EspressoX.seekProgress(R.id.seekbar_volume, Player.MAX_VOLUME)
EspressoX.slideInItem(R.id.slider_volume, Player.MAX_VOLUME.toFloat())
)
)

Expand All @@ -188,9 +191,7 @@ class GenerateScreenshots {
ViewMatchers.hasDescendant(
allOf(withId(R.id.title), withText(R.string.airplane_seatbelt_beeps))
),
EspressoX.seekProgress(
R.id.seekbar_time_period, Player.MAX_TIME_PERIOD - Player.MIN_TIME_PERIOD - 30
)
EspressoX.slideInItem(R.id.slider_time_period, Player.MAX_TIME_PERIOD.toFloat() - 300)
)
)

Expand All @@ -210,7 +211,9 @@ class GenerateScreenshots {

EspressoX.waitForView(withId(R.id.list_presets), 100, 5)
.perform(
actionOnItemAtPosition<PresetFragment.ViewHolder>(1, EspressoX.clickOn(R.id.button_play))
actionOnItemAtPosition<PresetFragment.ViewHolder>(
1, EspressoX.clickInItem(R.id.button_play)
)
)

Thread.sleep(SLEEP_PERIOD_BEFORE_SCREENGRAB)
Expand All @@ -222,7 +225,7 @@ class GenerateScreenshots {
onView(withId(R.id.list_sound)).perform(
actionOnItem<SoundLibraryFragment.ViewHolder>(
ViewMatchers.hasDescendant(allOf(withId(R.id.title), withText(R.string.birds))),
EspressoX.clickOn(R.id.button_play)
EspressoX.clickInItem(R.id.button_play)
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
*/
const val EXTRA_CURRENT_NAVIGATED_FRAGMENT = "current_fragment"

private const val TAG = "MainActivity"
private const val PREF_APP_THEME = "app_theme"
private const val APP_THEME_LIGHT = 0
private const val APP_THEME_DARK = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SeekBar
import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment
Expand All @@ -17,6 +16,7 @@ import com.github.ashutoshgngwr.noice.sound.Sound
import com.github.ashutoshgngwr.noice.sound.player.Player
import com.github.ashutoshgngwr.noice.sound.player.PlayerManager
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.slider.Slider
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_sound_list.view.*
import kotlinx.android.synthetic.main.layout_list_item__sound.view.*
Expand Down Expand Up @@ -166,18 +166,17 @@ class SoundLibraryFragment : Fragment(R.layout.fragment_sound_list) {
val sound = Sound.get(soundKey)
val isPlaying = players.containsKey(soundKey)
holder.itemView.title.text = context.getString(sound.titleResId)
holder.itemView.seekbar_volume.isEnabled = isPlaying
holder.itemView.seekbar_time_period.isEnabled = isPlaying
holder.itemView.slider_volume.isEnabled = isPlaying
holder.itemView.slider_time_period.isEnabled = isPlaying
holder.itemView.button_play.isChecked = isPlaying
if (isPlaying) {
requireNotNull(players[soundKey]).also {
holder.itemView.seekbar_volume.progress = it.volume
holder.itemView.seekbar_time_period.progress = it.timePeriod - Player.MIN_TIME_PERIOD
holder.itemView.slider_volume.value = it.volume.toFloat()
holder.itemView.slider_time_period.value = it.timePeriod.toFloat()
}
} else {
holder.itemView.seekbar_volume.progress = Player.DEFAULT_VOLUME
holder.itemView.seekbar_time_period.progress =
Player.DEFAULT_TIME_PERIOD - Player.MIN_TIME_PERIOD
holder.itemView.slider_volume.value = Player.DEFAULT_VOLUME.toFloat()
holder.itemView.slider_time_period.value = Player.DEFAULT_TIME_PERIOD.toFloat()
}

holder.itemView.layout_time_period.visibility = if (sound.isLooping) {
Expand All @@ -191,29 +190,23 @@ class SoundLibraryFragment : Fragment(R.layout.fragment_sound_list) {
inner class ViewHolder(view: View, @LayoutRes layoutID: Int) : RecyclerView.ViewHolder(view) {

// set listeners in holders to avoid object recreation on view recycle
private val seekBarChangeListener = object : SeekBar.OnSeekBarChangeListener {
private val sliderChangeListener = object : Slider.OnChangeListener {

override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
if (!fromUser) {
return
}

val player = players[dataSet[adapterPosition].data] ?: return
when (seekBar.id) {
R.id.seekbar_volume -> {
player.setVolume(progress)
when (slider.id) {
R.id.slider_volume -> {
player.setVolume(value.toInt())
}
R.id.seekbar_time_period -> {
player.timePeriod = Player.MIN_TIME_PERIOD + progress
R.id.slider_time_period -> {
player.timePeriod = value.toInt()
}
}
}

// unsubscribe from events during the seek action or it will cause adapter to refresh during
// the action causing adapterPosition to become -1 (POSITION_NONE). On resubscribing,
// this will also cause an update (#onPlayerManagerUpdate) since those events are sticky.
override fun onStartTrackingTouch(seekBar: SeekBar?) = unregisterFromEventBus()
override fun onStopTrackingTouch(seekBar: SeekBar?) = registerOnEventBus()
}

init {
Expand All @@ -223,10 +216,14 @@ class SoundLibraryFragment : Fragment(R.layout.fragment_sound_list) {
}

private fun initSoundItem(view: View) {
view.seekbar_volume.max = Player.MAX_VOLUME
view.seekbar_volume.setOnSeekBarChangeListener(seekBarChangeListener)
view.seekbar_time_period.max = Player.MAX_TIME_PERIOD - Player.MIN_TIME_PERIOD
view.seekbar_time_period.setOnSeekBarChangeListener(seekBarChangeListener)
view.slider_volume.valueFrom = 0.0f
view.slider_volume.valueTo = Player.MAX_VOLUME.toFloat()
view.slider_volume.addOnChangeListener(sliderChangeListener)
view.slider_volume.setLabelFormatter { "${(it * 100).toInt() / Player.MAX_VOLUME}%" }
view.slider_time_period.valueFrom = Player.MIN_TIME_PERIOD.toFloat()
view.slider_time_period.valueTo = Player.MAX_TIME_PERIOD.toFloat()
view.slider_time_period.addOnChangeListener(sliderChangeListener)
view.slider_time_period.setLabelFormatter { "${it.toInt() / 60}m ${it.toInt() % 60}s" }
view.button_play.setOnClickListener {
val listItem = dataSet.getOrNull(adapterPosition) ?: return@setOnClickListener
if (players.containsKey(listItem.data)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ class WakeUpTimerFragment : Fragment(R.layout.fragment_wake_up_timer) {
DialogFragment().show(childFragmentManager) {
val presets = Preset.readAllFromUserPreferences(requireContext()).map { it.name }
title(R.string.select_preset)
singleChoiceItems(presets.toTypedArray(), presets.indexOf(selectedPresetName)) { choice ->
selectedPresetName = presets[choice]
notifyUpdate()
if (presets.isNotEmpty()) {
singleChoiceItems(presets.toTypedArray(), presets.indexOf(selectedPresetName)) { choice ->
selectedPresetName = presets[choice]
notifyUpdate()
}
} else {
message(R.string.preset_info__description)
positiveButton(android.R.string.ok)
}
}
}
Expand Down
Loading

0 comments on commit a4c08db

Please sign in to comment.