Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add episode screen and associated functionality to watch app #821

Merged
merged 11 commits into from
Mar 9, 2023

Conversation

mchowning
Copy link
Contributor

Description

Adds the episode screen to the watch app along with the associated functionality.

The EpisodeViewModel implementation very closely follows the logic in the EpisodeFragment and EpisodeFragmentViewModel.

Testing Instructions

Verify that you can access the episode screen in each of the following ways:

  • Tapping on the episode/podcast name in the Now Playing screen
  • Tapping on an episode in the Up Next queue
  • Tapping on an episode on the podcast screen

From the episode screen, you should see the following UI:

  • The Top of the screen has the podcast name, followed by the podcast title
  • The download, play, and, queue buttons are tinted based on the podcast
  • Below the play button is the episode date, amount of time left, and download size of the episode
  • Below that is a list with the options: archive, star, mark as played, and go to podcast

From the episode screen, check the following functionality:

  • Tapping the download button should have the following actions (with the button UI updating appropriately for each state):
    • if not downloaded, start a download
    • if a download is in progress, cancel the download
    • if the episode is downloaded, present a confirmation dialog for deleting the download. Confirming on that dialog should delete the download and briefly present a notification screen notifying the user that the download was removed (tapping on the notification screen will dismiss the notification even earlier than that 2 second timeout).
  • Tapping the play button should start playing the episode (or pause it if it is already playing. The UI should reflect whether the button is a play or a pause button.
  • Tapping the add-to-queue button should:
    • If the episode is in the Up Next queue, remove the episode from the queue and briefly present a notification dialog advising the user that the episode was removed from the queue.
    • If the episode is not in the Up Next queue, and...
      • If the Up Next queue is empty, add the episode to the Up Next queue
      • If the Up Next queue is not empty, present a screen asking where to add the episode to the queue.
  • Tapping the archive/unarchive, star/unstar, mark as played/unplayed buttons should update the episode state appropriately, and the button's UI should update to reflect the new state.
  • Tapping the go-to-podcast button should take you to the podcast screen

Screenshots or Screencast

image

Checklist

  • If this is a user-facing change, I have added an entry in CHANGELOG.md
  • I have considered whether it makes sense to add tests for my changes
  • All strings that need to be localized are in modules/services/localization/src/main/res/values/strings.xml
  • Any jetpack compose components I added or changed are covered by compose previews

I have tested any UI changes...

  • for accessibility with TalkBack

@mchowning mchowning added the [Area] Wear OS watch app label Mar 8, 2023
@mchowning mchowning requested a review from a team as a code owner March 8, 2023 02:04
TextP50(
text = podcast.title,
maxLines = 1,
color = Color(0xFFDADCE0),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I need to create a watch theme similar to what we have for the automotive app (but with compose in mind) to handle these colors. I'll do that in a separate PR though.

Comment on lines +139 to +146
// FIXME this is a hack to avoid an issue where this listener says downloads
// on the watch app are enqueued when they are actually still running.
val queriedState = workManager.getWorkInfoById(workInfo.id).get().state
if (Util.isWearOs(context) && queriedState == WorkInfo.State.RUNNING) {
getRequirementsAsync(episode)
} else {
getRequirementsAndSetStatusAsync(episode)
}
Copy link
Contributor Author

@mchowning mchowning Mar 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really have a solid understanding of why this is happening on the watch app. Any thoughts, suggestions you might have would be appreciated.

At a high level, the DownloadEpisodeTask is what does the work, and while it is waiting on the download, the DownloadManagerImpl's listener (in ::beginMonitoringWorkManager) recieves an "enqueued" event, even though the download is not actually enqueued and is actively running in the DownloadEpisodeTask's download()...blockingAwait() call (as can be seen by checking workManger.getWorkInfoById like I do here).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to understand this part. Maybe @geekygecko can explain it.

@@ -470,6 +484,10 @@ class DownloadManagerImpl @Inject constructor(
}

private fun updateNotification() {

// Don't show these notifications on wear os
if (Util.isWearOs(context)) return
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a good feel for how to use notifications on the watch yet. It feels like we shouldn't use them as much as we do in the app, so I've disabled this one for now (also, it's not working on the watch currently), but perhaps we'll want to add it back later. Let me know if you have any thoughts here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we're not setting up notification channels for the wear os app inside PocketCastsWearApplication -> setupApp() : notificationHelper.setupNotificationChannels()

I can see notification by adding it:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Thanks for that. I'll make this update in a separate PR since this one is already way too big.

Comment on lines +145 to +147
if (!Util.isWearOs(context)) {
setForegroundAsync(createForegroundInfo())
}
Copy link
Contributor Author

@mchowning mchowning Mar 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is throwing an error on the watch because it tries to create a foreground notification, and notifications aren't working currently.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be resolved by setting up notification channels, haven't tested it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bet you're right. I'll enable notifications in a separate PR.

Copy link
Contributor

@ashiagr ashiagr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, @mattchowning! 🥇

I haven’t matched UI with Figma as it is still evolving. I don't have much feedback at this point, just that app crashes on playing an episode after it is marked played:

I/Timber$Forest: Playback: Play now: 4b573437-5881-44b1-813c-3dbe5c8abf7c 194: The Top 6 Ways To Come Up With Your Business Idea
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: au.com.shiftyjelly.pocketcasts.debug, PID: 19340
    java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.kt:435)
        at androidx.room.SharedSQLiteStatement.assertNotMainThread(SharedSQLiteStatement.kt:52)
        at androidx.room.SharedSQLiteStatement.acquire(SharedSQLiteStatement.kt:74)
        at au.com.shiftyjelly.pocketcasts.models.db.dao.EpisodeDao_Impl.unarchive(EpisodeDao_Impl.java:1169)
        at au.com.shiftyjelly.pocketcasts.repositories.podcast.EpisodeManagerImpl.unarchive(EpisodeManagerImpl.kt:720)
        at au.com.shiftyjelly.pocketcasts.repositories.playback.PlaybackManager.playNowSync(PlaybackManager.kt:373)
        at au.com.shiftyjelly.pocketcasts.repositories.playback.PlaybackManager.playNowSync$default(PlaybackManager.kt:369)
        at au.com.shiftyjelly.pocketcasts.wear.ui.episode.EpisodeViewModel$play$1.invokeSuspend(EpisodeViewModel.kt:197)
device-2023-03-09-134346.mp4

@@ -470,6 +484,10 @@ class DownloadManagerImpl @Inject constructor(
}

private fun updateNotification() {

// Don't show these notifications on wear os
if (Util.isWearOs(context)) return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we're not setting up notification channels for the wear os app inside PocketCastsWearApplication -> setupApp() : notificationHelper.setupNotificationChannels()

I can see notification by adding it:

Comment on lines +145 to +147
if (!Util.isWearOs(context)) {
setForegroundAsync(createForegroundInfo())
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be resolved by setting up notification channels, haven't tested it though.

Comment on lines +139 to +146
// FIXME this is a hack to avoid an issue where this listener says downloads
// on the watch app are enqueued when they are actually still running.
val queriedState = workManager.getWorkInfoById(workInfo.id).get().state
if (Util.isWearOs(context) && queriedState == WorkInfo.State.RUNNING) {
getRequirementsAsync(episode)
} else {
getRequirementsAndSetStatusAsync(episode)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to understand this part. Maybe @geekygecko can explain it.

@mchowning
Copy link
Contributor Author

I don't have much feedback at this point, just that app crashes on playing an episode after it is marked played

Well that's because you shouldn't be doing that!!! 😆

Seriously though, great catch. I fixed it in 81d847d.

@mchowning mchowning enabled auto-merge March 9, 2023 19:07
@mchowning mchowning merged commit 2c11282 into add/wear Mar 9, 2023
@mchowning mchowning deleted the update/episode-screen branch March 9, 2023 19:31
@ashiagr ashiagr mentioned this pull request Jul 22, 2024
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants