diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 9c741d0e..fa0bb8bb 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -10,6 +10,6 @@
|스크린샷|
|:--:|
|파일첨부바람|
-
+
## 📮 관련 이슈
- Resolved: #이슈번호
diff --git a/README.md b/README.md
index f5aec8a3..efe3ec5c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,68 @@
-# Android
+# TOASTER-AOS
+
+
+더 이상 링크를 태우지 마세요. 토스트 먹듯이 간단하게!
+유저가 링크를 산재된 플랫폼에 저장함으로 인해 발생하는 모든 불편함을 토스터에서 해소해줄 수 있어요.
+
+- 33기 DO SOPT APP-JAM (2023.12.17 ~ )
+- Development Environment : `Hedgehog | 2023.1.1`
+
+
+
+## AOS Developer
+
+| [상욱](operawook@catholic.ac.kr) | [이삭](lsls4868@gmail.com) | [채은](parkchangel@naver.com) | [민영](codingmy@naver.com) |
+| :--: | :--: | :--: | :--: |
+|
|
|
|
|
+|
`타이머페이지` |
`메인페이지` `링크저장` |
`로그인, 검색` `마이페이지` |
`카테고리페이지` |
+
+
+
+## 💻 Code Convention
+[NOTION Code Convetion Link](https://hill-agenda-2b0.notion.site/Code-Convention-f492a5bdf5b444a6aae561e53d9d4e10)
+
+
+## 🔖 Branch Strategy
+[NOTION Branch Strategy](https://hill-agenda-2b0.notion.site/Branch-Strategy-e3a9c5e70f6241ae9ccad544666b095c?pvs=4)
+
+
+## 🎁 Git Convention
+[NOTION Git Convention](https://hill-agenda-2b0.notion.site/Git-Convention-064dee5df78e4b0c9dd59d18c775a460?pvs=4)
+
+
+## 💻 Kanban Board
+[GIT Kanban Board](https://github.com/orgs/Link-MIND/projects/1/views/1)
+
+
+## 📜 Project Plan
+[Project Plan](https://hill-agenda-2b0.notion.site/7a635a2c014c470899899073be2ff49f?v=4de94ec87af045d8ba9a69afa39511af)
+
+### 📂 Module
+```bash
+├── LinkMind-Android
+├── 📁 app
+├── 📁 build-logic
+├── 📁 Convention
+├── 📁 core
+│ ├── 🗂️ auth
+│ ├── 🗂️ authimpl
+│ ├── 🗂️ common
+│ ├── 🗂️ datastore
+│ ├── 🗂️ model
+│ ├── 🗂️ network
+│ ├── 🗂️ ui
+├── 📁 data
+│ ├── 🗂️ linkminddata
+│ ├── 🗂️ oauthdata
+├── 📁 data-local
+│ ├── 🗂️ linkminddata-local
+├── 📁 data- remote
+│ ├── 🗂️ linkminddata-remote
+├── 📁 domain
+│ ├── 🗂️ linkminddomain
+│ ├── 🗂️ oauthdomain
+├── 📁 feature
+│ ├── 🗂️ mainfeature
+```
+
+
diff --git a/core/network/src/main/java/org/sopt/network/authenticator/LinkMindAuthenticator.kt b/core/network/src/main/java/org/sopt/network/authenticator/LinkMindAuthenticator.kt
index ac87d61e..f90ded7e 100644
--- a/core/network/src/main/java/org/sopt/network/authenticator/LinkMindAuthenticator.kt
+++ b/core/network/src/main/java/org/sopt/network/authenticator/LinkMindAuthenticator.kt
@@ -3,6 +3,7 @@ package org.sopt.network.authenticator
import android.content.Context
import com.jakewharton.processphoenix.ProcessPhoenix
import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import okhttp3.Authenticator
import okhttp3.Request
@@ -23,7 +24,7 @@ class LinkMindAuthenticator @Inject constructor(
if (response.code == CODE_TOKEN_EXPIRED) {
val newTokens = runCatching {
runBlocking {
- tokenRefreshService.postAuthRefresh()
+ tokenRefreshService.postAuthRefresh(dataStore.flowRefreshToken().first())
}
}.onSuccess {
runBlocking {
diff --git a/core/network/src/main/java/org/sopt/network/interceptor/AuthenticationIntercept.kt b/core/network/src/main/java/org/sopt/network/interceptor/AuthenticationIntercept.kt
index 228d4534..8bcdac37 100644
--- a/core/network/src/main/java/org/sopt/network/interceptor/AuthenticationIntercept.kt
+++ b/core/network/src/main/java/org/sopt/network/interceptor/AuthenticationIntercept.kt
@@ -25,8 +25,7 @@ class AuthenticationIntercept @Inject constructor(
runBlocking { dataStore.setAutoLogin(false) }
ProcessPhoenix.triggerRebirth(context, intentProvider.getAuthIntent())
}
- response.close()
- return chain.proceed(authRequest)
+ return response
}
private fun handleRequest(originalRequest: Request) =
diff --git a/core/network/src/main/java/org/sopt/network/service/TokenRefreshService.kt b/core/network/src/main/java/org/sopt/network/service/TokenRefreshService.kt
index 60a05c10..caba2bad 100644
--- a/core/network/src/main/java/org/sopt/network/service/TokenRefreshService.kt
+++ b/core/network/src/main/java/org/sopt/network/service/TokenRefreshService.kt
@@ -2,9 +2,12 @@ package org.sopt.network.service
import org.sopt.network.model.response.ResponsePostAuthRefreshDto
import org.sopt.network.model.response.base.BaseResponse
+import retrofit2.http.Header
import retrofit2.http.POST
interface TokenRefreshService {
@POST("auth/token")
- suspend fun postAuthRefresh(): BaseResponse
+ suspend fun postAuthRefresh(
+ @Header("refreshToken") refreshToken: String,
+ ): BaseResponse
}
diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts
index 02fad677..72367584 100644
--- a/core/ui/build.gradle.kts
+++ b/core/ui/build.gradle.kts
@@ -9,5 +9,6 @@ android {
buildFeatures {
dataBinding = true
+ viewBinding = true
}
}
diff --git a/core/ui/src/main/java/org/sopt/ui/base/BindingActivity.kt b/core/ui/src/main/java/org/sopt/ui/base/BindingActivity.kt
index 1f1dbb74..2be4df52 100644
--- a/core/ui/src/main/java/org/sopt/ui/base/BindingActivity.kt
+++ b/core/ui/src/main/java/org/sopt/ui/base/BindingActivity.kt
@@ -1,23 +1,22 @@
package org.sopt.ui.base
import android.os.Bundle
+import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
-import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity
-import androidx.databinding.DataBindingUtil
-import androidx.databinding.ViewDataBinding
+import androidx.viewbinding.ViewBinding
import org.sopt.ui.context.hideKeyboard
-abstract class BindingActivity(
- @LayoutRes private val layoutRes: Int,
+abstract class BindingActivity(
+ private val inflater: (LayoutInflater) -> T,
) : AppCompatActivity() {
protected lateinit var binding: T
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- binding = DataBindingUtil.setContentView(this, layoutRes)
- binding.lifecycleOwner = this
+ binding = inflater(layoutInflater)
+ setContentView(binding.root)
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
diff --git a/core/ui/src/main/java/org/sopt/ui/base/BindingBottomSheetDialogFragment.kt b/core/ui/src/main/java/org/sopt/ui/base/BindingBottomSheetDialogFragment.kt
new file mode 100644
index 00000000..27aecf9d
--- /dev/null
+++ b/core/ui/src/main/java/org/sopt/ui/base/BindingBottomSheetDialogFragment.kt
@@ -0,0 +1,44 @@
+package org.sopt.ui.base
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import androidx.viewbinding.ViewBinding
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+
+abstract class BindingBottomSheetDialogFragment(
+ private val inflater: (LayoutInflater) -> T,
+) : BottomSheetDialogFragment() {
+ private var _binding: T? = null
+ protected val binding get() = requireNotNull(_binding) { { "binding object is not initialized" } }
+
+ override fun onStart() {
+ super.onStart()
+ dialog?.window?.apply {
+ setLayout(
+ WindowManager.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
+ )
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View {
+ _binding = inflater(layoutInflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ }
+
+ override fun onDestroyView() {
+ _binding = null
+ super.onDestroyView()
+ }
+}
diff --git a/core/ui/src/main/java/org/sopt/ui/base/BindingDialogFragment.kt b/core/ui/src/main/java/org/sopt/ui/base/BindingDialogFragment.kt
index 07630999..b7180671 100644
--- a/core/ui/src/main/java/org/sopt/ui/base/BindingDialogFragment.kt
+++ b/core/ui/src/main/java/org/sopt/ui/base/BindingDialogFragment.kt
@@ -5,13 +5,11 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
-import androidx.annotation.LayoutRes
-import androidx.databinding.DataBindingUtil
-import androidx.databinding.ViewDataBinding
import androidx.fragment.app.DialogFragment
+import androidx.viewbinding.ViewBinding
-abstract class BindingDialogFragment(
- @LayoutRes val layoutRes: Int,
+abstract class BindingDialogFragment(
+ private val inflater: (LayoutInflater) -> T,
) : DialogFragment() {
private var _binding: T? = null
protected val binding get() = requireNotNull(_binding) { { "binding object is not initialized" } }
@@ -31,13 +29,12 @@ abstract class BindingDialogFragment(
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
- _binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
+ _binding = inflater(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- binding.lifecycleOwner = viewLifecycleOwner
}
override fun onDestroyView() {
diff --git a/core/ui/src/main/java/org/sopt/ui/base/BindingFragment.kt b/core/ui/src/main/java/org/sopt/ui/base/BindingFragment.kt
index 812252c3..0d4a5ac9 100644
--- a/core/ui/src/main/java/org/sopt/ui/base/BindingFragment.kt
+++ b/core/ui/src/main/java/org/sopt/ui/base/BindingFragment.kt
@@ -4,25 +4,23 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.annotation.LayoutRes
-import androidx.databinding.DataBindingUtil
-import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
+import androidx.viewbinding.ViewBinding
-abstract class BindingFragment(
- @LayoutRes private val layoutRes: Int,
+abstract class BindingFragment(
+ private val inflater: (LayoutInflater) -> T,
) : Fragment() {
private var _binding: T? = null
- protected val binding get() = requireNotNull(_binding) {
- }
+ protected val binding
+ get() = requireNotNull(_binding) {
+ }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
- _binding = DataBindingUtil.inflate(inflater, layoutRes, container, false)
- binding.lifecycleOwner = viewLifecycleOwner
+ _binding = inflater(layoutInflater)
return binding.root
}
diff --git a/feature/mainfeature/src/main/AndroidManifest.xml b/feature/mainfeature/src/main/AndroidManifest.xml
index 241ed066..55c534aa 100644
--- a/feature/mainfeature/src/main/AndroidManifest.xml
+++ b/feature/mainfeature/src/main/AndroidManifest.xml
@@ -1,38 +1,40 @@
+ xmlns:tools="http://schemas.android.com/tools">
-
+
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/feature/mainfeature/src/main/java/designsystem/components/bottomsheet/LinkMindBottomSheet.kt b/feature/mainfeature/src/main/java/designsystem/components/bottomsheet/LinkMindBottomSheet.kt
new file mode 100644
index 00000000..0023a237
--- /dev/null
+++ b/feature/mainfeature/src/main/java/designsystem/components/bottomsheet/LinkMindBottomSheet.kt
@@ -0,0 +1,72 @@
+package designsystem.components.bottomsheet
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import androidx.annotation.StringRes
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import designsystem.components.button.state.LinkMIndFullWidthButtonState
+import org.sopt.mainfeature.databinding.BottomSheetDialogLinkmindBinding
+import org.sopt.ui.view.onThrottleClick
+
+class LinkMindBottomSheet(context: Context) {
+ private val binding: BottomSheetDialogLinkmindBinding = BottomSheetDialogLinkmindBinding.inflate(LayoutInflater.from(context))
+ private val bottomSheetDialog: BottomSheetDialog = BottomSheetDialog(context).apply {
+ setContentView(binding.root)
+ }
+
+ init {
+ binding.ivBottomSheetClose.onThrottleClick { dismiss() }
+
+ binding.btnBottomSheet.state = LinkMIndFullWidthButtonState.DISABLE
+
+ bottomSheetDialog.window?.let { window ->
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
+ window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
+ binding.etvBottomSheet.editText.requestFocus()
+ }
+
+ binding.etvBottomSheet.apply {
+ throttleAfterTextChanged {
+ handleTextChange()
+ }
+
+ onClickTextClear {
+ binding.btnBottomSheet.state = LinkMIndFullWidthButtonState.DISABLE
+ }
+ }
+ }
+
+ fun bottomSheetConfirmBtnClick(onClick: () -> Unit) {
+ binding.btnBottomSheet.btnClick {
+ onClick()
+ }
+ }
+
+ private fun handleTextChange() {
+ binding.tvBottomSheetErrorText.visibility = if (showErrorMsg()) View.VISIBLE else View.GONE
+ binding.btnBottomSheet.state =
+ if (!showErrorMsg() && isTextLongEnough()) LinkMIndFullWidthButtonState.ENABLE_PRIMARY else LinkMIndFullWidthButtonState.DISABLE
+ }
+
+ private fun isTextLongEnough() = binding.etvBottomSheet.editText.text.length > 1
+
+ fun setTitle(@StringRes textId: Int) {
+ binding.tvBottomSheetTitle.setText(textId)
+ }
+
+ fun showErrorMsg(): Boolean = binding.etvBottomSheet.editText.text.length > 10
+
+ fun setErroMsg(@StringRes textId: Int) {
+ binding.tvBottomSheetErrorText.setText(textId)
+ }
+
+ fun show() {
+ bottomSheetDialog.show()
+ }
+
+ fun dismiss() {
+ bottomSheetDialog.dismiss()
+ }
+}
diff --git a/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindBlockButton.kt b/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindBlockButton.kt
index c353cb5c..a3321f6a 100644
--- a/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindBlockButton.kt
+++ b/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindBlockButton.kt
@@ -6,7 +6,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
-import designsystem.components.button.state.LinkMindButtonFullWidthState
+import designsystem.components.button.state.LinkMindButtonState
import org.sopt.mainfeature.R
import org.sopt.mainfeature.databinding.ButtonBlockLinkmindBinding
import org.sopt.ui.view.onThrottleClick
@@ -20,33 +20,35 @@ class LinkMindBlockButton @JvmOverloads constructor(
private val binding: ButtonBlockLinkmindBinding
- var state: LinkMindButtonFullWidthState = LinkMindButtonFullWidthState.ENABLE
+ var state: LinkMindButtonState = LinkMindButtonState.ENABLE
set(value) {
field = value
when (field) {
- LinkMindButtonFullWidthState.ENABLE -> {
- setBtnEnable(R.color.black)
+ LinkMindButtonState.ENABLE -> {
+ setBtnEnable(R.drawable.shape_neutrals850_fill_12_rect)
}
- LinkMindButtonFullWidthState.DISABLE -> {
- setBtnDisable(R.color.black)
+ LinkMindButtonState.DISABLE -> {
+ setBtnDisable(R.drawable.shape_neutrals200_fill_12_rect)
}
}
}
- private fun setBtnEnable(textColorResId: Int) {
+ private fun setBtnEnable(drawableResId: Int) {
binding.apply {
clBtnMediumWidthLinkmind.isClickable = true
clBtnMediumWidthLinkmind.isFocusable = true
- tvBtn.setTextColor(ContextCompat.getColor(context, textColorResId))
+ tvBtn.setTextColor(ContextCompat.getColor(context, R.color.white))
+ clBtnMediumWidthLinkmind.setBackgroundResource(drawableResId)
}
}
- private fun setBtnDisable(textColorResId: Int) {
+ private fun setBtnDisable(drawableResId: Int) {
binding.apply {
clBtnMediumWidthLinkmind.isClickable = false
clBtnMediumWidthLinkmind.isFocusable = false
- clBtnMediumWidthLinkmind.setBackgroundColor(ContextCompat.getColor(context, textColorResId))
+ tvBtn.setTextColor(ContextCompat.getColor(context, R.color.white))
+ clBtnMediumWidthLinkmind.setBackgroundResource(drawableResId)
}
}
diff --git a/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindFullWidthButton.kt b/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindFullWidthButton.kt
index b27a2d3a..8e2d0637 100644
--- a/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindFullWidthButton.kt
+++ b/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindFullWidthButton.kt
@@ -6,7 +6,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
-import designsystem.components.button.state.LinkMindButtonFullWidthState
+import designsystem.components.button.state.LinkMIndFullWidthButtonState
import org.sopt.mainfeature.R
import org.sopt.mainfeature.databinding.ButtonFullWidthLinkmindBinding
import org.sopt.ui.view.onThrottleClick
@@ -20,31 +20,37 @@ class LinkMindFullWidthButton @JvmOverloads constructor(
private val binding: ButtonFullWidthLinkmindBinding
- var state: LinkMindButtonFullWidthState = LinkMindButtonFullWidthState.ENABLE
+ var state: LinkMIndFullWidthButtonState = LinkMIndFullWidthButtonState.ENABLE_PRIMARY
set(value) {
field = value
when (field) {
- LinkMindButtonFullWidthState.ENABLE -> {
- setBtnEnable(R.color.black)
+ LinkMIndFullWidthButtonState.ENABLE_PRIMARY -> {
+ setBtnEnable(R.color.primary)
}
- LinkMindButtonFullWidthState.DISABLE -> {
- setBtnDisable(R.color.black)
+ LinkMIndFullWidthButtonState.ENABLE_BLACK -> {
+ setBtnEnable(R.color.neutrals_black)
+ }
+
+ LinkMIndFullWidthButtonState.DISABLE -> {
+ setBtnDisable(R.color.neutrals100)
}
}
}
private fun setBtnEnable(textColorResId: Int) {
binding.apply {
- clBtnFullWidthLinkmind.isClickable = false
- clBtnFullWidthLinkmind.isFocusable = false
- tvBtn.setTextColor(ContextCompat.getColor(context, textColorResId))
+ clBtnFullWidthLinkmind.isClickable = true
+ clBtnFullWidthLinkmind.isFocusable = true
+ tvBtn.setTextColor(ContextCompat.getColor(context, R.color.neutrals_white))
+ clBtnFullWidthLinkmind.setBackgroundColor(ContextCompat.getColor(context, textColorResId))
}
}
private fun setBtnDisable(textColorResId: Int) {
binding.apply {
- clBtnFullWidthLinkmind.isClickable = true
- clBtnFullWidthLinkmind.isFocusable = true
+ clBtnFullWidthLinkmind.isClickable = false
+ clBtnFullWidthLinkmind.isFocusable = false
+ tvBtn.setTextColor(ContextCompat.getColor(context, R.color.neutrals_white))
clBtnFullWidthLinkmind.setBackgroundColor(ContextCompat.getColor(context, textColorResId))
}
}
diff --git a/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindPopUpButton.kt b/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindPopUpButton.kt
index efd7db1c..a6226044 100644
--- a/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindPopUpButton.kt
+++ b/feature/mainfeature/src/main/java/designsystem/components/button/LinkMindPopUpButton.kt
@@ -6,7 +6,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
-import designsystem.components.button.state.LinkMindButtonFullWidthState
+import designsystem.components.button.state.LinkMindButtonState
import org.sopt.mainfeature.R
import org.sopt.mainfeature.databinding.ButtonPopUpLinkmindBinding
import org.sopt.ui.view.onThrottleClick
@@ -20,15 +20,15 @@ class LinkMindPopUpButton @JvmOverloads constructor(
private val binding: ButtonPopUpLinkmindBinding
- var state: LinkMindButtonFullWidthState = LinkMindButtonFullWidthState.ENABLE
+ var state: LinkMindButtonState = LinkMindButtonState.ENABLE
set(value) {
field = value
when (field) {
- LinkMindButtonFullWidthState.ENABLE -> {
+ LinkMindButtonState.ENABLE -> {
setBtnEnable()
}
- LinkMindButtonFullWidthState.DISABLE -> {
+ LinkMindButtonState.DISABLE -> {
setBtnDisable()
}
}
@@ -38,7 +38,8 @@ class LinkMindPopUpButton @JvmOverloads constructor(
binding.apply {
clBtnHalfWidthLinkmind.isClickable = true
clBtnHalfWidthLinkmind.isFocusable = true
- tvBtn.setTextColor(ContextCompat.getColor(context, R.color.black))
+ tvBtn.setTextColor(ContextCompat.getColor(context, R.color.white))
+ clBtnHalfWidthLinkmind.setBackgroundResource(R.drawable.shape_primary_fill_8_rect)
}
}
@@ -46,8 +47,8 @@ class LinkMindPopUpButton @JvmOverloads constructor(
binding.apply {
clBtnHalfWidthLinkmind.isClickable = false
clBtnHalfWidthLinkmind.isFocusable = false
- tvBtn.setTextColor(ContextCompat.getColor(context, R.color.black))
- clBtnHalfWidthLinkmind.setBackgroundColor(ContextCompat.getColor(context, R.color.black))
+ tvBtn.setTextColor(ContextCompat.getColor(context, R.color.neutrals400))
+ clBtnHalfWidthLinkmind.setBackgroundResource(R.drawable.shape_neutrals_fill_8_rect)
}
}
diff --git a/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMIndFullWidthButtonState.kt b/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMIndFullWidthButtonState.kt
new file mode 100644
index 00000000..6f128712
--- /dev/null
+++ b/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMIndFullWidthButtonState.kt
@@ -0,0 +1,4 @@
+package designsystem.components.button.state
+enum class LinkMIndFullWidthButtonState {
+ ENABLE_PRIMARY, ENABLE_BLACK, DISABLE
+}
diff --git a/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMindButtonFullWidthState.kt b/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMindButtonState.kt
similarity index 61%
rename from feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMindButtonFullWidthState.kt
rename to feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMindButtonState.kt
index b092a11d..77aca73e 100644
--- a/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMindButtonFullWidthState.kt
+++ b/feature/mainfeature/src/main/java/designsystem/components/button/state/LinkMindButtonState.kt
@@ -1,5 +1,5 @@
package designsystem.components.button.state
-enum class LinkMindButtonFullWidthState {
+enum class LinkMindButtonState {
ENABLE, DISABLE
}
diff --git a/feature/mainfeature/src/main/java/designsystem/components/dialog/LinkMindDialog.kt b/feature/mainfeature/src/main/java/designsystem/components/dialog/LinkMindDialog.kt
index bd46ba6a..838a76cf 100644
--- a/feature/mainfeature/src/main/java/designsystem/components/dialog/LinkMindDialog.kt
+++ b/feature/mainfeature/src/main/java/designsystem/components/dialog/LinkMindDialog.kt
@@ -10,8 +10,10 @@ import android.view.Window
import android.view.WindowManager
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
+import designsystem.components.button.state.LinkMindButtonState
import org.sopt.mainfeature.databinding.DialogLinkmindBinding
import org.sopt.ui.view.caculateMarignDialog
+import org.sopt.ui.view.onThrottleClick
class LinkMindDialog constructor(private val context: Context) {
@@ -63,11 +65,17 @@ class LinkMindDialog constructor(private val context: Context) {
return this
}
+ fun setCloseBtn() =
+ binding.ivDialogCancel.onThrottleClick {
+ dismiss()
+ }
+
fun setPositiveButton(
@StringRes text: Int,
onClickListener: (view: View) -> (Unit),
): LinkMindDialog {
binding.btnPositive.apply {
+ state = LinkMindButtonState.ENABLE
setText(context.getText(text).toString())
setOnClickListener(onClickListener)
dismiss()
@@ -80,6 +88,7 @@ class LinkMindDialog constructor(private val context: Context) {
onClickListener: (view: View) -> (Unit) = {},
): LinkMindDialog {
binding.btnNegative.apply {
+ state = LinkMindButtonState.DISABLE
visibility = View.VISIBLE
setText(context.getText(text).toString())
setOnClickListener(onClickListener)
diff --git a/feature/mainfeature/src/main/java/designsystem/components/edittext/LinkMindEditTextBox.kt b/feature/mainfeature/src/main/java/designsystem/components/edittext/LinkMindEditTextBox.kt
index c3113720..d562398a 100644
--- a/feature/mainfeature/src/main/java/designsystem/components/edittext/LinkMindEditTextBox.kt
+++ b/feature/mainfeature/src/main/java/designsystem/components/edittext/LinkMindEditTextBox.kt
@@ -33,16 +33,10 @@ class LinkMindEditTextBox @JvmOverloads constructor(
preventFocusClearedByAdjustResize()
}
}
-
- binding.ivCancel.onThrottleClick {
- binding.editText.text.clear()
- }
-
binding.editText.doAfterTextChanged { text ->
binding.ivCancel.visibility =
- if (text.isNullOrEmpty()) View.GONE else View.VISIBLE
+ if (text.isNullOrEmpty()) View.INVISIBLE else View.VISIBLE
}
-
val typedArray =
context.obtainStyledAttributes(attrs, R.styleable.EditTextSearch, defStyleAttr, 0)
@@ -52,6 +46,12 @@ class LinkMindEditTextBox @JvmOverloads constructor(
typedArray.recycle()
}
+ fun onClickTextClear(onClick: () -> Unit) {
+ binding.ivCancel.onThrottleClick {
+ binding.editText.text.clear()
+ onClick()
+ }
+ }
/**
* 실제 사용하면서 사이드 효과 측정할게염
@@ -60,7 +60,7 @@ class LinkMindEditTextBox @JvmOverloads constructor(
binding.editText.doAfterTextChanged { text ->
val isTextEmpty = text.isNullOrEmpty()
- binding.ivCancel.visibility = if (isTextEmpty) View.GONE else View.VISIBLE
+ binding.ivCancel.visibility = if (isTextEmpty) View.INVISIBLE else View.VISIBLE
if (!isTextEmpty) {
editThrottleValue.setDelay(text.toString(), 300L) {
diff --git a/feature/mainfeature/src/main/java/designsystem/components/toast/LinkMindSnackBar.kt b/feature/mainfeature/src/main/java/designsystem/components/toast/LinkMindSnackBar.kt
new file mode 100644
index 00000000..0eff3192
--- /dev/null
+++ b/feature/mainfeature/src/main/java/designsystem/components/toast/LinkMindSnackBar.kt
@@ -0,0 +1,37 @@
+package designsystem.components.toast
+
+import android.content.Context
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.content.ContextCompat
+import com.google.android.material.snackbar.Snackbar
+import org.sopt.mainfeature.R
+import org.sopt.mainfeature.databinding.LayoutToasterSnackbarBinding
+
+fun Context.linkMindSnackBar(view: View, message: String, warning: Boolean = false) {
+ Snackbar.make(view, "", Snackbar.LENGTH_LONG).apply {
+ val snackbarBinding = LayoutToasterSnackbarBinding.inflate(LayoutInflater.from(this@linkMindSnackBar))
+
+ (this.view as Snackbar.SnackbarLayout).apply {
+ removeAllViews()
+ setPadding(0, 0, 0, 0)
+ setBackgroundColor(ContextCompat.getColor(this@linkMindSnackBar, android.R.color.transparent))
+
+ if (warning) snackbarBinding.ivToast.setImageResource(R.drawable.ic_alert_18_white)
+ snackbarBinding.tvToast.text = message
+
+ addView(snackbarBinding.root, 0)
+ }
+
+ snackbarBinding.root.layoutParams = FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ ).apply {
+ gravity = Gravity.CENTER
+ }
+
+ show()
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/ExamDesignActivity.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/ExamDesignActivity.kt
new file mode 100644
index 00000000..184ab30b
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/ExamDesignActivity.kt
@@ -0,0 +1,80 @@
+package org.sopt.mainfeature
+
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+import dagger.hilt.android.AndroidEntryPoint
+import designsystem.components.bottomsheet.LinkMindBottomSheet
+import designsystem.components.button.state.LinkMIndFullWidthButtonState
+import designsystem.components.button.state.LinkMindButtonState
+import designsystem.components.dialog.LinkMindDialog
+import org.sopt.mainfeature.databinding.ActivityDesignComponentsBinding
+import timber.log.Timber
+
+@AndroidEntryPoint
+class ExamDesignActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityDesignComponentsBinding
+
+ private val linkMindDialog by lazy {
+ LinkMindDialog(this)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityDesignComponentsBinding.inflate(layoutInflater)
+
+ binding.progress.apply {
+ setProgressBarMain(63)
+ }
+ binding.btnBlock.apply {
+ state = LinkMindButtonState.ENABLE
+ btnClick {
+ }
+ }
+ binding.etv.apply {
+ onClickTextClear {
+ Timber.d("SaK")
+ }
+ throttleAfterTextChanged {
+ Timber.d("SaK")
+ }
+ }
+
+ binding.btnBlock2.apply {
+ state = LinkMindButtonState.DISABLE
+ }
+ binding.btnFull.apply {
+ state = LinkMIndFullWidthButtonState.ENABLE_PRIMARY
+ }
+ binding.btnFull1.apply {
+ state = LinkMIndFullWidthButtonState.ENABLE_BLACK
+ }
+ binding.btnFull2.apply {
+ state = LinkMIndFullWidthButtonState.DISABLE
+ }
+ setContentView(binding.root)
+ showRevokeCommonDialog()
+
+ val linkMindBottomSheet = LinkMindBottomSheet(this)
+ linkMindBottomSheet.show()
+ linkMindBottomSheet.apply {
+ setTitle(R.string.text_clip)
+ setErroMsg(R.string.text_clip)
+ bottomSheetConfirmBtnClick {
+ Log.d("test", "test")
+ }
+ }
+ }
+
+ private fun showRevokeCommonDialog() {
+ linkMindDialog.setTitle(R.string.text_home)
+ .setSubtitle(R.string.text_clip)
+ .setNegativeButton(R.string.text_home) {
+ linkMindDialog.dismiss()
+ }
+ .setPositiveButton(R.string.text_home) {
+ linkMindDialog.dismiss()
+ }
+ .show()
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/SplashActivity.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/SplashActivity.kt
new file mode 100644
index 00000000..d3c400cc
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/SplashActivity.kt
@@ -0,0 +1,15 @@
+package org.sopt.mainfeature
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import org.sopt.mainfeature.onboarding.LoginActivity
+
+class SplashActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val intent = Intent(this, LoginActivity::class.java)
+ startActivity(intent)
+ finish()
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/onboarding/LoginActivity.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/onboarding/LoginActivity.kt
index f23b5174..9079a4a5 100644
--- a/feature/mainfeature/src/main/java/org/sopt/mainfeature/onboarding/LoginActivity.kt
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/onboarding/LoginActivity.kt
@@ -8,14 +8,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
-import designsystem.components.dialog.LinkMindDialog
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.sopt.datastore.datastore.SecurityDataStore
import org.sopt.mainfeature.MainActivity
-import org.sopt.mainfeature.R
import org.sopt.mainfeature.databinding.ActivityLoginBinding
import org.sopt.oauthdomain.interactor.OAuthInteractor
import org.sopt.ui.context.toast
@@ -33,9 +31,6 @@ class LoginActivity : AppCompatActivity() {
@Inject
lateinit var dataStore: SecurityDataStore
- private val linkMindDialog by lazy {
- LinkMindDialog(this)
- }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
@@ -43,19 +38,8 @@ class LoginActivity : AppCompatActivity() {
initCheckAutoLogin()
initKakaoLoginBtnClickListener()
initAuthStateObserver()
- showRevokeCommonDialog()
- }
- private fun showRevokeCommonDialog() {
- linkMindDialog.setTitle(R.string.text_home)
- .setSubtitle(R.string.text_clip)
- .setNegativeButton(R.string.text_home) {
- linkMindDialog.dismiss()
- }
- .setPositiveButton(R.string.text_home) {
- linkMindDialog.dismiss()
- }
- .show()
}
+
private fun initCheckAutoLogin() {
lifecycleScope.launch {
if (dataStore.flowAutoLogin().first()) {
@@ -89,6 +73,7 @@ class LoginActivity : AppCompatActivity() {
is UiState.Failure -> {
this@LoginActivity.toast(state.msg)
}
+
is UiState.Loading -> {}
else -> {}
}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CenterSnapHelper.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CenterSnapHelper.kt
new file mode 100644
index 00000000..5b1cd1ce
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CenterSnapHelper.kt
@@ -0,0 +1,36 @@
+package org.sopt.mainfeature.timer
+
+import android.view.View
+import androidx.recyclerview.widget.LinearSnapHelper
+import androidx.recyclerview.widget.OrientationHelper
+import androidx.recyclerview.widget.RecyclerView
+
+class CenterSnapHelper : LinearSnapHelper() {
+
+ override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray? {
+ val out = IntArray(2)
+ if (layoutManager.canScrollHorizontally()) {
+ out[0] = distanceToCenter(layoutManager, targetView, OrientationHelper.createHorizontalHelper(layoutManager))
+ } else {
+ out[0] = 0
+ }
+
+ if (layoutManager.canScrollVertically()) {
+ out[1] = distanceToCenter(layoutManager, targetView, OrientationHelper.createVerticalHelper(layoutManager))
+ } else {
+ out[1] = 0
+ }
+ return out
+ }
+
+ private fun distanceToCenter(layoutManager: RecyclerView.LayoutManager, targetView: View, helper: OrientationHelper): Int {
+ val childCenter = helper.getDecoratedStart(targetView) + helper.getDecoratedMeasurement(targetView) / 2
+ val containerCenter: Int
+ containerCenter = if (layoutManager.clipToPadding) {
+ helper.startAfterPadding + helper.totalSpace / 2
+ } else {
+ helper.end / 2
+ }
+ return childCenter - containerCenter
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CompleteTimerAdapter.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CompleteTimerAdapter.kt
new file mode 100644
index 00000000..75ee6af6
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CompleteTimerAdapter.kt
@@ -0,0 +1,30 @@
+package org.sopt.mainfeature.timer
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import org.sopt.mainfeature.databinding.ItemTimerCompleteBinding
+import org.sopt.mainfeature.timer.dummymodel.Timer
+import org.sopt.ui.view.ItemDiffCallback
+
+class CompleteTimerAdapter(
+ private val onClicked: (Timer) -> Unit,
+) : ListAdapter(DiffUtil) {
+ override fun onBindViewHolder(holder: CompleteTimerViewHolder, position: Int) {
+ holder.onBind(getItem(position))
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CompleteTimerViewHolder {
+ return CompleteTimerViewHolder(
+ ItemTimerCompleteBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+ onClicked,
+ )
+ }
+
+ companion object {
+ private val DiffUtil = ItemDiffCallback(
+ onItemsTheSame = { old, new -> old.id == new.id },
+ onContentsTheSame = { old, new -> old == new },
+ )
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CompleteTimerViewHolder.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CompleteTimerViewHolder.kt
new file mode 100644
index 00000000..e53b71a3
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/CompleteTimerViewHolder.kt
@@ -0,0 +1,30 @@
+package org.sopt.mainfeature.timer
+
+import androidx.recyclerview.widget.RecyclerView
+import org.sopt.mainfeature.databinding.ItemTimerCompleteBinding
+import org.sopt.mainfeature.timer.dummymodel.Timer
+
+class CompleteTimerViewHolder(
+ private val binding: ItemTimerCompleteBinding,
+ private val onClicked: (Timer) -> Unit,
+) : RecyclerView.ViewHolder(binding.root) {
+ fun onBind(data: Timer?) {
+ if (data == null) return
+ with(binding) {
+ val ampm = if (data.am) AM else PM
+ val minute = if (data.minute >= 10) data.minute.toString() else MINUTE_FORMAT.format(data.minute)
+ tvItemTimerCompleteCategory.text = data.category
+ tvItemTimerCompleteTime.text = TIME_FORMAT.format(data.day, ampm, data.hour, minute)
+ tvItemTimerCompleteRead.setOnClickListener {
+ onClicked(data)
+ }
+ }
+ }
+
+ companion object {
+ private const val TIME_FORMAT = "%s %s %d:%s"
+ private const val MINUTE_FORMAT = "0%d"
+ private const val AM = "오전"
+ private const val PM = "오후"
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/ExampleTimePickerFragment.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/ExampleTimePickerFragment.kt
new file mode 100644
index 00000000..b5c4b3f7
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/ExampleTimePickerFragment.kt
@@ -0,0 +1,124 @@
+package org.sopt.mainfeature.timer
+
+import android.os.Bundle
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import org.sopt.mainfeature.databinding.FragmentExampleTimePickerBinding
+import org.sopt.mainfeature.timer.dummymodel.PickerItem
+import org.sopt.ui.base.BindingFragment
+
+class ExampleTimePickerFragment : BindingFragment({ FragmentExampleTimePickerBinding.inflate(it) }) {
+ private lateinit var textAdapter: TextAdapter
+ private lateinit var numberAdapter1: NumberAdapter
+ private lateinit var numberAdapter2: NumberAdapter
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ setupRecyclerViews()
+ }
+
+ private fun setupRecyclerViews() {
+ val list1 = generateList1()
+ val list2 = generateNumberList(1, 12)
+ val list3 = generateNumberList(0, 59)
+ textAdapter = TextAdapter()
+ numberAdapter1 = NumberAdapter()
+ numberAdapter2 = NumberAdapter()
+ setupRecyclerView2(binding.rv1, list1, textAdapter)
+ setupRecyclerView1(binding.rv2, list2, numberAdapter1)
+ setupRecyclerView1(binding.rv3, list3, numberAdapter2)
+ }
+
+ private fun generateList1() = listOf(PickerItem("", false), PickerItem("오전", true), PickerItem("오후", false), PickerItem("", false))
+
+ private fun generateNumberList(start: Int, end: Int): MutableList {
+ val list = mutableListOf()
+ list.add(PickerItem(end.toString(), false))
+ list.add(PickerItem(start.toString(), true))
+ for (i in start + 1..end - 1) {
+ list.add(PickerItem(i.toString(), false))
+ }
+ return list
+ }
+
+ private fun setupRecyclerView1(recyclerView: RecyclerView, list: List, numberAdapter: NumberAdapter) {
+ val snapHolder = CenterSnapHelper().apply {
+ attachToRecyclerView(recyclerView)
+ }
+
+ with(numberAdapter) {
+ submitList(list)
+ recyclerView.adapter = this
+ numberAdapter
+ }
+
+ recyclerView.itemAnimator = null
+ recyclerView.scrollToPosition(numberAdapter.getMiddlePosition())
+ recyclerView.addOnScrollListener(
+ object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ super.onScrollStateChanged(recyclerView, newState)
+ val centerView = snapHolder.findSnapView(recyclerView.layoutManager)
+ val pos = recyclerView.layoutManager?.getPosition(centerView!!)
+ val newList: MutableList = numberAdapter.currentList.mapIndexed { index, item ->
+ item.copy(isSelected = index == pos!! % numberAdapter.currentList.size)
+ }.toMutableList()
+ numberAdapter.run {
+ submitList(newList)
+ notifyDataSetChanged()
+ }
+ }
+ },
+ )
+ recyclerView.onFlingListener = object : RecyclerView.OnFlingListener() {
+ override fun onFling(velocityX: Int, velocityY: Int): Boolean {
+ val centerView = snapHolder.findSnapView(recyclerView.layoutManager)
+ val pos = recyclerView.layoutManager?.getPosition(centerView!!)
+ val newList: MutableList = numberAdapter.currentList.mapIndexed { index, item ->
+ item.copy(isSelected = index == pos!! % numberAdapter.currentList.size)
+ }.toMutableList()
+ numberAdapter.run {
+ submitList(newList)
+ notifyDataSetChanged()
+ }
+ return false
+ }
+ }
+ }
+
+ private fun setupRecyclerView2(recyclerView: RecyclerView, list: List, textAdapter: TextAdapter) {
+ val snapHolder = CenterSnapHelper().apply {
+ attachToRecyclerView(recyclerView)
+ }
+
+ with(textAdapter) {
+ submitList(list)
+ recyclerView.adapter = this
+ textAdapter
+ }
+
+ recyclerView.itemAnimator = null
+ recyclerView.addOnScrollListener(
+ object : RecyclerView.OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ super.onScrollStateChanged(recyclerView, newState)
+ val centerView = snapHolder.findSnapView(recyclerView.layoutManager)
+ val pos = recyclerView.layoutManager?.getPosition(centerView!!)
+ val newList: MutableList = textAdapter.currentList.mapIndexed { index, item ->
+ item.copy(isSelected = index == pos)
+ }.toMutableList()
+ textAdapter.submitList(newList)
+ }
+ },
+ )
+ recyclerView.onFlingListener = object : RecyclerView.OnFlingListener() {
+ override fun onFling(velocityX: Int, velocityY: Int): Boolean {
+ val centerView = snapHolder.findSnapView(recyclerView.layoutManager)
+ val pos = recyclerView.layoutManager?.getPosition(centerView!!)
+ val newList: MutableList = textAdapter.currentList.mapIndexed { index, item ->
+ item.copy(isSelected = index == pos)
+ }.toMutableList()
+ textAdapter.submitList(newList)
+ return false
+ }
+ }
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/NumberAdapter.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/NumberAdapter.kt
new file mode 100644
index 00000000..a9f1d757
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/NumberAdapter.kt
@@ -0,0 +1,31 @@
+package org.sopt.mainfeature.timer
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import org.sopt.mainfeature.databinding.ItemNumberPickerBinding
+import org.sopt.mainfeature.timer.dummymodel.PickerItem
+import org.sopt.ui.view.ItemDiffCallback
+import kotlin.math.round
+
+class NumberAdapter : ListAdapter(DiffUtil) {
+ override fun onBindViewHolder(holder: NumberViewHolder, position: Int) {
+ val realPosition = position % currentList.size
+ holder.onBind(getItem(realPosition))
+ }
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NumberViewHolder {
+ return NumberViewHolder(
+ ItemNumberPickerBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+ )
+ }
+ override fun getItemCount(): Int = Int.MAX_VALUE
+
+ fun getMiddlePosition() =
+ round(Int.MAX_VALUE / 2.0).toInt() - round(Int.MAX_VALUE / 2.0).toInt() % currentList.size
+ companion object {
+ private val DiffUtil = ItemDiffCallback(
+ onItemsTheSame = { old, new -> old == new },
+ onContentsTheSame = { old, new -> old == new },
+ )
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/NumberViewHolder.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/NumberViewHolder.kt
new file mode 100644
index 00000000..411948be
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/NumberViewHolder.kt
@@ -0,0 +1,22 @@
+package org.sopt.mainfeature.timer
+
+import androidx.recyclerview.widget.RecyclerView
+import org.sopt.mainfeature.R
+import org.sopt.mainfeature.databinding.ItemNumberPickerBinding
+import org.sopt.mainfeature.timer.dummymodel.PickerItem
+
+class NumberViewHolder(
+ val binding: ItemNumberPickerBinding,
+) : RecyclerView.ViewHolder(binding.root) {
+ fun onBind(data: PickerItem?) {
+ if (data == null) return
+ with(binding) {
+ if (data.isSelected) {
+ tvText.setTextAppearance(R.style.Typography_suit_bold_18)
+ } else {
+ tvText.setTextAppearance(R.style.Typography_suit_regular_16)
+ }
+ tvText.text = data.text
+ }
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TextAdapter.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TextAdapter.kt
new file mode 100644
index 00000000..b92a9d3b
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TextAdapter.kt
@@ -0,0 +1,25 @@
+package org.sopt.mainfeature.timer
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import org.sopt.mainfeature.databinding.ItemNumberPickerBinding
+import org.sopt.mainfeature.timer.dummymodel.PickerItem
+import org.sopt.ui.view.ItemDiffCallback
+
+class TextAdapter : ListAdapter(DiffUtil) {
+ override fun onBindViewHolder(holder: NumberViewHolder, position: Int) {
+ holder.onBind(getItem(position))
+ }
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NumberViewHolder {
+ return NumberViewHolder(
+ ItemNumberPickerBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+ )
+ }
+ companion object {
+ private val DiffUtil = ItemDiffCallback(
+ onItemsTheSame = { old, new -> old == new },
+ onContentsTheSame = { old, new -> old == new },
+ )
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TextViewHolder.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TextViewHolder.kt
new file mode 100644
index 00000000..966550ce
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TextViewHolder.kt
@@ -0,0 +1,22 @@
+package org.sopt.mainfeature.timer
+
+import androidx.recyclerview.widget.RecyclerView
+import org.sopt.mainfeature.R
+import org.sopt.mainfeature.databinding.ItemNumberPickerBinding
+import org.sopt.mainfeature.timer.dummymodel.PickerItem
+
+class TextViewHolder(
+ val binding: ItemNumberPickerBinding,
+) : RecyclerView.ViewHolder(binding.root) {
+ fun onBind(data: PickerItem?) {
+ if (data == null) return
+ with(binding) {
+ if (data.isSelected) {
+ tvText.setTextAppearance(R.style.Typography_suit_bold_18)
+ } else {
+ tvText.setTextAppearance(R.style.Typography_suit_regular_16)
+ }
+ tvText.text = data.text
+ }
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TimerFragment.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TimerFragment.kt
index d2adf09e..14f3d79e 100644
--- a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TimerFragment.kt
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/TimerFragment.kt
@@ -1,61 +1,87 @@
package org.sopt.mainfeature.timer
+import android.content.res.ColorStateList
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.core.view.isGone
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
+import androidx.fragment.app.commit
import org.sopt.mainfeature.R
+import org.sopt.mainfeature.databinding.FragmentTimerBinding
+import org.sopt.mainfeature.timer.dummymodel.Timer
+import org.sopt.mainfeature.timer.modifytimer.ModifyTimerBottomSheetFragment
+import org.sopt.ui.fragment.colorOf
+import org.sopt.ui.fragment.snackBar
-// TODO: Rename parameter arguments, choose names that match
-// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
-private const val ARG_PARAM1 = "param1"
-private const val ARG_PARAM2 = "param2"
-
-/**
- * A simple [Fragment] subclass.
- * Use the [TimerFragment.newInstance] factory method to
- * create an instance of this fragment.
- */
class TimerFragment : Fragment() {
- // TODO: Rename and change types of parameters
- private var param1: String? = null
- private var param2: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- arguments?.let {
- param1 = it.getString(ARG_PARAM1)
- param2 = it.getString(ARG_PARAM2)
+ private var _binding: FragmentTimerBinding? = null
+ private val binding
+ get() = requireNotNull(_binding) {
}
- }
-
+ private lateinit var completeTimerAdapter: CompleteTimerAdapter
+ private lateinit var waitTimerAdapter: WaitTimerAdapter
+ var timerExist = true
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.fragment_timer, container, false)
+ _binding = FragmentTimerBinding.inflate(layoutInflater)
+ return binding.root
}
- companion object {
- /**
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @param param1 Parameter 1.
- * @param param2 Parameter 2.
- * @return A new instance of fragment TimerFragment.
- */
- // TODO: Rename and change types and number of parameters
- @JvmStatic
- fun newInstance(param1: String, param2: String) =
- TimerFragment().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM1, param1)
- putString(ARG_PARAM2, param2)
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.tvTimerTitle.setOnClickListener {
+ if (timerExist) {
+ binding.svTimerExist.isVisible = true
+ binding.llTimerNotExist.isGone = true
+ timerExist = false
+ } else {
+ binding.svTimerExist.isGone = true
+ binding.llTimerNotExist.isVisible = true
+ timerExist = true
}
+ }
+
+ completeTimerAdapter = CompleteTimerAdapter({ snackBar(binding.root, { "안녕" }) })
+ waitTimerAdapter = WaitTimerAdapter({}, { ModifyTimerBottomSheetFragment.newInstance(it.id).show(parentFragmentManager, this.tag) })
+
+ val list = listOf(
+ Timer(1, "네이버", "일요일", true, 8, 37),
+ Timer(1, "네이버", "일요일", true, 8, 37),
+ )
+ // val list = emptyList()
+ completeTimerAdapter.submitList(list)
+ waitTimerAdapter.submitList(list)
+ binding.tvTimerCompleteCount.text = list.count().toString()
+ if (list.count() != 0) {
+ val color = colorOf(R.color.primary)
+ val textColor = colorOf(R.color.white)
+ val colorStateList = ColorStateList.valueOf(color)
+ binding.flTimerCompleteCount.backgroundTintList = colorStateList
+ binding.tvTimerCompleteCount.setTextColor(textColor)
+ binding.tvTimerNotComplete.isGone = true
+ } else {
+ binding.tvTimerNotComplete.isVisible = true
+ }
+ binding.rvTimerComplete.adapter = completeTimerAdapter
+ binding.rvTimerWait.adapter = waitTimerAdapter
+
+ binding.ivTimerPlus.setOnClickListener {
+ parentFragmentManager.commit {
+ val exampleTimePickerFragment = ExampleTimePickerFragment()
+ replace(R.id.fcv_main, exampleTimePickerFragment)
+ }
+ }
+ }
+
+ override fun onDestroyView() {
+ _binding = null
+ super.onDestroyView()
}
}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/WaitTimerAdapter.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/WaitTimerAdapter.kt
new file mode 100644
index 00000000..acd797e8
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/WaitTimerAdapter.kt
@@ -0,0 +1,32 @@
+package org.sopt.mainfeature.timer
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import org.sopt.mainfeature.databinding.ItemTimerWaitBinding
+import org.sopt.mainfeature.timer.dummymodel.Timer
+import org.sopt.ui.view.ItemDiffCallback
+
+class WaitTimerAdapter(
+ private val onToggleClicked: (Timer) -> Unit,
+ private val onMoreClicked: (Timer) -> Unit,
+) : ListAdapter(DiffUtil) {
+ override fun onBindViewHolder(holder: WaitTimerViewHolder, position: Int) {
+ holder.onBind(getItem(position))
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WaitTimerViewHolder {
+ return WaitTimerViewHolder(
+ ItemTimerWaitBinding.inflate(LayoutInflater.from(parent.context), parent, false),
+ onToggleClicked,
+ onMoreClicked,
+ )
+ }
+
+ companion object {
+ private val DiffUtil = ItemDiffCallback(
+ onItemsTheSame = { old, new -> old.id == new.id },
+ onContentsTheSame = { old, new -> old == new },
+ )
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/WaitTimerViewHolder.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/WaitTimerViewHolder.kt
new file mode 100644
index 00000000..280f059b
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/WaitTimerViewHolder.kt
@@ -0,0 +1,36 @@
+package org.sopt.mainfeature.timer
+
+import androidx.recyclerview.widget.RecyclerView
+import org.sopt.mainfeature.databinding.ItemTimerWaitBinding
+import org.sopt.mainfeature.timer.dummymodel.Timer
+
+class WaitTimerViewHolder(
+ private val binding: ItemTimerWaitBinding,
+ private val onToggleClicked: (Timer) -> Unit,
+ private val onMoreClicked: (Timer) -> Unit,
+) : RecyclerView.ViewHolder(binding.root) {
+
+ fun onBind(data: Timer?) {
+ if (data == null) return
+ with(binding) {
+ tvItemTimerWaitCategory.text = data.category
+ val ampm = if (data.am) AM else PM
+ val minute = if (data.minute != 0) MINUTE_FORMAT.format(data.minute) else ""
+ tvItemTimerWaitWhen.text = TIME_FORMAT.format(data.day, ampm, data.hour, minute)
+
+ tgItemTimerWait.setOnClickListener {
+ onToggleClicked(data)
+ }
+ ivItemTimerWaitMore.setOnClickListener {
+ onMoreClicked(data)
+ }
+ }
+ }
+
+ companion object {
+ private const val TIME_FORMAT = "매주 %s %s %d시%s마다"
+ private const val MINUTE_FORMAT = " %d분"
+ private const val AM = "오전"
+ private const val PM = "오후"
+ }
+}
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/dummymodel/PickerItem.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/dummymodel/PickerItem.kt
new file mode 100644
index 00000000..db555807
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/dummymodel/PickerItem.kt
@@ -0,0 +1,6 @@
+package org.sopt.mainfeature.timer.dummymodel
+
+data class PickerItem(
+ val text: String,
+ val isSelected: Boolean,
+)
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/dummymodel/Timer.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/dummymodel/Timer.kt
new file mode 100644
index 00000000..1b222f73
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/dummymodel/Timer.kt
@@ -0,0 +1,10 @@
+package org.sopt.mainfeature.timer.dummymodel
+
+data class Timer(
+ val id: Int,
+ val category: String,
+ val day: String,
+ val am: Boolean,
+ val hour: Int,
+ val minute: Int,
+)
diff --git a/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/modifytimer/ModifyTimerBottomSheetFragment.kt b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/modifytimer/ModifyTimerBottomSheetFragment.kt
new file mode 100644
index 00000000..ae7ac2bf
--- /dev/null
+++ b/feature/mainfeature/src/main/java/org/sopt/mainfeature/timer/modifytimer/ModifyTimerBottomSheetFragment.kt
@@ -0,0 +1,33 @@
+package org.sopt.mainfeature.timer.modifytimer
+
+import android.os.Bundle
+import android.view.View
+import org.sopt.mainfeature.databinding.FragmentModifyTimerBottomSheetBinding
+import org.sopt.ui.base.BindingBottomSheetDialogFragment
+
+class ModifyTimerBottomSheetFragment :
+ BindingBottomSheetDialogFragment({ FragmentModifyTimerBottomSheetBinding.inflate(it) }) {
+ var id: Int? = null
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.ivModifyTimerClose.setOnClickListener {
+ dismiss()
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ id = arguments?.getInt("id")
+ }
+ companion object {
+ fun newInstance(id: Int): ModifyTimerBottomSheetFragment {
+ val args = Bundle().apply {
+ putInt("id", id)
+ }
+ return ModifyTimerBottomSheetFragment().apply {
+ arguments = args
+ }
+ }
+ }
+}
diff --git a/feature/mainfeature/src/main/res/drawable/ic_alarm_24.xml b/feature/mainfeature/src/main/res/drawable/ic_alarm_24.xml
new file mode 100644
index 00000000..3754e762
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_alarm_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_alarm_disabled_20.xml b/feature/mainfeature/src/main/res/drawable/ic_alarm_disabled_20.xml
new file mode 100644
index 00000000..58e15972
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_alarm_disabled_20.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_alert_18_white.xml b/feature/mainfeature/src/main/res/drawable/ic_alert_18_white.xml
new file mode 100644
index 00000000..452fd619
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_alert_18_white.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_check_18_white.xml b/feature/mainfeature/src/main/res/drawable/ic_check_18_white.xml
new file mode 100644
index 00000000..0ea78935
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_check_18_white.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_clip_unclicked.xml b/feature/mainfeature/src/main/res/drawable/ic_clip_unclicked.xml
new file mode 100644
index 00000000..3f5592a1
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_clip_unclicked.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_close_20.xml b/feature/mainfeature/src/main/res/drawable/ic_close_20.xml
new file mode 100644
index 00000000..b4529451
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_close_20.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_close_24.xml b/feature/mainfeature/src/main/res/drawable/ic_close_24.xml
index cde145a5..9933b993 100644
--- a/feature/mainfeature/src/main/res/drawable/ic_close_24.xml
+++ b/feature/mainfeature/src/main/res/drawable/ic_close_24.xml
@@ -8,13 +8,13 @@
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
- android:strokeColor="#444444"
+ android:strokeColor="#4C4C4C"
android:strokeLineCap="round"/>
diff --git a/feature/mainfeature/src/main/res/drawable/ic_ellipse_18.xml b/feature/mainfeature/src/main/res/drawable/ic_ellipse_18.xml
new file mode 100644
index 00000000..b00cd2d5
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_ellipse_18.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_home_unclicked.xml b/feature/mainfeature/src/main/res/drawable/ic_home_unclicked.xml
new file mode 100644
index 00000000..f1bc01c5
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_home_unclicked.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_more_24.xml b/feature/mainfeature/src/main/res/drawable/ic_more_24.xml
new file mode 100644
index 00000000..24045e52
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_more_24.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_my_unclicked.xml b/feature/mainfeature/src/main/res/drawable/ic_my_unclicked.xml
new file mode 100644
index 00000000..67f0d5e1
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_my_unclicked.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_plus_24.xml b/feature/mainfeature/src/main/res/drawable/ic_plus_24.xml
new file mode 100644
index 00000000..1aed0500
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_plus_24.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/ic_timer_unclicked.xml b/feature/mainfeature/src/main/res/drawable/ic_timer_unclicked.xml
new file mode 100644
index 00000000..24c71c91
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/ic_timer_unclicked.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/img_timer_none.png b/feature/mainfeature/src/main/res/drawable/img_timer_none.png
new file mode 100644
index 00000000..2309b097
Binary files /dev/null and b/feature/mainfeature/src/main/res/drawable/img_timer_none.png differ
diff --git a/feature/mainfeature/src/main/res/drawable/progress_bar_horizontal.xml b/feature/mainfeature/src/main/res/drawable/progress_bar_horizontal.xml
index e57518fb..89974156 100644
--- a/feature/mainfeature/src/main/res/drawable/progress_bar_horizontal.xml
+++ b/feature/mainfeature/src/main/res/drawable/progress_bar_horizontal.xml
@@ -3,7 +3,7 @@
-
-
+
@@ -11,8 +11,8 @@
-
+
-
\ No newline at end of file
+
diff --git a/feature/mainfeature/src/main/res/drawable/sel_bnv_clip.xml b/feature/mainfeature/src/main/res/drawable/sel_bnv_clip.xml
new file mode 100644
index 00000000..62303d42
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/sel_bnv_clip.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/sel_bnv_home.xml b/feature/mainfeature/src/main/res/drawable/sel_bnv_home.xml
new file mode 100644
index 00000000..e0fd41e4
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/sel_bnv_home.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/sel_bnv_my.xml b/feature/mainfeature/src/main/res/drawable/sel_bnv_my.xml
new file mode 100644
index 00000000..6b3dfcb6
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/sel_bnv_my.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/sel_bnv_text_color.xml b/feature/mainfeature/src/main/res/drawable/sel_bnv_text_color.xml
new file mode 100644
index 00000000..cc71e979
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/sel_bnv_text_color.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/sel_bnv_timer.xml b/feature/mainfeature/src/main/res/drawable/sel_bnv_timer.xml
new file mode 100644
index 00000000..d037ffcd
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/sel_bnv_timer.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_gray_fill_12_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_gray_fill_12_rect.xml
new file mode 100644
index 00000000..afc68716
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_gray_fill_12_rect.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_neutrals200_fill_12_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_neutrals200_fill_12_rect.xml
new file mode 100644
index 00000000..ddf1993b
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_neutrals200_fill_12_rect.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_neutrals850_fill_12_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_neutrals850_fill_12_rect.xml
new file mode 100644
index 00000000..d2e03697
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_neutrals850_fill_12_rect.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_12_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_12_rect.xml
new file mode 100644
index 00000000..7e887629
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_12_rect.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_8_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_8_rect.xml
new file mode 100644
index 00000000..4a905979
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_8_rect.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_top20_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_top20_rect.xml
new file mode 100644
index 00000000..f9de4df9
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_neutrals_fill_top20_rect.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_primary_fill_4_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_primary_fill_4_rect.xml
new file mode 100644
index 00000000..e02acda3
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_primary_fill_4_rect.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_primary_fill_8_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_primary_fill_8_rect.xml
new file mode 100644
index 00000000..5a9aefbc
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_primary_fill_8_rect.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/drawable/shape_white_fill_12_rect.xml b/feature/mainfeature/src/main/res/drawable/shape_white_fill_12_rect.xml
new file mode 100644
index 00000000..7241ec2c
--- /dev/null
+++ b/feature/mainfeature/src/main/res/drawable/shape_white_fill_12_rect.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/activity_design_components.xml b/feature/mainfeature/src/main/res/layout/activity_design_components.xml
new file mode 100644
index 00000000..edf77706
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/activity_design_components.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/activity_main.xml b/feature/mainfeature/src/main/res/layout/activity_main.xml
index 81ff76ad..ed1a79e2 100644
--- a/feature/mainfeature/src/main/res/layout/activity_main.xml
+++ b/feature/mainfeature/src/main/res/layout/activity_main.xml
@@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/button_block_linkmind.xml b/feature/mainfeature/src/main/res/layout/button_block_linkmind.xml
index 208180c0..c4d032e7 100644
--- a/feature/mainfeature/src/main/res/layout/button_block_linkmind.xml
+++ b/feature/mainfeature/src/main/res/layout/button_block_linkmind.xml
@@ -2,21 +2,22 @@
+ android:layout_marginHorizontal="20dp"
+ android:paddingVertical="21dp">
diff --git a/feature/mainfeature/src/main/res/layout/button_full_width_linkmind.xml b/feature/mainfeature/src/main/res/layout/button_full_width_linkmind.xml
index cf4cfdca..543097c3 100644
--- a/feature/mainfeature/src/main/res/layout/button_full_width_linkmind.xml
+++ b/feature/mainfeature/src/main/res/layout/button_full_width_linkmind.xml
@@ -16,6 +16,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
+ android:textAppearance="@style/Typography.suit.bold_16"
app:layout_constraintTop_toTopOf="parent"
tools:text="BTN" />
diff --git a/feature/mainfeature/src/main/res/layout/button_pop_up_linkmind.xml b/feature/mainfeature/src/main/res/layout/button_pop_up_linkmind.xml
index 13f0cde2..43fb1597 100644
--- a/feature/mainfeature/src/main/res/layout/button_pop_up_linkmind.xml
+++ b/feature/mainfeature/src/main/res/layout/button_pop_up_linkmind.xml
@@ -9,18 +9,19 @@
android:id="@+id/cl_btn_half_width_linkmind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingVertical="14dp"
- android:paddingHorizontal="44dp">
+ android:paddingHorizontal="44dp"
+ android:paddingVertical="14dp">
diff --git a/feature/mainfeature/src/main/res/layout/dialog_linkmind.xml b/feature/mainfeature/src/main/res/layout/dialog_linkmind.xml
index fcccde9c..369ecf41 100644
--- a/feature/mainfeature/src/main/res/layout/dialog_linkmind.xml
+++ b/feature/mainfeature/src/main/res/layout/dialog_linkmind.xml
@@ -3,26 +3,39 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/black"
- android:padding="24dp">
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_neutrals_fill_12_rect"
+ android:paddingHorizontal="24dp"
+ android:paddingTop="20dp"
+ android:paddingBottom="24dp">
+
+
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_neutrals_fill_12_rect">
@@ -25,7 +26,7 @@
android:layout_height="wrap_content"
android:padding="8dp"
android:src="@drawable/ic_cancle_24"
- android:visibility="gone"
+ android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
diff --git a/feature/mainfeature/src/main/res/layout/edit_text_search_box_linkmind.xml b/feature/mainfeature/src/main/res/layout/edit_text_search_box_linkmind.xml
index 79379035..3ecf2663 100644
--- a/feature/mainfeature/src/main/res/layout/edit_text_search_box_linkmind.xml
+++ b/feature/mainfeature/src/main/res/layout/edit_text_search_box_linkmind.xml
@@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_neutrals_fill_12_rect">
diff --git a/feature/mainfeature/src/main/res/layout/fragment_example_time_picker.xml b/feature/mainfeature/src/main/res/layout/fragment_example_time_picker.xml
new file mode 100644
index 00000000..1648cca6
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/fragment_example_time_picker.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/fragment_modify_timer_bottom_sheet.xml b/feature/mainfeature/src/main/res/layout/fragment_modify_timer_bottom_sheet.xml
new file mode 100644
index 00000000..fe60400f
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/fragment_modify_timer_bottom_sheet.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/fragment_timer.xml b/feature/mainfeature/src/main/res/layout/fragment_timer.xml
index 503353e9..c72b9e77 100644
--- a/feature/mainfeature/src/main/res/layout/fragment_timer.xml
+++ b/feature/mainfeature/src/main/res/layout/fragment_timer.xml
@@ -1,13 +1,309 @@
-
+
+
+ android:layout_height="56dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
-
+
+
+
+
+
+
+
+
+
+ android:layout_height="wrap_content"
+ android:background="@drawable/shape_gray_fill_12_rect"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/item_number_picker.xml b/feature/mainfeature/src/main/res/layout/item_number_picker.xml
new file mode 100644
index 00000000..295cf4fb
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/item_number_picker.xml
@@ -0,0 +1,10 @@
+
+
diff --git a/feature/mainfeature/src/main/res/layout/item_timer_complete.xml b/feature/mainfeature/src/main/res/layout/item_timer_complete.xml
new file mode 100644
index 00000000..220769d7
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/item_timer_complete.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/item_timer_wait.xml b/feature/mainfeature/src/main/res/layout/item_timer_wait.xml
new file mode 100644
index 00000000..89556102
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/item_timer_wait.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/layout/layout_toaster_snackbar.xml b/feature/mainfeature/src/main/res/layout/layout_toaster_snackbar.xml
new file mode 100644
index 00000000..b343cd82
--- /dev/null
+++ b/feature/mainfeature/src/main/res/layout/layout_toaster_snackbar.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/mainfeature/src/main/res/menu/main_nav_menu.xml b/feature/mainfeature/src/main/res/menu/main_nav_menu.xml
index e0ebdbc0..4f6e41b1 100644
--- a/feature/mainfeature/src/main/res/menu/main_nav_menu.xml
+++ b/feature/mainfeature/src/main/res/menu/main_nav_menu.xml
@@ -1,27 +1,33 @@
-