Skip to content

Commit 428aa96

Browse files
committed
Add still watching feature
1 parent a0f965e commit 428aa96

21 files changed

+578
-45
lines changed

app/src/main/java/org/jellyfin/androidtv/di/AppModule.kt

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import org.jellyfin.androidtv.ui.navigation.NavigationRepository
3333
import org.jellyfin.androidtv.ui.navigation.NavigationRepositoryImpl
3434
import org.jellyfin.androidtv.ui.picture.PictureViewerViewModel
3535
import org.jellyfin.androidtv.ui.playback.PlaybackControllerContainer
36+
import org.jellyfin.androidtv.ui.playback.WatchTrackerViewModel
37+
import org.jellyfin.androidtv.ui.playback.stillwatching.StillWatchingViewModel
3638
import org.jellyfin.androidtv.ui.playback.nextup.NextUpViewModel
3739
import org.jellyfin.androidtv.ui.playback.segment.MediaSegmentRepository
3840
import org.jellyfin.androidtv.ui.playback.segment.MediaSegmentRepositoryImpl
@@ -104,6 +106,8 @@ val appModule = module {
104106
// Non API related
105107
single { DataRefreshService() }
106108
single { PlaybackControllerContainer() }
109+
single { WatchTrackerViewModel() }
110+
107111

108112
single<UserRepository> { UserRepositoryImpl() }
109113
single<UserViewsRepository> { UserViewsRepositoryImpl(get()) }
@@ -118,6 +122,7 @@ val appModule = module {
118122
viewModel { UserLoginViewModel(get(), get(), get(), get(defaultDeviceInfo)) }
119123
viewModel { ServerAddViewModel(get()) }
120124
viewModel { NextUpViewModel(get(), get(), get(), get()) }
125+
viewModel { StillWatchingViewModel() }
121126
viewModel { PictureViewerViewModel(get()) }
122127
viewModel { ScreensaverViewModel(get()) }
123128
viewModel { SearchViewModel(get()) }

app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt

+6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.jellyfin.androidtv.preference.constant.ClockBehavior
99
import org.jellyfin.androidtv.preference.constant.NextUpBehavior
1010
import org.jellyfin.androidtv.preference.constant.RatingType
1111
import org.jellyfin.androidtv.preference.constant.RefreshRateSwitchingBehavior
12+
import org.jellyfin.androidtv.preference.constant.StillWatchingBehavior
1213
import org.jellyfin.androidtv.preference.constant.WatchedIndicatorBehavior
1314
import org.jellyfin.androidtv.preference.constant.ZoomMode
1415
import org.jellyfin.androidtv.ui.playback.segment.MediaSegmentAction
@@ -86,6 +87,11 @@ class UserPreferences(context: Context) : SharedPreferenceStore(
8687
*/
8788
var cinemaModeEnabled = booleanPreference("pref_enable_cinema_mode", true)
8889

90+
/**
91+
* Enable still watching
92+
*/
93+
var stillWatchingEnabled = enumPreference("pref_enable_still_watching", StillWatchingBehavior.DEFAULT)
94+
8995
/* Playback - Video */
9096
/**
9197
* Whether to use an external playback application or not.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.jellyfin.androidtv.preference.constant
2+
3+
import org.jellyfin.androidtv.R
4+
import org.jellyfin.preference.PreferenceEnum
5+
6+
enum class StillWatchingBehavior(
7+
override val nameRes: Int
8+
) : PreferenceEnum {
9+
TEST_EPISODE_COUNT(R.string.lbl_still_watching_test_episode_count),
10+
TEST_MIN_MINUTES(R.string.lbl_still_watching_test_min_minutes),
11+
/**
12+
* Takes shorter than Netflix implementation to show still watching screen.
13+
*/
14+
SHORT(R.string.lbl_still_watching_short),
15+
/**
16+
* Default behavior for still watching. Matches Netflix implementation
17+
*/
18+
DEFAULT(R.string.lbl_still_watching_default),
19+
/**
20+
* Takes longer than Netflix implementation to show still watching screen.
21+
*/
22+
LONG(R.string.lbl_still_watching_long),
23+
/**
24+
* Takes longer than Netflix implementation to show still watching screen.
25+
*/
26+
VERY_LONG(R.string.lbl_still_watching_very_long),
27+
/**
28+
* Disables still watching screen.
29+
*/
30+
DISABLED(R.string.state_disabled)
31+
}

app/src/main/java/org/jellyfin/androidtv/ui/browsing/MainActivity.kt

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import org.jellyfin.androidtv.ui.ScreensaverViewModel
2525
import org.jellyfin.androidtv.ui.background.AppBackground
2626
import org.jellyfin.androidtv.ui.navigation.NavigationAction
2727
import org.jellyfin.androidtv.ui.navigation.NavigationRepository
28+
import org.jellyfin.androidtv.ui.playback.WatchTrackerViewModel
2829
import org.jellyfin.androidtv.ui.screensaver.InAppScreensaver
2930
import org.jellyfin.androidtv.ui.startup.StartupActivity
3031
import org.jellyfin.androidtv.util.applyTheme
@@ -39,6 +40,7 @@ class MainActivity : FragmentActivity() {
3940
private val userRepository by inject<UserRepository>()
4041
private val screensaverViewModel by viewModel<ScreensaverViewModel>()
4142
private val workManager by inject<WorkManager>()
43+
private val watchTracker by inject<WatchTrackerViewModel>();
4244

4345
private lateinit var binding: ActivityMainBinding
4446

@@ -168,6 +170,10 @@ class MainActivity : FragmentActivity() {
168170
super.onUserInteraction()
169171

170172
screensaverViewModel.notifyInteraction(false)
173+
174+
if (watchTracker.getItemIsEpisode()) {
175+
watchTracker.onUserInteraction()
176+
}
171177
}
172178

173179
@Suppress("RestrictedApi") // False positive

app/src/main/java/org/jellyfin/androidtv/ui/itemdetail/FullDetailsFragment.java

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.jellyfin.androidtv.ui.playback.MediaManager;
6464
import org.jellyfin.androidtv.ui.playback.PlaybackLauncher;
6565
import org.jellyfin.androidtv.ui.playback.VideoQueueManager;
66+
import org.jellyfin.androidtv.ui.playback.WatchTrackerViewModel;
6667
import org.jellyfin.androidtv.ui.presentation.CardPresenter;
6768
import org.jellyfin.androidtv.ui.presentation.CustomListRowPresenter;
6869
import org.jellyfin.androidtv.ui.presentation.InfoCardPresenter;
@@ -153,6 +154,7 @@ public class FullDetailsFragment extends Fragment implements RecordingIndicatorV
153154
private final Lazy<KeyProcessor> keyProcessor = inject(KeyProcessor.class);
154155
final Lazy<PlaybackHelper> playbackHelper = inject(PlaybackHelper.class);
155156
private final Lazy<ImageHelper> imageHelper = inject(ImageHelper.class);
157+
private final Lazy<WatchTrackerViewModel> watchTracker = inject(WatchTrackerViewModel.class);
156158

157159
@Nullable
158160
@Override
@@ -1205,6 +1207,7 @@ public void onResponse(List<BaseItemDto> response) {
12051207
if (item.getType() == BaseItemKind.MUSIC_ARTIST) {
12061208
mediaManager.getValue().playNow(requireContext(), response, 0, shuffle);
12071209
} else {
1210+
if (item.getType() == BaseItemKind.EPISODE && response.size() > 1) watchTracker.getValue().startWatchTime();
12081211
videoQueueManager.getValue().setCurrentVideoQueue(response);
12091212
Destination destination = KoinJavaComponent.<PlaybackLauncher>get(PlaybackLauncher.class).getPlaybackDestination(item.getType(), pos);
12101213
navigationRepository.getValue().navigate(destination);

app/src/main/java/org/jellyfin/androidtv/ui/navigation/Destinations.kt

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.jellyfin.androidtv.ui.navigation
22

33
import androidx.core.os.bundleOf
4-
import kotlinx.serialization.encodeToString
54
import kotlinx.serialization.json.Json
65
import org.jellyfin.androidtv.constant.Extras
76
import org.jellyfin.androidtv.ui.browsing.BrowseGridFragment

0 commit comments

Comments
 (0)