의약품 이름: $itemName
").append("의약품 영문 이름: $itemEnglishName
") + .append("의약품 시퀀스 번호: $itemSequence
").append("의약품 허가 날짜: $itemPermitDate
") + .append("제조사 이름: $entpName
").append("제조사 영문 이름: $entpEnglishName
") + .append("제조및수입사: $consignmentManufacturer
").append("성분 이름: $ingredientName
") + .append("주성분의 영문 이름: $mainIngredientEnglish
").append("총 함량: $totalContent
") + .append("저장 방법: $storageMethod
").append("유효 기간: $validTerm
") + .append("패키지 단위: $packUnit
") + } + + val result = Html.fromHtml(builder.toString(), Html.FROM_HTML_MODE_COMPACT) + builder.clear() + stringBuilder.clear() + result + } ?: "".toSpanned() + } + + + suspend fun toGranuleInfo(context: Context, granuleDto: GranuleIdentificationInfoDto): Spanned = + mutableMapOf$title
") + data.forEach { (key, value) -> + builder.append("$key: $value
") + } + } + Html.fromHtml(builder.toString(), Html.FROM_HTML_MODE_COMPACT).toSpanned() + } ?: "".toSpanned() + + builder.clear() + dataMap.clear() + result + } + +} \ No newline at end of file diff --git a/android/core/common/src/main/java/com/android/mediproject/core/common/network/MediDispatchers.kt b/android/core/common/src/main/java/com/android/mediproject/core/common/network/MediDispatchers.kt new file mode 100644 index 000000000..89cead538 --- /dev/null +++ b/android/core/common/src/main/java/com/android/mediproject/core/common/network/MediDispatchers.kt @@ -0,0 +1,13 @@ +package com.android.mediproject.core.common.network + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class Dispatcher(val mediDispatcher: MediDispatchers) + +enum class MediDispatchers { + Default, + IO, + Main, +} \ No newline at end of file diff --git a/android/core/common/src/main/java/com/android/mediproject/core/common/network/di/DispatchersModule.kt b/android/core/common/src/main/java/com/android/mediproject/core/common/network/di/DispatchersModule.kt new file mode 100644 index 000000000..546bd74fd --- /dev/null +++ b/android/core/common/src/main/java/com/android/mediproject/core/common/network/di/DispatchersModule.kt @@ -0,0 +1,26 @@ +package com.android.mediproject.core.common.network.di + +import com.android.mediproject.core.common.network.Dispatcher +import com.android.mediproject.core.common.network.MediDispatchers +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +@Module +@InstallIn(SingletonComponent::class) +object DispatchersModule { + @Provides + @Dispatcher(MediDispatchers.IO) + fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO + + @Provides + @Dispatcher(MediDispatchers.Default) + fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default + + @Provides + @Dispatcher(MediDispatchers.Main) + fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main +} \ No newline at end of file diff --git a/android/core/common/src/main/java/com/android/mediproject/core/common/paging/PagingUtil.kt b/android/core/common/src/main/java/com/android/mediproject/core/common/paging/PagingUtil.kt new file mode 100644 index 000000000..13443de22 --- /dev/null +++ b/android/core/common/src/main/java/com/android/mediproject/core/common/paging/PagingUtil.kt @@ -0,0 +1,36 @@ +package com.android.mediproject.core.common.paging + +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.paging.LoadState +import androidx.paging.PagingDataAdapter +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.progressindicator.CircularProgressIndicator + +/** + * PagingDataAdapter의 상태 변화를 감지하여 로딩 상태에 따라 View를 보여주는 함수 + * + * @param msgTextView 로딩 상태가 아닐 때 보여줄 메시지를 가진 TextView + * @param listView RecyclerView + * @param progressBar 로딩 상태일 때 보여줄 ProgressBar + * @param emptyMsg 로딩 상태가 아닐 때 보여줄 메시지 + */ +fun PagingDataAdapter<*, *>.setOnStateChangedListener( + msgTextView: TextView, + listView: RecyclerView, + progressBar: CircularProgressIndicator, + emptyMsg: String +) { + var isFirstLoad = true + addLoadStateListener { loadState -> + isFirstLoad = loadState.refresh is LoadState.Loading + if (isFirstLoad) listView.scrollToPosition(0) + + msgTextView.text = emptyMsg + + progressBar.isVisible = isFirstLoad + listView.isVisible = (!isFirstLoad && (loadState.source.refresh !is LoadState.Loading)) + msgTextView.isVisible = + ((!isFirstLoad && loadState.source.refresh !is LoadState.Loading) && itemCount == 0) + } +} \ No newline at end of file diff --git a/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/DimensionUtil.kt b/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/DimensionUtil.kt new file mode 100644 index 000000000..ff413156c --- /dev/null +++ b/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/DimensionUtil.kt @@ -0,0 +1,20 @@ +package com.android.mediproject.core.common.uiutil + +import android.content.Context +import android.util.TypedValue + +fun dpToPx(context: Context, dp: Int): Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), context.resources.displayMetrics +).toInt() + +fun spToPx(context: Context, sp: Int): Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, sp.toFloat(), context.resources.displayMetrics +).toInt() + +fun Int.dpToPx(context: Context): Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics +).toInt() + +fun Int.spToPx(context: Context): Int = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, this.toFloat(), context.resources.displayMetrics +).toInt() \ No newline at end of file diff --git a/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/Keyboard.kt b/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/Keyboard.kt new file mode 100644 index 000000000..557e7e4ea --- /dev/null +++ b/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/Keyboard.kt @@ -0,0 +1,21 @@ +package com.android.mediproject.core.common.uiutil + +import android.content.Context +import android.view.inputmethod.InputMethodManager +import androidx.fragment.app.Fragment + +/** + * 키보드를 숨기는 함수 + * @return Unit + */ +fun Fragment.hideKeyboard() { + activity?.also { it -> + // 현재 포커스가 있는 뷰를 찾는다. + if (it.currentFocus != null) { + // 키보드 숨기기 + (it.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow( + it.currentFocus?.windowToken, InputMethodManager.HIDE_NOT_ALWAYS + ) + } + } +} \ No newline at end of file diff --git a/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/SystemBarStyler.kt b/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/SystemBarStyler.kt new file mode 100644 index 000000000..0dd98b659 --- /dev/null +++ b/android/core/common/src/main/java/com/android/mediproject/core/common/uiutil/SystemBarStyler.kt @@ -0,0 +1,127 @@ +package com.android.mediproject.core.common.uiutil + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import androidx.core.view.WindowCompat +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.properties.Delegates + +@SuppressLint("InternalInsetResource", "DiscouragedApi") +@Singleton +class SystemBarStyler @Inject constructor( +) : LayoutController { + enum class StatusBarColor { + BLACK, WHITE + } + + enum class NavigationBarColor { + BLACK, WHITE + } + + enum class SpacingType { + MARGIN, PADDING + } + + private var acitivityLayoutController: LayoutController? = null + + private lateinit var window: Window + + data class ChangeView(val view: View, val type: SpacingType) + + private var statusBarHeight by Delegates.notNull