Skip to content

Commit

Permalink
#16 Add a standalone Composable to handle trakt sync history
Browse files Browse the repository at this point in the history
  • Loading branch information
moallemi committed Jun 16, 2024
1 parent 8c0cf58 commit 6ee6790
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 0 deletions.
12 changes: 12 additions & 0 deletions feature/trakt-buttons/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
id("io.filmtime.gradle.android.feature")
id("io.filmtime.gradle.android.library.compose")
}

android {
namespace = "io.filmtime.feature.trakt.buttons"
}

dependencies {
implementation(project(":domain:trakt:history"))
}
Empty file.
21 changes: 21 additions & 0 deletions feature/trakt-buttons/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions feature/trakt-buttons/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.filmtime.feature.trakt.buttons.addremovehistory

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.PlaylistAdd
import androidx.compose.material.icons.rounded.PlaylistRemove
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.filmtime.core.designsystem.composable.FilmTimeFilledTonalButton
import io.filmtime.core.designsystem.theme.PreviewFilmTimeTheme
import io.filmtime.core.designsystem.theme.ThemePreviews
import io.filmtime.data.model.VideoType

@Composable
fun TraktAddRemoveHistoryButton(
modifier: Modifier = Modifier,
videoType: VideoType,
tmdbId: Int,
) {
val viewModel = hiltViewModel<TraktHistoryViewModel>()
val state by viewModel.state.collectAsStateWithLifecycle()

LaunchedEffect(videoType, tmdbId) {
viewModel.checkIfIsWatched(videoType, tmdbId)
}

TraktAddRemoveHistoryButton(
state = state,
modifier = modifier,
onClick = {
if (state.isWatched) {
viewModel.removeItemFromHistory(tmdbId)
} else {
viewModel.addItemToHistory()
}
},
)
}

@Composable
private fun TraktAddRemoveHistoryButton(
state: TraktAddRemoveUiState,
modifier: Modifier = Modifier,
onClick: () -> Unit,
) {
FilmTimeFilledTonalButton(
isLoading = state.isLoading,
onClick = onClick,
enabled = !state.isError,
title = {
if (state.isWatched) {
Text("Mark as unwatched")
} else {
Text("Mark as watched")
}
},
leadingIcon = {
if (state.isWatched) {
Icon(
imageVector = Icons.Rounded.PlaylistRemove,
contentDescription = "Add to history button",
)
} else {
Icon(
imageVector = Icons.AutoMirrored.Rounded.PlaylistAdd,
contentDescription = "Remove from history button",
)
}
},
)
}

@ThemePreviews
@Composable
private fun TraktAddRemoveHistoryButtonPreview() {
PreviewFilmTimeTheme {
TraktAddRemoveHistoryButton(
state = TraktAddRemoveUiState(
isLoading = false,
),
onClick = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.filmtime.feature.trakt.buttons.addremovehistory

data class TraktAddRemoveUiState(
val isLoading: Boolean = true,
val isWatched: Boolean = false,
val isError: Boolean = false,
val traktId: Int? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.filmtime.feature.trakt.buttons.addremovehistory

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.filmtime.data.model.Result.Failure
import io.filmtime.data.model.Result.Success
import io.filmtime.data.model.VideoType
import io.filmtime.domain.trakt.history.AddToHistoryUseCase
import io.filmtime.domain.trakt.history.IsMovieWatchedUseCase
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
internal class TraktHistoryViewModel @Inject constructor(
private val addToHistory: AddToHistoryUseCase,
private val isMovieWatchedUseCase: IsMovieWatchedUseCase,
) : ViewModel() {

private val _state = MutableStateFlow(TraktAddRemoveUiState())
val state = _state.asStateFlow()

fun checkIfIsWatched(videoType: VideoType, tmdbId: Int) = viewModelScope.launch {
_state.update { state -> state.copy(isLoading = true) }

when (val result = isMovieWatchedUseCase(tmdbId)) {
is Success -> _state.update { state ->
state.copy(isWatched = result.data.isWatched, isLoading = false, traktId = result.data.traktId)
}

is Failure -> _state.update { state -> state.copy(isLoading = false, isError = true) }
}
}

fun addItemToHistory() = viewModelScope.launch {
val traktId = state.value.traktId ?: return@launch

_state.update { state -> state.copy(isLoading = true) }

when (addToHistory(traktId)) {
is Success -> _state.update { state -> state.copy(isWatched = true, isLoading = false) }
is Failure -> _state.update { state -> state.copy(isLoading = false) }
}
}

fun removeItemFromHistory(traktId: Int) = viewModelScope.launch {
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ include(":data:database")
include(":data:bookmarks")
include(":domain:bookmarks")
include(":core:browser")
include(":feature:trakt-buttons")

0 comments on commit 6ee6790

Please sign in to comment.