├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── assets │ ├── detail.png │ ├── home.png │ ├── movies.png │ └── trakt.png ├── ci-gradle.properties ├── pr-labeler.yml ├── pull_request_template.md ├── release-drafter.yml └── workflows │ ├── build.yml │ ├── pr-labeler.yml │ ├── publish-google-play.yml │ └── release-drafter.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml └── kotlinc.xml ├── .run └── Film-Time [spotlessApply].run.xml ├── .scripts └── pre-commit ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── app ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── io │ │ └── filmtime │ │ └── ExampleInstrumentedTest.kt │ ├── googlePlay │ └── play │ │ └── release-notes │ │ └── en-US │ │ └── internal.txt │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-playstore.png │ ├── java │ └── io │ │ └── filmtime │ │ ├── FilmTimeApplication.kt │ │ ├── MainActivity.kt │ │ └── ui │ │ ├── FilmTimeApp.kt │ │ └── navigation │ │ ├── FilmTimeNavHost.kt │ │ ├── FilmTimeNavigationBar.kt │ │ ├── RootDestination.kt │ │ └── RootScreen.kt │ └── res │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml │ └── xml │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── build.gradle.kts ├── core ├── browser │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── core │ │ └── browser │ │ └── ContextExt.kt ├── design-system │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── core │ │ └── designsystem │ │ ├── PaddingValuesExt.kt │ │ ├── composable │ │ ├── AlertDialog.kt │ │ ├── Button.kt │ │ ├── ProgressBar.kt │ │ └── TopBar.kt │ │ └── theme │ │ ├── Color.kt │ │ ├── Preview.kt │ │ ├── Previews.kt │ │ ├── Theme.kt │ │ └── Type.kt ├── libs │ ├── logger │ │ ├── build.gradle.kts │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── io │ │ │ └── filmtime │ │ │ └── core │ │ │ └── libs │ │ │ └── logger │ │ │ ├── AppLogger.kt │ │ │ ├── Logger.kt │ │ │ └── Module.kt │ └── tracker │ │ ├── build.gradle.kts │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── core │ │ └── libs │ │ └── tracker │ │ ├── AppFirebaseTracker.kt │ │ ├── Module.kt │ │ └── Tracker.kt ├── resources │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── res │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ └── values │ │ └── ic_launcher_background.xml └── ui │ ├── common │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── io │ │ │ └── filmtime │ │ │ └── core │ │ │ └── ui │ │ │ └── common │ │ │ ├── UiMessage.kt │ │ │ ├── componnents │ │ │ ├── BookmarkButton.kt │ │ │ ├── ErrorContent.kt │ │ │ ├── ExpandableText.kt │ │ │ ├── LoadingCastSectionRow.kt │ │ │ ├── LoadingVideoSectionRow.kt │ │ │ ├── PeopleInCreditsRow.kt │ │ │ ├── PersonSearchCard.kt │ │ │ ├── RatingCard.kt │ │ │ ├── RatingsInfo.kt │ │ │ ├── Select.kt │ │ │ ├── SelectTextField.kt │ │ │ ├── VideoCard.kt │ │ │ ├── VideoDescription.kt │ │ │ ├── VideoInfo.kt │ │ │ ├── VideoSearchCard.kt │ │ │ ├── VideoSectionRow.kt │ │ │ ├── VideoThumbnailCard.kt │ │ │ ├── VideoThumbnailGrid.kt │ │ │ ├── VideoThumbnailInfo.kt │ │ │ ├── VideoThumbnailPoster.kt │ │ │ ├── VideoTrailerRow.kt │ │ │ └── placeholder │ │ │ │ ├── Placeholder.kt │ │ │ │ ├── PlaceholderDefaults.kt │ │ │ │ └── PlaceholderHighlight.kt │ │ │ ├── extensions │ │ │ └── ContextExt.kt │ │ │ └── graphics │ │ │ └── ShimmerBrush.kt │ │ └── res │ │ ├── drawable │ │ ├── ic_imdb.xml │ │ ├── ic_rt_fresh.xml │ │ ├── ic_rt_hidden.xml │ │ ├── ic_rt_rotten.xml │ │ ├── ic_tmdb_square.xml │ │ ├── ic_trakt.xml │ │ └── tmdb_square_color.xml │ │ ├── raw │ │ ├── error.json │ │ └── network_lost.json │ │ └── values │ │ └── strings.xml │ └── navigation │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── io │ └── filmtime │ └── core │ └── ui │ └── navigation │ ├── DestinationRoute.kt │ └── NavigationExt.kt ├── data ├── api │ ├── tmdb │ │ ├── build.gradle.kts │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── io │ │ │ └── filmtime │ │ │ └── data │ │ │ └── api │ │ │ └── tmdb │ │ │ ├── ApiModule.kt │ │ │ ├── CreditsExt.kt │ │ │ ├── EpisodeThumbnailExt.kt │ │ │ ├── MovieCollectionExt.kt │ │ │ ├── MovieVideoExt.kt │ │ │ ├── TmdbMoviesRemoteSource.kt │ │ │ ├── TmdbMoviesRemoteSourceImpl.kt │ │ │ ├── TmdbSearchRemoteSource.kt │ │ │ ├── TmdbSearchRemoteSourceImpl.kt │ │ │ ├── TmdbShowsRemoteSource.kt │ │ │ ├── TmdbShowsRemoteSourceImpl.kt │ │ │ └── VideoThumbnailExt.kt │ └── trakt │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── api │ │ └── trakt │ │ ├── TraktAuthRemoteSource.kt │ │ ├── TraktAuthRemoteSourceImpl.kt │ │ ├── TraktRemoteSource.kt │ │ ├── TraktRemoteSourceImpl.kt │ │ ├── TraktSearchRemoteSource.kt │ │ ├── TraktSearchRemoteSourceImpl.kt │ │ ├── TraktSourceModule.kt │ │ ├── TraktSyncRemoteSource.kt │ │ ├── TraktSyncRemoteSourceImpl.kt │ │ └── model │ │ ├── RatingsExt.kt │ │ ├── SeasonsExt.kt │ │ └── TraktAccessTokenExt.kt ├── bookmarks │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── bookmarks │ │ ├── BookmarksModule.kt │ │ ├── BookmarksRepository.kt │ │ └── BookmarksRepositoryImpl.kt ├── database │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ ├── schemas │ │ └── io.filmtime.data.database.FilmTimeDatabase │ │ │ └── 1.json │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── database │ │ ├── DatabaseModule.kt │ │ ├── FilmTimeDatabase.kt │ │ ├── StringListConverter.kt │ │ ├── dao │ │ ├── BookmarksDao.kt │ │ └── MovieDetailDao.kt │ │ └── entity │ │ ├── BookmarkEntity.kt │ │ └── MovieDetailEntity.kt ├── model │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── model │ │ ├── EpisodeThumbnail.kt │ │ ├── ExternalID.kt │ │ ├── GeneralError.kt │ │ ├── MovieCollection.kt │ │ ├── MovieVideo.kt │ │ ├── Person.kt │ │ ├── Ratings.kt │ │ ├── Result.kt │ │ ├── SearchResult.kt │ │ ├── SearchType.kt │ │ ├── StreamInfo.kt │ │ ├── TraktEpisodeHistory.kt │ │ ├── TraktMovieHistory.kt │ │ ├── TraktTokens.kt │ │ ├── VideoDetail.kt │ │ ├── VideoGenre.kt │ │ └── VideoThumbnail.kt ├── network │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── network │ │ ├── NetworkModule.kt │ │ ├── TmdbCollectionService.kt │ │ ├── TmdbCreditsResponse.kt │ │ ├── TmdbDiscoverService.kt │ │ ├── TmdbErrorResponse.kt │ │ ├── TmdbMovieDetailsResponse.kt │ │ ├── TmdbMoviesService.kt │ │ ├── TmdbSearchListResponse.kt │ │ ├── TmdbSearchService.kt │ │ ├── TmdbShowDetailsResponse.kt │ │ ├── TmdbShowListResponse.kt │ │ ├── TmdbShowsService.kt │ │ ├── TmdbVideoListResponse.kt │ │ ├── adapter │ │ ├── NetworkCallAdapterFactory.kt │ │ ├── NetworkResponse.kt │ │ ├── NetworkResponseAdapter.kt │ │ └── NetworkResponseCall.kt │ │ ├── annotation │ │ ├── TmdbApi.kt │ │ └── TraktApi.kt │ │ ├── interceptor │ │ ├── TmdbApiKeyInterceptor.kt │ │ ├── TraktAuthInterceptor.kt │ │ └── TraktHeadersInterceptor.kt │ │ ├── model │ │ ├── CollectionResponse.kt │ │ ├── TmdbSeasonResponse.kt │ │ └── TmdbVideoResponse.kt │ │ └── trakt │ │ ├── SyncHistoryRequest.kt │ │ ├── SyncHistoryResponse.kt │ │ ├── TraktAccessTokenResponse.kt │ │ ├── TraktAuthService.kt │ │ ├── TraktErrorResponse.kt │ │ ├── TraktExtendedRatingsResponse.kt │ │ ├── TraktExtendedSeasonResponse.kt │ │ ├── TraktGetTokenRequest.kt │ │ ├── TraktHistoryResponse.kt │ │ ├── TraktMovieIDLookupResponse.kt │ │ ├── TraktSearchService.kt │ │ ├── TraktService.kt │ │ ├── TraktSyncService.kt │ │ └── TraktWatched.kt ├── storage │ └── trakt │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── storage │ │ └── trakt │ │ ├── TraktAuthLocalSource.kt │ │ ├── TraktAuthLocalSourceImpl.kt │ │ └── TraktStorageModule.kt ├── tmdb-movies │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── fimltime │ │ └── data │ │ └── tmdb │ │ └── movies │ │ ├── MovieDetailEntityExt.kt │ │ ├── MoviesByGenrePagingSource.kt │ │ ├── MoviesPagingSource.kt │ │ ├── TmdbMovieRepository.kt │ │ ├── TmdbMovieRepositoryImpl.kt │ │ ├── TmdbMoviesModule.kt │ │ └── VideoDetailExt.kt ├── tmdb-search │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── tmdb │ │ └── search │ │ ├── SearchPagingSource.kt │ │ ├── TmdbSearchModule.kt │ │ ├── TmdbSearchRepository.kt │ │ └── TmdbSearchRepositoryImpl.kt ├── tmdb-shows │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── tmdb │ │ └── shows │ │ ├── ShowsByGenrePagingSource.kt │ │ ├── ShowsPagingSource.kt │ │ ├── TmdbShowsModule.kt │ │ ├── TmdbShowsRepository.kt │ │ ├── TmdbShowsRepositoryImpl.kt │ │ └── VideoDetailExt.kt ├── trakt-auth │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── data │ │ └── trakt │ │ └── auth │ │ ├── TraktAuthModule.kt │ │ ├── TraktAuthRepository.kt │ │ └── TraktAuthRepositoryImpl.kt └── trakt │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── io │ └── filmtime │ └── data │ └── trakt │ ├── TraktHistoryRepository.kt │ ├── TraktHistoryRepositoryImpl.kt │ ├── TraktModule.kt │ ├── TraktRepository.kt │ ├── TraktRepositoryImpl.kt │ └── model │ └── VideoTypeExt.kt ├── docs └── API-Keys.md ├── domain ├── bookmarks │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── bookmarks │ │ ├── AddBookmarkUseCase.kt │ │ ├── DeleteBookmarkUseCase.kt │ │ ├── ObserveBookmarkUseCase.kt │ │ ├── di │ │ └── BookmarksModule.kt │ │ └── impl │ │ ├── AddBookmarkUseCaseImpl.kt │ │ ├── DeleteBookmarkUseCaseImpl.kt │ │ └── ObserveBookmarkUseCaseImpl.kt ├── stream │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── stream │ │ ├── FakeGetStreamInfoUseCase.kt │ │ ├── GetStreamInfoUseCase.kt │ │ └── StreamModule.kt ├── tmdb-movies │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── tmdb │ │ └── movies │ │ ├── GetBookmarkedMoviesUseCase.kt │ │ ├── GetMovieCollectionUseCase.kt │ │ ├── GetMovieCreditsUseCase.kt │ │ ├── GetMovieDetailsUseCase.kt │ │ ├── GetMovieVideosUseCase.kt │ │ ├── GetMoviesByGenreUseCase.kt │ │ ├── GetMoviesListUseCase.kt │ │ ├── GetSimilarMoviesUseCase.kt │ │ ├── ObserveMoviesStreamUseCase.kt │ │ ├── di │ │ └── TmdbMoviesUseCaseModule.kt │ │ ├── impl │ │ ├── GetBookmarkedMoviesUseCaseImpl.kt │ │ ├── GetMovieCollectionUseCaseImpl.kt │ │ ├── GetMovieCreditsUseCaseImpl.kt │ │ ├── GetMovieDetailsUseCaseImpl.kt │ │ ├── GetMovieVideosUseCaseImpl.kt │ │ ├── GetMoviesByGenreUseCaseImpl.kt │ │ ├── GetMoviesListUseCaseImpl.kt │ │ ├── GetSimilarMoviesUseCaseImpl.kt │ │ └── ObserveMoviesStreamUseCaseImpl.kt │ │ └── model │ │ └── VideoListTypeExt.kt ├── tmdb-search │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── tmdb │ │ └── search │ │ ├── SearchTmdbUseCase.kt │ │ ├── di │ │ └── TmdbSearchUseCaseModule.kt │ │ └── impl │ │ └── SearchTmdbUseCaseImpl.kt ├── tmdb-shows │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── tmdb │ │ └── shows │ │ ├── GetBookmarkedShowsUseCase.kt │ │ ├── GetEpisodesBySeasonUseCase.kt │ │ ├── GetShowCreditsUseCase.kt │ │ ├── GetShowDetailsUseCase.kt │ │ ├── GetShowVideosUseCase.kt │ │ ├── GetShowsByGenreUseCase.kt │ │ ├── GetShowsListUseCase.kt │ │ ├── GetSimilarShowsUseCase.kt │ │ ├── GetTrendingShowsUseCase.kt │ │ ├── ObserveShowsStreamUseCase.kt │ │ ├── di │ │ └── TmdbShowsDomainModule.kt │ │ ├── impl │ │ ├── GetBookmarkedShowsUseCaseImpl.kt │ │ ├── GetEpisodesBySeasonUseCaseImpl.kt │ │ ├── GetShowCreditsUseCaseImpl.kt │ │ ├── GetShowDetailsUseCaseImpl.kt │ │ ├── GetShowVideosUseCaseImpl.kt │ │ ├── GetShowsByGenreUseCaseImpl.kt │ │ ├── GetShowsListUseCaseImpl.kt │ │ ├── GetSimilarShowsUseCaseImpl.kt │ │ ├── GetTrendingShowsUseCaseImpl.kt │ │ └── ObserveShowsStreamUseCaseImpl.kt │ │ └── model │ │ └── VideoListTypeExt.kt └── trakt │ ├── auth │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── trakt │ │ └── auth │ │ ├── GetTraktAccessTokenUseCase.kt │ │ ├── GetTraktAuthStateUseCase.kt │ │ ├── LogoutTraktUseCase.kt │ │ ├── TraktAuthModule.kt │ │ └── impl │ │ ├── GetTraktAccessTokenUseCaseImpl.kt │ │ ├── GetTraktAuthStateUseCaseImpl.kt │ │ └── LogoutTraktUseCaseImpl.kt │ ├── history │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── domain │ │ └── trakt │ │ └── history │ │ ├── AddEpisodeToHistoryUseCase.kt │ │ ├── AddMovieToHistoryUseCase.kt │ │ ├── IsMovieWatchedUseCase.kt │ │ ├── IsShowWatchedUseCase.kt │ │ ├── RemoveEpisodeFromHistoryUseCase.kt │ │ ├── RemoveMovieFromHistoryUseCase.kt │ │ ├── TraktHistoryModule.kt │ │ └── impl │ │ ├── AddEpisodeToHistoryUseCaseImpl.kt │ │ ├── AddMovieToHistoryUseCaseImpl.kt │ │ ├── IsMovieWatchedUseCaseImpl.kt │ │ ├── IsShowWatchedUseCaseImpl.kt │ │ ├── RemoveEpisodeFromHistoryUseCaseImpl.kt │ │ └── RemoveMovieFromHistoryUseCaseImpl.kt │ └── trakt │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── io │ └── filmtime │ └── domain │ └── trakt │ ├── GetRatingsUseCase.kt │ ├── GetRatingsUseCaseImpl.kt │ └── TraktModule.kt ├── feature ├── credits │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── credits │ │ ├── CreditsUiState.kt │ │ ├── CreditsViewModel.kt │ │ └── components │ │ ├── CreditRowItem.kt │ │ ├── CreditsRow.kt │ │ └── PeopleInCreditsRow.kt ├── home │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── io │ │ │ └── filmtime │ │ │ └── feature │ │ │ └── home │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── io │ │ │ │ └── filmtime │ │ │ │ └── feature │ │ │ │ └── home │ │ │ │ ├── HomeNavigation.kt │ │ │ │ ├── HomeScreen.kt │ │ │ │ ├── HomeUiState.kt │ │ │ │ └── HomeViewModel.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── trakt.xml │ │ │ └── values │ │ │ └── strings.xml │ │ └── test │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── home │ │ └── ExampleUnitTest.kt ├── movie-detail │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── io │ │ │ └── filmtime │ │ │ └── feature │ │ │ └── movie │ │ │ └── detail │ │ │ ├── MovieDetailNavigation.kt │ │ │ ├── MovieDetailScreen.kt │ │ │ ├── MovieDetailState.kt │ │ │ └── MovieDetailViewModel.kt │ │ └── res │ │ └── drawable │ │ ├── bookmark.xml │ │ ├── bookmark_border.xml │ │ └── play_circle.xml ├── movies │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── movies │ │ ├── MoviesNavigation.kt │ │ ├── MoviesScreen.kt │ │ ├── MoviesUiState.kt │ │ └── MoviesViewModel.kt ├── player │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── player │ │ ├── PlayerNavigation.kt │ │ └── VideoPlayer.kt ├── search │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── search │ │ ├── SearchNavigation.kt │ │ ├── SearchScreen.kt │ │ ├── SearchUiState.kt │ │ ├── SearchViewModel.kt │ │ └── components │ │ └── SearchTypeChip.kt ├── settings │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── io │ │ │ └── filmtime │ │ │ └── feature │ │ │ └── settings │ │ │ ├── SettingsNavigation.kt │ │ │ ├── SettingsScreen.kt │ │ │ ├── SettingsUiState.kt │ │ │ ├── SettingsViewModel.kt │ │ │ └── components │ │ │ ├── FilmTimeCard.kt │ │ │ └── TraktCard.kt │ │ └── res │ │ ├── drawable-night │ │ └── ic_trakt_wide_red.xml │ │ ├── drawable │ │ └── ic_trakt_wide_red.xml │ │ └── values │ │ └── strings.xml ├── show-detail │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── io │ │ │ └── filmtime │ │ │ └── feature │ │ │ └── show │ │ │ └── detail │ │ │ ├── ShowDetailNavigation.kt │ │ │ ├── ShowDetailScreen.kt │ │ │ ├── ShowDetailState.kt │ │ │ ├── ShowDetailViewModel.kt │ │ │ └── components │ │ │ ├── EpisodeThumbnailCard.kt │ │ │ └── SeasonsSection.kt │ │ └── res │ │ └── drawable │ │ └── rectangle_badge_checkmark.xml ├── shows │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── shows │ │ ├── ShowsNavigation.kt │ │ ├── ShowsScreen.kt │ │ ├── ShowsUiState.kt │ │ └── ShowsViewModel.kt ├── similar │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── similar │ │ ├── SimilarUiState.kt │ │ ├── SimilarVideosRow.kt │ │ └── SimilarViewModel.kt ├── trakt-buttons │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── trakt │ │ └── buttons │ │ └── addremovehistory │ │ ├── TraktAddRemoveHistoryButton.kt │ │ ├── TraktAddRemoveUiState.kt │ │ └── TraktMovieHistoryViewModel.kt ├── trakt-login │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── trakt │ │ └── login │ │ ├── TraktLoginNavigation.kt │ │ ├── TraktLoginScreen.kt │ │ └── TraktLoginViewModel.kt ├── video-thumbnail-grid-genre │ ├── .gitignore │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── io │ │ └── filmtime │ │ └── feature │ │ └── video │ │ └── thumbnail │ │ └── grid │ │ └── genre │ │ ├── VideoGridGenreNavigation.kt │ │ ├── VideoGridGenreScreen.kt │ │ ├── VideoGridGenreViewModel.kt │ │ └── VideoThumbnailGridUiState.kt └── video-thumbnail-grid │ ├── build.gradle.kts │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── io │ └── filmtime │ └── feature │ └── video │ └── thumbnail │ └── grid │ ├── VideoThumbnailGridNavigation.kt │ ├── VideoThumbnailGridScreen.kt │ ├── VideoThumbnailGridUiState.kt │ └── VideoThumbnailGridViewModel.kt ├── gradle.properties ├── gradle ├── build-logic │ ├── convention │ │ ├── build.gradle.kts │ │ └── src │ │ │ └── main │ │ │ └── kotlin │ │ │ └── io │ │ │ └── filmtime │ │ │ └── gradle │ │ │ ├── Compose.kt │ │ │ ├── GooglePlayPublish.kt │ │ │ ├── KotlinAndroid.kt │ │ │ ├── ProductFlavors.kt │ │ │ ├── ProjectExt.kt │ │ │ ├── VersionCode.kt │ │ │ ├── Versions.kt │ │ │ └── plugins │ │ │ ├── ApplicationComposePlugin.kt │ │ │ ├── ApplicationPlugin.kt │ │ │ ├── DataPlugin.kt │ │ │ ├── DomainPlugin.kt │ │ │ ├── FeaturePlugin.kt │ │ │ ├── HiltPlugin.kt │ │ │ ├── LibraryComposePlugin.kt │ │ │ ├── LibraryJvmPlugin.kt │ │ │ ├── LibraryPlugin.kt │ │ │ ├── RoomPlugin.kt │ │ │ └── TvApplicationPlugin.kt │ ├── gradle.properties │ └── settings.gradle.kts ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── release ├── clean-secrets.sh ├── decrypt-secrets.sh ├── encrypt-secrets.sh ├── filmtime-debug.jks ├── filmtime-release.gpg ├── google-play-publish.gpg └── google-services.gpg ├── settings.gradle.kts └── tv ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── io │ └── filmtime │ └── tv │ ├── FilmTimeTvApp.kt │ ├── FilmTimeTvApplication.kt │ ├── MainActivity.kt │ └── ui │ ├── component │ ├── CastItem.kt │ ├── CastsRow.kt │ ├── DetailHeader.kt │ ├── DetailPoster.kt │ ├── ErrorScreen.kt │ ├── MovieInformation.kt │ ├── MoviesRow.kt │ ├── RowWithSeparator.kt │ ├── SimilarSection.kt │ ├── TvBookmarkButton.kt │ ├── VerticalMovieCard.kt │ └── WatchHistoryButton.kt │ ├── credits │ ├── CreditsUiState.kt │ └── CreditsViewModel.kt │ ├── detail │ └── movie │ │ ├── DetailNavigation.kt │ │ ├── MovieDetailSceen.kt │ │ ├── MovieDetailState.kt │ │ └── MovieDetailViewModel.kt │ ├── home │ ├── HomeNavigation.kt │ ├── HomeScreen.kt │ ├── HomeUiState.kt │ └── HomeViewModel.kt │ ├── movies │ ├── MoviesNavigation.kt │ └── MoviesScreen.kt │ ├── navigation │ ├── NavigationExt.kt │ ├── TabBar.kt │ ├── TabDestination.kt │ ├── TabItem.kt │ └── TvNavHost.kt │ ├── search │ ├── SearchNavigation.kt │ └── SearchScreen.kt │ ├── series │ ├── SeriesScreen.kt │ └── ShowsNavigation.kt │ ├── settings │ ├── SettingsNavigation.kt │ └── SettingsScreen.kt │ ├── similar │ ├── SimilarUiState.kt │ └── SimilarViewModel.kt │ ├── theme │ ├── Color.kt │ ├── Theme.kt │ └── Type.kt │ └── traktbutton │ ├── TraktAddRemoveUiState.kt │ └── TraktMovieHistoryViewModel.kt └── res ├── drawable ├── ic_banner_background.xml └── ic_banner_foreground.xml ├── mipmap-anydpi-v26 └── ic_banner.xml ├── mipmap-hdpi └── ic_banner.png ├── mipmap-mdpi └── ic_banner.png ├── mipmap-xhdpi └── ic_banner.png ├── mipmap-xxhdpi └── ic_banner.png ├── mipmap-xxxhdpi └── ic_banner.png └── values ├── colors.xml ├── strings.xml └── themes.xml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{kt,kts}] 4 | charset = utf-8 5 | max_line_length = 120 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | ij_kotlin_continuation_indent_size = 2 11 | ij_kotlin_allow_trailing_comma = true 12 | ij_kotlin_allow_trailing_comma_on_call_site = true 13 | ktlint_function_naming_ignore_when_annotated_with = Composable 14 | 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: moallemi 2 | -------------------------------------------------------------------------------- /.github/assets/detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moallemi/Film-Time/abf5e404eb2d1c9cb2a913b54271c898c01ec131/.github/assets/detail.png -------------------------------------------------------------------------------- /.github/assets/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moallemi/Film-Time/abf5e404eb2d1c9cb2a913b54271c898c01ec131/.github/assets/home.png -------------------------------------------------------------------------------- /.github/assets/movies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moallemi/Film-Time/abf5e404eb2d1c9cb2a913b54271c898c01ec131/.github/assets/movies.png -------------------------------------------------------------------------------- /.github/assets/trakt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moallemi/Film-Time/abf5e404eb2d1c9cb2a913b54271c898c01ec131/.github/assets/trakt.png -------------------------------------------------------------------------------- /.github/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | feature: ['feature/*', 'feat/*'] 2 | fix: ['fix/*', 'bugfix/*', 'hotfix/*'] 3 | maintenance: ['chore/*'] 4 | release: ['release/*'] -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly. 2 | 3 | Take a look at the [contributing guidelines](https://github.com/moallemi/Film-Time/blob/dev/CONTRIBUTING.md) for this project. 4 | 5 | ### Description 6 | 7 | ### Checklist 8 | - [ ] Make sure to open a GitHub issue as a bug/feature request before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea 9 | - [ ] Ensure the linter (code style) passes 10 | - [ ] Appropriate docs were updated (if necessary) 11 | 12 | Fixes # -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$NEXT_PATCH_VERSION' 2 | tag-template: '$NEXT_PATCH_VERSION' 3 | categories: 4 | - title: '🚀 Features' 5 | labels: 6 | - 'feature' 7 | - 'enhancement' 8 | - title: '🐞 Bug Fixes' 9 | labels: 10 | - 'fix' 11 | - 'bugfix' 12 | - 'bug' 13 | - title: '🧰 Maintenance' 14 | labels: 15 | - 'maintenance' 16 | - 'chore' 17 | exclude-labels: 18 | - 'release' 19 | - 'skip-changelog' 20 | template: | 21 | ## What’s Changed 22 | 23 | $CHANGES 24 | 25 | **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION -------------------------------------------------------------------------------- /.github/workflows/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | name: PR Labeler 2 | on: 3 | pull_request: 4 | types: [opened] 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | pr-labeler: 11 | permissions: 12 | contents: read 13 | pull-requests: write 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: TimonVS/pr-labeler-action@v5 17 | with: 18 | repo-token: ${{ secrets.GITHUB_TOKEN }} 19 | configuration-path: .github/pr-labeler.yml 20 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | update_draft_release: 10 | permissions: 11 | contents: write 12 | pull-requests: write 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: release-drafter/release-drafter@v6 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.scripts/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./gradlew spotlessApply -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | These versions of Film Time are currently being supported with security updates. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 1.0.0 | :x: | 10 | 11 | ## Reporting a Vulnerability 12 | 13 | Contact @moallemi for vulnerability reports. 14 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/io/filmtime/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package io.filmtime 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("io.filmtime", appContext.packageName) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/googlePlay/play/release-notes/en-US/internal.txt: -------------------------------------------------------------------------------- 1 | Internal Release 2 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moallemi/Film-Time/abf5e404eb2d1c9cb2a913b54271c898c01ec131/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/io/filmtime/FilmTimeApplication.kt: -------------------------------------------------------------------------------- 1 | package io.filmtime 2 | 3 | import android.app.Application 4 | import dagger.hilt.android.HiltAndroidApp 5 | 6 | @HiltAndroidApp 7 | class FilmTimeApplication : Application() 8 | -------------------------------------------------------------------------------- /app/src/main/java/io/filmtime/ui/navigation/RootScreen.kt: -------------------------------------------------------------------------------- 1 | package io.filmtime.ui.navigation 2 | 3 | import io.filmtime.core.ui.navigation.DestinationRoute 4 | import io.filmtime.feature.home.GRAPH_HOME_ROUTE 5 | import io.filmtime.feature.movies.GRAPH_MOVIES_ROUTE 6 | import io.filmtime.feature.search.GRAPH_SEARCH_ROUTE 7 | import io.filmtime.feature.settings.GRAPH_SETTINGS_ROUTE 8 | import io.filmtime.feature.shows.GRAPH_SHOWS_ROUTE 9 | 10 | sealed class RootScreen(val destinationRoute: DestinationRoute) { 11 | data object Home : RootScreen(GRAPH_HOME_ROUTE) 12 | data object Movies : RootScreen(GRAPH_MOVIES_ROUTE) 13 | data object Shows : RootScreen(GRAPH_SHOWS_ROUTE) 14 | data object Search : RootScreen(GRAPH_SEARCH_ROUTE) 15 | data object Settings : RootScreen(GRAPH_SETTINGS_ROUTE) 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Film Time 3 | Home 4 | Movies 5 | Series 6 | Search 7 | Settings 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |