Skip to content

Commit

Permalink
- Now, tags are retrieved from the server
Browse files Browse the repository at this point in the history
  • Loading branch information
DesarrolloAntonio committed May 15, 2024
1 parent 94ad5b4 commit 4492ae8
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 36 deletions.
10 changes: 10 additions & 0 deletions data/src/main/java/com/desarrollodroide/data/di/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import com.desarrollodroide.data.repository.SettingsRepository
import com.desarrollodroide.data.repository.SettingsRepositoryImpl
import com.desarrollodroide.data.repository.SystemRepository
import com.desarrollodroide.data.repository.SystemRepositoryImpl
import com.desarrollodroide.data.repository.TagsRepository
import com.desarrollodroide.data.repository.TagsRepositoryImpl
import com.desarrollodroide.network.retrofit.FileRemoteDataSource
import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
Expand Down Expand Up @@ -94,6 +96,14 @@ fun dataModule() = module {
) as SystemRepository
}

single {
TagsRepositoryImpl(
apiService = get(),
tagsDao = get(),
errorHandler = get()
) as TagsRepository
}



single { FileRemoteDataSource() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fun databaseModule() = module {

single { BookmarksDatabase.create(androidContext()) }
single { get<BookmarksDatabase>().bookmarksDao() }
single { get<BookmarksDatabase>().tagDao() }

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.desarrollodroide.data.local.room.dao

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.desarrollodroide.data.local.room.entity.TagEntity
import kotlinx.coroutines.flow.Flow

@Dao
interface TagDao {
@Query("SELECT * FROM tags")
fun getAllTags(): Flow<List<TagEntity>>

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTag(tag: TagEntity)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllTags(tags: List<TagEntity>)

@Delete
suspend fun deleteTag(tag: TagEntity)

@Query("DELETE FROM tags")
suspend fun deleteAllTags()
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import androidx.sqlite.db.SupportSQLiteDatabase
import com.desarrollodroide.data.local.room.dao.BookmarksDao
import com.desarrollodroide.data.local.room.entity.BookmarkEntity
import com.desarrollodroide.data.local.room.converters.TagsConverter
import com.desarrollodroide.data.local.room.dao.TagDao
import com.desarrollodroide.data.local.room.entity.TagEntity

@Database(entities = [BookmarkEntity::class], version = 3)
@Database(entities = [BookmarkEntity::class, TagEntity::class], version = 4)
@TypeConverters(TagsConverter::class)
abstract class BookmarksDatabase : RoomDatabase() {

abstract fun bookmarksDao(): BookmarksDao

abstract fun tagDao(): TagDao

companion object {

Expand All @@ -31,13 +33,28 @@ abstract class BookmarksDatabase : RoomDatabase() {
}
}

val MIGRATION_3_4: Migration = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
// Create table statement updated to include n_bookmarks
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS `tags` (
`id` INTEGER PRIMARY KEY NOT NULL,
`name` TEXT NOT NULL,
`n_bookmarks` INTEGER NOT NULL
)
"""
)
}
}

fun create(context: Context): BookmarksDatabase {
return Room.databaseBuilder(
context,
BookmarksDatabase::class.java, "bookmarks_database"
)
.allowMainThreadQueries()
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4)
.build()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.desarrollodroide.data.local.room.entity

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "tags")
data class TagEntity(
@PrimaryKey(autoGenerate = true) val id: Int,
val name: String,
@ColumnInfo(name = "n_bookmarks") val nBookmarks: Int,
)
14 changes: 14 additions & 0 deletions data/src/main/java/com/desarrollodroide/data/mapper/Mapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.desarrollodroide.data.mapper

import com.desarrollodroide.data.UserPreferences
import com.desarrollodroide.data.local.room.entity.BookmarkEntity
import com.desarrollodroide.data.local.room.entity.TagEntity
import com.desarrollodroide.model.*
import com.desarrollodroide.network.model.*

Expand Down Expand Up @@ -59,6 +60,19 @@ fun TagDTO.toDomainModel() = Tag(
nBookmarks = nBookmarks?:0
)

fun TagDTO.toEntityModel() = TagEntity(
id = id?:0,
name = name?:"",
nBookmarks = nBookmarks?:0
)

fun TagEntity.toDomainModel() = Tag(
id = id,
name = name,
selected = false,
nBookmarks = nBookmarks
)

fun Account.toRequestBody() =
LoginRequestPayload(
username = userName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.desarrollodroide.data.extensions.toBodyJson
import com.desarrollodroide.data.extensions.toJson
import com.desarrollodroide.data.local.room.dao.BookmarksDao
import com.desarrollodroide.data.mapper.*
import com.desarrollodroide.data.repository.paging.MoviePagingSource
import com.desarrollodroide.data.repository.paging.BookmarkPagingSource
import com.desarrollodroide.model.Bookmark
import com.desarrollodroide.model.Tag
import com.desarrollodroide.model.UpdateCachePayload
Expand Down Expand Up @@ -68,7 +68,7 @@ class BookmarksRepositoryImpl(
return Pager(
config = PagingConfig(pageSize = 20, prefetchDistance = 2),
pagingSourceFactory = {
MoviePagingSource(
BookmarkPagingSource(
remoteDataSource = apiService,
bookmarksDao = bookmarksDao,
serverUrl = serverUrl,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.desarrollodroide.data.repository

import kotlinx.coroutines.flow.Flow
import com.desarrollodroide.common.result.Result
import com.desarrollodroide.model.Tag

interface TagsRepository {
fun getTags(
token: String,
serverUrl: String
): Flow<Result<List<Tag>?>>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.desarrollodroide.data.repository

import com.desarrollodroide.common.result.ErrorHandler
import com.desarrollodroide.data.extensions.removeTrailingSlash
import com.desarrollodroide.data.local.room.dao.TagDao
import com.desarrollodroide.data.mapper.*
import com.desarrollodroide.model.Tag
import com.desarrollodroide.network.model.TagsDTO
import com.desarrollodroide.network.retrofit.NetworkBoundResource
import com.desarrollodroide.network.retrofit.RetrofitNetwork
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map

class TagsRepositoryImpl(
private val apiService: RetrofitNetwork,
private val tagsDao: TagDao,
private val errorHandler: ErrorHandler
) : TagsRepository {

override fun getTags(
token: String,
serverUrl: String
) = object :
NetworkBoundResource<TagsDTO, List<Tag>>(errorHandler = errorHandler) {

override suspend fun saveRemoteData(response: TagsDTO) {
response.message?.map { it.toEntityModel() }?.let { tagsList ->
tagsDao.deleteAllTags()
tagsDao.insertAllTags(tagsList)
}
}

override fun fetchFromLocal(): Flow<List<Tag>> = tagsDao.getAllTags().map {
it.map { it.toDomainModel() }
}

override suspend fun fetchFromRemote() = apiService.getTags(
authorization = "Bearer $token",
url = "${serverUrl.removeTrailingSlash()}/api/v1/tags"
)

override fun shouldFetch(data: List<Tag>?) = true

}.asFlow().flowOn(Dispatchers.IO)

}

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.desarrollodroide.data.repository.paging

import android.util.Log
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.desarrollodroide.data.extensions.removeTrailingSlash
Expand All @@ -15,7 +16,7 @@ import kotlinx.coroutines.flow.map
import retrofit2.HttpException
import java.io.IOException

class MoviePagingSource(
class BookmarkPagingSource(
private val remoteDataSource: RetrofitNetwork,
private val bookmarksDao: BookmarksDao,
private val serverUrl: String,
Expand Down Expand Up @@ -53,8 +54,10 @@ class MoviePagingSource(
nextKey = if ((bookmarksDto.body()?.page ?: 0) >= (bookmarksDto.body()?.maxPage ?: 0)) null else page + 1
)
} catch (exception: IOException) {
Log.e("BookmarkPagingSource", "IOException", exception)
return loadFromLocalWhenError()
} catch (exception: HttpException) {
Log.e("BookmarkPagingSource", "HttpException", exception)
return loadFromLocalWhenError()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.desarrollodroide.domain.usecase

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import com.desarrollodroide.common.result.Result
import com.desarrollodroide.data.repository.TagsRepository
import com.desarrollodroide.model.Tag

class GetTagsUseCase(
private val tagsRepository: TagsRepository
) {
operator fun invoke(
serverUrl: String,
token: String,
): Flow<Result<List<Tag>?>> {
return tagsRepository.getTags(
token = token,
serverUrl = serverUrl
).flowOn(Dispatchers.IO)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.desarrollodroide.network.model

class TagsDTO (
val ok: Boolean?,
val message: List<TagDTO>?
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.desarrollodroide.network.model.LivenessResponseDTO
import com.desarrollodroide.network.model.LoginResponseDTO
import com.desarrollodroide.network.model.SessionDTO
import com.desarrollodroide.network.model.TagDTO
import okhttp3.ResponseBody
import com.desarrollodroide.network.model.TagsDTO
import retrofit2.Response
import retrofit2.http.*

Expand Down Expand Up @@ -81,10 +81,11 @@ interface RetrofitNetwork {
): Response<BookmarkResponseDTO>

// Get tags
@GET("/api/tags")
@GET()
suspend fun getTags(
@Header("X-Session-Id") xSessionId: String
): Response<List<TagDTO>>
@Url url: String,
@Header("Authorization") authorization: String,
): Response<TagsDTO>

// Rename tag
@PUT("/api/tags")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.desarrollodroide.domain.usecase.DownloadFileUseCase
import com.desarrollodroide.domain.usecase.EditBookmarkUseCase
import com.desarrollodroide.domain.usecase.GetBookmarksUseCase
import com.desarrollodroide.domain.usecase.GetPagingBookmarksUseCase
import com.desarrollodroide.domain.usecase.GetTagsUseCase
import com.desarrollodroide.domain.usecase.SendLoginUseCase
import com.desarrollodroide.domain.usecase.SendLogoutUseCase
import com.desarrollodroide.domain.usecase.SystemLivenessUseCase
Expand Down Expand Up @@ -87,6 +88,12 @@ fun appModule() = module {
)
}

single {
GetTagsUseCase(
tagsRepository = get()
)
}

single { ThemeManagerImpl(get()) as ThemeManager }


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fun presenterModule() = module {
FeedViewModel(
bookmarkDatabase = get(),
settingsPreferenceDataSource = get(),
getBookmarksUseCase = get(),
getTagsUseCase = get(),
deleteBookmarkUseCase = get(),
updateBookmarkCacheUseCase = get(),
getPagingBookmarksUseCase = get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -31,12 +31,12 @@ import com.desarrollodroide.pagekeeper.ui.components.CategoriesType
fun CategoriesView(
onApply: (List<Tag>) -> Unit,
onDismiss: () -> Unit,
uniqueCategories: State<List<Tag>>,
uniqueCategories: MutableState<List<Tag>>,
) {
val context = LocalContext.current
val sortingOptions = remember { mutableStateListOf(Tag("Alphabetical order"), Tag("Date")) }
val selectedSorting = remember { mutableStateOf(listOf<Tag>()) }
val mutableUniqueCategories = remember { mutableStateOf(uniqueCategories.value) }
val mutableUniqueCategories = remember { mutableStateOf(uniqueCategories) }

val selectedTags = remember { mutableStateOf(listOf<Tag>()) }

Expand Down Expand Up @@ -64,7 +64,7 @@ fun CategoriesView(
Categories(
categoriesType = CategoriesType.SELECTABLES,
showCategories = true,
uniqueCategories = mutableUniqueCategories,
uniqueCategories = uniqueCategories,
selectedTags = selectedTags,
onCategoriesSelectedChanged = { tags ->
selectedTags.value = tags
Expand Down
Loading

0 comments on commit 4492ae8

Please sign in to comment.