diff --git a/android/app/src/main/java/com/created/team201/presentation/common/customview/dayofselector/DayOfWeek.kt b/android/app/src/main/java/com/created/team201/presentation/common/customview/dayofselector/DayOfWeek.kt new file mode 100644 index 000000000..2541d283e --- /dev/null +++ b/android/app/src/main/java/com/created/team201/presentation/common/customview/dayofselector/DayOfWeek.kt @@ -0,0 +1,22 @@ +package com.created.team201.presentation.common.customview.dayofselector + +import androidx.annotation.StringRes +import com.created.team201.R + +enum class DayOfWeek(@StringRes val stringRes: Int) { + MONDAY(R.string.monday), + TUESDAY(R.string.tuesday), + WEDNESDAY(R.string.wednesday), + THURSDAY(R.string.thursday), + FRIDAY(R.string.friday), + SATURDAY(R.string.saturday), + SUNDAY(R.string.sunday), + ; + + companion object { + fun getValuesWithStartDay(startDay: DayOfWeek = MONDAY): List { + val values = DayOfWeek.values() + return values.slice(startDay.ordinal until values.size) + values.slice(0 until startDay.ordinal) + } + } +} diff --git a/android/app/src/main/java/com/created/team201/presentation/common/customview/dayofselector/DayOfWeekSelector.kt b/android/app/src/main/java/com/created/team201/presentation/common/customview/dayofselector/DayOfWeekSelector.kt new file mode 100644 index 000000000..feb84bef5 --- /dev/null +++ b/android/app/src/main/java/com/created/team201/presentation/common/customview/dayofselector/DayOfWeekSelector.kt @@ -0,0 +1,169 @@ +package com.created.team201.presentation.common.customview.dayofselector + +import android.content.Context +import android.content.res.TypedArray +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.TextView +import androidx.annotation.DrawableRes +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.res.ResourcesCompat +import androidx.core.view.children +import androidx.databinding.BindingAdapter +import com.created.team201.R +import com.created.team201.databinding.ViewDayOfWeekSelectorBinding + +class DayOfWeekSelector @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, +) : ConstraintLayout(context, attrs) { + + private val binding: ViewDayOfWeekSelectorBinding by lazy { + ViewDayOfWeekSelectorBinding.inflate(LayoutInflater.from(context), this, true) + } + + private val dayTextViews: Map by lazy { initDayTextViews() } + + private val textViewDays: Map by lazy { initTextViewDays() } + + private var canMultiSelect: Boolean = false + + private var dayOnClick: DayOnClickListener? = null + + fun interface DayOnClickListener { + fun onClick(day: DayOfWeek) + } + + init { + attrs?.let { setTypedArray(getAttrs(it)) } + setupDayTexts() + setupDayClickListeners() + } + + private fun initDayTextViews(): Map = + DayOfWeek.getValuesWithStartDay() + .zip(binding.clDayOfWeekBackground.children.filterIsInstance().toList()) + .toMap() + + private fun initTextViewDays(): Map = + dayTextViews.entries.associateBy({ it.value }, { it.key }) + + private fun getAttrs(attrs: AttributeSet): TypedArray { + return context.obtainStyledAttributes(attrs, R.styleable.DayOfWeekSelector) + } + + private fun setTypedArray(typedArray: TypedArray) { + canMultiSelect = + typedArray.getBoolean(R.styleable.DayOfWeekSelector_canMultipleSelect, false) + + if (canMultiSelect) { + dayTextViews.values.forEach { + it.background = getBackground(R.drawable.bg_day_of_week_selector_multi_select) + } + } else { + dayTextViews.values.forEach { + it.background = getBackground(R.drawable.bg_day_of_week_selector_single_select) + } + } + + typedArray.recycle() + } + + private fun getBackground(@DrawableRes id: Int): Drawable? = ResourcesCompat.getDrawable( + resources, + id, + null, + ) + + private fun setupDayClickListeners() { + dayTextViews.values.forEach { dayTextView -> + dayTextView.setOnClickListener { it -> + val clickedDay: DayOfWeek = + requireNotNull(textViewDays[it]) { "$it 에 해당하는 요일이 존재하지 않습니다." } + if (canMultiSelect) { + selectDayTextView(dayTextView) + dayOnClick?.onClick(clickedDay) + return@setOnClickListener + } + + if (it.isSelected) return@setOnClickListener + + selectDayTextView(dayTextView) + + dayTextViews.values + .filterNot { it == dayTextView } + .forEach { it.isSelected = false } + dayOnClick?.onClick(clickedDay) + } + } + } + + private fun setupDayTexts() { + val days: List = DayOfWeek.getValuesWithStartDay() + dayTextViews.values.forEachIndexed { index, textView -> + textView.text = resources.getString(days[index].stringRes) + } + } + + fun setSelectableDays(selectableDays: List) { + dayTextViews.keys.forEach { + if (selectableDays.contains(it)) { + dayTextViews[it]?.isEnabled = true + return@forEach + } + dayTextViews[it]?.isEnabled = false + } + } + + fun selectDay(day: DayOfWeek) { + dayTextViews[day]?.isSelected = true + } + + fun selectDays(days: List) { + days.forEach { day -> + val textView: TextView = + requireNotNull(dayTextViews[day]) { "$day 에 해당하는 TextView가 존재하지 않습니다." } + + textView.isSelected = !(textView.isSelected) + } + } + + private fun selectDayTextView(day: TextView) { + day.isSelected = !day.isSelected + } + + fun getSelectedDays(): List { + val selectedDayTextViews: List = dayTextViews.values.filter { it.isSelected } + return selectedDayTextViews.map { requireNotNull(textViewDays[it]) { "$it 에 해당하는 요일이 존재하지 않습니다." } } + } + + fun setDayOnClickListener(dayOnClickListener: DayOnClickListener) { + dayOnClick = dayOnClickListener + } + + fun getSelectedDaysSize(): Int { + return dayTextViews.values.count { it.isSelected } + } + + companion object { + + @JvmStatic + @BindingAdapter("selectableDays") + fun setSelectableDays( + dayOfWeekSelector: DayOfWeekSelector, + selectableDays: List, + ) { + dayOfWeekSelector.setSelectableDays(selectableDays) + } + + @JvmStatic + @BindingAdapter("dayOnClick") + fun setDayOnClickListener( + dayOfWeekSelector: DayOfWeekSelector, + dayOnClickListener: DayOnClickListener, + ) { + dayOfWeekSelector.setDayOnClickListener(dayOnClickListener) + } + } +} diff --git a/android/app/src/main/java/com/created/team201/presentation/studyDetail/StudyDetailActivity.kt b/android/app/src/main/java/com/created/team201/presentation/studyDetail/StudyDetailActivity.kt index 5776933bc..ba55d7520 100644 --- a/android/app/src/main/java/com/created/team201/presentation/studyDetail/StudyDetailActivity.kt +++ b/android/app/src/main/java/com/created/team201/presentation/studyDetail/StudyDetailActivity.kt @@ -21,6 +21,7 @@ import com.created.team201.presentation.report.model.ReportCategory import com.created.team201.presentation.studyDetail.StudyDetailState.Guest import com.created.team201.presentation.studyDetail.StudyDetailState.Master import com.created.team201.presentation.studyDetail.adapter.StudyParticipantsAdapter +import com.created.team201.presentation.studyDetail.bottomSheet.StudyStartBottomSheetFragment import com.created.team201.presentation.studyDetail.model.PeriodFormat import com.created.team201.presentation.studyDetail.model.StudyDetailUIModel import dagger.hilt.android.AndroidEntryPoint @@ -154,7 +155,11 @@ class StudyDetailActivity : } private fun onMasterClickMainButton() { - studyDetailViewModel.startStudy(studyId) + val studyStartBottomSheetFragment = StudyStartBottomSheetFragment.newInstance(studyId) + studyStartBottomSheetFragment.show( + supportFragmentManager, + studyStartBottomSheetFragment.tag, + ) } private fun onNothingClickMainButton() { @@ -165,7 +170,7 @@ class StudyDetailActivity : removeAllFragment() LoginBottomSheetFragment().show( supportFragmentManager, - LoginBottomSheetFragment.TAG_LOGIN_BOTTOM_SHEET + LoginBottomSheetFragment.TAG_LOGIN_BOTTOM_SHEET, ) } diff --git a/android/app/src/main/java/com/created/team201/presentation/studyDetail/bottomSheet/StudyStartBottomSheetFragment.kt b/android/app/src/main/java/com/created/team201/presentation/studyDetail/bottomSheet/StudyStartBottomSheetFragment.kt new file mode 100644 index 000000000..c7a390d9f --- /dev/null +++ b/android/app/src/main/java/com/created/team201/presentation/studyDetail/bottomSheet/StudyStartBottomSheetFragment.kt @@ -0,0 +1,79 @@ +package com.created.team201.presentation.studyDetail.bottomSheet + +import android.os.Bundle +import android.view.View +import android.widget.Toast +import androidx.fragment.app.activityViewModels +import com.created.team201.R +import com.created.team201.databinding.FragmentStudyStartBottomSheetBinding +import com.created.team201.presentation.common.BindingBottomSheetFragment +import com.created.team201.presentation.studyDetail.StudyDetailViewModel + +class StudyStartBottomSheetFragment : + BindingBottomSheetFragment( + R.layout.fragment_study_start_bottom_sheet, + ) { + private val studyDetailViewModel: StudyDetailViewModel by activityViewModels() + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + initBinding() + setupDayOnClickListener() + } + + private fun initBinding() { + binding.viewModel = studyDetailViewModel + binding.onCancelClickListener = { dismiss() } + binding.onStartClickListener = ::onStartButtonClick + binding.lifecycleOwner = viewLifecycleOwner + } + + private fun setupDayOnClickListener() { + binding.dowsStudyStartBottomSheetDayOfWeekSelector.setDayOnClickListener { + val selectedDaysSize: Int = + binding.dowsStudyStartBottomSheetDayOfWeekSelector.getSelectedDaysSize() + + if (selectedDaysSize > 0) { + binding.tvStudyStartBottomSheetBtnStart.isEnabled = true + return@setDayOnClickListener + } + binding.tvStudyStartBottomSheetBtnStart.isEnabled = false + } + } + + private fun onStartButtonClick() { +// val studyId = arguments?.getLong(KEY_STUDY_ID) ?: INVALID_STUDY_ID +// validateStudyId(studyId) +// studyDetailViewModel.startStudy(studyId) ToDo: 서버 연결시 수정 + Toast.makeText( + context, + binding.dowsStudyStartBottomSheetDayOfWeekSelector.getSelectedDays().toString(), + Toast.LENGTH_SHORT, + ).show() + dismiss() + } + + private fun validateStudyId(studyId: Long) { + if (studyId == INVALID_STUDY_ID) { + Toast.makeText( + context, + getString(R.string.study_start_bottom_sheet_dialog_fragment_not_valid_study), + Toast.LENGTH_SHORT, + ).show() + dismiss() + } + } + + companion object { + private const val KEY_STUDY_ID: String = "KEY_STUDY_ID" + private const val INVALID_STUDY_ID: Long = 0L + + fun newInstance(studyId: Long): StudyStartBottomSheetFragment = + StudyStartBottomSheetFragment().apply { + arguments = Bundle().apply { + putLong(KEY_STUDY_ID, studyId) + } + } + } +} diff --git a/android/app/src/main/res/drawable/bg_day_of_week_selector.xml b/android/app/src/main/res/drawable/bg_day_of_week_selector.xml new file mode 100644 index 000000000..03a498b63 --- /dev/null +++ b/android/app/src/main/res/drawable/bg_day_of_week_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/android/app/src/main/res/drawable/bg_day_of_week_selector_multi_select.xml b/android/app/src/main/res/drawable/bg_day_of_week_selector_multi_select.xml new file mode 100644 index 000000000..5330c06b9 --- /dev/null +++ b/android/app/src/main/res/drawable/bg_day_of_week_selector_multi_select.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/bg_day_of_week_selector_single_select.xml b/android/app/src/main/res/drawable/bg_day_of_week_selector_single_select.xml new file mode 100644 index 000000000..42562f156 --- /dev/null +++ b/android/app/src/main/res/drawable/bg_day_of_week_selector_single_select.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_close.xml b/android/app/src/main/res/drawable/ic_close.xml new file mode 100644 index 000000000..00b7a4a59 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_close.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/selector_study_start_bottom_sheet_btn_start_text_color.xml b/android/app/src/main/res/drawable/selector_study_start_bottom_sheet_btn_start_text_color.xml new file mode 100644 index 000000000..43dd78307 --- /dev/null +++ b/android/app/src/main/res/drawable/selector_study_start_bottom_sheet_btn_start_text_color.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/app/src/main/res/layout/fragment_study_start_bottom_sheet.xml b/android/app/src/main/res/layout/fragment_study_start_bottom_sheet.xml new file mode 100644 index 000000000..a480dbb9f --- /dev/null +++ b/android/app/src/main/res/layout/fragment_study_start_bottom_sheet.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/view_day_of_week_selector.xml b/android/app/src/main/res/layout/view_day_of_week_selector.xml new file mode 100644 index 000000000..4fe4d1d00 --- /dev/null +++ b/android/app/src/main/res/layout/view_day_of_week_selector.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/values/attrs.xml b/android/app/src/main/res/values/attrs.xml index 32b42aff7..36ea79d79 100644 --- a/android/app/src/main/res/values/attrs.xml +++ b/android/app/src/main/res/values/attrs.xml @@ -32,4 +32,8 @@ + + + + diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index 0a025a6b2..244df2b7b 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -16,6 +16,7 @@ #0E4429 #A2FF86 #799E82 + #CC3AD353 #0D1117 #181B21 diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index c1f7b2a7b..be3698937 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -99,7 +99,7 @@ 개설한 스터디 관리하기 스터디원 참여하기(%d/%d) - 시작하기(%d/%d) + 요일 선택하기(%d/%d) 아직 준비중인 기능입니다 스터디장에게 문의하기 수락을 기다리고 있어요 @@ -114,6 +114,11 @@ 탈퇴한 유저에요 스터디 성공률 %d%% + + 스터디 요일 + 시작하기 + 유효하지 않은 스터디입니다. + 참여한 스터디 관리하기 개설한 스터디 관리하기 @@ -263,4 +268,13 @@ 아직 준비중인 기능이에요!\n조금만 기다려주세요! + + + + + + + + +