Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]#36 링크 관련 API 구현 및 링크 추가/수정 화면, 검색 화면에 연결 #37

Merged
merged 15 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
6609491
[FEATURE] #36 링크 삭제, 링크 수정, 검색 링크 목록, 링크 상세 조회 API, Datasource, UseCa…
l5x5l Aug 12, 2024
3b4d90a
[FEATURE] #36 검색화면 검색 API 연동
l5x5l Aug 13, 2024
7dbefb4
[FEATURE] #36 검색화면 bottomSheet 내 포킷 목록 조회 API 연결
l5x5l Aug 13, 2024
705af20
[FEATURE] #36 검색화면의 link상세 bottomSheet 구현 및 기존 bottomSheet에 공유 제외 클릭 …
l5x5l Aug 15, 2024
57744de
[BASE] #36 data 모듈에 room, sharedPreferences 관련 세팅 및 데이터베이스 구성
l5x5l Aug 15, 2024
f7b72c5
[FEATURE] #36 최근 검색어 관련 기능 구현
l5x5l Aug 15, 2024
109e096
[FEATURE] #36 즐겨찾기 등록/취소 API, datasource, useCase 구현
l5x5l Aug 15, 2024
0ac5cba
[FEATURE] #36 검색 화면에 즐겨찾기 등록/취소 API 연결
l5x5l Aug 15, 2024
3414906
[FIX] #36 페이징 클래스에서 아이템 수정이 반영되지 않는 문제 수정
l5x5l Aug 15, 2024
32185ee
[FEATURE] #36 링크 추가, open graph 링크 메타 정보 조회 api, datasource, reposito…
l5x5l Aug 16, 2024
47dfc58
[FEATURE] #36 링크 추가 화면에 링크 추가, 링크 수정, 링크 메타 정보 조회 useCase 연결
l5x5l Aug 16, 2024
b13599e
[FIX] #36 링크 추가 화면에서 링크 입력 도중 1초 이상 시간 소요시 키보드를 강제 종료시키는 문제 수정
l5x5l Aug 16, 2024
07dd2d3
[CHORE] #36 ktlint 적용
l5x5l Aug 16, 2024
41b3047
[FEATURE] #36 미분류 카테고리 컨텐츠 조회 API, datasource, api 구현
l5x5l Aug 16, 2024
3a47025
[FIX] #36 rootNavHost에 링크 추가/삭제 화면 인자 변경 반영
l5x5l Aug 16, 2024
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
4 changes: 1 addition & 3 deletions app/src/main/java/pokitmons/pokit/navigation/RootNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@ fun RootNavHost(
composable(
route = AddLink.routeWithArgs,
arguments = AddLink.arguments
) { navBackStackEntry ->
) {
val viewModel: AddLinkViewModel = hiltViewModel()
val linkId = navBackStackEntry.arguments?.getString(AddLink.linkIdArg)
AddLinkScreenContainer(
linkId = linkId,
viewModel = viewModel,
onBackPressed = navHostController::popBackStack,
onNavigateToAddPokit = {
Expand Down
8 changes: 8 additions & 0 deletions data/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ dependencies {
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

// room
implementation(libs.room.runtime)
annotationProcessor(libs.room.compiler)
kapt(libs.room.compiler)

// kotest
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotlin.reflect)
Expand All @@ -68,6 +73,9 @@ dependencies {

implementation(project(":domain"))

// jsoup
implementation(libs.jsoup)

// mockk
testImplementation(libs.mockk)
androidTestImplementation(libs.mockk.android)
Expand Down
55 changes: 55 additions & 0 deletions data/src/main/java/pokitmons/pokit/data/api/LinkApi.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package pokitmons.pokit.data.api

import pokitmons.pokit.data.model.link.request.ModifyLinkRequest
import pokitmons.pokit.data.model.link.response.ApplyBookmarkResponse
import pokitmons.pokit.data.model.link.response.GetLinkResponse
import pokitmons.pokit.data.model.link.response.GetLinksResponse
import pokitmons.pokit.data.model.link.response.ModifyLinkResponse
import pokitmons.pokit.domain.model.link.LinksSort
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query

Expand All @@ -19,4 +27,51 @@ interface LinkApi {
@Query("endDate") endDate: String? = null,
@Query("categoryIds") categoryIds: List<Int>? = null,
): GetLinksResponse

@GET("content")
suspend fun searchLinks(
@Query("page") page: Int = 0,
@Query("size") size: Int = 10,
@Query("sort") sort: List<String> = listOf(LinksSort.RECENT.value),
@Query("isRead") isRead: Boolean = false,
@Query("favorites") favorites: Boolean = false,
@Query("startDate") startDate: String? = null,
@Query("endDate") endDate: String? = null,
@Query("categoryIds") categoryIds: List<Int>? = null,
@Query("searchWord") searchWord: String = "",
): GetLinksResponse

@PUT("content/{contentId}")
suspend fun deleteLink(
@Path("contentId") contentId: Int = 0,
)

@POST("content/{contentId}")
suspend fun getLink(
@Path("contentId") contentId: Int = 0,
): GetLinkResponse

@PATCH("content/{contentId}")
suspend fun modifyLink(
@Path("contentId") contentId: Int,
@Body modifyLinkRequest: ModifyLinkRequest,
): ModifyLinkResponse

@POST("content")
suspend fun createLink(
@Body createLinkRequest: ModifyLinkRequest,
): ModifyLinkResponse

@PUT("content/{contentId}/bookmark")
suspend fun cancelBookmark(@Path("contentId") contentId: Int)

@POST("content/{contentId}/bookmark")
suspend fun applyBookmark(@Path("contentId") contentId: Int): ApplyBookmarkResponse

@GET("content/uncategorized")
suspend fun getUncategorizedLinks(
@Query("page") page: Int = 0,
@Query("size") size: Int = 10,
@Query("sort") sort: List<String> = listOf(LinksSort.RECENT.value),
): GetLinksResponse
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package pokitmons.pokit.data.datasource.local.search

import android.content.SharedPreferences
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import pokitmons.pokit.data.room.dao.SearchWordDao
import pokitmons.pokit.data.room.entity.SearchWord
import java.util.Calendar
import javax.inject.Inject

class LocalSearchWordDataSource @Inject constructor(
private val searchWordDao: SearchWordDao,
private val sharedPreferences: SharedPreferences,
) : SearchDataSource {
companion object {
const val USE_RECENT_WORD_SP_KEY = "use_recent_word"
}

private val useRecentSearchWords = MutableStateFlow(
sharedPreferences.getBoolean(USE_RECENT_WORD_SP_KEY, false)
)

override fun getSearchWord(): Flow<List<String>> {
return searchWordDao.getRecentSearchWords()
}

override suspend fun addSearchWord(searchWord: String) {
val currentDateString = Calendar.getInstance()
val searchWordEntity = SearchWord(
word = searchWord,
searchedAt = currentDateString.timeInMillis.toString()
)
searchWordDao.addSearchWord(searchWord = searchWordEntity)
}

override suspend fun removeSearchWord(searchWord: String) {
searchWordDao.removeSearchWord(searchWord)
}

override suspend fun removeAllSearchWords() {
searchWordDao.removeAllSearchWords()
}

override suspend fun setUseRecentSearchWord(use: Boolean): Boolean {
sharedPreferences.edit().putBoolean(USE_RECENT_WORD_SP_KEY, use).apply()
useRecentSearchWords.update { use }
return use
}

override fun getUseRecentSearchWord(): Flow<Boolean> {
return useRecentSearchWords
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package pokitmons.pokit.data.datasource.local.search

import kotlinx.coroutines.flow.Flow

interface SearchDataSource {
fun getSearchWord(): Flow<List<String>>
suspend fun addSearchWord(searchWord: String)
suspend fun removeSearchWord(searchWord: String)
suspend fun removeAllSearchWords()
suspend fun setUseRecentSearchWord(use: Boolean): Boolean
fun getUseRecentSearchWord(): Flow<Boolean>
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package pokitmons.pokit.data.datasource.remote.link

import pokitmons.pokit.data.model.link.request.ModifyLinkRequest
import pokitmons.pokit.data.model.link.response.GetLinkResponse
import pokitmons.pokit.data.model.link.response.GetLinksResponse
import pokitmons.pokit.data.model.link.response.LinkCardResponse
import pokitmons.pokit.data.model.link.response.ModifyLinkResponse
import pokitmons.pokit.domain.model.link.LinksSort

interface LinkDataSource {
Expand All @@ -15,4 +19,39 @@ interface LinkDataSource {
endDate: String? = null,
categoryIds: List<Int>? = null,
): GetLinksResponse

suspend fun searchLinks(
page: Int = 0,
size: Int = 10,
sort: List<String> = listOf(LinksSort.RECENT.value),
isRead: Boolean = false,
favorites: Boolean = false,
startDate: String? = null,
endDate: String? = null,
categoryIds: List<Int>? = null,
searchWord: String = "",
): GetLinksResponse

suspend fun deleteLink(contentId: Int)

suspend fun getLink(contentId: Int): GetLinkResponse

suspend fun modifyLink(
contentId: Int,
modifyLinkRequest: ModifyLinkRequest,
): ModifyLinkResponse

suspend fun createLink(
createLinkRequest: ModifyLinkRequest,
): ModifyLinkResponse

suspend fun setBookmark(contentId: Int, bookmarked: Boolean)

suspend fun getLinkCard(url: String): LinkCardResponse

suspend fun getUncategorizedLinks(
page: Int = 0,
size: Int = 10,
sort: List<String> = listOf(LinksSort.RECENT.value),
): GetLinksResponse
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package pokitmons.pokit.data.datasource.remote.link

import org.jsoup.Jsoup
import pokitmons.pokit.data.api.LinkApi
import pokitmons.pokit.data.model.link.request.ModifyLinkRequest
import pokitmons.pokit.data.model.link.response.GetLinkResponse
import pokitmons.pokit.data.model.link.response.GetLinksResponse
import pokitmons.pokit.data.model.link.response.LinkCardResponse
import pokitmons.pokit.data.model.link.response.ModifyLinkResponse
import javax.inject.Inject

class RemoteLinkDataSource @Inject constructor(
Expand Down Expand Up @@ -30,4 +35,75 @@ class RemoteLinkDataSource @Inject constructor(
categoryIds = categoryIds
)
}

override suspend fun searchLinks(
page: Int,
size: Int,
sort: List<String>,
isRead: Boolean,
favorites: Boolean,
startDate: String?,
endDate: String?,
categoryIds: List<Int>?,
searchWord: String,
): GetLinksResponse {
return linkApi.searchLinks(
page = page,
size = size,
sort = sort,
isRead = isRead,
favorites = favorites,
startDate = startDate,
endDate = endDate,
categoryIds = categoryIds,
searchWord = searchWord
)
}

override suspend fun deleteLink(contentId: Int) {
return linkApi.deleteLink(contentId = contentId)
}

override suspend fun getLink(contentId: Int): GetLinkResponse {
return linkApi.getLink(contentId)
}

override suspend fun modifyLink(
contentId: Int,
modifyLinkRequest: ModifyLinkRequest,
): ModifyLinkResponse {
return linkApi.modifyLink(
contentId = contentId,
modifyLinkRequest = modifyLinkRequest
)
}

override suspend fun createLink(createLinkRequest: ModifyLinkRequest): ModifyLinkResponse {
return linkApi.createLink(
createLinkRequest = createLinkRequest
)
}

override suspend fun setBookmark(contentId: Int, bookmarked: Boolean) {
if (bookmarked) {
linkApi.applyBookmark(contentId)
} else {
linkApi.cancelBookmark(contentId)
}
}

override suspend fun getLinkCard(url: String): LinkCardResponse {
val document = Jsoup.connect(url).get()
val image = document.select("meta[property=og:image]").attr("content").ifEmpty { null }
val title = document.select("meta[property=og:title]").attr("content")
return LinkCardResponse(
url = url,
image = image,
title = title
)
}

override suspend fun getUncategorizedLinks(page: Int, size: Int, sort: List<String>): GetLinksResponse {
return linkApi.getUncategorizedLinks(page = page, size = size, sort = sort)
}
}
25 changes: 25 additions & 0 deletions data/src/main/java/pokitmons/pokit/data/di/core/room/RoomModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package pokitmons.pokit.data.di.core.room

import android.content.Context
import androidx.room.Room
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import pokitmons.pokit.data.room.database.AppDatabase
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object RoomModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "pokitDatabase.db").build()
}

@Provides
@Singleton
fun providerSearchWordDao(database: AppDatabase) = database.searchWordDao()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package pokitmons.pokit.data.di.core.sharedpreferences

import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object SharedPreferencesModule {
@Provides
@Singleton
fun provideSharedPreferences(
@ApplicationContext context: Context,
): SharedPreferences {
return context.getSharedPreferences("pokit_shared_preferences", MODE_PRIVATE)
}
}
23 changes: 23 additions & 0 deletions data/src/main/java/pokitmons/pokit/data/di/search/SearchModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package pokitmons.pokit.data.di.search

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import pokitmons.pokit.data.datasource.local.search.LocalSearchWordDataSource
import pokitmons.pokit.data.datasource.local.search.SearchDataSource
import pokitmons.pokit.data.repository.search.SearchRepositoryImpl
import pokitmons.pokit.domain.repository.search.SearchRepository
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
abstract class SearchModule {
@Binds
@Singleton
abstract fun bindSearchRepository(searchRepositoryImpl: SearchRepositoryImpl): SearchRepository

@Binds
@Singleton
abstract fun bindSearchDataSource(searchDataSourceImpl: LocalSearchWordDataSource): SearchDataSource
}
Loading
Loading