Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2434a04
feat: Implement custom Snackbar component
yusufnasserdev Aug 18, 2025
19917db
Merge branch 'develop' into feature/snackbar-host
yusufnasserdev Aug 18, 2025
8d4daf3
Merge branch 'develop' into feature/snackbar-host
yusufnasserdev Aug 19, 2025
ce31e1d
feat: Implement global snackbar and refactor movie list caching
yusufnasserdev Aug 19, 2025
26d9f7a
refactor: improve readability and error handling in CustomMovieListRe…
yusufnasserdev Aug 19, 2025
4585fba
feat: implement bookmark bottom sheet for movies
yusufnasserdev Aug 19, 2025
0900e6a
feat: integrate BookmarkBottomSheet into TrendingMovies and ContinueW…
yusufnasserdev Aug 19, 2025
cdfb99f
feat: Implement bookmark functionality in TopRated screen
yusufnasserdev Aug 19, 2025
0da91b6
feat: implement bookmark bottom sheet functionality
yusufnasserdev Aug 19, 2025
93525bf
feat: integrate bookmark bottom sheet into movie category screen
yusufnasserdev Aug 19, 2025
63e8ad0
Merge branch 'develop' into feature/snackbar-host
yusufnasserdev Aug 19, 2025
3241527
Merge branch 'develop' into feature/snackbar-host
yusufnasserdev Aug 19, 2025
4f53f66
refactor: pass CustomMovieListLocalDataSource to AuthenticationReposi…
yusufnasserdev Aug 19, 2025
2b8fee5
feat: clear all cache before caching movie lists and memberships
yusufnasserdev Aug 19, 2025
11619ef
refactor: remove save tv show functionality
yusufnasserdev Aug 19, 2025
2be2964
test: update CustomMovieListRepositoryImplTest to use assertThrows an…
yusufnasserdev Aug 19, 2025
26919eb
feat: Implement bookmark functionality in TopMoviesPicks
yusufnasserdev Aug 19, 2025
1c37b27
feat: pass movieId to onManageBookmarkClicked
yusufnasserdev Aug 19, 2025
e3543e4
feat: Add bookmark functionality to actor details screen
yusufnasserdev Aug 19, 2025
35b8e7c
Refactor: Standardize SnackBar and contract naming
yusufnasserdev Aug 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion app/src/main/java/com/london/app/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowInsetsControllerCompat
import com.london.app.navigation.NavHostGraph
import com.london.data.local.preference.readLanguageCode
import com.london.data.worker.MovieListSyncWorker
import com.london.designsystem.theme.NovixTheme
import com.london.domain.service.AppPreferencesService
import com.london.presentation.localization.LocalizationManager
Expand All @@ -39,6 +40,9 @@ class MainActivity : ComponentActivity() {
@Inject
lateinit var localizationManager: LocalizationManager

@Inject
lateinit var workManager: androidx.work.WorkManager

override fun attachBaseContext(newBase: Context) {
val languageCode = readLanguageCode(newBase)
val localeWrappedContext = newBase.wrapWithLocale(Locale.forLanguageTag(languageCode))
Expand Down Expand Up @@ -75,6 +79,8 @@ class MainActivity : ComponentActivity() {
}
}
}

MovieListSyncWorker.schedulePeriodicSync(workManager)
}
}

Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/com/london/app/NovixApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ class NovixApplication : Application(), Configuration.Provider {
super.onCreate()
timberConfig()

WorkManager.initialize(this, workManagerConfiguration)
MovieListSyncWorker.schedulePeriodicSync(WorkManager.getInstance(applicationContext))
WorkManager.initialize(context = this, configuration = workManagerConfiguration)
}

