├── .editorconfig
├── .gitattributes
├── .github
├── scripts
│ └── mac-disk-cleanup.sh
└── workflows
│ ├── baseline-profile.yml
│ ├── build.yml
│ ├── gradle-wrapper.yaml
│ └── todo.yml
├── .gitignore
├── .idea
├── checkstyle-idea.xml
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── copyright
│ ├── Chris_Banes_Apache_v2.xml
│ ├── Google_Apache_v2_0.xml
│ └── profiles_settings.xml
├── dictionaries
│ ├── chris.xml
│ └── chrisbanes.xml
├── encodings.xml
├── icon.png
├── inspectionProfiles
│ ├── ktlint.xml
│ └── profiles_settings.xml
├── kotlinc.xml
└── vcs.xml
├── .ruby-version
├── .swiftlint.yml
├── .xcode-version
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── android-app
├── app
│ ├── benchmark-rules.pro
│ ├── build.gradle.kts
│ ├── proguard-rules-chucker.pro
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ ├── screenshots
│ │ │ └── Screenshots.kt
│ │ │ └── test
│ │ │ └── smoke
│ │ │ └── SmokeTest.kt
│ │ ├── debug
│ │ ├── AndroidManifest.xml
│ │ └── res
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ └── strings.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── generated
│ │ │ └── baselineProfiles
│ │ │ │ ├── baseline-prof.txt
│ │ │ │ └── startup-prof.txt
│ │ ├── kotlin
│ │ │ └── app
│ │ │ │ └── tivi
│ │ │ │ ├── TiviActivity.kt
│ │ │ │ ├── TiviApplication.kt
│ │ │ │ └── home
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-anydpi-v26
│ │ │ ├── ic_launcher_background.xml
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.webp
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.webp
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.webp
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.webp
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.webp
│ │ │ ├── values-night
│ │ │ ├── colors.xml
│ │ │ ├── sys_ui.xml
│ │ │ └── themes.xml
│ │ │ ├── values-notnight-v27
│ │ │ └── sys_ui.xml
│ │ │ ├── values-v29
│ │ │ └── themes.xml
│ │ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ ├── sys_ui.xml
│ │ │ └── themes.xml
│ │ │ └── xml
│ │ │ ├── backup_rules.xml
│ │ │ └── data_extraction_rules.xml
│ │ └── qa
│ │ └── res
│ │ └── values
│ │ └── leak_canary.xml
├── benchmark
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── benchmark
│ │ ├── BaselineProfileGenerator.kt
│ │ ├── StartupBenchmark.kt
│ │ └── Utils.kt
└── common-test
│ ├── build.gradle.kts
│ └── src
│ └── main
│ └── kotlin
│ └── app
│ └── tivi
│ └── app
│ └── test
│ └── AppScenarios.kt
├── api
├── tmdb
│ ├── build.gradle.kts
│ └── src
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── tmdb
│ │ │ ├── TmdbComponent.kt
│ │ │ ├── TmdbImageSizes.kt
│ │ │ ├── TmdbImageUrlProvider.kt
│ │ │ ├── TmdbInitializer.kt
│ │ │ ├── TmdbManager.kt
│ │ │ └── TmdbOAuthInfo.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── tmdb
│ │ │ └── TmdbPlatformComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── tmdb
│ │ └── TmdbPlatformComponent.kt
└── trakt
│ ├── build.gradle.kts
│ └── src
│ ├── commonMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── trakt
│ │ ├── Anticipated.kt
│ │ ├── TiviTrakt.kt
│ │ └── TraktComponent.kt
│ ├── iosMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── trakt
│ │ └── TraktPlatformComponent.kt
│ └── jvmMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── trakt
│ └── TraktPlatformComponent.kt
├── art
├── account.png
├── banner.png
├── episode-details.gif
├── show-details.gif
├── theme-baseline.sketch
└── tivi-art.sketch
├── build.gradle.kts
├── common
├── imageloading
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── imageloading
│ │ │ └── ImageLoadingPlatformComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── imageloading
│ │ │ ├── EpisodeImageModelInterceptor.kt
│ │ │ ├── HideArtworkInterceptor.kt
│ │ │ ├── ImageLoader.kt
│ │ │ ├── ImageLoaderCleanupInitializer.kt
│ │ │ ├── ImageLoadingComponent.kt
│ │ │ ├── SeasonImageModelInterceptor.kt
│ │ │ ├── ShowImageModelInterceptor.kt
│ │ │ └── TmdbImageEntityCoilInterceptor.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── imageloading
│ │ │ └── ImageLoadingPlatformComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── common
│ │ └── imageloading
│ │ └── ImageLoadingPlatformComponent.kt
└── ui
│ ├── circuit
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ ├── EventSink.kt
│ │ ├── navigation
│ │ ├── DeepLinker.kt
│ │ └── LocalNavigator.kt
│ │ └── overlays
│ │ ├── BottomSheetOverlay.kt
│ │ └── DialogOverlay.kt
│ ├── compose
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── compose
│ │ │ ├── Coil.kt
│ │ │ ├── ColorExtractor.android.kt
│ │ │ ├── ReportDrawnWhen.kt
│ │ │ ├── theme
│ │ │ └── Platform.kt
│ │ │ └── ui
│ │ │ └── Icon.android.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── compose
│ │ │ ├── ColorExtractor.kt
│ │ │ ├── EntryGrid.kt
│ │ │ ├── HazeScaffold.kt
│ │ │ ├── Layout.kt
│ │ │ ├── LazyList.kt
│ │ │ ├── LazyPagingExtensions.kt
│ │ │ ├── LogCompositions.kt
│ │ │ ├── Modifier.kt
│ │ │ ├── NestedScaffold.kt
│ │ │ ├── ReportDrawnWhen.kt
│ │ │ ├── RetainedCoroutineScope.kt
│ │ │ ├── TiviCompositionLocals.kt
│ │ │ ├── TiviPreferenceExtensions.kt
│ │ │ ├── UiMessage.kt
│ │ │ ├── WindowSizeClass.kt
│ │ │ ├── theme
│ │ │ ├── Color.kt
│ │ │ ├── Platform.kt
│ │ │ ├── Shape.kt
│ │ │ ├── Theme.kt
│ │ │ └── Type.kt
│ │ │ └── ui
│ │ │ ├── AppBar.kt
│ │ │ ├── AutoSizedCircularProgressIndicator.kt
│ │ │ ├── Backdrop.kt
│ │ │ ├── BackdropCard.kt
│ │ │ ├── Clickable.kt
│ │ │ ├── DateTimeDialogs.kt
│ │ │ ├── DateTimeTextFields.kt
│ │ │ ├── Empty.kt
│ │ │ ├── ExpandingSummary.kt
│ │ │ ├── GradientScrim.kt
│ │ │ ├── Icon.kt
│ │ │ ├── IconButtonScrim.kt
│ │ │ ├── Image.kt
│ │ │ ├── LoadingButton.kt
│ │ │ ├── PaddingValues.kt
│ │ │ ├── Position.kt
│ │ │ ├── PosterCard.kt
│ │ │ ├── Preference.kt
│ │ │ ├── RefreshButton.kt
│ │ │ ├── SearchTextField.kt
│ │ │ ├── SortChip.kt
│ │ │ ├── SortMenuPopup.kt
│ │ │ ├── Surface.kt
│ │ │ ├── UserProfileButton.kt
│ │ │ └── WindowInsets.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── compose
│ │ │ ├── Coil.kt
│ │ │ ├── ColorExtractor.ios.kt
│ │ │ ├── ReportDrawnWhen.kt
│ │ │ ├── theme
│ │ │ └── Platform.kt
│ │ │ └── ui
│ │ │ ├── DateTimeDialogs.kt
│ │ │ ├── Icon.ios.kt
│ │ │ └── Sheets.kt
│ │ ├── jvmCommon
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── common
│ │ │ └── compose
│ │ │ └── ui
│ │ │ └── DateTimeDialogs.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── common
│ │ └── compose
│ │ ├── Coil.kt
│ │ ├── ColorExtractor.jvm.kt
│ │ ├── ReportDrawnWhen.kt
│ │ ├── theme
│ │ └── Platform.kt
│ │ └── ui
│ │ └── Icon.jvm.kt
│ ├── resources
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── String.kt
│ │ │ ├── TiviDateFormatter.kt
│ │ │ └── TiviTextCreator.kt
│ │ ├── commonMain
│ │ ├── composeResources
│ │ │ ├── font
│ │ │ │ ├── dm_sans_bold.ttf
│ │ │ │ ├── dm_sans_medium.ttf
│ │ │ │ └── dm_sans_regular.ttf
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ ├── common
│ │ │ └── ui
│ │ │ │ └── resources
│ │ │ │ ├── Fonts.kt
│ │ │ │ └── Resources.kt
│ │ │ └── util
│ │ │ ├── GenreStringer.kt
│ │ │ ├── String.kt
│ │ │ ├── TiviDateFormatter.kt
│ │ │ └── TiviTextCreator.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── String.kt
│ │ │ ├── TiviDateFormatter.kt
│ │ │ └── TiviTextCreator.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── util
│ │ ├── String.kt
│ │ ├── TiviDateFormatter.kt
│ │ └── TiviTextCreator.kt
│ └── screens
│ ├── build.gradle.kts
│ └── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── screens
│ ├── Parcelize.kt
│ └── Screens.kt
├── compose-stability.conf
├── core
├── analytics
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── analytics
│ │ │ ├── AnalyticsPlatformComponent.kt
│ │ │ └── TiviFirebaseAnalytics.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── analytics
│ │ │ ├── Analytics.kt
│ │ │ ├── AnalyticsComponent.kt
│ │ │ └── AnalyticsInitializer.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── analytics
│ │ │ └── AnalyticsPlatformComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── core
│ │ └── analytics
│ │ └── AnalyticsPlatformComponent.kt
├── base
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ ├── animations
│ │ └── Lerp.kt
│ │ ├── app
│ │ └── ApplicationInfo.kt
│ │ ├── appinitializers
│ │ └── AppInitializer.kt
│ │ ├── base
│ │ └── InvokeStatus.kt
│ │ ├── extensions
│ │ └── Lazy.kt
│ │ ├── inject
│ │ └── Scopes.kt
│ │ └── util
│ │ ├── AppCoroutineDispatchers.kt
│ │ ├── Collections.kt
│ │ ├── CoroutineContext.kt
│ │ └── Result.kt
├── logging
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── AndroidSetCrashReportingEnabledAction.kt
│ │ │ ├── CrashlyticsAndroidInitializer.kt
│ │ │ └── LoggerPlatformComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── CrashReportingInitializer.kt
│ │ │ ├── KermitInitializer.kt
│ │ │ ├── LoggerComponent.kt
│ │ │ ├── RecordingLoggerWriter.kt
│ │ │ └── SetCrashReportingEnabledAction.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── CrashlyticsIosInitializer.kt
│ │ │ └── LoggerPlatformComponent.kt
│ │ ├── jvmMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ └── LoggerPlatformComponent.kt
│ │ └── mobileMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── util
│ │ └── CrashlyticsLoggerWriter.kt
├── notifications
│ ├── core
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── androidMain
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── app
│ │ │ │ │ └── tivi
│ │ │ │ │ └── core
│ │ │ │ │ └── notifications
│ │ │ │ │ ├── AndroidNotificationManager.kt
│ │ │ │ │ ├── NotificationPlatformComponent.kt
│ │ │ │ │ ├── PendingNotificationStore.kt
│ │ │ │ │ └── PostNotificationBroadcastReceiver.kt
│ │ │ └── res
│ │ │ │ └── drawable
│ │ │ │ └── outline_tv_gen_24.xml
│ │ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── app
│ │ │ │ └── tivi
│ │ │ │ └── core
│ │ │ │ └── notifications
│ │ │ │ ├── NotificationManager.kt
│ │ │ │ └── NotificationsComponent.kt
│ │ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── app
│ │ │ │ └── tivi
│ │ │ │ └── core
│ │ │ │ └── notifications
│ │ │ │ ├── IosNotificationManager.kt
│ │ │ │ └── NotificationPlatformComponent.kt
│ │ │ └── jvmMain
│ │ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── notifications
│ │ │ ├── EmptyNotificationManager.kt
│ │ │ └── NotificationPlatformComponent.kt
│ └── protos
│ │ ├── build.gradle.kts
│ │ └── src
│ │ └── commonMain
│ │ └── proto
│ │ └── pending.proto
├── performance
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── perf
│ │ │ ├── AndroidTracer.kt
│ │ │ └── PerformanceComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── perf
│ │ │ ├── PerformanceComponent.kt
│ │ │ └── Tracer.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── perf
│ │ │ └── PerformanceComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── core
│ │ └── perf
│ │ └── PerformanceComponent.kt
├── permissions
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── permissions
│ │ │ ├── PermissionsController.android.kt
│ │ │ └── PermissionsPlatformComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── permissions
│ │ │ ├── PermissionsComponent.kt
│ │ │ └── PermissionsController.common.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── permissions
│ │ │ └── PermissionsPlatformComponent.kt
│ │ ├── jvmMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── core
│ │ │ └── permissions
│ │ │ └── PermissionsPlatformComponent.kt
│ │ └── mokoImplMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── core
│ │ └── permissions
│ │ └── PermissionsController.ios.kt
├── powercontroller
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── AndroidPowerController.kt
│ │ │ └── PowerControllerComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ ├── PowerController.kt
│ │ │ └── PowerControllerComponent.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── util
│ │ │ └── PowerControllerComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── util
│ │ └── PowerControllerComponent.kt
└── preferences
│ ├── build.gradle.kts
│ └── src
│ ├── androidMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── settings
│ │ └── PreferencesComponent.kt
│ ├── commonMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── settings
│ │ ├── Preference.kt
│ │ ├── PreferencesComponent.kt
│ │ ├── TiviPreferences.kt
│ │ └── TiviPreferencesImpl.kt
│ ├── iosMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── settings
│ │ └── PreferencesPlatformComponent.kt
│ └── jvmMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── settings
│ └── PreferencesPlatformComponent.kt
├── data
├── anticipatedshows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── anticipatedshows
│ │ ├── AnticipatedShowsBinds.kt
│ │ ├── AnticipatedShowsDataSource.kt
│ │ ├── AnticipatedShowsLastRequestStore.kt
│ │ ├── AnticipatedShowsStore.kt
│ │ └── TraktAnticipatedShowsDataSource.kt
├── db-sqldelight
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── SqlDelightDatabasePlatformComponent.kt
│ │ ├── commonMain
│ │ ├── kotlin
│ │ │ └── app
│ │ │ │ └── tivi
│ │ │ │ └── data
│ │ │ │ ├── DatabaseFactory.kt
│ │ │ │ ├── SqlDelightDatabaseComponent.kt
│ │ │ │ ├── SqlDelightTransactionRunner.kt
│ │ │ │ ├── Utils.kt
│ │ │ │ ├── columnadaptors
│ │ │ │ ├── DayOfWeekColumnAdapter.kt
│ │ │ │ ├── ImageTypeColumnAdapter.kt
│ │ │ │ ├── InstantLongColumnAdapter.kt
│ │ │ │ ├── InstantStringColumnAdapter.kt
│ │ │ │ ├── LocalDateColumnAdapter.kt
│ │ │ │ ├── LocalDateTimeColumnAdapter.kt
│ │ │ │ ├── LocalTimeColumnAdapter.kt
│ │ │ │ ├── PendingActionColumnAdapter.kt
│ │ │ │ ├── RequestColumnAdapter.kt
│ │ │ │ ├── ShowStatusColumnAdapter.kt
│ │ │ │ └── TimeZoneColumnAdapter.kt
│ │ │ │ ├── daos
│ │ │ │ ├── SqlDelightAnticipatedShowsDao.kt
│ │ │ │ ├── SqlDelightEntityDao.kt
│ │ │ │ ├── SqlDelightEpisodeWatchEntryDao.kt
│ │ │ │ ├── SqlDelightEpisodesDao.kt
│ │ │ │ ├── SqlDelightFollowedShowsDao.kt
│ │ │ │ ├── SqlDelightLastRequestDao.kt
│ │ │ │ ├── SqlDelightLibraryShowsDao.kt
│ │ │ │ ├── SqlDelightPopularShowsDao.kt
│ │ │ │ ├── SqlDelightRecommendedShowsDao.kt
│ │ │ │ ├── SqlDelightRelatedShowsDao.kt
│ │ │ │ ├── SqlDelightSeasonsDao.kt
│ │ │ │ ├── SqlDelightShowImagesDao.kt
│ │ │ │ ├── SqlDelightTiviShowDao.kt
│ │ │ │ ├── SqlDelightTrendingShowsDao.kt
│ │ │ │ ├── SqlDelightUserDao.kt
│ │ │ │ └── SqlDelightWatchedShowsDao.kt
│ │ │ │ └── paging
│ │ │ │ ├── KeyedQueryPagingSource.kt
│ │ │ │ ├── OffsetQueryPagingSource.kt
│ │ │ │ └── QueryPagingSource.kt
│ │ └── sqldelight
│ │ │ ├── app
│ │ │ └── tivi
│ │ │ │ └── data
│ │ │ │ ├── anticipated_shows.sq
│ │ │ │ ├── episode_watch_entries.sq
│ │ │ │ ├── episodes.sq
│ │ │ │ ├── last_requests.sq
│ │ │ │ ├── library_shows.sq
│ │ │ │ ├── myshows_entries.sq
│ │ │ │ ├── popular_shows.sq
│ │ │ │ ├── recommended_entries.sq
│ │ │ │ ├── related_shows.sq
│ │ │ │ ├── seasons.sq
│ │ │ │ ├── show.sq
│ │ │ │ ├── show_images.sq
│ │ │ │ ├── shows_last_watched.sq
│ │ │ │ ├── shows_next_to_watch.sq
│ │ │ │ ├── shows_view_watch_stats.sq
│ │ │ │ ├── trending_shows.sq
│ │ │ │ ├── upnext_shows.sq
│ │ │ │ ├── users.sq
│ │ │ │ └── watched_entries.sq
│ │ │ └── migrations
│ │ │ ├── 29.sqm
│ │ │ ├── 30.sqm
│ │ │ ├── 31.sqm
│ │ │ ├── 32.sqm
│ │ │ ├── 33.sqm
│ │ │ └── 34.sqm
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── SqlDelightDatabasePlatformComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── SqlDelightDatabasePlatformComponent.kt
├── db
│ ├── build.gradle.kts
│ ├── room-schemas
│ │ ├── 1.json
│ │ ├── 10.json
│ │ ├── 11.json
│ │ ├── 12.json
│ │ ├── 13.json
│ │ ├── 14.json
│ │ ├── 15.json
│ │ ├── 16.json
│ │ ├── 17.json
│ │ ├── 18.json
│ │ ├── 19.json
│ │ ├── 2.json
│ │ ├── 20.json
│ │ ├── 21.json
│ │ ├── 22.json
│ │ ├── 23.json
│ │ ├── 24.json
│ │ ├── 25.json
│ │ ├── 26.json
│ │ ├── 27.json
│ │ ├── 28.json
│ │ ├── 29.json
│ │ ├── 3.json
│ │ ├── 30.json
│ │ ├── 31.json
│ │ ├── 32.json
│ │ ├── 4.json
│ │ ├── 5.json
│ │ ├── 6.json
│ │ ├── 7.json
│ │ ├── 8.json
│ │ └── 9.json
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ ├── daos
│ │ ├── AnticipatedShowsDao.kt
│ │ ├── EntityDao.kt
│ │ ├── EntryDao.kt
│ │ ├── EpisodeWatchEntryDao.kt
│ │ ├── EpisodesDao.kt
│ │ ├── FollowedShowsDao.kt
│ │ ├── LastRequestDao.kt
│ │ ├── LibraryShowsDao.kt
│ │ ├── PaginatedEntryDao.kt
│ │ ├── PairEntryDao.kt
│ │ ├── PopularDao.kt
│ │ ├── RecommendedDao.kt
│ │ ├── RelatedShowsDao.kt
│ │ ├── SeasonsDao.kt
│ │ ├── ShowFtsDao.kt
│ │ ├── ShowTmdbImagesDao.kt
│ │ ├── TiviShowDao.kt
│ │ ├── TrendingDao.kt
│ │ ├── UserDao.kt
│ │ └── WatchedShowDao.kt
│ │ └── db
│ │ └── DatabaseTransactionRunner.kt
├── episodes
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── episodes
│ │ ├── EpisodeBinds.kt
│ │ ├── EpisodeLastRequestStore.kt
│ │ ├── EpisodeWatchLastRequestStore.kt
│ │ ├── EpisodeWatchStore.kt
│ │ ├── SeasonLastRequestStore.kt
│ │ ├── SeasonsEpisodesRepository.kt
│ │ ├── ShowSeasonsLastRequestStore.kt
│ │ └── datasource
│ │ ├── EpisodeDataSource.kt
│ │ ├── EpisodeWatchesDataSource.kt
│ │ └── SeasonsEpisodesDataSource.kt
├── followedshows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── followedshows
│ │ ├── FollowedShowsBinds.kt
│ │ ├── FollowedShowsDataSource.kt
│ │ ├── FollowedShowsLastRequestStore.kt
│ │ ├── FollowedShowsRepository.kt
│ │ └── TraktFollowedShowsDataSource.kt
├── legacy
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ ├── lastrequests
│ │ ├── EntityLastRequestStore.kt
│ │ └── GroupLastRequestStore.kt
│ │ ├── mappers
│ │ ├── EpisodeIdToTraktIdMapper.kt
│ │ ├── Mapper.kt
│ │ ├── Mappers.kt
│ │ ├── SeasonIdToTraktIdMapper.kt
│ │ ├── ShowIdToTmdbIdMapper.kt
│ │ ├── ShowIdToTraktIdMapper.kt
│ │ ├── ShowIdToTraktOrImdbIdMapper.kt
│ │ ├── TmdbEpisodeDetailToEpisode.kt
│ │ ├── TmdbEpisodeToEpisode.kt
│ │ ├── TmdbSeasonDetailToSeason.kt
│ │ ├── TmdbSeasonToSeason.kt
│ │ ├── TmdbSeasonToSeasonWithEpisodes.kt
│ │ ├── TmdbShowDetailToShowImages.kt
│ │ ├── TmdbShowDetailToTiviShow.kt
│ │ ├── TmdbShowPageResultToTiviShows.kt
│ │ ├── TmdbShowToTiviShow.kt
│ │ ├── TraktBaseShowToWatchedShowEntry.kt
│ │ ├── TraktEpisodeToEpisode.kt
│ │ ├── TraktHistoryEntryToEpisode.kt
│ │ ├── TraktHistoryItemToEpisodeWatchEntry.kt
│ │ ├── TraktListItemToFollowedShowEntry.kt
│ │ ├── TraktListItemToTiviShow.kt
│ │ ├── TraktSeasonToSeason.kt
│ │ ├── TraktSeasonToSeasonWithEpisodes.kt
│ │ ├── TraktShowToTiviShow.kt
│ │ ├── TraktStatusToShowStatus.kt
│ │ ├── TraktTrendingShowToTiviShow.kt
│ │ ├── TraktTrendingShowToTrendingShowEntry.kt
│ │ └── UserToTraktUser.kt
│ │ └── util
│ │ ├── ItemSyncer.kt
│ │ └── StoreExtensions.kt
├── licenses
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── licenses
│ │ │ ├── LicenseDataPlatformComponent.kt
│ │ │ └── fetcher
│ │ │ └── AndroidLicensesFetcherImpl.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── licenses
│ │ │ ├── LicenseDataComponent.kt
│ │ │ ├── LicensesState.kt
│ │ │ ├── fetcher
│ │ │ └── LicensesFetcher.kt
│ │ │ └── store
│ │ │ ├── LicensesStore.kt
│ │ │ └── LicensesStoreImpl.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── licenses
│ │ │ ├── LicenseDataPlatformComponent.kt
│ │ │ └── fetcher
│ │ │ └── IosLicensesFetcherImpl.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── licenses
│ │ ├── LicenseDataPlatformComponent.kt
│ │ └── fetcher
│ │ └── JvmLicensesFetcherImpl.kt
├── models
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ ├── compoundmodels
│ │ ├── EntryWithShow.kt
│ │ ├── EpisodeWithSeason.kt
│ │ ├── EpisodeWithWatches.kt
│ │ ├── LibraryShow.kt
│ │ ├── SeasonWithEpisodes.kt
│ │ ├── SeasonWithEpisodesAndWatches.kt
│ │ ├── SeasonWithShow.kt
│ │ ├── ShowSeasonEpisode.kt
│ │ └── UpNextEntry.kt
│ │ ├── imagemodels
│ │ ├── EpisodeImageModel.kt
│ │ ├── ImageModel.kt
│ │ ├── SeasonImageModel.kt
│ │ └── ShowImageModel.kt
│ │ ├── models
│ │ ├── ActionDate.kt
│ │ ├── AnticipatedShowEntry.kt
│ │ ├── Entry.kt
│ │ ├── Episode.kt
│ │ ├── EpisodeWatchEntry.kt
│ │ ├── FollowedShowEntry.kt
│ │ ├── Genre.kt
│ │ ├── LastRequest.kt
│ │ ├── Notification.kt
│ │ ├── PendingAction.kt
│ │ ├── PopularShowEntry.kt
│ │ ├── RecommendedShowEntry.kt
│ │ ├── RelatedShowEntry.kt
│ │ ├── Request.kt
│ │ ├── Season.kt
│ │ ├── ShowImages.kt
│ │ ├── ShowStatus.kt
│ │ ├── ShowTmdbImage.kt
│ │ ├── SortOption.kt
│ │ ├── TiviEntity.kt
│ │ ├── TiviShow.kt
│ │ ├── TraktUser.kt
│ │ ├── TrendingShowEntry.kt
│ │ └── WatchedShowEntry.kt
│ │ ├── util
│ │ ├── DateTimeUtils.kt
│ │ ├── ImageEntityUtils.kt
│ │ └── MergeShowUtils.kt
│ │ └── views
│ │ ├── ShowsNextToWatch.kt
│ │ └── ShowsWatchStats.kt
├── popularshows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── popularshows
│ │ ├── PopularShowsBinds.kt
│ │ ├── PopularShowsDataSource.kt
│ │ ├── PopularShowsLastRequestStore.kt
│ │ ├── PopularShowsStore.kt
│ │ └── TraktPopularShowsDataSource.kt
├── recommendedshows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── recommendedshows
│ │ ├── RecommendedShowsBinds.kt
│ │ ├── RecommendedShowsDataSource.kt
│ │ ├── RecommendedShowsLastRequestStore.kt
│ │ ├── RecommendedShowsStore.kt
│ │ └── TraktRecommendedShowsDataSource.kt
├── relatedshows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── relatedshows
│ │ ├── RelatedShowsBinds.kt
│ │ ├── RelatedShowsDataSource.kt
│ │ ├── RelatedShowsLastRequestStore.kt
│ │ ├── RelatedShowsStore.kt
│ │ ├── TmdbRelatedShowsDataSourceImpl.kt
│ │ └── TraktRelatedShowsDataSourceImpl.kt
├── search
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── search
│ │ ├── SearchBinds.kt
│ │ ├── SearchDataSource.kt
│ │ ├── SearchRepository.kt
│ │ └── TmdbSearchDataSource.kt
├── showimages
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── showimages
│ │ ├── ShowImagesBinds.kt
│ │ ├── ShowImagesDataSource.kt
│ │ ├── ShowImagesLastRequestStore.kt
│ │ ├── ShowImagesStore.kt
│ │ └── TmdbShowImagesDataSource.kt
├── shows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── shows
│ │ ├── ShowDataSource.kt
│ │ ├── ShowLastRequestStore.kt
│ │ ├── ShowStore.kt
│ │ ├── ShowsBinds.kt
│ │ ├── TmdbShowDataSourceImpl.kt
│ │ └── TraktShowDataSourceImpl.kt
├── test
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidUnitTest
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── DatabaseTest.kt
│ │ ├── commonTest
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ ├── data
│ │ │ ├── DatabaseTest.kt
│ │ │ ├── dao
│ │ │ │ ├── EpisodeWatchEntryTest.kt
│ │ │ │ ├── EpisodesTest.kt
│ │ │ │ └── SeasonsTest.kt
│ │ │ └── repositories
│ │ │ │ ├── FollowedShowRepositoryTest.kt
│ │ │ │ └── SeasonsEpisodesRepositoryTest.kt
│ │ │ └── utils
│ │ │ ├── AuthorizedAuthStore.kt
│ │ │ ├── Dispatchers.kt
│ │ │ ├── FakeEpisodeDataSource.kt
│ │ │ ├── FakeEpisodeWatchesDataSource.kt
│ │ │ ├── FakeFollowedShowsDataSource.kt
│ │ │ ├── FakeSeasonsEpisodesDataSource.kt
│ │ │ ├── Fakes.kt
│ │ │ ├── ObjectGraph.kt
│ │ │ ├── SampleData.kt
│ │ │ └── TestTransactionRunner.kt
│ │ ├── jvmTest
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── DatabaseTest.kt
│ │ └── nativeTest
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── DatabaseTest.kt
├── traktauth
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── traktauth
│ │ │ ├── AndroidTraktLoginAction.kt
│ │ │ ├── AndroidTraktRefreshTokenAction.kt
│ │ │ ├── AppAuthAuthStateWrapper.kt
│ │ │ ├── LoginTraktActivityResultContract.kt
│ │ │ ├── TraktAuthComponent.kt
│ │ │ ├── TraktAuthInitializer.kt
│ │ │ └── store
│ │ │ ├── BlockStoreAuthStore.kt
│ │ │ ├── PreferencesAuthStore.kt
│ │ │ └── TiviAuthStore.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── traktauth
│ │ │ ├── AuthState.kt
│ │ │ ├── TraktAuthComponent.kt
│ │ │ ├── TraktAuthRepository.kt
│ │ │ ├── TraktAuthState.kt
│ │ │ ├── TraktLoginAction.kt
│ │ │ ├── TraktOAuthInfo.kt
│ │ │ ├── TraktRefreshTokenAction.kt
│ │ │ └── store
│ │ │ └── AuthStore.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── data
│ │ │ └── traktauth
│ │ │ ├── IosAuthStore.kt
│ │ │ └── TraktAuthComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── traktauth
│ │ ├── DesktopAuthStore.kt
│ │ ├── DesktopTraktLoginAction.kt
│ │ ├── DesktopTraktRefreshTokenAction.kt
│ │ └── TraktAuthComponent.kt
├── traktusers
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── traktusers
│ │ ├── TraktUsersBinds.kt
│ │ ├── TraktUsersDataSource.kt
│ │ ├── TraktUsersLastRequestStore.kt
│ │ ├── TraktUsersRepository.kt
│ │ └── UsersDataSource.kt
├── trendingshows
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── data
│ │ └── trendingshows
│ │ ├── TraktTrendingShowsDataSource.kt
│ │ ├── TrendingShowsBinds.kt
│ │ ├── TrendingShowsDataSource.kt
│ │ ├── TrendingShowsLastRequestStore.kt
│ │ └── TrendingShowsStore.kt
└── watchedshows
│ ├── build.gradle.kts
│ └── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── data
│ └── watchedshows
│ ├── TraktWatchedShowsDataSource.kt
│ ├── WatchedShowsBinds.kt
│ ├── WatchedShowsDataSource.kt
│ ├── WatchedShowsLastRequestStore.kt
│ └── WatchedShowsStore.kt
├── desktop-app
├── build.gradle.kts
└── src
│ └── jvmMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── Main.kt
├── docs
├── _config.yml
└── privacypolicy.md
├── domain
├── build.gradle.kts
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── domain
│ ├── Interactor.kt
│ ├── PaginatedEntryRemoteMediator.kt
│ ├── RefreshOnlyRemoteMediator.kt
│ ├── interactors
│ ├── AddEpisodeWatch.kt
│ ├── ChangeSeasonFollowStatus.kt
│ ├── ChangeSeasonWatchedStatus.kt
│ ├── ChangeShowFollowStatus.kt
│ ├── ClearUserDetails.kt
│ ├── FetchLicensesList.kt
│ ├── GetTraktAuthState.kt
│ ├── LoginTrakt.kt
│ ├── LogoutTrakt.kt
│ ├── RefreshTraktTokens.kt
│ ├── RemoveEpisodeWatch.kt
│ ├── RemoveEpisodeWatches.kt
│ ├── ScheduleDebugEpisodeNotification.kt
│ ├── ScheduleEpisodeNotifications.kt
│ ├── SearchShows.kt
│ ├── UpdateAnticipatedShows.kt
│ ├── UpdateEpisodeDetails.kt
│ ├── UpdateLibraryShows.kt
│ ├── UpdatePopularShows.kt
│ ├── UpdateRecommendedShows.kt
│ ├── UpdateRelatedShows.kt
│ ├── UpdateShowDetails.kt
│ ├── UpdateShowImages.kt
│ ├── UpdateShowSeasons.kt
│ ├── UpdateTmdbConfig.kt
│ ├── UpdateTrendingShows.kt
│ ├── UpdateUpNextEpisodes.kt
│ └── UpdateUserDetails.kt
│ └── observers
│ ├── ObserveAnticipatedShows.kt
│ ├── ObserveEpisodeDetails.kt
│ ├── ObserveEpisodeWatches.kt
│ ├── ObserveNextShowEpisodesToWatch.kt
│ ├── ObservePagedAnticipatedShows.kt
│ ├── ObservePagedLibraryShows.kt
│ ├── ObservePagedPopularShows.kt
│ ├── ObservePagedRecommendedShows.kt
│ ├── ObservePagedTrendingShows.kt
│ ├── ObservePagedUpNextShows.kt
│ ├── ObservePopularShows.kt
│ ├── ObserveRecommendedShows.kt
│ ├── ObserveRelatedShows.kt
│ ├── ObserveShowDetails.kt
│ ├── ObserveShowDetailsForEpisodeId.kt
│ ├── ObserveShowFollowStatus.kt
│ ├── ObserveShowImages.kt
│ ├── ObserveShowNextEpisodeToWatch.kt
│ ├── ObserveShowSeasonsEpisodesWatches.kt
│ ├── ObserveShowViewStats.kt
│ ├── ObserveTraktAuthState.kt
│ ├── ObserveTrendingShows.kt
│ └── ObserveUserDetails.kt
├── fastlane
├── Fastfile
├── Matchfile
├── metadata
│ └── android
│ │ └── en_US
│ │ ├── full_description.txt
│ │ ├── images
│ │ ├── featureGraphic.png
│ │ ├── icon.png
│ │ └── phoneScreenshots
│ │ │ ├── 0_home.png
│ │ │ ├── 1_show_details.png
│ │ │ ├── 2_upnext.png
│ │ │ ├── 3_library.png
│ │ │ └── 4_search.png
│ │ ├── short_description.txt
│ │ ├── title.txt
│ │ └── video.txt
└── screenshots
│ ├── en-US
│ ├── iPad Pro (12.9-inch) (3rd generation)-1_Home.png
│ ├── iPad Pro (12.9-inch) (3rd generation)-2_ShowDetails.png
│ ├── iPad Pro (12.9-inch) (3rd generation)-3_UpNext.png
│ ├── iPad Pro (12.9-inch) (3rd generation)-4_Library.png
│ ├── iPad Pro (12.9-inch) (3rd generation)-5_Search.png
│ ├── iPhone 15 Pro Max-1_Home.png
│ ├── iPhone 15 Pro Max-2_ShowDetails.png
│ ├── iPhone 15 Pro Max-3_UpNext.png
│ ├── iPhone 15 Pro Max-4_Library.png
│ ├── iPhone 15 Pro Max-5_Search.png
│ ├── iPhone SE (3rd generation)-1_Home.png
│ ├── iPhone SE (3rd generation)-2_ShowDetails.png
│ ├── iPhone SE (3rd generation)-3_UpNext.png
│ ├── iPhone SE (3rd generation)-4_Library.png
│ └── iPhone SE (3rd generation)-5_Search.png
│ └── screenshots.html
├── gradle.properties
├── gradle
├── build-logic
│ ├── convention
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── gradle
│ │ │ ├── Android.kt
│ │ │ ├── AndroidApplicationConventionPlugin.kt
│ │ │ ├── AndroidApplicationLicensesHandler.kt
│ │ │ ├── AndroidLibraryConventionPlugin.kt
│ │ │ ├── AndroidTestConventionPlugin.kt
│ │ │ ├── AssetCopyTask.kt
│ │ │ ├── ComposeMultiplatformConventionPlugin.kt
│ │ │ ├── IosLicensesHandler.kt
│ │ │ ├── Java.kt
│ │ │ ├── Kotlin.kt
│ │ │ ├── KotlinAndroidConventionPlugin.kt
│ │ │ ├── KotlinMultiplatformConventionPlugin.kt
│ │ │ ├── Licensee.kt
│ │ │ ├── RootConventionPlugin.kt
│ │ │ ├── Spotless.kt
│ │ │ ├── VersionCatalog.kt
│ │ │ └── Versions.kt
│ ├── gradle.properties
│ └── settings.gradle.kts
├── dependencyGraph.gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ios-app
└── Tivi
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Settings.bundle
│ └── Root.plist
│ ├── Tivi.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── Tivi Prod (StoreKit).xcscheme
│ │ ├── Tivi Prod.xcscheme
│ │ ├── Tivi QA.xcscheme
│ │ └── UITests.xcscheme
│ ├── Tivi.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ ├── Tivi
│ ├── Assets.xcassets
│ │ ├── AppIcon-QA.appiconset
│ │ │ ├── AppIcon-QA.png
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── AppIcon.png
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Auth.swift
│ ├── ContentView.swift
│ ├── GoogleService-Info.plist
│ ├── Info.plist
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ └── TiviApp.swift
│ ├── UITests
│ ├── Extensions.swift
│ ├── Screenshots.swift
│ └── SnapshotHelper.swift
│ └── xcconfig
│ ├── Project.xcconfig
│ ├── Tivi-Prod-Debug.xcconfig
│ ├── Tivi-Prod-Release.xcconfig
│ ├── Tivi-QA-Debug.xcconfig
│ ├── Tivi-QA-Release.xcconfig
│ ├── UITests.xcconfig
│ └── common
│ ├── Debug.xcconfig
│ ├── Prod.xcconfig
│ ├── QA.xcconfig
│ └── Release.xcconfig
├── release
├── GoogleService-Info.plist.gpg
├── app-debug.jks
├── app-release.gpg
├── clean-secrets.sh
├── decrypt-secrets.sh
├── encrypt-secrets.sh
├── google-services.gpg
└── play-account.gpg
├── renovate.json
├── room2sqld.py
├── settings.gradle.kts
├── shared
├── common
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── inject
│ │ │ ├── SharedActivityComponent.kt
│ │ │ └── SharedPlatformApplicationComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ ├── appinitializers
│ │ │ └── AppInitializers.kt
│ │ │ └── inject
│ │ │ ├── SharedApplicationComponent.kt
│ │ │ └── SharedUiComponent.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── inject
│ │ │ └── SharedPlatformApplicationComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── inject
│ │ └── SharedPlatformApplicationComponent.kt
├── prod
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ ├── androidMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── inject
│ │ │ ├── AndroidActivityComponent.kt
│ │ │ └── AndroidApplicationComponent.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── inject
│ │ │ ├── ProdApplicationComponent.kt
│ │ │ └── ProdUiComponent.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── app
│ │ │ └── tivi
│ │ │ └── inject
│ │ │ ├── HomeUiControllerComponent.kt
│ │ │ └── IosApplicationComponent.kt
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── inject
│ │ ├── DesktopApplicationComponent.kt
│ │ └── WindowComponent.kt
└── qa
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ ├── androidMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── inject
│ │ ├── AndroidActivityComponent.kt
│ │ └── AndroidApplicationComponent.kt
│ ├── commonMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── inject
│ │ ├── QaApplicationComponent.kt
│ │ └── QaUiComponent.kt
│ ├── iosMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── inject
│ │ ├── HomeUiControllerComponent.kt
│ │ └── IosApplicationComponent.kt
│ └── jvmMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── inject
│ ├── DesktopApplicationComponent.kt
│ └── WindowComponent.kt
├── spotless
├── cb-copyright.txt
└── google-copyright.txt
├── tasks
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── tasks
│ │ ├── AndroidTasks.kt
│ │ ├── BootBroadcastReceiver.kt
│ │ ├── ScheduleEpisodeNotificationsWorker.kt
│ │ ├── SyncLibraryShowsWorker.kt
│ │ ├── TasksPlatformComponent.kt
│ │ └── TiviWorkerFactory.kt
│ ├── commonMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── tasks
│ │ ├── Tasks.kt
│ │ ├── TasksComponent.kt
│ │ └── TasksInitializer.kt
│ ├── iosMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── tasks
│ │ ├── IosTasks.kt
│ │ └── TasksPlatformComponent.kt
│ └── jvmMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── tasks
│ └── TasksPlatformComponent.kt
├── thirdparty
└── androidx
│ └── paging
│ └── compose
│ ├── build.gradle.kts
│ └── src
│ ├── androidMain
│ └── kotlin
│ │ └── PagingPlaceholders.android.kt
│ ├── commonMain
│ └── kotlin
│ │ ├── LazyFoundationExtensions.kt
│ │ ├── LazyPagingItems.kt
│ │ └── PagingPlaceholders.kt
│ ├── iosMain
│ └── kotlin
│ │ └── PagingPlaceholders.ios.kt
│ └── jvmMain
│ └── kotlin
│ └── PagingPlaceholders.jvm.kt
└── ui
├── account
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── account
│ ├── AccountComponent.kt
│ ├── AccountPresenter.kt
│ ├── AccountUi.kt
│ └── AccountUiState.kt
├── anticipated
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── anticipated
│ ├── AnticipatedShows.kt
│ ├── AnticipatedShowsComponent.kt
│ ├── AnticipatedShowsPresenter.kt
│ └── AnticipatedShowsUiState.kt
├── developer
├── log
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── developer
│ │ └── log
│ │ ├── DevLog.kt
│ │ ├── DevLogComponent.kt
│ │ ├── DevLogPresenter.kt
│ │ └── DevLogUiState.kt
├── notifications
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── developer
│ │ └── notifications
│ │ ├── DevNotifications.kt
│ │ ├── DevNotificationsComponent.kt
│ │ ├── DevNotificationsPresenter.kt
│ │ └── DevNotificationsUiState.kt
└── settings
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── settings
│ └── developer
│ ├── DevSettings.kt
│ ├── DevSettingsComponent.kt
│ ├── DevSettingsPresenter.kt
│ └── DevSettingsUiState.kt
├── discover
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── discover
│ ├── Discover.kt
│ ├── DiscoverComponent.kt
│ ├── DiscoverPresenter.kt
│ └── DiscoverUiState.kt
├── episode
├── details
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── episodedetails
│ │ ├── EpisodeDetails.kt
│ │ ├── EpisodeDetailsComponent.kt
│ │ ├── EpisodeDetailsPresenter.kt
│ │ └── EpisodeDetailsUiState.kt
└── track
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── episode
│ └── track
│ ├── EpisodeTrack.kt
│ ├── EpisodeTrackComponent.kt
│ ├── EpisodeTrackPresenter.kt
│ └── EpisodeTrackUiState.kt
├── library
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── library
│ ├── Library.kt
│ ├── LibraryComponent.kt
│ ├── LibraryPresenter.kt
│ └── LibraryUiState.kt
├── licenses
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── settings
│ └── licenses
│ ├── Licenses.kt
│ ├── LicensesComponent.kt
│ ├── LicensesPresenter.kt
│ └── LicensesUiState.kt
├── popular
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── popular
│ ├── PopularShows.kt
│ ├── PopularShowsComponent.kt
│ ├── PopularShowsPresenter.kt
│ └── PopularShowsUiState.kt
├── recommended
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── recommended
│ ├── Recommended.kt
│ ├── RecommendedShowsComponent.kt
│ ├── RecommendedShowsPresenter.kt
│ └── RecommendedShowsUiState.kt
├── root
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ ├── commonMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── home
│ │ ├── Home.kt
│ │ ├── RootUiComponent.kt
│ │ ├── RootViewModel.kt
│ │ └── TiviContent.kt
│ └── iosMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── TiviUiViewController.kt
├── search
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── search
│ ├── Search.kt
│ ├── SearchComponent.kt
│ ├── SearchPresenter.kt
│ └── SearchUiState.kt
├── settings
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ ├── androidMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── settings
│ │ └── Platform.kt
│ ├── commonMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── settings
│ │ ├── Platform.kt
│ │ ├── Settings.kt
│ │ ├── SettingsComponent.kt
│ │ ├── SettingsPresenter.kt
│ │ └── SettingsUiState.kt
│ ├── iosMain
│ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── settings
│ │ └── Platform.kt
│ └── jvmMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── settings
│ └── Platform.kt
├── show
├── details
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ └── app
│ │ └── tivi
│ │ └── showdetails
│ │ └── details
│ │ ├── ShowDetails.kt
│ │ ├── ShowDetailsComponent.kt
│ │ ├── ShowDetailsPresenter.kt
│ │ └── ShowDetailsUiState.kt
└── seasons
│ ├── build.gradle.kts
│ ├── lint-baseline.xml
│ └── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── showdetails
│ └── seasons
│ ├── ShowSeasons.kt
│ ├── ShowSeasonsComponent.kt
│ ├── ShowSeasonsPresenter.kt
│ └── ShowSeasonsUiState.kt
├── trending
├── build.gradle.kts
├── lint-baseline.xml
└── src
│ └── commonMain
│ └── kotlin
│ └── app
│ └── tivi
│ └── home
│ └── trending
│ ├── Trending.kt
│ ├── TrendingShowsComponent.kt
│ ├── TrendingShowsPresenter.kt
│ └── TrendingShowsUiState.kt
└── upnext
├── build.gradle.kts
├── lint-baseline.xml
└── src
└── commonMain
└── kotlin
└── app
└── tivi
└── home
└── upnext
├── UpNext.kt
├── UpNextComponent.kt
├── UpNextPresenter.kt
└── UpNextUiState.kt
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_size = 2
6 | indent_style = space
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.{kt,kts}]
11 | ij_kotlin_imports_layout = *
12 | ktlint_code_style = intellij_idea
13 | ktlint_standard_discouraged-comment-location = disabled
14 | ktlint_standard_function-expression-body = disabled
15 | ktlint_function_naming_ignore_when_annotated_with = Composable
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
3 | *.bat text eol=crlf
4 | *.jar binary
5 |
--------------------------------------------------------------------------------
/.github/workflows/gradle-wrapper.yaml:
--------------------------------------------------------------------------------
1 | name: gradle-wrapper
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - 'gradlew'
7 | - 'gradlew.bat'
8 | - 'gradle/wrapper/'
9 |
10 | jobs:
11 | validate:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: gradle/wrapper-validation-action@v3
16 |
--------------------------------------------------------------------------------
/.github/workflows/todo.yml:
--------------------------------------------------------------------------------
1 | name: TODO <> Issues
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
14 | - uses: alstr/todo-to-issue-action@v5
15 |
--------------------------------------------------------------------------------
/.idea/checkstyle-idea.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
15 |
16 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/copyright/Chris_Banes_Apache_v2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/copyright/Google_Apache_v2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/dictionaries/chris.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | spdx
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/dictionaries/chrisbanes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | tmdb
5 | trakt
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/.idea/icon.png
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/ktlint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.3.4
2 |
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | included:
2 | - ios-app/Tivi
3 |
4 | excluded:
5 | - ios-app/Tivi/UITests/SnapshotHelper.swift
6 | - ios-app/Tivi/Pods
7 |
8 | strict: true
9 |
10 | disabled_rules:
11 | - todo
12 |
--------------------------------------------------------------------------------
/.xcode-version:
--------------------------------------------------------------------------------
1 | 15.3
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem 'cocoapods', '~> 1.15'
4 | gem 'fastlane'
5 | gem 'screengrab'
6 |
--------------------------------------------------------------------------------
/android-app/app/benchmark-rules.pro:
--------------------------------------------------------------------------------
1 | -dontobfuscate
2 | -dontwarn com.google.errorprone.annotations.InlineMe
3 |
--------------------------------------------------------------------------------
/android-app/app/proguard-rules-chucker.pro:
--------------------------------------------------------------------------------
1 | # Chucker uses GSON and TypeToken:
2 | # https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#gson-with-full-mode
3 | -keepattributes Signature
4 | -keep class com.google.gson.reflect.TypeToken { *; }
5 | -keep class * extends com.google.gson.reflect.TypeToken
--------------------------------------------------------------------------------
/android-app/app/src/main/res/drawable-anydpi-v26/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android-app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android-app/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/android-app/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/android-app/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/android-app/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/android-app/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/android-app/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/android-app/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/android-app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/android-app/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/android-app/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
11 |
12 |
13 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/android-app/benchmark/src/main/kotlin/app/tivi/benchmark/Utils.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.benchmark
5 |
6 | import android.Manifest
7 | import android.os.Build
8 | import androidx.test.uiautomator.UiDevice
9 |
10 | fun UiDevice.allowNotifications(packageName: String) {
11 | if (Build.VERSION.SDK_INT >= 33) {
12 | executeShellCommand("pm grant $packageName ${Manifest.permission.POST_NOTIFICATIONS}")
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/android-app/common-test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.android")
8 | }
9 |
10 | android {
11 | namespace = "app.tivi.app.test"
12 | }
13 |
14 | dependencies {
15 | implementation(projects.core.base)
16 | api(libs.androidx.uiautomator)
17 | }
18 |
--------------------------------------------------------------------------------
/api/tmdb/src/commonMain/kotlin/app/tivi/tmdb/TmdbInitializer.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tmdb
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import app.tivi.inject.ApplicationCoroutineScope
8 | import app.tivi.util.launchOrThrow
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class TmdbInitializer(
13 | private val tmdbManager: Lazy,
14 | private val scope: ApplicationCoroutineScope,
15 | ) : AppInitializer {
16 | override fun initialize() {
17 | scope.launchOrThrow {
18 | tmdbManager.value.refreshConfiguration()
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/api/tmdb/src/commonMain/kotlin/app/tivi/tmdb/TmdbOAuthInfo.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tmdb
5 |
6 | data class TmdbOAuthInfo(
7 | val apiKey: String,
8 | )
9 |
--------------------------------------------------------------------------------
/art/account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/art/account.png
--------------------------------------------------------------------------------
/art/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/art/banner.png
--------------------------------------------------------------------------------
/art/episode-details.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/art/episode-details.gif
--------------------------------------------------------------------------------
/art/show-details.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/art/show-details.gif
--------------------------------------------------------------------------------
/art/theme-baseline.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/art/theme-baseline.sketch
--------------------------------------------------------------------------------
/art/tivi-art.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/art/tivi-art.sketch
--------------------------------------------------------------------------------
/common/imageloading/src/androidMain/kotlin/app/tivi/common/imageloading/ImageLoadingPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.imageloading
5 |
6 | import android.app.Application
7 | import coil3.PlatformContext
8 | import me.tatarka.inject.annotations.Provides
9 | import okio.FileSystem
10 |
11 | actual interface ImageLoadingPlatformComponent {
12 | @Provides
13 | fun providePlatformContext(application: Application): PlatformContext = application
14 |
15 | @Provides
16 | fun provideFileSystem(): FileSystem = FileSystem.SYSTEM
17 | }
18 |
--------------------------------------------------------------------------------
/common/imageloading/src/iosMain/kotlin/app/tivi/common/imageloading/ImageLoadingPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.imageloading
5 |
6 | import coil3.PlatformContext
7 | import me.tatarka.inject.annotations.Provides
8 | import okio.FileSystem
9 |
10 | actual interface ImageLoadingPlatformComponent {
11 | @Provides
12 | fun providePlatformContext(): PlatformContext = PlatformContext.INSTANCE
13 |
14 | @Provides
15 | fun provideFileSystem(): FileSystem = FileSystem.SYSTEM
16 | }
17 |
--------------------------------------------------------------------------------
/common/imageloading/src/jvmMain/kotlin/app/tivi/common/imageloading/ImageLoadingPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.imageloading
5 |
6 | import coil3.PlatformContext
7 | import me.tatarka.inject.annotations.Provides
8 | import okio.FileSystem
9 |
10 | actual interface ImageLoadingPlatformComponent {
11 | @Provides
12 | fun providePlatformContext(): PlatformContext = PlatformContext.INSTANCE
13 |
14 | @Provides
15 | fun provideFileSystem(): FileSystem = FileSystem.SYSTEM
16 | }
17 |
--------------------------------------------------------------------------------
/common/ui/circuit/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/common/ui/circuit/src/commonMain/kotlin/app/tivi/navigation/LocalNavigator.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.navigation
5 |
6 | import androidx.compose.runtime.staticCompositionLocalOf
7 | import com.slack.circuit.runtime.Navigator
8 |
9 | /**
10 | * Yes, I don't like this either. I'm a bit stuck though due to
11 | * https://github.com/slackhq/circuit/issues/653
12 | */
13 | val LocalNavigator = staticCompositionLocalOf { Navigator.NoOp }
14 |
--------------------------------------------------------------------------------
/common/ui/compose/src/androidMain/kotlin/app/tivi/common/compose/Coil.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.ui.graphics.ImageBitmap
7 | import androidx.compose.ui.graphics.asImageBitmap
8 | import coil3.Image
9 | import coil3.annotation.ExperimentalCoilApi
10 | import coil3.toBitmap
11 |
12 | @OptIn(ExperimentalCoilApi::class)
13 | internal actual fun Image.toComposeImageBitmap(): ImageBitmap = toBitmap().asImageBitmap()
14 |
--------------------------------------------------------------------------------
/common/ui/compose/src/androidMain/kotlin/app/tivi/common/compose/ColorExtractor.android.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import coil3.request.ImageRequest
7 | import coil3.request.allowHardware
8 | import coil3.request.allowRgb565
9 |
10 | internal actual fun ImageRequest.Builder.prepareForColorExtractor(): ImageRequest.Builder {
11 | return allowHardware(false)
12 | .allowRgb565(true)
13 | }
14 |
--------------------------------------------------------------------------------
/common/ui/compose/src/androidMain/kotlin/app/tivi/common/compose/ReportDrawnWhen.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import android.os.Build
7 | import androidx.compose.runtime.Composable
8 |
9 | @Composable
10 | actual fun ReportDrawnWhen(predicate: () -> Boolean) {
11 | // ReportDrawnWhen routinely causes crashes on API < 25:
12 | // https://issuetracker.google.com/issues/260506820
13 | if (Build.VERSION.SDK_INT >= 25) {
14 | androidx.activity.compose.ReportDrawnWhen(predicate)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/common/ui/compose/src/androidMain/kotlin/app/tivi/common/compose/ui/Icon.android.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.ui
5 |
6 | import androidx.compose.material.icons.Icons
7 | import androidx.compose.material.icons.automirrored.filled.ArrowBack
8 | import androidx.compose.ui.graphics.vector.ImageVector
9 |
10 | actual val Icons.AutoMirrored.Filled.ArrowBackForPlatform: ImageVector
11 | get() = ArrowBack
12 |
--------------------------------------------------------------------------------
/common/ui/compose/src/commonMain/kotlin/app/tivi/common/compose/Modifier.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.ui.Modifier
7 |
8 | inline fun Modifier.thenIf(
9 | condition: Boolean,
10 | whenFalse: Modifier.() -> Modifier = { this },
11 | whenTrue: Modifier.() -> Modifier,
12 | ): Modifier = if (condition) whenTrue() else whenFalse()
13 |
--------------------------------------------------------------------------------
/common/ui/compose/src/commonMain/kotlin/app/tivi/common/compose/ReportDrawnWhen.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.runtime.Composable
7 |
8 | @Composable
9 | expect fun ReportDrawnWhen(predicate: () -> Boolean)
10 |
--------------------------------------------------------------------------------
/common/ui/compose/src/commonMain/kotlin/app/tivi/common/compose/TiviPreferenceExtensions.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2020, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.runtime.collectAsState
8 | import app.tivi.settings.Preference
9 |
10 | @Composable
11 | fun Preference.collectAsState() = flow.collectAsState(defaultValue)
12 |
--------------------------------------------------------------------------------
/common/ui/compose/src/commonMain/kotlin/app/tivi/common/compose/WindowSizeClass.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.material3.windowsizeclass.WindowSizeClass
7 | import androidx.compose.runtime.staticCompositionLocalOf
8 |
9 | val LocalWindowSizeClass = staticCompositionLocalOf {
10 | error("No WindowSizeClass available")
11 | }
12 |
--------------------------------------------------------------------------------
/common/ui/compose/src/commonMain/kotlin/app/tivi/common/compose/theme/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2020, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.theme
5 |
6 | import androidx.compose.material3.ColorScheme
7 | import androidx.compose.runtime.Composable
8 |
9 | @Composable
10 | internal expect fun colorScheme(
11 | useDarkColors: Boolean,
12 | useDynamicColors: Boolean,
13 | ): ColorScheme
14 |
--------------------------------------------------------------------------------
/common/ui/compose/src/commonMain/kotlin/app/tivi/common/compose/theme/Shape.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2020, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.theme
5 |
6 | import androidx.compose.foundation.shape.CircleShape
7 | import androidx.compose.material3.Shapes
8 |
9 | val TiviShapes = Shapes(small = CircleShape)
10 |
--------------------------------------------------------------------------------
/common/ui/compose/src/iosMain/kotlin/app/tivi/common/compose/Coil.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.ui.graphics.ImageBitmap
7 | import androidx.compose.ui.graphics.asComposeImageBitmap
8 | import coil3.Image
9 | import coil3.annotation.ExperimentalCoilApi
10 | import coil3.toBitmap
11 |
12 | @OptIn(ExperimentalCoilApi::class)
13 | internal actual fun Image.toComposeImageBitmap(): ImageBitmap = toBitmap().asComposeImageBitmap()
14 |
--------------------------------------------------------------------------------
/common/ui/compose/src/iosMain/kotlin/app/tivi/common/compose/ColorExtractor.ios.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import coil3.request.ImageRequest
7 |
8 | internal actual fun ImageRequest.Builder.prepareForColorExtractor(): ImageRequest.Builder = this
9 |
--------------------------------------------------------------------------------
/common/ui/compose/src/iosMain/kotlin/app/tivi/common/compose/ReportDrawnWhen.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.runtime.Composable
7 |
8 | @Composable
9 | actual fun ReportDrawnWhen(predicate: () -> Boolean) {
10 | }
11 |
--------------------------------------------------------------------------------
/common/ui/compose/src/iosMain/kotlin/app/tivi/common/compose/theme/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.theme
5 |
6 | import androidx.compose.material3.ColorScheme
7 | import androidx.compose.runtime.Composable
8 |
9 | @Composable
10 | internal actual fun colorScheme(
11 | useDarkColors: Boolean,
12 | useDynamicColors: Boolean,
13 | ): ColorScheme = when {
14 | useDarkColors -> TiviDarkColors
15 | else -> TiviLightColors
16 | }
17 |
--------------------------------------------------------------------------------
/common/ui/compose/src/iosMain/kotlin/app/tivi/common/compose/ui/Icon.ios.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.ui
5 |
6 | import androidx.compose.material.icons.Icons
7 | import androidx.compose.ui.graphics.vector.ImageVector
8 |
9 | actual val Icons.AutoMirrored.Filled.ArrowBackForPlatform: ImageVector
10 | get() = ArrowBackIosFixed
11 |
--------------------------------------------------------------------------------
/common/ui/compose/src/jvmMain/kotlin/app/tivi/common/compose/Coil.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.ui.graphics.ImageBitmap
7 | import androidx.compose.ui.graphics.asComposeImageBitmap
8 | import coil3.Image
9 | import coil3.annotation.ExperimentalCoilApi
10 | import coil3.toBitmap
11 |
12 | @OptIn(ExperimentalCoilApi::class)
13 | internal actual fun Image.toComposeImageBitmap(): ImageBitmap = toBitmap().asComposeImageBitmap()
14 |
--------------------------------------------------------------------------------
/common/ui/compose/src/jvmMain/kotlin/app/tivi/common/compose/ColorExtractor.jvm.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import coil3.request.ImageRequest
7 |
8 | internal actual fun ImageRequest.Builder.prepareForColorExtractor(): ImageRequest.Builder = this
9 |
--------------------------------------------------------------------------------
/common/ui/compose/src/jvmMain/kotlin/app/tivi/common/compose/ReportDrawnWhen.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose
5 |
6 | import androidx.compose.runtime.Composable
7 |
8 | @Composable
9 | actual fun ReportDrawnWhen(predicate: () -> Boolean) {
10 | }
11 |
--------------------------------------------------------------------------------
/common/ui/compose/src/jvmMain/kotlin/app/tivi/common/compose/theme/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.theme
5 |
6 | import androidx.compose.material3.ColorScheme
7 | import androidx.compose.runtime.Composable
8 |
9 | @Composable
10 | internal actual fun colorScheme(
11 | useDarkColors: Boolean,
12 | useDynamicColors: Boolean,
13 | ): ColorScheme = when {
14 | useDarkColors -> TiviDarkColors
15 | else -> TiviLightColors
16 | }
17 |
--------------------------------------------------------------------------------
/common/ui/compose/src/jvmMain/kotlin/app/tivi/common/compose/ui/Icon.jvm.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.compose.ui
5 |
6 | import androidx.compose.material.icons.Icons
7 | import androidx.compose.ui.graphics.vector.ImageVector
8 |
9 | actual val Icons.AutoMirrored.Filled.ArrowBackForPlatform: ImageVector
10 | get() = TODO("Not yet implemented")
11 |
--------------------------------------------------------------------------------
/common/ui/resources/src/androidMain/kotlin/app/tivi/util/String.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | actual fun String.fmt(vararg args: Any?): String = format(*args)
7 |
--------------------------------------------------------------------------------
/common/ui/resources/src/commonMain/composeResources/font/dm_sans_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/common/ui/resources/src/commonMain/composeResources/font/dm_sans_bold.ttf
--------------------------------------------------------------------------------
/common/ui/resources/src/commonMain/composeResources/font/dm_sans_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/common/ui/resources/src/commonMain/composeResources/font/dm_sans_medium.ttf
--------------------------------------------------------------------------------
/common/ui/resources/src/commonMain/composeResources/font/dm_sans_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/common/ui/resources/src/commonMain/composeResources/font/dm_sans_regular.ttf
--------------------------------------------------------------------------------
/common/ui/resources/src/commonMain/kotlin/app/tivi/common/ui/resources/Fonts.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.common.ui.resources
5 |
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.text.font.FontFamily
8 | import androidx.compose.ui.text.font.FontWeight
9 | import org.jetbrains.compose.resources.Font
10 |
11 | val DmSansFontFamily: FontFamily
12 | @Composable get() = FontFamily(
13 | Font(Res.font.dm_sans_regular, weight = FontWeight.Normal),
14 | Font(Res.font.dm_sans_medium, weight = FontWeight.Medium),
15 | Font(Res.font.dm_sans_bold, weight = FontWeight.Bold),
16 | )
17 |
--------------------------------------------------------------------------------
/common/ui/resources/src/commonMain/kotlin/app/tivi/util/String.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | expect fun String.fmt(vararg args: Any?): String
7 |
--------------------------------------------------------------------------------
/common/ui/resources/src/jvmMain/kotlin/app/tivi/util/String.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | actual fun String.fmt(vararg args: Any?): String = format(*args)
7 |
--------------------------------------------------------------------------------
/common/ui/screens/src/commonMain/kotlin/app/tivi/screens/Parcelize.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.screens
5 |
6 | @Target(AnnotationTarget.CLASS)
7 | @Retention(AnnotationRetention.BINARY)
8 | annotation class Parcelize
9 |
--------------------------------------------------------------------------------
/compose-stability.conf:
--------------------------------------------------------------------------------
1 | // Consider all Tivi models as stable
2 | app.tivi.data.compoundmodels.*
3 | app.tivi.data.imagemodels.*
4 | app.tivi.data.models.*
5 | app.tivi.data.views.*
6 |
7 | // Consider kotlin collections stable
8 | kotlin.collections.*
9 |
10 | // Consider kotlinx.datetime models stable
11 | kotlinx.datetime.DayOfWeek
12 | kotlinx.datetime.Instant
13 | kotlinx.datetime.LocalDate
14 | kotlinx.datetime.LocalDateTime
15 | kotlinx.datetime.LocalTime
16 | kotlinx.datetime.TimeZone
17 | kotlin.time.Duration
18 |
19 | kotlinx.coroutines.CoroutineScope
20 |
21 | androidx.paging.compose.LazyPagingItems
22 |
23 | coil3.compose.AsyncImagePainter.State
24 |
--------------------------------------------------------------------------------
/core/analytics/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.multiplatform")
8 | }
9 |
10 | kotlin {
11 | sourceSets {
12 | commonMain {
13 | dependencies {
14 | implementation(projects.core.base)
15 | api(projects.core.preferences)
16 | }
17 | }
18 |
19 | androidMain {
20 | dependencies {
21 | implementation(libs.google.firebase.analytics)
22 | implementation(libs.kotlininject.runtime)
23 | }
24 | }
25 | }
26 | }
27 |
28 | android {
29 | namespace = "app.tivi.core.analytics"
30 | }
31 |
--------------------------------------------------------------------------------
/core/analytics/src/androidMain/kotlin/app/tivi/core/analytics/AnalyticsPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.analytics
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface AnalyticsPlatformComponent {
10 | @ApplicationScope
11 | @Provides
12 | fun provideTiviFirebaseAnalytics(bind: TiviFirebaseAnalytics): Analytics = bind
13 | }
14 |
--------------------------------------------------------------------------------
/core/analytics/src/commonMain/kotlin/app/tivi/core/analytics/Analytics.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2021, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.analytics
5 |
6 | import kotlin.experimental.ExperimentalObjCName
7 | import kotlin.native.ObjCName
8 |
9 | @OptIn(ExperimentalObjCName::class)
10 | @ObjCName(swiftName = "TiviAnalytics")
11 | interface Analytics {
12 | fun trackScreenView(
13 | name: String,
14 | arguments: Map? = null,
15 | )
16 |
17 | fun setEnabled(enabled: Boolean)
18 | }
19 |
--------------------------------------------------------------------------------
/core/analytics/src/commonMain/kotlin/app/tivi/core/analytics/AnalyticsComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.analytics
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import me.tatarka.inject.annotations.IntoSet
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | expect interface AnalyticsPlatformComponent
11 |
12 | interface AnalyticsComponent : AnalyticsPlatformComponent {
13 | @Provides
14 | @IntoSet
15 | fun provideAnalyticsInitializer(impl: AnalyticsInitializer): AppInitializer = impl
16 | }
17 |
--------------------------------------------------------------------------------
/core/analytics/src/iosMain/kotlin/app/tivi/core/analytics/AnalyticsPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.analytics
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface AnalyticsPlatformComponent {
10 | @get:Provides
11 | @get:ApplicationScope
12 | val analytics: Analytics
13 | }
14 |
--------------------------------------------------------------------------------
/core/analytics/src/jvmMain/kotlin/app/tivi/core/analytics/AnalyticsPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.analytics
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface AnalyticsPlatformComponent {
10 | @Provides
11 | @ApplicationScope
12 | fun provideAnalytics(): Analytics = object : Analytics {
13 | override fun trackScreenView(name: String, arguments: Map?) = Unit
14 | override fun setEnabled(enabled: Boolean) = Unit
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/core/base/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(libs.kotlin.coroutines.core)
14 | api(libs.kotlininject.runtime)
15 | api(libs.kermit.kermit)
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/animations/Lerp.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.animations
5 |
6 | fun lerp(
7 | startValue: Float,
8 | endValue: Float,
9 | fraction: Float,
10 | ) = startValue + fraction * (endValue - startValue)
11 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/app/ApplicationInfo.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.app
5 |
6 | data class ApplicationInfo(
7 | val packageName: String,
8 | val debugBuild: Boolean,
9 | val flavor: Flavor,
10 | val versionName: String,
11 | val versionCode: Int,
12 | val cachePath: () -> String,
13 | val platform: Platform,
14 | )
15 |
16 | enum class Platform {
17 | IOS,
18 | ANDROID,
19 | DESKTOP,
20 | }
21 |
22 | enum class Flavor {
23 | Qa,
24 | Standard,
25 | }
26 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/appinitializers/AppInitializer.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.appinitializers
5 |
6 | fun interface AppInitializer {
7 | fun initialize()
8 | }
9 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/base/InvokeStatus.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.base
5 |
6 | sealed class InvokeStatus
7 | object InvokeStarted : InvokeStatus()
8 | object InvokeSuccess : InvokeStatus()
9 | data class InvokeError(val throwable: Throwable) : InvokeStatus()
10 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/extensions/Lazy.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.extensions
5 |
6 | @Suppress("NOTHING_TO_INLINE")
7 | inline fun unsafeLazy(noinline initializer: () -> T): Lazy = lazy(LazyThreadSafetyMode.NONE, initializer)
8 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/inject/Scopes.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import kotlinx.coroutines.CoroutineScope
7 | import me.tatarka.inject.annotations.Scope
8 |
9 | @Scope
10 | annotation class ApplicationScope
11 |
12 | @Scope
13 | annotation class ActivityScope
14 |
15 | typealias ApplicationCoroutineScope = CoroutineScope
16 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/util/AppCoroutineDispatchers.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import kotlinx.coroutines.CoroutineDispatcher
7 |
8 | data class AppCoroutineDispatchers(
9 | val io: CoroutineDispatcher,
10 | val databaseWrite: CoroutineDispatcher,
11 | val databaseRead: CoroutineDispatcher,
12 | val computation: CoroutineDispatcher,
13 | val main: CoroutineDispatcher,
14 | )
15 |
--------------------------------------------------------------------------------
/core/base/src/commonMain/kotlin/app/tivi/util/Result.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import kotlinx.coroutines.CancellationException
7 |
8 | inline fun T.cancellableRunCatching(block: T.() -> R): Result {
9 | return try {
10 | Result.success(block())
11 | } catch (ce: CancellationException) {
12 | throw ce
13 | } catch (e: Throwable) {
14 | Result.failure(e)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/core/logging/src/androidMain/kotlin/app/tivi/util/CrashlyticsAndroidInitializer.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import co.touchlab.crashkios.crashlytics.enableCrashlytics
8 | import co.touchlab.kermit.Logger
9 |
10 | internal object CrashlyticsAndroidInitializer : AppInitializer {
11 | override fun initialize() {
12 | enableCrashlytics()
13 |
14 | // Add Crashlytics log writer
15 | Logger.addLogWriter(CrashlyticsLoggerWriter())
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/logging/src/androidMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import me.tatarka.inject.annotations.IntoSet
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | actual interface LoggerPlatformComponent {
11 | @Provides
12 | @IntoSet
13 | fun provideCrashlyticsAndroidInitializer(): AppInitializer = CrashlyticsAndroidInitializer
14 |
15 | @Provides
16 | fun bindSetCrashReportingEnabledAction(): SetCrashReportingEnabledAction {
17 | return AndroidSetCrashReportingEnabledAction
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/core/logging/src/commonMain/kotlin/app/tivi/util/LoggerComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import me.tatarka.inject.annotations.IntoSet
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | expect interface LoggerPlatformComponent
11 |
12 | interface LoggerComponent : LoggerPlatformComponent {
13 | @Provides
14 | @IntoSet
15 | fun provideCrashReportingInitializer(impl: CrashReportingInitializer): AppInitializer = impl
16 |
17 | @Provides
18 | @IntoSet
19 | fun provideKermitInitializer(impl: KermitInitializer): AppInitializer = impl
20 | }
21 |
--------------------------------------------------------------------------------
/core/logging/src/commonMain/kotlin/app/tivi/util/SetCrashReportingEnabledAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | fun interface SetCrashReportingEnabledAction {
7 | operator fun invoke(enabled: Boolean)
8 | }
9 |
--------------------------------------------------------------------------------
/core/logging/src/iosMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import me.tatarka.inject.annotations.IntoSet
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | actual interface LoggerPlatformComponent {
11 | @get:Provides
12 | val setCrashReportingEnabledAction: SetCrashReportingEnabledAction
13 |
14 | @Provides
15 | @IntoSet
16 | fun provideCrashlyticsIosInitializer(): AppInitializer = CrashlyticsIosInitializer
17 | }
18 |
--------------------------------------------------------------------------------
/core/logging/src/jvmMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import me.tatarka.inject.annotations.Provides
7 |
8 | actual interface LoggerPlatformComponent {
9 | @Provides
10 | fun bindSetCrashReportingEnabledAction(): SetCrashReportingEnabledAction {
11 | return NoopSetCrashReportingEnabledAction
12 | }
13 | }
14 |
15 | private object NoopSetCrashReportingEnabledAction : SetCrashReportingEnabledAction {
16 | override fun invoke(enabled: Boolean) {}
17 | }
18 |
--------------------------------------------------------------------------------
/core/notifications/core/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/core/notifications/core/src/androidMain/kotlin/app/tivi/core/notifications/NotificationPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.notifications
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface NotificationPlatformComponent {
10 |
11 | @Provides
12 | @ApplicationScope
13 | fun provideNotificationManager(impl: AndroidNotificationManager): NotificationManager = impl
14 | }
15 |
--------------------------------------------------------------------------------
/core/notifications/core/src/commonMain/kotlin/app/tivi/core/notifications/NotificationsComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.notifications
5 |
6 | expect interface NotificationPlatformComponent
7 |
8 | interface NotificationsComponent : NotificationPlatformComponent
9 |
--------------------------------------------------------------------------------
/core/notifications/core/src/iosMain/kotlin/app/tivi/core/notifications/NotificationPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.notifications
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface NotificationPlatformComponent {
10 |
11 | @Provides
12 | @ApplicationScope
13 | fun provideNotificationManager(impl: IosNotificationManager): NotificationManager = impl
14 | }
15 |
--------------------------------------------------------------------------------
/core/notifications/core/src/jvmMain/kotlin/app/tivi/core/notifications/EmptyNotificationManager.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.notifications
5 |
6 | internal object EmptyNotificationManager : NotificationManager
7 |
--------------------------------------------------------------------------------
/core/notifications/core/src/jvmMain/kotlin/app/tivi/core/notifications/NotificationPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.notifications
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface NotificationPlatformComponent {
10 |
11 | @Provides
12 | @ApplicationScope
13 | fun provideNotificationManager(): NotificationManager = EmptyNotificationManager
14 | }
15 |
--------------------------------------------------------------------------------
/core/notifications/protos/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.multiplatform")
8 | alias(libs.plugins.wire)
9 | }
10 |
11 | kotlin {
12 | sourceSets {
13 | commonMain {
14 | dependencies {
15 | api(projects.core.base)
16 | api(libs.wire.runtime)
17 | }
18 | }
19 | }
20 | }
21 |
22 | wire {
23 | kotlin {}
24 | }
25 |
26 | android {
27 | namespace = "app.tivi.core.notifications.proto"
28 | }
29 |
--------------------------------------------------------------------------------
/core/notifications/protos/src/commonMain/proto/pending.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | import "google/protobuf/timestamp.proto";
4 |
5 | package app.tivi.core.notifications.proto;
6 |
7 | message PendingNotification {
8 | string id = 1;
9 | string title = 2;
10 | string message = 3;
11 | string channel_id = 4;
12 | optional string deeplink_url = 5;
13 | optional google.protobuf.Timestamp date = 6;
14 | }
15 |
16 | message PendingNotifications {
17 | repeated PendingNotification pending = 1;
18 | }
19 |
--------------------------------------------------------------------------------
/core/performance/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.multiplatform")
8 | }
9 |
10 | kotlin {
11 | sourceSets {
12 | commonMain {
13 | dependencies {
14 | implementation(projects.core.base)
15 | implementation(libs.kotlininject.runtime)
16 | }
17 | }
18 |
19 | androidMain {
20 | dependencies {
21 | implementation(libs.google.firebase.perf)
22 | }
23 | }
24 | }
25 | }
26 |
27 | android {
28 | namespace = "app.tivi.core.perf"
29 | }
30 |
--------------------------------------------------------------------------------
/core/performance/src/androidMain/kotlin/app/tivi/core/perf/PerformanceComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.perf
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PerformanceComponent {
10 | @ApplicationScope
11 | @Provides
12 | fun provideTracer(bind: AndroidTracer): Tracer = bind
13 | }
14 |
--------------------------------------------------------------------------------
/core/performance/src/commonMain/kotlin/app/tivi/core/perf/PerformanceComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.perf
5 |
6 | expect interface PerformanceComponent
7 |
--------------------------------------------------------------------------------
/core/performance/src/commonMain/kotlin/app/tivi/core/perf/Tracer.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2021, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.perf
5 |
6 | fun interface Tracer {
7 | fun trace(
8 | name: String,
9 | block: () -> Unit,
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/core/performance/src/iosMain/kotlin/app/tivi/core/perf/PerformanceComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.perf
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PerformanceComponent {
10 | @ApplicationScope
11 | @Provides
12 | fun provideTracer(): Tracer = Tracer { _, block -> block() }
13 | }
14 |
--------------------------------------------------------------------------------
/core/performance/src/jvmMain/kotlin/app/tivi/core/perf/PerformanceComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.perf
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PerformanceComponent {
10 | @ApplicationScope
11 | @Provides
12 | fun provideTracer(): Tracer = Tracer { _, block -> block() }
13 | }
14 |
--------------------------------------------------------------------------------
/core/permissions/src/androidMain/kotlin/app/tivi/core/permissions/PermissionsController.android.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.permissions
5 |
6 | import androidx.activity.ComponentActivity
7 |
8 | fun PermissionsController.bind(activity: ComponentActivity) {
9 | if (this is MokoPermissionControllerWrapper) {
10 | mokoPermissionController.bind(activity)
11 | } else {
12 | error("PermissionsController does not wrap Moko Permissions")
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/core/permissions/src/androidMain/kotlin/app/tivi/core/permissions/PermissionsPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.permissions
5 |
6 | import android.app.Application
7 | import app.tivi.inject.ApplicationScope
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | actual interface PermissionsPlatformComponent {
11 | @Provides
12 | @ApplicationScope
13 | fun providePermissionController(application: Application): PermissionsController {
14 | return MokoPermissionControllerWrapper(
15 | mokoPermissionController = dev.icerock.moko.permissions.PermissionsController(application),
16 | )
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/core/permissions/src/commonMain/kotlin/app/tivi/core/permissions/PermissionsComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.permissions
5 |
6 | expect interface PermissionsPlatformComponent
7 |
8 | interface PermissionsComponent : PermissionsPlatformComponent
9 |
--------------------------------------------------------------------------------
/core/permissions/src/iosMain/kotlin/app/tivi/core/permissions/PermissionsPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.core.permissions
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PermissionsPlatformComponent {
10 | @Provides
11 | @ApplicationScope
12 | fun providePermissionController(): PermissionsController {
13 | return MokoPermissionControllerWrapper(
14 | mokoPermissionController = dev.icerock.moko.permissions.ios.PermissionsController(),
15 | )
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/core/powercontroller/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.multiplatform")
8 | }
9 |
10 | kotlin {
11 | sourceSets {
12 | commonMain {
13 | dependencies {
14 | implementation(projects.core.base)
15 | api(projects.core.preferences)
16 | }
17 | }
18 |
19 | androidMain {
20 | dependencies {
21 | implementation(libs.androidx.core)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
29 | android {
30 | namespace = "app.tivi.core.powercontroller"
31 | }
32 |
--------------------------------------------------------------------------------
/core/powercontroller/src/androidMain/kotlin/app/tivi/util/PowerControllerComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PowerControllerComponent {
10 | @Provides
11 | @ApplicationScope
12 | fun providePowerController(bind: AndroidPowerController): PowerController = bind
13 | }
14 |
--------------------------------------------------------------------------------
/core/powercontroller/src/commonMain/kotlin/app/tivi/util/PowerControllerComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | expect interface PowerControllerComponent
7 |
--------------------------------------------------------------------------------
/core/powercontroller/src/iosMain/kotlin/app/tivi/util/PowerControllerComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PowerControllerComponent {
10 | @Provides
11 | @ApplicationScope
12 | fun providePowerController(bind: DefaultPowerController): PowerController = bind
13 | }
14 |
--------------------------------------------------------------------------------
/core/powercontroller/src/jvmMain/kotlin/app/tivi/util/PowerControllerComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.util
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface PowerControllerComponent {
10 | @Provides
11 | @ApplicationScope
12 | fun providePowerController(bind: DefaultPowerController): PowerController = bind
13 | }
14 |
--------------------------------------------------------------------------------
/core/preferences/src/commonMain/kotlin/app/tivi/settings/Preference.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | import kotlinx.coroutines.flow.Flow
7 |
8 | interface Preference {
9 | val defaultValue: T
10 |
11 | val flow: Flow
12 | suspend fun set(value: T)
13 | suspend fun get(): T
14 | }
15 |
16 | suspend fun Preference.toggle() = set(!get())
17 |
--------------------------------------------------------------------------------
/core/preferences/src/commonMain/kotlin/app/tivi/settings/PreferencesComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | expect interface PreferencesPlatformComponent
10 |
11 | interface PreferencesComponent : PreferencesPlatformComponent {
12 | val preferences: TiviPreferences
13 |
14 | @ApplicationScope
15 | @Provides
16 | fun providePreferences(bind: TiviPreferencesImpl): TiviPreferences = bind
17 | }
18 |
--------------------------------------------------------------------------------
/core/preferences/src/iosMain/kotlin/app/tivi/settings/PreferencesPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import com.russhwolf.settings.NSUserDefaultsSettings
8 | import com.russhwolf.settings.ObservableSettings
9 | import me.tatarka.inject.annotations.Provides
10 | import platform.Foundation.NSUserDefaults
11 |
12 | actual interface PreferencesPlatformComponent {
13 | @ApplicationScope
14 | @Provides
15 | fun provideSettings(delegate: NSUserDefaults): ObservableSettings = NSUserDefaultsSettings(delegate)
16 | }
17 |
--------------------------------------------------------------------------------
/core/preferences/src/jvmMain/kotlin/app/tivi/settings/PreferencesPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import com.russhwolf.settings.ObservableSettings
8 | import com.russhwolf.settings.PreferencesSettings
9 | import java.util.prefs.Preferences
10 | import me.tatarka.inject.annotations.Provides
11 |
12 | actual interface PreferencesPlatformComponent {
13 | @ApplicationScope
14 | @Provides
15 | fun provideSettings(delegate: Preferences): ObservableSettings = PreferencesSettings(delegate)
16 | }
17 |
--------------------------------------------------------------------------------
/data/anticipatedshows/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 |
19 | api(libs.store)
20 | implementation(libs.kotlinx.atomicfu)
21 |
22 | implementation(libs.kotlininject.runtime)
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/data/anticipatedshows/src/commonMain/kotlin/app/tivi/data/anticipatedshows/AnticipatedShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.anticipatedshows
5 |
6 | import me.tatarka.inject.annotations.Provides
7 |
8 | interface AnticipatedShowsBinds {
9 | @Provides
10 | fun provideTraktAnticipatedShowsDataSource(
11 | bind: TraktAnticipatedShowsDataSource,
12 | ): AnticipatedShowsDataSource = bind
13 | }
14 |
--------------------------------------------------------------------------------
/data/anticipatedshows/src/commonMain/kotlin/app/tivi/data/anticipatedshows/AnticipatedShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.anticipatedshows
5 |
6 | import app.tivi.data.models.AnticipatedShowEntry
7 | import app.tivi.data.models.TiviShow
8 |
9 | fun interface AnticipatedShowsDataSource {
10 | suspend operator fun invoke(
11 | page: Int,
12 | pageSize: Int,
13 | ): List>
14 | }
15 |
--------------------------------------------------------------------------------
/data/anticipatedshows/src/commonMain/kotlin/app/tivi/data/anticipatedshows/AnticipatedShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.anticipatedshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.GroupLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class AnticipatedShowsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : GroupLastRequestStore(Request.ANTICIPATED_SHOWS, dao)
15 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/SqlDelightTransactionRunner.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data
5 |
6 | import app.tivi.data.db.DatabaseTransactionRunner
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class SqlDelightTransactionRunner(private val db: Database) : DatabaseTransactionRunner {
11 | override fun invoke(block: () -> T): T {
12 | return db.transactionWithResult {
13 | block()
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/Utils.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data
5 |
6 | internal val Boolean.sqlValue: Long get() = if (this) 1 else 0
7 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/ImageTypeColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import app.tivi.data.models.ImageType
8 |
9 | internal object ImageTypeColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): ImageType {
11 | return ImageType.entries.first { it.storageKey == databaseValue }
12 | }
13 |
14 | override fun encode(value: ImageType): String = value.storageKey
15 | }
16 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/InstantLongColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import kotlinx.datetime.Instant
8 |
9 | internal object InstantLongColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: Long): Instant = Instant.fromEpochMilliseconds(databaseValue)
11 | override fun encode(value: Instant): Long = value.toEpochMilliseconds()
12 | }
13 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/InstantStringColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import kotlinx.datetime.Instant
8 |
9 | internal object InstantStringColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): Instant = Instant.parse(databaseValue)
11 | override fun encode(value: Instant): String = value.toString()
12 | }
13 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/LocalDateColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import kotlinx.datetime.LocalDate
8 |
9 | internal object LocalDateColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): LocalDate = LocalDate.parse(databaseValue)
11 | override fun encode(value: LocalDate): String = value.toString()
12 | }
13 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/LocalDateTimeColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import kotlinx.datetime.LocalDateTime
8 |
9 | internal object LocalDateTimeColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): LocalDateTime = LocalDateTime.parse(databaseValue)
11 | override fun encode(value: LocalDateTime): String = value.toString()
12 | }
13 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/LocalTimeColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import kotlinx.datetime.LocalTime
8 |
9 | internal object LocalTimeColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): LocalTime = LocalTime.parse(databaseValue)
11 | override fun encode(value: LocalTime): String = value.toString()
12 | }
13 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/PendingActionColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import app.tivi.data.models.PendingAction
8 |
9 | internal object PendingActionColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): PendingAction {
11 | return PendingAction.entries.first { it.value == databaseValue }
12 | }
13 |
14 | override fun encode(value: PendingAction): String = value.value
15 | }
16 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/RequestColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import app.tivi.data.models.Request
8 |
9 | internal object RequestColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): Request {
11 | return Request.entries.first { it.tag == databaseValue }
12 | }
13 |
14 | override fun encode(value: Request): String = value.tag
15 | }
16 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/ShowStatusColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import app.tivi.data.models.ShowStatus
8 |
9 | internal object ShowStatusColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): ShowStatus {
11 | return ShowStatus.entries.first { it.storageKey == databaseValue }
12 | }
13 |
14 | override fun encode(value: ShowStatus): String = value.storageKey
15 | }
16 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/columnadaptors/TimeZoneColumnAdapter.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.columnadaptors
5 |
6 | import app.cash.sqldelight.ColumnAdapter
7 | import kotlinx.datetime.TimeZone
8 |
9 | internal object TimeZoneColumnAdapter : ColumnAdapter {
10 | override fun decode(databaseValue: String): TimeZone = TimeZone.of(databaseValue)
11 | override fun encode(value: TimeZone): String = value.id
12 | }
13 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/kotlin/app/tivi/data/daos/SqlDelightEntityDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.Database
7 | import app.tivi.data.models.TiviEntity
8 |
9 | interface SqlDelightEntityDao : EntityDao {
10 | val db: Database
11 |
12 | override fun insert(entities: List) {
13 | db.transaction {
14 | for (entity in entities) {
15 | insert(entity)
16 | }
17 | }
18 | }
19 |
20 | override fun upsert(entities: List) {
21 | db.transaction {
22 | for (entity in entities) {
23 | upsert(entity)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/sqldelight/app/tivi/data/shows_last_watched.sq:
--------------------------------------------------------------------------------
1 | CREATE VIEW `shows_last_watched` AS SELECT
2 | shows.id AS show_id,
3 | s.id AS season_id,
4 | eps.id AS episode_id,
5 | MAX((1000 * s.number) + eps.number) AS last_watched_abs_number
6 | FROM shows
7 | INNER JOIN seasons AS s ON shows.id = s.show_id
8 | INNER JOIN episodes AS eps ON eps.season_id = s.id
9 | INNER JOIN episode_watch_entries AS ew ON ew.episode_id = eps.id
10 | WHERE
11 | s.number != 0
12 | AND s.ignored = 0
13 | GROUP BY shows.id
14 | ORDER BY ew.watched_at DESC;
15 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/sqldelight/app/tivi/data/shows_view_watch_stats.sq:
--------------------------------------------------------------------------------
1 | CREATE VIEW `shows_view_watch_stats` AS
2 | SELECT shows.id AS show_id,
3 | COUNT(*) AS episode_count,
4 | COUNT(ew.watched_at) AS watched_episode_count
5 | FROM shows
6 | INNER JOIN seasons AS s ON shows.id = s.show_id
7 | INNER JOIN episodes AS eps ON eps.season_id = s.id
8 | LEFT JOIN episode_watch_entries AS ew ON ew.episode_id = eps.id
9 | WHERE eps.first_aired IS NOT NULL
10 | AND datetime(eps.first_aired) < datetime('now')
11 | AND s.number != 0
12 | AND s.ignored = 0
13 | GROUP BY shows.id;
14 |
15 | -- queries
16 |
17 | watchStatsForShowId:
18 | SELECT * FROM shows_view_watch_stats
19 | WHERE show_id = :showId;
20 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/sqldelight/migrations/32.sqm:
--------------------------------------------------------------------------------
1 | -- drop FTS table (for existing Room generated DBs)
2 |
3 | DROP TRIGGER IF EXISTS room_fts_content_sync_shows_fts_BEFORE_UPDATE;
4 | DROP TRIGGER IF EXISTS room_fts_content_sync_shows_fts_BEFORE_DELETE;
5 | DROP TRIGGER IF EXISTS room_fts_content_sync_shows_fts_AFTER_UPDATE;
6 | DROP TRIGGER IF EXISTS room_fts_content_sync_shows_fts_AFTER_INSERT;
7 | DROP TABLE IF EXISTS `shows_fts`;
8 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/sqldelight/migrations/33.sqm:
--------------------------------------------------------------------------------
1 |
2 | -- delete duplicate related shows
3 | DELETE FROM `related_shows` WHERE rowid NOT IN (
4 | SELECT MIN(rowid)
5 | FROM related_shows
6 | GROUP BY show_id, other_show_id
7 | );
8 |
9 | -- finally add an index to make sure this doesn't happen in the future
10 | CREATE UNIQUE INDEX IF NOT EXISTS `index_related_shows_unique` ON `related_shows` (`show_id`, `other_show_id`);
11 |
--------------------------------------------------------------------------------
/data/db-sqldelight/src/commonMain/sqldelight/migrations/34.sqm:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS `anticipated_shows` (
2 | `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
3 | `show_id` INTEGER NOT NULL,
4 | `page` INTEGER AS kotlin.Int NOT NULL,
5 | `page_order` INTEGER AS kotlin.Int NOT NULL,
6 | FOREIGN KEY(`show_id`) REFERENCES `shows`(`id`) ON UPDATE CASCADE ON DELETE CASCADE
7 | );
8 |
--------------------------------------------------------------------------------
/data/db/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | implementation(projects.core.base)
14 | api(projects.data.models)
15 | api(libs.paging.common)
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/EntryDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.compoundmodels.EntryWithShow
7 | import app.tivi.data.models.Entry
8 |
9 | /**
10 | * This interface represents a DAO which contains entities which are part of a single collective list.
11 | */
12 | interface EntryDao> : EntityDao {
13 | fun deleteAll()
14 | }
15 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/LastRequestDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.models.LastRequest
7 | import app.tivi.data.models.Request
8 |
9 | interface LastRequestDao : EntityDao {
10 |
11 | fun lastRequest(request: Request, entityId: Long): LastRequest?
12 |
13 | fun requestCount(request: Request, entityId: Long): Int
14 | }
15 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/LibraryShowsDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import androidx.paging.PagingSource
7 | import app.tivi.data.compoundmodels.LibraryShow
8 | import app.tivi.data.models.SortOption
9 |
10 | interface LibraryShowsDao {
11 | fun pagedListLastWatched(
12 | sort: SortOption,
13 | filter: String?,
14 | onlyFollowed: Boolean,
15 | ): PagingSource
16 | }
17 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/PaginatedEntryDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.compoundmodels.EntryWithShow
7 | import app.tivi.data.models.PaginatedEntry
8 |
9 | interface PaginatedEntryDao> : EntryDao {
10 | fun deletePage(page: Int)
11 | fun getLastPage(): Int?
12 | }
13 |
14 | fun > PaginatedEntryDao.updatePage(
15 | page: Int,
16 | entities: List,
17 | ) {
18 | deletePage(page)
19 | upsert(entities)
20 | }
21 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/PairEntryDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.compoundmodels.EntryWithShow
7 | import app.tivi.data.models.MultipleEntry
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | /**
11 | * This interface represents a DAO which contains entities which are part of a collective list for a given show.
12 | */
13 | interface PairEntryDao> : EntityDao {
14 | fun entriesWithShowsObservable(showId: Long): Flow>
15 | fun deleteWithShowId(showId: Long)
16 | }
17 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/RelatedShowsDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.compoundmodels.RelatedShowEntryWithShow
7 | import app.tivi.data.models.RelatedShowEntry
8 | import kotlinx.coroutines.flow.Flow
9 |
10 | interface RelatedShowsDao : PairEntryDao {
11 | fun entriesObservable(showId: Long): Flow>
12 | fun deleteAll()
13 | }
14 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/ShowFtsDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.models.TiviShow
7 |
8 | interface ShowFtsDao {
9 |
10 | fun search(filter: String): List
11 | }
12 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/daos/UserDao.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.daos
5 |
6 | import app.tivi.data.models.TraktUser
7 | import kotlinx.coroutines.flow.Flow
8 |
9 | interface UserDao : EntityDao {
10 |
11 | fun observeMe(): Flow
12 |
13 | fun observeTraktUser(username: String): Flow
14 |
15 | fun getUser(username: String): TraktUser?
16 |
17 | fun getId(username: String): Long?
18 |
19 | fun deleteWithUsername(username: String)
20 |
21 | fun deleteMe()
22 |
23 | fun deleteAll()
24 | }
25 |
--------------------------------------------------------------------------------
/data/db/src/commonMain/kotlin/app/tivi/data/db/DatabaseTransactionRunner.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.db
5 |
6 | interface DatabaseTransactionRunner {
7 | operator fun invoke(block: () -> T): T
8 | }
9 |
--------------------------------------------------------------------------------
/data/episodes/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.core.preferences)
14 | api(projects.data.models)
15 | api(projects.data.traktauth)
16 | implementation(projects.data.db)
17 | implementation(projects.data.legacy) // remove this eventually
18 |
19 | api(projects.api.trakt)
20 | api(projects.api.tmdb)
21 |
22 | implementation(libs.kotlininject.runtime)
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/data/episodes/src/commonMain/kotlin/app/tivi/data/episodes/EpisodeLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.episodes
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class EpisodeLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : EntityLastRequestStore(Request.EPISODE_DETAILS, dao)
15 |
--------------------------------------------------------------------------------
/data/episodes/src/commonMain/kotlin/app/tivi/data/episodes/EpisodeWatchLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.episodes
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class EpisodeWatchLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : EntityLastRequestStore(Request.SHOW_EPISODE_WATCHES, dao)
15 |
--------------------------------------------------------------------------------
/data/episodes/src/commonMain/kotlin/app/tivi/data/episodes/SeasonLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.episodes
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class SeasonLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : EntityLastRequestStore(Request.SEASON_DETAILS, dao)
15 |
--------------------------------------------------------------------------------
/data/episodes/src/commonMain/kotlin/app/tivi/data/episodes/ShowSeasonsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.episodes
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class ShowSeasonsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : EntityLastRequestStore(Request.SHOW_SEASONS, dao)
15 |
--------------------------------------------------------------------------------
/data/followedshows/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | api(projects.data.traktauth)
15 | implementation(projects.data.db)
16 | implementation(projects.data.legacy) // remove this eventually
17 |
18 | api(projects.api.trakt)
19 | api(projects.api.tmdb)
20 |
21 | api(libs.store)
22 | implementation(libs.kotlinx.atomicfu)
23 |
24 | implementation(libs.kotlininject.runtime)
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/data/followedshows/src/commonMain/kotlin/app/tivi/data/followedshows/FollowedShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.followedshows
5 |
6 | import me.tatarka.inject.annotations.Provides
7 |
8 | interface FollowedShowsBinds {
9 | @Provides
10 | fun provideTraktFollowedShowsDataSource(
11 | bind: TraktFollowedShowsDataSource,
12 | ): FollowedShowsDataSource = bind
13 | }
14 |
--------------------------------------------------------------------------------
/data/followedshows/src/commonMain/kotlin/app/tivi/data/followedshows/FollowedShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.followedshows
5 |
6 | import app.moviebase.trakt.model.TraktList
7 | import app.tivi.data.models.FollowedShowEntry
8 | import app.tivi.data.models.TiviShow
9 |
10 | interface FollowedShowsDataSource {
11 | suspend fun getListShows(listId: Int): List>
12 | suspend fun addShowIdsToList(listId: Int, shows: List)
13 | suspend fun removeShowIdsFromList(listId: Int, shows: List)
14 | suspend fun getFollowedListId(): TraktList
15 | }
16 |
--------------------------------------------------------------------------------
/data/followedshows/src/commonMain/kotlin/app/tivi/data/followedshows/FollowedShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.followedshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.GroupLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class FollowedShowsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : GroupLastRequestStore(Request.FOLLOWED_SHOWS, dao)
15 |
--------------------------------------------------------------------------------
/data/legacy/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.core.base)
14 | api(projects.api.trakt)
15 | api(projects.api.tmdb)
16 | api(projects.data.models)
17 | implementation(projects.data.db)
18 |
19 | api(libs.store)
20 |
21 | implementation(libs.kotlininject.runtime)
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/EpisodeIdToTraktIdMapper.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.tivi.data.daos.EpisodesDao
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class EpisodeIdToTraktIdMapper(
11 | private val dao: EpisodesDao,
12 | ) : Mapper {
13 | override fun map(from: Long): Int {
14 | return dao.episodeTraktIdForId(from)
15 | ?: throw IllegalArgumentException("Episode with id $from does not exist")
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/Mapper.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | fun interface Mapper {
7 | fun map(from: F): T
8 | }
9 |
10 | fun interface IndexedMapper {
11 | fun map(index: Int, from: F): T
12 | }
13 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/SeasonIdToTraktIdMapper.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.tivi.data.daos.SeasonsDao
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class SeasonIdToTraktIdMapper(
11 | private val dao: SeasonsDao,
12 | ) : Mapper {
13 | override fun map(from: Long): Int {
14 | return dao.traktIdForId(from)
15 | ?: throw IllegalArgumentException("Trakt Id for season id $from does not exist")
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/ShowIdToTmdbIdMapper.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.tivi.data.daos.TiviShowDao
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class ShowIdToTmdbIdMapper(
11 | private val showDao: TiviShowDao,
12 | ) : Mapper {
13 | override fun map(from: Long) = showDao.getTmdbIdForShowId(from)
14 | }
15 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/ShowIdToTraktIdMapper.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.tivi.data.daos.TiviShowDao
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class ShowIdToTraktIdMapper(
11 | private val showDao: TiviShowDao,
12 | ) : Mapper {
13 | override fun map(from: Long): Int? {
14 | return showDao.getTraktIdForShowId(from)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/ShowIdToTraktOrImdbIdMapper.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.tivi.data.daos.TiviShowDao
7 | import app.tivi.data.db.DatabaseTransactionRunner
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class ShowIdToTraktOrImdbIdMapper(
12 | private val showDao: TiviShowDao,
13 | private val transactionRunner: DatabaseTransactionRunner,
14 | ) : Mapper {
15 | override fun map(from: Long): String? = transactionRunner {
16 | showDao.getTraktIdForShowId(from)?.toString()
17 | ?: showDao.getImdbIdForShowId(from)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TmdbEpisodeDetailToEpisode.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.tmdb.model.TmdbEpisodeDetail
7 | import app.tivi.data.models.Episode
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TmdbEpisodeDetailToEpisode : Mapper {
12 | override fun map(from: TmdbEpisodeDetail): Episode = Episode(
13 | seasonId = 0,
14 | tmdbId = from.id,
15 | title = from.name,
16 | number = from.episodeNumber,
17 | summary = from.overview,
18 | tmdbBackdropPath = from.stillPath,
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TmdbEpisodeToEpisode.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.tmdb.model.TmdbEpisode
7 | import app.tivi.data.models.Episode
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TmdbEpisodeToEpisode : Mapper {
12 | override fun map(from: TmdbEpisode): Episode = Episode(
13 | seasonId = 0,
14 | tmdbId = from.id,
15 | title = from.name,
16 | number = from.episodeNumber,
17 | summary = from.overview,
18 | tmdbBackdropPath = from.stillPath,
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TmdbSeasonToSeason.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.tmdb.model.TmdbSeason
7 | import app.tivi.data.models.Season
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TmdbSeasonToSeason : Mapper {
12 | override fun map(from: TmdbSeason) = Season(
13 | showId = 0,
14 | tmdbId = from.id,
15 | number = from.seasonNumber,
16 | title = from.name,
17 | summary = from.overview,
18 | episodeCount = from.episodeCount,
19 | tmdbPosterPath = from.posterPath,
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TmdbShowToTiviShow.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.tmdb.model.TmdbShow
7 | import app.tivi.data.models.TiviShow
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TmdbShowToTiviShow : Mapper {
12 | override fun map(from: TmdbShow) = TiviShow(
13 | tmdbId = from.id,
14 | title = from.name,
15 | summary = from.overview,
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TraktHistoryEntryToEpisode.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.trakt.model.TraktHistoryItem
7 | import app.tivi.data.models.Episode
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TraktHistoryEntryToEpisode(
12 | private val mapper: TraktEpisodeToEpisode,
13 | ) : Mapper {
14 |
15 | override fun map(from: TraktHistoryItem) = mapper.map(requireNotNull(from.episode))
16 | }
17 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TraktHistoryItemToEpisodeWatchEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.trakt.model.TraktHistoryItem
7 | import app.tivi.data.models.EpisodeWatchEntry
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TraktHistoryItemToEpisodeWatchEntry : Mapper {
12 | override fun map(from: TraktHistoryItem) = EpisodeWatchEntry(
13 | episodeId = 0,
14 | traktId = from.id?.toLong(),
15 | watchedAt = requireNotNull(from.watchedAt),
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TraktListItemToFollowedShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.trakt.model.TraktUserListItem
7 | import app.tivi.data.models.FollowedShowEntry
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TraktListItemToFollowedShowEntry : Mapper {
12 | override fun map(from: TraktUserListItem) = FollowedShowEntry(
13 | showId = 0,
14 | followedAt = from.listedAt,
15 | traktId = from.id,
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TraktListItemToTiviShow.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.trakt.model.TraktUserListItem
7 | import app.tivi.data.models.TiviShow
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TraktListItemToTiviShow(
12 | private val showMapper: TraktShowToTiviShow,
13 | ) : Mapper {
14 | override fun map(from: TraktUserListItem) = showMapper.map(from.show!!)
15 | }
16 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TraktTrendingShowToTiviShow.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.trakt.model.TraktTrendingShow
7 | import app.tivi.data.models.TiviShow
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TraktTrendingShowToTiviShow(
12 | private val showMapper: TraktShowToTiviShow,
13 | ) : Mapper {
14 | override fun map(from: TraktTrendingShow) = showMapper.map(from.show!!)
15 | }
16 |
--------------------------------------------------------------------------------
/data/legacy/src/commonMain/kotlin/app/tivi/data/mappers/TraktTrendingShowToTrendingShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2020, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.mappers
5 |
6 | import app.moviebase.trakt.model.TraktTrendingShow
7 | import app.tivi.data.models.TrendingShowEntry
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class TraktTrendingShowToTrendingShowEntry : Mapper {
12 |
13 | override fun map(from: TraktTrendingShow): TrendingShowEntry {
14 | return TrendingShowEntry(
15 | showId = 0,
16 | watchers = from.watchers ?: 0,
17 | page = 0,
18 | )
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/data/licenses/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.multiplatform")
8 | alias(libs.plugins.kotlin.serialization)
9 | }
10 |
11 | kotlin {
12 | sourceSets {
13 | commonMain {
14 | dependencies {
15 | api(projects.core.base)
16 | implementation(libs.kotlinx.serialization)
17 | }
18 | }
19 | }
20 | }
21 |
22 | android {
23 | namespace = "app.tivi.data.licenses"
24 | }
25 |
--------------------------------------------------------------------------------
/data/licenses/src/androidMain/kotlin/app/tivi/data/licenses/LicenseDataPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses
5 |
6 | import app.tivi.data.licenses.fetcher.AndroidLicensesFetcherImpl
7 | import app.tivi.data.licenses.fetcher.LicensesFetcher
8 | import app.tivi.inject.ApplicationScope
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | actual interface LicenseDataPlatformComponent {
12 |
13 | @ApplicationScope
14 | @Provides
15 | fun bindLicensesFetcher(fetcher: AndroidLicensesFetcherImpl): LicensesFetcher = fetcher
16 | }
17 |
--------------------------------------------------------------------------------
/data/licenses/src/commonMain/kotlin/app/tivi/data/licenses/LicenseDataComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses
5 |
6 | import app.tivi.data.licenses.store.LicensesStore
7 | import app.tivi.data.licenses.store.LicensesStoreImpl
8 | import app.tivi.inject.ApplicationScope
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | expect interface LicenseDataPlatformComponent
12 |
13 | interface LicenseDataComponent : LicenseDataPlatformComponent {
14 | @ApplicationScope
15 | @Provides
16 | fun bindLicensesStore(bind: LicensesStoreImpl): LicensesStore = bind
17 | }
18 |
--------------------------------------------------------------------------------
/data/licenses/src/commonMain/kotlin/app/tivi/data/licenses/LicensesState.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses
5 |
6 | import kotlinx.serialization.Serializable
7 |
8 | @Serializable
9 | data class LicenseItem(
10 | val groupId: String,
11 | val artifactId: String,
12 | val version: String,
13 | val spdxLicenses: List?,
14 | val name: String?,
15 | val scm: Scm?,
16 | )
17 |
18 | @Serializable
19 | data class SpdxLicense(
20 | val identifier: String,
21 | val name: String,
22 | val url: String,
23 | )
24 |
25 | @Serializable
26 | data class Scm(
27 | val url: String,
28 | )
29 |
--------------------------------------------------------------------------------
/data/licenses/src/commonMain/kotlin/app/tivi/data/licenses/fetcher/LicensesFetcher.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses.fetcher
5 |
6 | import app.tivi.data.licenses.LicenseItem
7 |
8 | interface LicensesFetcher {
9 | suspend operator fun invoke(): List
10 | }
11 |
--------------------------------------------------------------------------------
/data/licenses/src/commonMain/kotlin/app/tivi/data/licenses/store/LicensesStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses.store
5 |
6 | import app.tivi.data.licenses.LicenseItem
7 |
8 | interface LicensesStore {
9 | suspend fun getLicenses(): List
10 | }
11 |
--------------------------------------------------------------------------------
/data/licenses/src/iosMain/kotlin/app/tivi/data/licenses/LicenseDataPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses
5 |
6 | import app.tivi.data.licenses.fetcher.IosLicensesFetcherImpl
7 | import app.tivi.data.licenses.fetcher.LicensesFetcher
8 | import app.tivi.inject.ApplicationScope
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | actual interface LicenseDataPlatformComponent {
12 |
13 | @ApplicationScope
14 | @Provides
15 | fun bindLicensesFetcher(fetcher: IosLicensesFetcherImpl): LicensesFetcher = fetcher
16 | }
17 |
--------------------------------------------------------------------------------
/data/licenses/src/jvmMain/kotlin/app/tivi/data/licenses/LicenseDataPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses
5 |
6 | import app.tivi.data.licenses.fetcher.JvmLicensesFetcherImpl
7 | import app.tivi.data.licenses.fetcher.LicensesFetcher
8 | import app.tivi.inject.ApplicationScope
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | actual interface LicenseDataPlatformComponent {
12 |
13 | @ApplicationScope
14 | @Provides
15 | fun bindLicensesFetcher(fetcher: JvmLicensesFetcherImpl): LicensesFetcher = fetcher
16 | }
17 |
--------------------------------------------------------------------------------
/data/licenses/src/jvmMain/kotlin/app/tivi/data/licenses/fetcher/JvmLicensesFetcherImpl.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.licenses.fetcher
5 |
6 | import app.tivi.data.licenses.LicenseItem
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class JvmLicensesFetcherImpl : LicensesFetcher {
11 | override suspend fun invoke(): List {
12 | return emptyList()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/data/models/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.core.base)
14 | api(libs.kotlinx.datetime)
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/compoundmodels/EpisodeWithSeason.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.compoundmodels
5 |
6 | import app.tivi.data.models.Episode
7 | import app.tivi.data.models.Season
8 |
9 | data class EpisodeWithSeason(
10 | val episode: Episode,
11 | val season: Season,
12 | )
13 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/compoundmodels/LibraryShow.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.compoundmodels
5 |
6 | import app.tivi.data.models.TiviShow
7 | import app.tivi.data.models.WatchedShowEntry
8 | import app.tivi.data.views.ShowsWatchStats
9 |
10 | data class LibraryShow(
11 | val show: TiviShow,
12 | val stats: ShowsWatchStats?,
13 | val watchedEntry: WatchedShowEntry?,
14 | )
15 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/compoundmodels/SeasonWithEpisodes.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.compoundmodels
5 |
6 | import app.tivi.data.models.Episode
7 | import app.tivi.data.models.Season
8 |
9 | data class SeasonWithEpisodes(
10 | val season: Season,
11 | val episodes: List = emptyList(),
12 | )
13 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/compoundmodels/SeasonWithShow.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.compoundmodels
5 |
6 | import app.tivi.data.models.Season
7 | import app.tivi.data.models.TiviShow
8 |
9 | data class SeasonWithShow(
10 | val season: Season,
11 | val show: TiviShow,
12 | )
13 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/compoundmodels/ShowSeasonEpisode.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.compoundmodels
5 |
6 | import app.tivi.data.models.Episode
7 | import app.tivi.data.models.Season
8 | import app.tivi.data.models.TiviShow
9 |
10 | data class ShowSeasonEpisode(
11 | val show: TiviShow,
12 | val season: Season,
13 | val episode: Episode,
14 | )
15 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/compoundmodels/UpNextEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.compoundmodels
5 |
6 | import app.tivi.data.models.Episode
7 | import app.tivi.data.models.Season
8 | import app.tivi.data.models.TiviShow
9 |
10 | data class UpNextEntry(
11 | val show: TiviShow,
12 | val season: Season,
13 | val episode: Episode,
14 | )
15 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/imagemodels/EpisodeImageModel.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.imagemodels
5 |
6 | import app.tivi.data.models.Episode
7 |
8 | data class EpisodeImageModel(val id: Long) : ImageModel
9 |
10 | fun Episode.asImageModel(): EpisodeImageModel = EpisodeImageModel(id = id)
11 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/imagemodels/ImageModel.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.imagemodels
5 |
6 | interface ImageModel
7 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/imagemodels/SeasonImageModel.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.imagemodels
5 |
6 | import app.tivi.data.models.Season
7 |
8 | data class SeasonImageModel(val id: Long) : ImageModel
9 |
10 | fun Season.asImageModel(): SeasonImageModel = SeasonImageModel(id = id)
11 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/imagemodels/ShowImageModel.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.imagemodels
5 |
6 | import app.tivi.data.models.ImageType
7 | import app.tivi.data.models.TiviShow
8 |
9 | data class ShowImageModel(
10 | val id: Long,
11 | val imageType: ImageType = ImageType.BACKDROP,
12 | ) : ImageModel
13 |
14 | fun TiviShow.asImageModel(
15 | imageType: ImageType,
16 | ): ShowImageModel = ShowImageModel(id = id, imageType = imageType)
17 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/ActionDate.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | enum class ActionDate {
7 | NOW,
8 | AIR_DATE,
9 | }
10 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/AnticipatedShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | data class AnticipatedShowEntry(
7 | override val id: Long = 0,
8 | override val showId: Long,
9 | override val page: Int,
10 | val pageOrder: Int,
11 | ) : PaginatedEntry
12 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/Entry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | interface Entry : TiviEntity {
7 | val showId: Long
8 | }
9 |
10 | interface MultipleEntry : Entry {
11 | val otherShowId: Long
12 | }
13 |
14 | interface PaginatedEntry : Entry {
15 | val page: Int
16 | }
17 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/EpisodeWatchEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | import kotlinx.datetime.Instant
7 |
8 | data class EpisodeWatchEntry(
9 | override val id: Long = 0,
10 | val episodeId: Long,
11 | val traktId: Long? = null,
12 | val watchedAt: Instant,
13 | val pendingAction: PendingAction = PendingAction.NOTHING,
14 | ) : TiviEntity
15 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/FollowedShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | import kotlinx.datetime.Instant
7 |
8 | data class FollowedShowEntry(
9 | override val id: Long = 0,
10 | override val showId: Long,
11 | val followedAt: Instant? = null,
12 | val pendingAction: PendingAction = PendingAction.NOTHING,
13 | val traktId: Long? = null,
14 | ) : Entry
15 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/PendingAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | enum class PendingAction(val value: String) {
7 | NOTHING("nothing"),
8 | UPLOAD("upload"),
9 | DELETE("delete"),
10 | }
11 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/PopularShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | data class PopularShowEntry(
7 | override val id: Long = 0,
8 | override val showId: Long,
9 | override val page: Int,
10 | val pageOrder: Int,
11 | ) : PaginatedEntry
12 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/RecommendedShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | data class RecommendedShowEntry(
7 | override val id: Long = 0,
8 | override val showId: Long,
9 | override val page: Int,
10 | ) : PaginatedEntry
11 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/RelatedShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | data class RelatedShowEntry(
7 | override val id: Long = 0,
8 | override val showId: Long,
9 | override val otherShowId: Long,
10 | val orderIndex: Int,
11 | ) : MultipleEntry
12 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/ShowStatus.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | enum class ShowStatus(val storageKey: String) {
7 | ENDED("ended"),
8 | RETURNING("returning"),
9 | CANCELED("canceled"),
10 | IN_PRODUCTION("inproduction"),
11 | PLANNED("planned"),
12 | }
13 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/ShowTmdbImage.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | data class ShowTmdbImage(
7 | override val id: Long = 0,
8 | val showId: Long,
9 | override val path: String,
10 | override val type: ImageType,
11 | override val language: String? = null,
12 | override val rating: Float = 0f,
13 | override val isPrimary: Boolean = false,
14 | ) : TiviEntity,
15 | TmdbImageEntity
16 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/SortOption.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | enum class SortOption(val sqlValue: String) {
7 | LAST_WATCHED("last_watched"),
8 | AIR_DATE("recently_aired"),
9 | ALPHABETICAL("alpha"),
10 | DATE_ADDED("added"),
11 | }
12 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/TiviEntity.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | interface TiviEntity {
7 | val id: Long
8 | }
9 |
10 | interface TraktIdEntity {
11 | val traktId: Int?
12 | }
13 |
14 | interface TmdbIdEntity {
15 | val tmdbId: Int?
16 | }
17 |
18 | interface TmdbImageEntity : TiviEntity {
19 | val path: String
20 | val type: ImageType
21 | val language: String?
22 | val rating: Float
23 | val isPrimary: Boolean
24 | }
25 |
26 | enum class ImageType(val storageKey: String) {
27 | BACKDROP("backdrop"),
28 | POSTER("poster"),
29 | LOGO("logo"),
30 | }
31 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/TraktUser.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | import kotlinx.datetime.Instant
7 |
8 | data class TraktUser(
9 | override val id: Long = 0,
10 | val username: String,
11 | val name: String? = null,
12 | val joined: Instant? = null,
13 | val location: String? = null,
14 | val about: String? = null,
15 | val avatarUrl: String? = null,
16 | val vip: Boolean? = null,
17 | val isMe: Boolean = false,
18 | ) : TiviEntity
19 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/TrendingShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | data class TrendingShowEntry(
7 | override val id: Long = 0,
8 | override val showId: Long,
9 | override val page: Int,
10 | val watchers: Int,
11 | ) : PaginatedEntry
12 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/models/WatchedShowEntry.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.models
5 |
6 | import kotlinx.datetime.Instant
7 |
8 | data class WatchedShowEntry(
9 | override val id: Long = 0,
10 | override val showId: Long,
11 | val lastWatched: Instant,
12 | val lastUpdated: Instant,
13 | ) : Entry
14 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/util/DateTimeUtils.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.util
5 |
6 | import kotlin.time.Duration
7 | import kotlinx.datetime.Clock
8 | import kotlinx.datetime.Instant
9 |
10 | inline val Duration.inPast: Instant
11 | get() = Clock.System.now() - this
12 |
13 | fun Instant.durationSinceNow(): Duration = Clock.System.now() - this
14 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/util/ImageEntityUtils.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.util
5 |
6 | import app.tivi.data.models.ImageType
7 | import app.tivi.data.models.TmdbImageEntity
8 |
9 | internal fun findHighestRatedItem(items: Collection, type: ImageType): T? {
10 | if (items.size <= 1) {
11 | return items.firstOrNull()
12 | }
13 | return items.asSequence()
14 | .filter { it.type == type }
15 | .maxByOrNull { it.rating + (if (it.isPrimary) 10f else 0f) }
16 | }
17 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/views/ShowsNextToWatch.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.views
5 |
6 | data class ShowsNextToWatch(
7 | val showId: Long,
8 | val seasonId: Long,
9 | val episodeId: Long,
10 | )
11 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/app/tivi/data/views/ShowsWatchStats.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.views
5 |
6 | data class ShowsWatchStats(
7 | val showId: Long,
8 | val episodeCount: Int,
9 | val watchedEpisodeCount: Int,
10 | )
11 |
12 | /**
13 | * Only exists to make it easier to map from SqlDelight
14 | */
15 | fun ShowsWatchStats(
16 | showId: Long,
17 | episodeCount: Long,
18 | watchedEpisodeCount: Long,
19 | ): ShowsWatchStats = ShowsWatchStats(showId, episodeCount.toInt(), watchedEpisodeCount.toInt())
20 |
--------------------------------------------------------------------------------
/data/popularshows/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/popularshows/src/commonMain/kotlin/app/tivi/data/popularshows/PopularShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.popularshows
5 |
6 | import me.tatarka.inject.annotations.Provides
7 |
8 | interface PopularShowsBinds {
9 | @Provides
10 | fun provideTraktPopularShowsDataSource(
11 | bind: TraktPopularShowsDataSource,
12 | ): PopularShowsDataSource = bind
13 | }
14 |
--------------------------------------------------------------------------------
/data/popularshows/src/commonMain/kotlin/app/tivi/data/popularshows/PopularShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.popularshows
5 |
6 | import app.tivi.data.models.PopularShowEntry
7 | import app.tivi.data.models.TiviShow
8 |
9 | fun interface PopularShowsDataSource {
10 | suspend operator fun invoke(
11 | page: Int,
12 | pageSize: Int,
13 | ): List>
14 | }
15 |
--------------------------------------------------------------------------------
/data/popularshows/src/commonMain/kotlin/app/tivi/data/popularshows/PopularShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.popularshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.GroupLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class PopularShowsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : GroupLastRequestStore(Request.POPULAR_SHOWS, dao)
15 |
--------------------------------------------------------------------------------
/data/recommendedshows/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/recommendedshows/src/commonMain/kotlin/app/tivi/data/recommendedshows/RecommendedShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.recommendedshows
5 |
6 | import me.tatarka.inject.annotations.Provides
7 |
8 | interface RecommendedShowsBinds {
9 | @Provides
10 | fun provideTraktRecommendedShowsDataSource(
11 | bind: TraktRecommendedShowsDataSource,
12 | ): RecommendedShowsDataSource = bind
13 | }
14 |
--------------------------------------------------------------------------------
/data/recommendedshows/src/commonMain/kotlin/app/tivi/data/recommendedshows/RecommendedShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.recommendedshows
5 |
6 | import app.tivi.data.models.TiviShow
7 |
8 | interface RecommendedShowsDataSource {
9 | suspend operator fun invoke(page: Int, pageSize: Int): List
10 | }
11 |
--------------------------------------------------------------------------------
/data/recommendedshows/src/commonMain/kotlin/app/tivi/data/recommendedshows/RecommendedShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.recommendedshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.GroupLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class RecommendedShowsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : GroupLastRequestStore(Request.RECOMMENDED_SHOWS, dao)
15 |
--------------------------------------------------------------------------------
/data/relatedshows/src/commonMain/kotlin/app/tivi/data/relatedshows/RelatedShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.relatedshows
5 |
6 | import app.tivi.data.models.RelatedShowEntry
7 | import app.tivi.data.models.TiviShow
8 |
9 | fun interface RelatedShowsDataSource {
10 | suspend operator fun invoke(
11 | showId: Long,
12 | ): List>
13 | }
14 |
--------------------------------------------------------------------------------
/data/relatedshows/src/commonMain/kotlin/app/tivi/data/relatedshows/RelatedShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.relatedshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class RelatedShowsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : EntityLastRequestStore(Request.RELATED_SHOWS, dao)
15 |
--------------------------------------------------------------------------------
/data/search/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/search/src/commonMain/kotlin/app/tivi/data/search/SearchBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.search
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface SearchBinds {
10 | val TmdbSearchDataSource.bind: SearchDataSource
11 | @ApplicationScope @Provides
12 | get() = this
13 | }
14 |
--------------------------------------------------------------------------------
/data/search/src/commonMain/kotlin/app/tivi/data/search/SearchDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.search
5 |
6 | import app.tivi.data.models.ShowTmdbImage
7 | import app.tivi.data.models.TiviShow
8 |
9 | interface SearchDataSource {
10 | suspend fun search(query: String): List>>
11 | }
12 |
--------------------------------------------------------------------------------
/data/showimages/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/showimages/src/commonMain/kotlin/app/tivi/data/showimages/ShowImagesBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.showimages
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface ShowImagesBinds {
10 | @ApplicationScope
11 | @Provides
12 | fun bindShowImagesDataSource(bind: TmdbShowImagesDataSource): ShowImagesDataSource = bind
13 | }
14 |
--------------------------------------------------------------------------------
/data/showimages/src/commonMain/kotlin/app/tivi/data/showimages/ShowImagesDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.showimages
5 |
6 | import app.tivi.data.models.ShowTmdbImage
7 | import app.tivi.data.models.TiviShow
8 |
9 | interface ShowImagesDataSource {
10 | suspend fun getShowImages(show: TiviShow): List
11 | }
12 |
--------------------------------------------------------------------------------
/data/showimages/src/commonMain/kotlin/app/tivi/data/showimages/ShowImagesLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.showimages
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import app.tivi.inject.ApplicationScope
10 | import me.tatarka.inject.annotations.Inject
11 |
12 | @ApplicationScope
13 | @Inject
14 | class ShowImagesLastRequestStore(
15 | dao: LastRequestDao,
16 | ) : EntityLastRequestStore(Request.SHOW_IMAGES, dao)
17 |
--------------------------------------------------------------------------------
/data/shows/src/commonMain/kotlin/app/tivi/data/shows/ShowDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.shows
5 |
6 | import app.tivi.data.models.TiviShow
7 |
8 | interface ShowDataSource {
9 | suspend fun getShow(show: TiviShow): TiviShow
10 | }
11 |
--------------------------------------------------------------------------------
/data/shows/src/commonMain/kotlin/app/tivi/data/shows/ShowLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.shows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import app.tivi.inject.ApplicationScope
10 | import me.tatarka.inject.annotations.Inject
11 |
12 | @ApplicationScope
13 | @Inject
14 | class ShowLastRequestStore(
15 | dao: LastRequestDao,
16 | ) : EntityLastRequestStore(Request.SHOW_DETAILS, dao)
17 |
--------------------------------------------------------------------------------
/data/shows/src/commonMain/kotlin/app/tivi/data/shows/ShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.shows
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface ShowsBinds {
10 | @ApplicationScope
11 | @Provides
12 | fun bindTraktShowDataSource(bind: TraktShowDataSourceImpl): TraktShowDataSource = bind
13 |
14 | @ApplicationScope
15 | @Provides
16 | fun bindTmdbShowDataSource(bind: TmdbShowDataSourceImpl): TmdbShowDataSource = bind
17 | }
18 |
19 | typealias TmdbShowDataSource = ShowDataSource
20 | typealias TraktShowDataSource = ShowDataSource
21 |
--------------------------------------------------------------------------------
/data/test/src/androidUnitTest/kotlin/app/tivi/data/DatabaseTest.kt:
--------------------------------------------------------------------------------
1 | package app.tivi.data
2 |
3 | import app.cash.sqldelight.db.SqlDriver
4 | import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
5 |
6 | internal actual fun createTestSqlDriver(name: String): SqlDriver {
7 | return JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY).also { db ->
8 | Database.Schema.create(db)
9 | db.execute(null, "PRAGMA foreign_keys=ON", 0)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/data/test/src/commonTest/kotlin/app/tivi/utils/Dispatchers.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.utils
5 |
6 | import app.tivi.util.AppCoroutineDispatchers
7 | import kotlinx.coroutines.CoroutineDispatcher
8 | import kotlinx.coroutines.test.StandardTestDispatcher
9 |
10 | fun createSingleAppCoroutineDispatchers(
11 | testDispatcher: CoroutineDispatcher = StandardTestDispatcher(),
12 | ): AppCoroutineDispatchers = AppCoroutineDispatchers(
13 | io = testDispatcher,
14 | databaseRead = testDispatcher,
15 | databaseWrite = testDispatcher,
16 | computation = testDispatcher,
17 | main = testDispatcher,
18 | )
19 |
--------------------------------------------------------------------------------
/data/test/src/commonTest/kotlin/app/tivi/utils/FakeEpisodeDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.utils
5 |
6 | import app.tivi.data.episodes.TraktEpisodeDataSource
7 | import app.tivi.data.models.Episode
8 |
9 | class FakeEpisodeDataSource : TraktEpisodeDataSource {
10 | var result = Result.success(Episode.EMPTY)
11 |
12 | override suspend fun getEpisode(showId: Long, seasonNumber: Int, episodeNumber: Int): Episode {
13 | return result.getOrThrow()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/data/test/src/commonTest/kotlin/app/tivi/utils/Fakes.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.utils
5 |
6 | import app.tivi.data.traktauth.AuthState
7 | import app.tivi.data.traktauth.TraktLoginAction
8 | import app.tivi.data.traktauth.TraktRefreshTokenAction
9 |
10 | object SuccessTraktLoginAction : TraktLoginAction {
11 | override suspend fun invoke(): AuthState = AuthorizedAuthState
12 | }
13 |
14 | object SuccessRefreshTokenAction : TraktRefreshTokenAction {
15 | override suspend fun invoke(state: AuthState): AuthState = AuthorizedAuthState
16 | }
17 |
--------------------------------------------------------------------------------
/data/test/src/commonTest/kotlin/app/tivi/utils/TestTransactionRunner.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.utils
5 |
6 | import app.tivi.data.db.DatabaseTransactionRunner
7 |
8 | internal object TestTransactionRunner : DatabaseTransactionRunner {
9 | override fun invoke(block: () -> T): T = block()
10 | }
11 |
--------------------------------------------------------------------------------
/data/test/src/jvmTest/kotlin/app/tivi/data/DatabaseTest.kt:
--------------------------------------------------------------------------------
1 | package app.tivi.data
2 |
3 | import app.cash.sqldelight.db.SqlDriver
4 | import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
5 |
6 | internal actual fun createTestSqlDriver(name: String): SqlDriver {
7 | return JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY).also { db ->
8 | Database.Schema.create(db)
9 | db.execute(null, "PRAGMA foreign_keys=ON", 0)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/data/test/src/nativeTest/kotlin/app/tivi/data/DatabaseTest.kt:
--------------------------------------------------------------------------------
1 | package app.tivi.data
2 |
3 | import app.cash.sqldelight.db.SqlDriver
4 | import app.cash.sqldelight.driver.native.inMemoryDriver
5 |
6 | internal actual fun createTestSqlDriver(name: String): SqlDriver {
7 | return inMemoryDriver(Database.Schema, name).also { driver ->
8 | driver.execute(null, "PRAGMA foreign_keys=ON", 0)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/data/traktauth/src/androidMain/kotlin/app/tivi/data/traktauth/TraktAuthInitializer.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class TraktAuthInitializer(
11 | private val traktLoginAction: Lazy,
12 | ) : AppInitializer {
13 | override fun initialize() {
14 | traktLoginAction.value.registerActivityWatcher()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/data/traktauth/src/commonMain/kotlin/app/tivi/data/traktauth/TraktAuthComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | expect interface TraktAuthComponent
7 |
--------------------------------------------------------------------------------
/data/traktauth/src/commonMain/kotlin/app/tivi/data/traktauth/TraktAuthState.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | enum class TraktAuthState {
7 | LOGGED_IN,
8 | LOGGED_OUT,
9 | }
10 |
--------------------------------------------------------------------------------
/data/traktauth/src/commonMain/kotlin/app/tivi/data/traktauth/TraktLoginAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | interface TraktLoginAction {
7 | suspend operator fun invoke(): AuthState?
8 | }
9 |
--------------------------------------------------------------------------------
/data/traktauth/src/commonMain/kotlin/app/tivi/data/traktauth/TraktOAuthInfo.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | data class TraktOAuthInfo(
7 | val clientId: String,
8 | val clientSecret: String,
9 | val redirectUri: String,
10 | )
11 |
--------------------------------------------------------------------------------
/data/traktauth/src/commonMain/kotlin/app/tivi/data/traktauth/TraktRefreshTokenAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | interface TraktRefreshTokenAction {
7 | suspend operator fun invoke(state: AuthState): AuthState?
8 | }
9 |
--------------------------------------------------------------------------------
/data/traktauth/src/commonMain/kotlin/app/tivi/data/traktauth/store/AuthStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth.store
5 |
6 | import app.tivi.data.traktauth.AuthState
7 |
8 | interface AuthStore {
9 | suspend fun get(): AuthState?
10 | suspend fun save(state: AuthState)
11 | suspend fun clear()
12 | suspend fun isAvailable(): Boolean = true
13 | }
14 |
--------------------------------------------------------------------------------
/data/traktauth/src/jvmMain/kotlin/app/tivi/data/traktauth/DesktopAuthStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | import app.tivi.data.traktauth.store.AuthStore
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class DesktopAuthStore : AuthStore {
11 | override suspend fun get(): AuthState? {
12 | // TODO no-op for now
13 | return null
14 | }
15 |
16 | override suspend fun save(state: AuthState) {
17 | // TODO no-op for now
18 | }
19 |
20 | override suspend fun clear() {
21 | // TODO no-op for now
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/data/traktauth/src/jvmMain/kotlin/app/tivi/data/traktauth/DesktopTraktLoginAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | import me.tatarka.inject.annotations.Inject
7 |
8 | @Inject
9 | class DesktopTraktLoginAction : TraktLoginAction {
10 | override suspend operator fun invoke(): AuthState? {
11 | return null
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/data/traktauth/src/jvmMain/kotlin/app/tivi/data/traktauth/DesktopTraktRefreshTokenAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktauth
5 |
6 | import me.tatarka.inject.annotations.Inject
7 |
8 | @Inject
9 | class DesktopTraktRefreshTokenAction : TraktRefreshTokenAction {
10 | override suspend fun invoke(state: AuthState): AuthState? {
11 | // TODO
12 | return null
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/data/traktusers/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/traktusers/src/commonMain/kotlin/app/tivi/data/traktusers/TraktUsersBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktusers
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface TraktUsersBinds {
10 | @ApplicationScope
11 | @Provides
12 | fun provideTraktUsersDataSource(bind: TraktUsersDataSource): UsersDataSource = bind
13 | }
14 |
--------------------------------------------------------------------------------
/data/traktusers/src/commonMain/kotlin/app/tivi/data/traktusers/TraktUsersLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktusers
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.EntityLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class TraktUsersLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : EntityLastRequestStore(Request.USER_PROFILE, dao)
15 |
--------------------------------------------------------------------------------
/data/traktusers/src/commonMain/kotlin/app/tivi/data/traktusers/UsersDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.traktusers
5 |
6 | import app.tivi.data.models.TraktUser
7 |
8 | fun interface UsersDataSource {
9 | suspend fun getUser(slug: String): TraktUser
10 | }
11 |
--------------------------------------------------------------------------------
/data/trendingshows/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/trendingshows/src/commonMain/kotlin/app/tivi/data/trendingshows/TrendingShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.trendingshows
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface TrendingShowsBinds {
10 | @Provides
11 | @ApplicationScope
12 | fun provideTraktTrendingShowsDataSource(
13 | bind: TraktTrendingShowsDataSource,
14 | ): TrendingShowsDataSource = bind
15 | }
16 |
--------------------------------------------------------------------------------
/data/trendingshows/src/commonMain/kotlin/app/tivi/data/trendingshows/TrendingShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.trendingshows
5 |
6 | import app.tivi.data.models.TiviShow
7 | import app.tivi.data.models.TrendingShowEntry
8 |
9 | fun interface TrendingShowsDataSource {
10 | suspend operator fun invoke(
11 | page: Int,
12 | pageSize: Int,
13 | ): List>
14 | }
15 |
--------------------------------------------------------------------------------
/data/trendingshows/src/commonMain/kotlin/app/tivi/data/trendingshows/TrendingShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.trendingshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.GroupLastRequestStore
8 | import app.tivi.data.models.Request
9 | import app.tivi.inject.ApplicationScope
10 | import me.tatarka.inject.annotations.Inject
11 |
12 | @ApplicationScope
13 | @Inject
14 | class TrendingShowsLastRequestStore(
15 | dao: LastRequestDao,
16 | ) : GroupLastRequestStore(Request.TRENDING_SHOWS, dao)
17 |
--------------------------------------------------------------------------------
/data/watchedshows/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.kotlin.multiplatform")
7 | }
8 |
9 | kotlin {
10 | sourceSets {
11 | commonMain {
12 | dependencies {
13 | api(projects.data.models)
14 | implementation(projects.data.db)
15 | implementation(projects.data.legacy) // remove this eventually
16 |
17 | implementation(projects.api.trakt)
18 | implementation(projects.api.tmdb)
19 |
20 | api(libs.store)
21 | implementation(libs.kotlinx.atomicfu)
22 |
23 | implementation(libs.kotlininject.runtime)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/data/watchedshows/src/commonMain/kotlin/app/tivi/data/watchedshows/WatchedShowsBinds.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.watchedshows
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface WatchedShowsBinds {
10 | @Provides
11 | @ApplicationScope
12 | fun provideTraktWatchedShowsDataSource(
13 | bind: TraktWatchedShowsDataSource,
14 | ): WatchedShowsDataSource = bind
15 | }
16 |
--------------------------------------------------------------------------------
/data/watchedshows/src/commonMain/kotlin/app/tivi/data/watchedshows/WatchedShowsDataSource.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.watchedshows
5 |
6 | import app.tivi.data.models.TiviShow
7 | import app.tivi.data.models.WatchedShowEntry
8 |
9 | fun interface WatchedShowsDataSource {
10 | suspend operator fun invoke(): List>
11 | }
12 |
--------------------------------------------------------------------------------
/data/watchedshows/src/commonMain/kotlin/app/tivi/data/watchedshows/WatchedShowsLastRequestStore.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.data.watchedshows
5 |
6 | import app.tivi.data.daos.LastRequestDao
7 | import app.tivi.data.lastrequests.GroupLastRequestStore
8 | import app.tivi.data.models.Request
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class WatchedShowsLastRequestStore(
13 | dao: LastRequestDao,
14 | ) : GroupLastRequestStore(Request.WATCHED_SHOWS, dao)
15 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/domain/src/commonMain/kotlin/app/tivi/domain/interactors/FetchLicensesList.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2019, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.domain.interactors
5 |
6 | import app.tivi.data.licenses.LicenseItem
7 | import app.tivi.data.licenses.store.LicensesStore
8 | import app.tivi.domain.Interactor
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class FetchLicensesList(
13 | licensesStore: Lazy,
14 | ) : Interactor>() {
15 | private val licensesStore by licensesStore
16 |
17 | override suspend fun doWork(params: Unit): List {
18 | return licensesStore.getLicenses()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/domain/src/commonMain/kotlin/app/tivi/domain/interactors/LoginTrakt.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.domain.interactors
5 |
6 | import app.tivi.data.traktauth.AuthState
7 | import app.tivi.data.traktauth.TraktAuthRepository
8 | import app.tivi.domain.Interactor
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class LoginTrakt(
13 | traktAuthRepository: Lazy,
14 | ) : Interactor() {
15 | private val traktAuthRepository by traktAuthRepository
16 |
17 | override suspend fun doWork(params: Unit) = traktAuthRepository.login()
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/commonMain/kotlin/app/tivi/domain/interactors/LogoutTrakt.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.domain.interactors
5 |
6 | import app.tivi.data.traktauth.TraktAuthRepository
7 | import app.tivi.domain.Interactor
8 | import me.tatarka.inject.annotations.Inject
9 |
10 | @Inject
11 | class LogoutTrakt(
12 | private val traktAuthRepository: Lazy,
13 | private val clearUserDetails: Lazy,
14 | ) : Interactor() {
15 | override suspend fun doWork(params: Unit) {
16 | traktAuthRepository.value.logout()
17 | clearUserDetails.value.invoke(ClearUserDetails.Params("me"))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/domain/src/commonMain/kotlin/app/tivi/domain/interactors/RefreshTraktTokens.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.domain.interactors
5 |
6 | import app.tivi.data.traktauth.AuthState
7 | import app.tivi.data.traktauth.TraktAuthRepository
8 | import app.tivi.domain.Interactor
9 | import me.tatarka.inject.annotations.Inject
10 |
11 | @Inject
12 | class RefreshTraktTokens(
13 | traktAuthRepository: Lazy,
14 | ) : Interactor() {
15 | private val traktAuthRepository by traktAuthRepository
16 | override suspend fun doWork(params: Unit) = traktAuthRepository.refreshTokens()
17 | }
18 |
--------------------------------------------------------------------------------
/fastlane/Matchfile:
--------------------------------------------------------------------------------
1 | git_url("https://github.com/chrisbanes/ios-certificates.git")
2 | storage_mode("git")
3 | type("appstore")
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/full_description.txt:
--------------------------------------------------------------------------------
1 | Discover and track your favorite TV shows with Tivi, the ultimate app for Trakt.tv users. Seamlessly sync your watchlist and browse trending titles. With Tivi, you can manage your viewing history, rate and review content, and receive personalized recommendations.
2 |
3 | You may be wondering why the screenshots are filled with images of animals? Well rest assured, the app will display show imagery as expected. We just can't include them in the screenshots.
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/featureGraphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/featureGraphic.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/phoneScreenshots/0_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/phoneScreenshots/0_home.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/phoneScreenshots/1_show_details.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/phoneScreenshots/1_show_details.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/phoneScreenshots/2_upnext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/phoneScreenshots/2_upnext.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/phoneScreenshots/3_library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/phoneScreenshots/3_library.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/images/phoneScreenshots/4_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/images/phoneScreenshots/4_search.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/short_description.txt:
--------------------------------------------------------------------------------
1 | Your ultimate Trakt.tv companion to discover and track TV shows
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/title.txt:
--------------------------------------------------------------------------------
1 | Tivi
--------------------------------------------------------------------------------
/fastlane/metadata/android/en_US/video.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/metadata/android/en_US/video.txt
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-1_Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-1_Home.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-2_ShowDetails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-2_ShowDetails.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-3_UpNext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-3_UpNext.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-4_Library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-4_Library.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-5_Search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPad Pro (12.9-inch) (3rd generation)-5_Search.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone 15 Pro Max-1_Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone 15 Pro Max-1_Home.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone 15 Pro Max-2_ShowDetails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone 15 Pro Max-2_ShowDetails.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone 15 Pro Max-3_UpNext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone 15 Pro Max-3_UpNext.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone 15 Pro Max-4_Library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone 15 Pro Max-4_Library.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone 15 Pro Max-5_Search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone 15 Pro Max-5_Search.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone SE (3rd generation)-1_Home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone SE (3rd generation)-1_Home.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone SE (3rd generation)-2_ShowDetails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone SE (3rd generation)-2_ShowDetails.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone SE (3rd generation)-3_UpNext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone SE (3rd generation)-3_UpNext.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone SE (3rd generation)-4_Library.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone SE (3rd generation)-4_Library.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iPhone SE (3rd generation)-5_Search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/fastlane/screenshots/en-US/iPhone SE (3rd generation)-5_Search.png
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/AndroidApplicationConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 |
9 | class AndroidApplicationConventionPlugin : Plugin {
10 | override fun apply(target: Project) {
11 | with(target) {
12 | with(pluginManager) {
13 | apply("com.android.application")
14 | apply("org.gradle.android.cache-fix")
15 | }
16 |
17 | configureAndroid()
18 | configureLicensee()
19 | configureAndroidLicensesTasks()
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/AndroidLibraryConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 |
9 | class AndroidLibraryConventionPlugin : Plugin {
10 | override fun apply(target: Project) {
11 | with(target) {
12 | with(pluginManager) {
13 | apply("com.android.library")
14 | apply("org.gradle.android.cache-fix")
15 | }
16 |
17 | configureAndroid()
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/AndroidTestConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 |
9 | class AndroidTestConventionPlugin : Plugin {
10 | override fun apply(target: Project) {
11 | with(target) {
12 | with(pluginManager) {
13 | apply("com.android.test")
14 | apply("org.gradle.android.cache-fix")
15 | }
16 |
17 | configureAndroid()
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/Java.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Project
7 | import org.gradle.api.plugins.JavaPluginExtension
8 | import org.gradle.jvm.toolchain.JavaLanguageVersion
9 | import org.gradle.kotlin.dsl.configure
10 |
11 | fun Project.configureJava() {
12 | java {
13 | toolchain {
14 | languageVersion.set(JavaLanguageVersion.of(17))
15 | }
16 | }
17 | }
18 |
19 | private fun Project.java(action: JavaPluginExtension.() -> Unit) = extensions.configure(action)
20 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/Kotlin.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Project
7 |
8 | fun Project.configureKotlin() {
9 | // Configure Java to use our chosen language level. Kotlin will automatically pick this up
10 | configureJava()
11 | }
12 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/KotlinAndroidConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 |
9 | class KotlinAndroidConventionPlugin : Plugin {
10 | override fun apply(target: Project) {
11 | with(target) {
12 | with(pluginManager) {
13 | apply("org.jetbrains.kotlin.android")
14 | }
15 |
16 | configureSpotless()
17 | configureKotlin()
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/RootConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 |
9 | class RootConventionPlugin : Plugin {
10 | override fun apply(target: Project) = with(target) {
11 | configureSpotless()
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/VersionCatalog.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | import org.gradle.api.Project
7 | import org.gradle.api.artifacts.VersionCatalog
8 | import org.gradle.api.artifacts.VersionCatalogsExtension
9 | import org.gradle.kotlin.dsl.getByType
10 |
11 | internal val Project.libs: VersionCatalog
12 | get() = extensions.getByType().named("libs")
13 |
--------------------------------------------------------------------------------
/gradle/build-logic/convention/src/main/kotlin/app/tivi/gradle/Versions.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.gradle
5 |
6 | object Versions {
7 | const val COMPILE_SDK = 34
8 | const val MIN_SDK = 24
9 | const val TARGET_SDK = 34
10 | }
11 |
--------------------------------------------------------------------------------
/gradle/build-logic/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534
2 | org.gradle.parallel=true
3 | org.gradle.caching=true
4 | org.gradle.configureondemand=true
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '15.2'
2 |
3 | target 'Tivi' do
4 | use_frameworks!
5 |
6 | pod 'AppAuth', '1.7.5'
7 | pod 'FirebaseAnalytics', '11.4.0'
8 | pod 'FirebaseCrashlytics', '11.4.0'
9 | end
10 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Settings.bundle/Root.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | DefaultValue
9 | 1.0 (1000)
10 | Key
11 | SNAppVersion
12 | Title
13 | Version
14 | Type
15 | PSTitleValueSpecifier
16 |
17 |
18 | StringsTable
19 | Root
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi/Assets.xcassets/AppIcon-QA.appiconset/AppIcon-QA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/ios-app/Tivi/Tivi/Assets.xcassets/AppIcon-QA.appiconset/AppIcon-QA.png
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi/Assets.xcassets/AppIcon-QA.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "AppIcon-QA.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi/Assets.xcassets/AppIcon.appiconset/AppIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/ios-app/Tivi/Tivi/Assets.xcassets/AppIcon.appiconset/AppIcon.png
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "AppIcon.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ios-app/Tivi/Tivi/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/Tivi-Prod-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "common/Prod.xcconfig"
2 | #include "common/Debug.xcconfig"
3 | #include "Pods/Target Support Files/Pods-Tivi/Pods-Tivi.prod debug.xcconfig"
4 |
5 | PRODUCT_NAME = $(TARGET_NAME) Dev
6 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/Tivi-Prod-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "common/Prod.xcconfig"
2 | #include "common/Release.xcconfig"
3 | #include "Pods/Target Support Files/Pods-Tivi/Pods-Tivi.prod release.xcconfig"
4 |
5 | PRODUCT_NAME = $(TARGET_NAME)
6 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/Tivi-QA-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "common/QA.xcconfig"
2 | #include "common/Debug.xcconfig"
3 | #include "Pods/Target Support Files/Pods-Tivi/Pods-Tivi.qa debug.xcconfig"
4 |
5 | PRODUCT_NAME = $(TARGET_NAME) QA Dev
6 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/Tivi-QA-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "common/QA.xcconfig"
2 | #include "common/Release.xcconfig"
3 | #include "Pods/Target Support Files/Pods-Tivi/Pods-Tivi.qa release.xcconfig"
4 |
5 | PRODUCT_NAME = $(TARGET_NAME) QA
6 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/UITests.xcconfig:
--------------------------------------------------------------------------------
1 | DEVELOPMENT_TEAM = GLF74Y6P9T
2 | IPHONEOS_DEPLOYMENT_TARGET = 17.4
3 | PRODUCT_BUNDLE_IDENTIFIER = app.tivi.UITests
4 | PRODUCT_NAME = $(TARGET_NAME)
5 | TEST_TARGET_NAME = Tivi
6 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/common/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | DEBUG_INFORMATION_FORMAT = dwarf
2 | ENABLE_PREVIEWS = YES
3 | ENABLE_TESTABILITY = YES
4 | GCC_DYNAMIC_NO_PIC = NO
5 | GCC_OPTIMIZATION_LEVEL = 0
6 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited)
7 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE
8 | KOTLIN_FRAMEWORK_BUILD_TYPE = Debug
9 | ONLY_ACTIVE_ARCH = YES
10 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG
11 | SWIFT_OPTIMIZATION_LEVEL = -Onone
12 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/common/Prod.xcconfig:
--------------------------------------------------------------------------------
1 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon
2 | CODE_SIGN_IDENTITY = Apple Development
3 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Distribution
4 | CODE_SIGN_STYLE = Manual
5 | DEVELOPMENT_TEAM[sdk=iphoneos*] = GLF74Y6P9T
6 | PRODUCT_BUNDLE_IDENTIFIER = app.tivi.client
7 | PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*] = match AppStore app.tivi.client
8 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/common/QA.xcconfig:
--------------------------------------------------------------------------------
1 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-QA
2 | CODE_SIGN_IDENTITY = Apple Development
3 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Distribution
4 | CODE_SIGN_STYLE = Manual
5 | DEVELOPMENT_TEAM[sdk=iphoneos*] = GLF74Y6P9T
6 | PRODUCT_BUNDLE_IDENTIFIER = app.tivi.qa
7 | PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*] = match AppStore app.tivi.qa
8 |
--------------------------------------------------------------------------------
/ios-app/Tivi/xcconfig/common/Release.xcconfig:
--------------------------------------------------------------------------------
1 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
2 | ENABLE_NS_ASSERTIONS = NO
3 | MTL_ENABLE_DEBUG_INFO = NO
4 | SWIFT_COMPILATION_MODE = wholemodule
5 | SWIFT_OPTIMIZATION_LEVEL = -O
6 | VALIDATE_PRODUCT = YES
7 | KOTLIN_FRAMEWORK_BUILD_TYPE = Release
8 |
--------------------------------------------------------------------------------
/release/GoogleService-Info.plist.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/release/GoogleService-Info.plist.gpg
--------------------------------------------------------------------------------
/release/app-debug.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/release/app-debug.jks
--------------------------------------------------------------------------------
/release/app-release.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/release/app-release.gpg
--------------------------------------------------------------------------------
/release/google-services.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/release/google-services.gpg
--------------------------------------------------------------------------------
/release/play-account.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisbanes/tivi/a0c62c2c763c83e3a0ecf79b283224374bb06c4a/release/play-account.gpg
--------------------------------------------------------------------------------
/shared/common/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/shared/common/src/androidMain/kotlin/app/tivi/inject/SharedActivityComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2022, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import android.app.Activity
7 | import androidx.core.os.ConfigurationCompat
8 | import java.util.Locale
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | interface SharedActivityComponent {
12 | @get:Provides
13 | val activity: Activity
14 |
15 | @Provides
16 | fun provideActivityLocale(activity: Activity): Locale {
17 | return ConfigurationCompat.getLocales(activity.resources.configuration)
18 | .get(0) ?: Locale.getDefault()
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/shared/common/src/commonMain/kotlin/app/tivi/appinitializers/AppInitializers.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2017, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.appinitializers
5 |
6 | import app.tivi.core.perf.Tracer
7 | import me.tatarka.inject.annotations.Inject
8 |
9 | @Inject
10 | class AppInitializers(
11 | private val initializers: Lazy>,
12 | private val tracer: Tracer,
13 | ) : AppInitializer {
14 | override fun initialize() {
15 | tracer.trace("AppInitializers") {
16 | for (initializer in initializers.value) {
17 | initializer.initialize()
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/shared/prod/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/shared/prod/src/androidMain/kotlin/app/tivi/inject/AndroidActivityComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import android.app.Activity
7 | import me.tatarka.inject.annotations.Component
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | @ActivityScope
11 | @Component
12 | abstract class AndroidActivityComponent(
13 | @get:Provides override val activity: Activity,
14 | @Component val applicationComponent: AndroidApplicationComponent,
15 | ) : SharedActivityComponent,
16 | ProdUiComponent {
17 |
18 | companion object
19 | }
20 |
--------------------------------------------------------------------------------
/shared/prod/src/commonMain/kotlin/app/tivi/inject/ProdApplicationComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import app.tivi.app.Flavor
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface ProdApplicationComponent {
10 | @Provides
11 | fun provideFlavor(): Flavor = Flavor.Standard
12 | }
13 |
--------------------------------------------------------------------------------
/shared/prod/src/commonMain/kotlin/app/tivi/inject/ProdUiComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | interface ProdUiComponent : SharedUiComponent
7 |
--------------------------------------------------------------------------------
/shared/prod/src/jvmMain/kotlin/app/tivi/inject/DesktopApplicationComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import me.tatarka.inject.annotations.Component
7 |
8 | @Component
9 | @ApplicationScope
10 | abstract class DesktopApplicationComponent :
11 | SharedApplicationComponent,
12 | ProdApplicationComponent {
13 |
14 | companion object
15 | }
16 |
--------------------------------------------------------------------------------
/shared/prod/src/jvmMain/kotlin/app/tivi/inject/WindowComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import me.tatarka.inject.annotations.Component
7 |
8 | @ActivityScope
9 | @Component
10 | abstract class WindowComponent(
11 | @Component val applicationComponent: DesktopApplicationComponent,
12 | ) : ProdUiComponent {
13 |
14 | companion object
15 | }
16 |
--------------------------------------------------------------------------------
/shared/qa/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/shared/qa/src/androidMain/kotlin/app/tivi/inject/AndroidActivityComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import android.app.Activity
7 | import me.tatarka.inject.annotations.Component
8 | import me.tatarka.inject.annotations.Provides
9 |
10 | @ActivityScope
11 | @Component
12 | abstract class AndroidActivityComponent(
13 | @get:Provides override val activity: Activity,
14 | @Component val applicationComponent: AndroidApplicationComponent,
15 | ) : SharedActivityComponent,
16 | QaUiComponent {
17 |
18 | companion object
19 | }
20 |
--------------------------------------------------------------------------------
/shared/qa/src/commonMain/kotlin/app/tivi/inject/QaApplicationComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import app.tivi.app.Flavor
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface QaApplicationComponent {
10 | @Provides
11 | fun provideFlavor(): Flavor = Flavor.Qa
12 | }
13 |
--------------------------------------------------------------------------------
/shared/qa/src/commonMain/kotlin/app/tivi/inject/QaUiComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import app.tivi.developer.log.DevLogComponent
7 | import app.tivi.developer.notifications.DevNotificationsComponent
8 | import app.tivi.settings.developer.DevSettingsComponent
9 |
10 | interface QaUiComponent :
11 | SharedUiComponent,
12 | DevLogComponent,
13 | DevSettingsComponent,
14 | DevNotificationsComponent
15 |
--------------------------------------------------------------------------------
/shared/qa/src/jvmMain/kotlin/app/tivi/inject/DesktopApplicationComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import me.tatarka.inject.annotations.Component
7 |
8 | @Component
9 | @ApplicationScope
10 | abstract class DesktopApplicationComponent :
11 | SharedApplicationComponent,
12 | QaApplicationComponent {
13 |
14 | companion object
15 | }
16 |
--------------------------------------------------------------------------------
/shared/qa/src/jvmMain/kotlin/app/tivi/inject/WindowComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.inject
5 |
6 | import me.tatarka.inject.annotations.Component
7 |
8 | @ActivityScope
9 | @Component
10 | abstract class WindowComponent(
11 | @Component val applicationComponent: DesktopApplicationComponent,
12 | ) : QaUiComponent {
13 |
14 | companion object
15 | }
16 |
--------------------------------------------------------------------------------
/spotless/cb-copyright.txt:
--------------------------------------------------------------------------------
1 | // Copyright $YEAR, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/spotless/google-copyright.txt:
--------------------------------------------------------------------------------
1 | // Copyright $YEAR, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
--------------------------------------------------------------------------------
/tasks/src/androidMain/kotlin/app/tivi/tasks/BootBroadcastReceiver.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tasks
5 |
6 | import android.content.BroadcastReceiver
7 | import android.content.Context
8 | import android.content.Intent
9 |
10 | class BootBroadcastReceiver : BroadcastReceiver() {
11 | override fun onReceive(context: Context, intent: Intent) {
12 | // We don't need to do anything here, as the AppInitializers should do what we need
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tasks/src/androidMain/kotlin/app/tivi/tasks/TasksPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2020, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tasks
5 |
6 | import android.app.Application
7 | import androidx.work.WorkManager
8 | import app.tivi.inject.ApplicationScope
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | actual interface TasksPlatformComponent {
12 | @ApplicationScope
13 | @Provides
14 | fun provideShowTasks(bind: AndroidTasks): Tasks = bind
15 |
16 | @ApplicationScope
17 | @Provides
18 | fun provideWorkManager(application: Application): WorkManager {
19 | return WorkManager.getInstance(application)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tasks/src/commonMain/kotlin/app/tivi/tasks/Tasks.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tasks
5 |
6 | interface Tasks {
7 | fun setup() = Unit
8 |
9 | fun scheduleEpisodeNotifications()
10 | fun cancelEpisodeNotifications()
11 |
12 | fun scheduleLibrarySync()
13 | fun cancelLibrarySync()
14 | }
15 |
--------------------------------------------------------------------------------
/tasks/src/commonMain/kotlin/app/tivi/tasks/TasksComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2020, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tasks
5 |
6 | import app.tivi.appinitializers.AppInitializer
7 | import app.tivi.inject.ApplicationScope
8 | import me.tatarka.inject.annotations.IntoSet
9 | import me.tatarka.inject.annotations.Provides
10 |
11 | interface TasksComponent : TasksPlatformComponent {
12 | @ApplicationScope
13 | @Provides
14 | @IntoSet
15 | fun provideShowTasksInitializer(bind: TasksInitializer): AppInitializer = bind
16 | }
17 |
18 | expect interface TasksPlatformComponent
19 |
--------------------------------------------------------------------------------
/tasks/src/iosMain/kotlin/app/tivi/tasks/TasksPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tasks
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface TasksPlatformComponent {
10 | @ApplicationScope
11 | @Provides
12 | fun provideShowTasks(bind: IosTasks): Tasks = bind
13 | }
14 |
--------------------------------------------------------------------------------
/tasks/src/jvmMain/kotlin/app/tivi/tasks/TasksPlatformComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.tasks
5 |
6 | import app.tivi.inject.ApplicationScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | actual interface TasksPlatformComponent {
10 | @ApplicationScope
11 | @Provides
12 | fun provideShowTasks(): Tasks = EmptyShowTasks
13 | }
14 |
15 | object EmptyShowTasks : Tasks {
16 | override fun scheduleEpisodeNotifications() = Unit
17 | override fun cancelEpisodeNotifications() = Unit
18 | override fun scheduleLibrarySync() = Unit
19 | override fun cancelLibrarySync() = Unit
20 | }
21 |
--------------------------------------------------------------------------------
/thirdparty/androidx/paging/compose/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 |
5 | plugins {
6 | id("app.tivi.android.library")
7 | id("app.tivi.kotlin.multiplatform")
8 | id("app.tivi.compose")
9 | }
10 |
11 | kotlin {
12 | sourceSets {
13 | commonMain {
14 | dependencies {
15 | api(libs.paging.common)
16 | api(compose.runtime)
17 | }
18 | }
19 | }
20 | }
21 |
22 | android {
23 | namespace = "androidx.paging.compose"
24 | }
25 |
--------------------------------------------------------------------------------
/thirdparty/androidx/paging/compose/src/iosMain/kotlin/PagingPlaceholders.ios.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package androidx.paging.compose
5 |
6 | internal actual fun getPagingPlaceholderKey(index: Int): Any = index
7 |
--------------------------------------------------------------------------------
/thirdparty/androidx/paging/compose/src/jvmMain/kotlin/PagingPlaceholders.jvm.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package androidx.paging.compose
5 |
6 | internal actual fun getPagingPlaceholderKey(index: Int): Any = index
7 |
--------------------------------------------------------------------------------
/ui/account/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/anticipated/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ui/developer/log/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogUiState.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.developer.log
5 |
6 | import androidx.compose.runtime.Immutable
7 | import app.tivi.util.LogMessage
8 | import com.slack.circuit.runtime.CircuitUiEvent
9 | import com.slack.circuit.runtime.CircuitUiState
10 |
11 | @Immutable
12 | data class DevLogUiState(
13 | val logs: List,
14 | val eventSink: (DevLogUiEvent) -> Unit,
15 | ) : CircuitUiState
16 |
17 | sealed interface DevLogUiEvent : CircuitUiEvent {
18 | data object NavigateUp : DevLogUiEvent
19 | }
20 |
--------------------------------------------------------------------------------
/ui/developer/notifications/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/developer/settings/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/discover/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/episode/details/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/episode/track/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/library/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/licenses/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/popular/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/recommended/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/root/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/root/src/commonMain/kotlin/app/tivi/home/RootUiComponent.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2024, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.home
5 |
6 | import app.tivi.inject.ActivityScope
7 | import me.tatarka.inject.annotations.Provides
8 |
9 | interface RootUiComponent {
10 | @Provides
11 | @ActivityScope
12 | fun bindTiviContent(impl: DefaultTiviContent): TiviContent = impl
13 | }
14 |
--------------------------------------------------------------------------------
/ui/search/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/settings/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/settings/src/androidMain/kotlin/app/tivi/settings/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | import android.os.Build
7 | import androidx.annotation.ChecksSdkIntAtLeast
8 |
9 | @ChecksSdkIntAtLeast(api = 31)
10 | internal actual val DynamicColorsAvailable: Boolean = Build.VERSION.SDK_INT >= 31
11 | internal actual val OpenSourceLicenseAvailable: Boolean = true
12 |
--------------------------------------------------------------------------------
/ui/settings/src/commonMain/kotlin/app/tivi/settings/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | internal expect val DynamicColorsAvailable: Boolean
7 | internal expect val OpenSourceLicenseAvailable: Boolean
8 |
--------------------------------------------------------------------------------
/ui/settings/src/iosMain/kotlin/app/tivi/settings/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | internal actual val DynamicColorsAvailable: Boolean = false
7 |
8 | internal actual val OpenSourceLicenseAvailable: Boolean = true
9 |
--------------------------------------------------------------------------------
/ui/settings/src/jvmMain/kotlin/app/tivi/settings/Platform.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2023, Christopher Banes and the Tivi project contributors
2 | // SPDX-License-Identifier: Apache-2.0
3 |
4 | package app.tivi.settings
5 |
6 | internal actual val DynamicColorsAvailable: Boolean = false
7 | internal actual val OpenSourceLicenseAvailable: Boolean = false
8 |
--------------------------------------------------------------------------------
/ui/show/details/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/show/seasons/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/trending/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ui/upnext/lint-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------