private fun timberConfig() {
Expand All @@ -53,4 +52,4 @@ class NovixApplication : Application(), Configuration.Provider {
}
})
}
}
}
9 changes: 6 additions & 3 deletions app/src/main/java/com/london/app/navigation/NavHostGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import com.london.app.navigation.graph.mainNavGraph
import com.london.app.navigation.graph.onboardingNavGraph
import com.london.app.navigation.graph.splashNavGraph
import com.london.designsystem.component.NavBar
import com.london.designsystem.component.Scaffold
import com.london.designsystem.snackbar.CustomSnackBarUI
import com.london.designsystem.snackbar.ScaffoldWithSnackBar
import com.london.designsystem.snackbar.SnackBarData
import com.london.designsystem.theme.NovixTheme
import com.london.presentation.navigation.LocalNavController
import com.london.presentation.navigation.Screen.Account
Expand All @@ -32,7 +34,7 @@ fun NavHostGraph() {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val showBottomNav = navBackStackEntry.hasRoute(Home, Search, Categories, Lists(), Account)

Scaffold(
ScaffoldWithSnackBar(
containerColor = NovixTheme.colors.surface,
bottomBar = {
AnimatedVisibility(
Expand All @@ -48,7 +50,8 @@ fun NavHostGraph() {
navBackStackEntry = navBackStackEntry
)
}
}
},
snackBar = { data: SnackBarData -> CustomSnackBarUI(data = data) }
) { innerPadding ->
CompositionLocalProvider(LocalNavController provides navController) {
NavHost(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ fun NavGraphBuilder.mainNavGraph(
onNavigateBack = ::navigateUp
)
}
composable<Reviews> { ReviewsScreen(onNavigateBack = ::navigateUp) }

composable<Reviews> {
ReviewsScreen(onNavigateBack = ::navigateUp)
}
}
}

Expand All @@ -138,8 +141,8 @@ private fun NavGraphBuilder.homeNavGraph(navController: NavHostController) =
composable<TopRated> {
TopRatedScreen(
onNavigateBack = ::navigateUp,
onNaviagteToMovieDetalis = ::navigateToMovieDetails,
onNaviagteToTvShowDetalis = ::navigateToTvShowDetails
onNavigateToMovieDetails = ::navigateToMovieDetails,
onNavigateToTvShowDetails = ::navigateToTvShowDetails
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ interface SyncMetadataDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertSyncMetadata(metadata: SyncMetadataLocal)

@Query("DELETE FROM sync_metadata")
suspend fun clearAll()

companion object {
const val MOVIE_LISTS_SYNC_KEY = "movie_lists_sync"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class CustomMovieListLocalDataSourceImpl @Inject constructor(
movieListDao.updateItemCount(listId = listId, itemCount = itemCount)

override suspend fun shouldRefreshCache(): Boolean {
val metadata = syncMetadataDao.getSyncMetadata(SYNC_KEY)
val metadata = syncMetadataDao.getSyncMetadata(SyncMetadataDao.MOVIE_LISTS_SYNC_KEY)
return metadata == null ||
!metadata.isSuccess ||
(System.currentTimeMillis() - metadata.lastSyncTime) > CACHE_VALIDITY_MS
Expand All @@ -93,7 +93,7 @@ class CustomMovieListLocalDataSourceImpl @Inject constructor(
override suspend fun markCacheRefreshed(success: Boolean) {
syncMetadataDao.insertSyncMetadata(
SyncMetadataLocal(
syncKey = SYNC_KEY,
syncKey = SyncMetadataDao.MOVIE_LISTS_SYNC_KEY,
lastSyncTime = System.currentTimeMillis(),
isSuccess = success
)
Expand All @@ -103,10 +103,10 @@ class CustomMovieListLocalDataSourceImpl @Inject constructor(
override suspend fun clearAllCache() {
membershipDao.clearAll()
movieListDao.clearAll()
syncMetadataDao.clearAll()
}

private companion object {
const val CACHE_VALIDITY_MS = 30 * 60 * 1000L // 30 minutes
const val SYNC_KEY = SyncMetadataDao.MOVIE_LISTS_SYNC_KEY
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ object ApiConstants {
const val GET_LIST_DETAILS_PATH = "list/{list_id}"
const val ADD_MOVIE_TO_LIST_PATH = "list/{list_id}/add_item"
const val REMOVE_MOVIE_FROM_LIST_PATH = "list/{list_id}/remove_item"
const val GET_ACCOUNT_LISTS_PATH = "account/{account_id}/lists"
const val GET_ACCOUNT_LISTS_PATH = "account/0/lists"

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.london.data.repository.authentication

import com.london.data.local.preference.AuthenticationPreferences
import com.london.data.local.source.customLists.CustomMovieListLocalDataSource
import com.london.data.mapper.account.toEntity
import com.london.data.remote.model.authentication.RequestTokenResponse
import com.london.data.remote.model.authentication.SessionResponse
Expand All @@ -13,7 +14,8 @@ import javax.inject.Inject
class AuthenticationRepositoryImpl @Inject constructor(
private val authenticationRemoteDataSource: AuthenticationRemoteDataSource,
private val accountRemoteDataSource: AccountRemoteDataSource,
private val authenticationPreferences: AuthenticationPreferences
private val authenticationPreferences: AuthenticationPreferences,
private val customMovieListLocalDataSource: CustomMovieListLocalDataSource
) : AuthenticationRepository {
override suspend fun login(username: String, password: String): Boolean {

Expand Down Expand Up @@ -51,6 +53,7 @@ class AuthenticationRepositoryImpl @Inject constructor(
if (sessionId != null && !authenticationPreferences.isGuestMode()) {
authenticationRemoteDataSource.deleteSession(sessionId).getOrThrow()
}
customMovieListLocalDataSource.clearAllCache()
authenticationPreferences.clearAuthentication()
return true
}
Expand Down
Loading
Loading