From d8f01c8ac1c6fe375fc93afac5efb9e05363b6b3 Mon Sep 17 00:00:00 2001 From: seunggyu Date: Thu, 23 Mar 2023 23:47:56 +0900 Subject: [PATCH] Fixed Bugs --- app/src/main/AndroidManifest.xml | 8 + .../stitch/Util/SnackBarLabelCustom.kt | 62 ++++ .../com/seunggyu/stitch/data/RetrofitApi.kt | 14 +- .../seunggyu/stitch/data/RetrofitService.kt | 19 + .../model/request/CreateNewMatchRequest.kt | 4 +- .../data/model/request/JoinMatchRequest.kt | 9 + .../data/model/request/ReportRequest.kt | 15 + .../model/response/MatchDetailResponse.kt | 2 +- .../data/model/response/ReportResponse.kt | 21 ++ .../stitch/dialog/CustomAlertDialog.kt | 12 +- .../stitch/dialog/CustomAlertLabelDialog.kt | 63 ++++ .../dialog/MenuMemberBottomSheetDialog.kt | 55 +++ .../com/seunggyu/stitch/ui/CreateNewMatch.kt | 88 +++-- .../stitch/ui/MatchDetailPageActivity.kt | 282 ++++++++++++-- .../stitch/ui/MatchSettingActivity.kt | 141 +++++++ .../seunggyu/stitch/ui/ReportMatchActivity.kt | 142 +++++++ .../stitch/ui/fragment/home/HomeFragment.kt | 74 ++-- .../fragment/newmatch/MatchDetailFragment.kt | 10 +- .../ui/fragment/newmatch/MatchTypeFragment.kt | 3 + .../viewModel/CreateNewMatchViewModel.kt | 15 +- .../stitch/viewModel/MainViewModel.kt | 14 +- .../viewModel/MatchDetailPageViewModel.kt | 199 ++++++---- .../button_round_100_stroke_75_error.xml | 15 + app/src/main/res/drawable/ic_setting.xml | 20 + app/src/main/res/drawable/ic_verify.xml | 9 + .../res/layout/activity_match_detail_page.xml | 347 +++++++++++------- .../res/layout/activity_match_setting.xml | 145 ++++++++ app/src/main/res/layout/activity_report.xml | 127 +++++++ .../layout/dialog_bottomsheet_menu_member.xml | 104 ++++++ .../main/res/layout/snackbar_custom_label.xml | 46 +++ app/src/main/res/values/strings.xml | 6 + 31 files changed, 1750 insertions(+), 321 deletions(-) create mode 100644 app/src/main/java/com/seunggyu/stitch/Util/SnackBarLabelCustom.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/data/model/request/JoinMatchRequest.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/data/model/request/ReportRequest.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/data/model/response/ReportResponse.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertLabelDialog.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/dialog/MenuMemberBottomSheetDialog.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/ui/MatchSettingActivity.kt create mode 100644 app/src/main/java/com/seunggyu/stitch/ui/ReportMatchActivity.kt create mode 100644 app/src/main/res/drawable/button_round_100_stroke_75_error.xml create mode 100644 app/src/main/res/drawable/ic_setting.xml create mode 100644 app/src/main/res/drawable/ic_verify.xml create mode 100644 app/src/main/res/layout/activity_match_setting.xml create mode 100644 app/src/main/res/layout/activity_report.xml create mode 100644 app/src/main/res/layout/dialog_bottomsheet_menu_member.xml create mode 100644 app/src/main/res/layout/snackbar_custom_label.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index eca2771..8f60462 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -69,6 +69,14 @@ android:name=".ui.MatchLocationMapActivity" android:windowSoftInputMode="adjustNothing" android:exported="true" /> + + \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/Util/SnackBarLabelCustom.kt b/app/src/main/java/com/seunggyu/stitch/Util/SnackBarLabelCustom.kt new file mode 100644 index 0000000..6714fdd --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/Util/SnackBarLabelCustom.kt @@ -0,0 +1,62 @@ +package com.seunggyu.stitch.Util + +import android.content.res.Resources +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import com.google.android.material.snackbar.BaseTransientBottomBar.ANIMATION_MODE_SLIDE +import com.google.android.material.snackbar.Snackbar +import com.seunggyu.stitch.R +import com.seunggyu.stitch.databinding.SnackbarCustomBinding +import com.seunggyu.stitch.databinding.SnackbarCustomLabelBinding + +class SnackBarLabelCustom(view: View, private val message: String) { + + companion object { + + fun make(view: View, message: String) = SnackBarLabelCustom(view, message) + } + + private val context = view.context + private val snackbar = Snackbar.make(view, "", 5000) + private val snackbarLayout = snackbar.view as Snackbar.SnackbarLayout + + private val inflater = LayoutInflater.from(context) + private val snackbarBinding: SnackbarCustomLabelBinding = DataBindingUtil.inflate(inflater, R.layout.snackbar_custom_label, null, false) + + init { + initView() + initData() + } + + private fun initView() { + with(snackbarLayout) { + removeAllViews() + val mlayoutParams = snackbarLayout.layoutParams as ViewGroup.MarginLayoutParams + mlayoutParams.setMargins(16.dpToPx(), 0, 16.dpToPx(), 100.dpToPx()) + layoutParams = mlayoutParams + setPadding(0, 0, 0, 0) + setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent)) + addView(snackbarBinding.root, 0) + } + } + + private fun initData() { + snackbarBinding.tvSnackbarMsg.text = message + } + + fun show() { + snackbar.animationMode = ANIMATION_MODE_SLIDE + snackbar.show() + } + + fun Int.dpToPx(): Int { + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), + Resources.getSystem().displayMetrics + ).toInt() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/data/RetrofitApi.kt b/app/src/main/java/com/seunggyu/stitch/data/RetrofitApi.kt index 98ac4a7..80dc936 100644 --- a/app/src/main/java/com/seunggyu/stitch/data/RetrofitApi.kt +++ b/app/src/main/java/com/seunggyu/stitch/data/RetrofitApi.kt @@ -1,8 +1,6 @@ package com.seunggyu.stitch.data -import com.seunggyu.stitch.BuildConfig import com.seunggyu.stitch.Util.Constants.SERVER_ADDRESS -import com.seunggyu.stitch.data.RetrofitService import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import okhttp3.OkHttpClient @@ -13,9 +11,11 @@ import retrofit2.converter.moshi.MoshiConverterFactory object RetrofitApi { private const val BASE_URL = SERVER_ADDRESS - private val moshi: Moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() + private val moshi: Moshi by lazy { + Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + } private val okHttpClient: OkHttpClient by lazy { OkHttpClient.Builder() @@ -27,13 +27,13 @@ object RetrofitApi { private val retrofit: Retrofit by lazy { Retrofit.Builder() + .baseUrl(BASE_URL) .addConverterFactory(MoshiConverterFactory.create(moshi)) .client(okHttpClient) - .baseUrl(BASE_URL) .build() } val retrofitService: RetrofitService by lazy { retrofit.create(RetrofitService::class.java) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/seunggyu/stitch/data/RetrofitService.kt b/app/src/main/java/com/seunggyu/stitch/data/RetrofitService.kt index 298e27b..6e12d39 100644 --- a/app/src/main/java/com/seunggyu/stitch/data/RetrofitService.kt +++ b/app/src/main/java/com/seunggyu/stitch/data/RetrofitService.kt @@ -2,6 +2,8 @@ package com.seunggyu.stitch.data import com.seunggyu.stitch.data.model.User import com.seunggyu.stitch.data.model.request.CreateNewMatchRequest +import com.seunggyu.stitch.data.model.request.JoinMatchRequest +import com.seunggyu.stitch.data.model.request.ReportRequest import com.seunggyu.stitch.data.model.request.SignupRequest import com.seunggyu.stitch.data.model.response.* import retrofit2.Response @@ -25,6 +27,23 @@ interface RetrofitService { @Body createMatchRequest: CreateNewMatchRequest, ): Response + @POST("report") + suspend fun report( + @Body reportRequest: ReportRequest, + ): Response + + @DELETE("match/leave") + suspend fun quitMatch( + @Query("memberId") memberId: String, + @Query("matchId") matchId: String, + ): Response + + @PUT("match/join/id={id}") + suspend fun joinMatch( + @Path("id") id: String, + @Body joinMatchRequest: JoinMatchRequest, + ): Response + // 홈화면 매치 가져오기 @GET("match/home") suspend fun getHomeData(): Response diff --git a/app/src/main/java/com/seunggyu/stitch/data/model/request/CreateNewMatchRequest.kt b/app/src/main/java/com/seunggyu/stitch/data/model/request/CreateNewMatchRequest.kt index 29de19c..4bd7aa4 100644 --- a/app/src/main/java/com/seunggyu/stitch/data/model/request/CreateNewMatchRequest.kt +++ b/app/src/main/java/com/seunggyu/stitch/data/model/request/CreateNewMatchRequest.kt @@ -32,6 +32,6 @@ data class CreateNewMatchRequest( val numOfMembsers: Int?, @Json(name = "startTime") val startTime: String?, - @Json(name = "isTeach") - val isTeach: Boolean?, + @Json(name = "teach") + val teach: Boolean?, ) \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/data/model/request/JoinMatchRequest.kt b/app/src/main/java/com/seunggyu/stitch/data/model/request/JoinMatchRequest.kt new file mode 100644 index 0000000..738d075 --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/data/model/request/JoinMatchRequest.kt @@ -0,0 +1,9 @@ +package com.seunggyu.stitch.data.model.request + + +import com.squareup.moshi.Json + +data class JoinMatchRequest( + @Json(name = "id") + val id: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/data/model/request/ReportRequest.kt b/app/src/main/java/com/seunggyu/stitch/data/model/request/ReportRequest.kt new file mode 100644 index 0000000..bf62dc6 --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/data/model/request/ReportRequest.kt @@ -0,0 +1,15 @@ +package com.seunggyu.stitch.data.model.request + + +import com.squareup.moshi.Json + +data class ReportRequest( + @Json(name = "matchId") + val matchId: String?, + @Json(name = "memberId") + val memberId: String?, + @Json(name = "reason") + val reason: String?, + @Json(name = "reporterId") + val reporterId: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/data/model/response/MatchDetailResponse.kt b/app/src/main/java/com/seunggyu/stitch/data/model/response/MatchDetailResponse.kt index d818169..075ff29 100644 --- a/app/src/main/java/com/seunggyu/stitch/data/model/response/MatchDetailResponse.kt +++ b/app/src/main/java/com/seunggyu/stitch/data/model/response/MatchDetailResponse.kt @@ -5,7 +5,7 @@ import com.squareup.moshi.Json data class MatchDetailResponse( @Json(name = "joinedMembers") - val joinedMembers: List?, + val joinedMembers: List?, @Json(name = "match") val match: Match? ) \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/data/model/response/ReportResponse.kt b/app/src/main/java/com/seunggyu/stitch/data/model/response/ReportResponse.kt new file mode 100644 index 0000000..dced498 --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/data/model/response/ReportResponse.kt @@ -0,0 +1,21 @@ +package com.seunggyu.stitch.data.model.response + + +import com.squareup.moshi.Json + +data class ReportResponse( + @Json(name = "id") + val id: String?, + @Json(name = "matchId") + val matchId: String?, + @Json(name = "memberId") + val memberId: String?, + @Json(name = "reason") + val reason: String?, + @Json(name = "reporterId") + val reporterId: String?, + @Json(name = "sk") + val sk: String?, + @Json(name = "type") + val type: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertDialog.kt b/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertDialog.kt index 2e2d24b..4155250 100644 --- a/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertDialog.kt +++ b/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertDialog.kt @@ -3,6 +3,7 @@ package com.seunggyu.stitch.dialog import android.app.Dialog import android.content.Context import android.os.Bundle +import androidx.core.content.ContextCompat import androidx.databinding.DataBindingUtil import com.seunggyu.stitch.R import com.seunggyu.stitch.databinding.DialogCustomAlertBinding @@ -12,7 +13,8 @@ class CustomAlertDialog( private val _title: String, private val _description: String, private val _negativeText: String, - private val _positiveText: String + private val _positiveText: String, + private val _color: String, ) : Dialog(context) { private lateinit var binding: DialogCustomAlertBinding @@ -38,6 +40,14 @@ class CustomAlertDialog( negativeText = _negativeText positiveText = _positiveText + when(_color) { + "error" -> { + binding.btnAlertPositive.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.button_round_100_stroke_75_error)) + binding.btnAlertPositive.text = "삭제하기" + binding.btnAlertPositive.setTextColor(ContextCompat.getColor(context, R.color.white)) + } + } + btnAlertNegative.setOnClickListener { listener?.invoke(false) dismiss() diff --git a/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertLabelDialog.kt b/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertLabelDialog.kt new file mode 100644 index 0000000..de7b4bc --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/dialog/CustomAlertLabelDialog.kt @@ -0,0 +1,63 @@ +package com.seunggyu.stitch.dialog + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import com.seunggyu.stitch.R +import com.seunggyu.stitch.databinding.DialogCustomAlertBinding + +class CustomAlertLabelDialog( + context: Context, + private val _title: String, + private val _description: String, + private val _negativeText: String, + private val _positiveText: String, + private val _color: String, +) : Dialog(context) { + + private lateinit var binding: DialogCustomAlertBinding + + private var listener: ((Boolean) -> Unit)? = null + + fun setDialogListener(listener: (Boolean) -> Unit) { + this.listener = listener + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DialogCustomAlertBinding.inflate(layoutInflater) + setContentView(binding.root) + + init() + } + + fun init() { + with(binding) { + title = _title + description = _description + negativeText = _negativeText + positiveText = _positiveText + + when(_color) { + "error" -> { + binding.btnAlertPositive.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.button_round_100_stroke_75_error)) + binding.btnAlertPositive.text = "삭제하기" + binding.btnAlertPositive.setTextColor(ContextCompat.getColor(context, R.color.white)) + } + } + + btnAlertNegative.setOnClickListener { + listener?.invoke(false) + dismiss() + } + + btnAlertPositive.setOnClickListener { + listener?.invoke(true) + dismiss() + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/dialog/MenuMemberBottomSheetDialog.kt b/app/src/main/java/com/seunggyu/stitch/dialog/MenuMemberBottomSheetDialog.kt new file mode 100644 index 0000000..062fcf2 --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/dialog/MenuMemberBottomSheetDialog.kt @@ -0,0 +1,55 @@ +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.activityViewModels +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.seunggyu.stitch.GlobalApplication +import com.seunggyu.stitch.databinding.DialogBottomsheetMatchDetailTimeBinding +import com.seunggyu.stitch.databinding.DialogBottomsheetMenuMemberBinding +import com.seunggyu.stitch.ui.ReportMatchActivity +import com.seunggyu.stitch.viewModel.CreateNewMatchViewModel + +// accessType +// 0 : 매치에서 참여자인경우 (신고하기, 매치취소하기, 취소) +// 1 : 매치에서 참여자가 아닌경우 (신고하기, 취소) +// 2 : 프로필 상대방 신고하는 경우 (신고하기, 취소) + +class MenuMemberBottomSheetDialog(accessType: Int) : + BottomSheetDialogFragment() { + private lateinit var binding: DialogBottomsheetMenuMemberBinding + private val viewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + binding = DialogBottomsheetMenuMemberBinding.inflate(inflater, container, false) + + dialogInit() + + return binding.root + } + + private fun dialogInit() { + binding.btnMenuReport?.setOnClickListener { + val intent = Intent(requireContext(), ReportMatchActivity::class.java) + intent.putExtra("matchId", viewModel.passedMatchId.toString()) + intent.putExtra("memberId", "0") + intent.putExtra("reporterId", GlobalApplication.prefs.getString("userId")) + startActivity(intent) + dismiss() + } + binding.btnMenuQuit?.setOnClickListener { + viewModel.quitMatch() + dismiss() + } + binding.btnMenuCancel?.setOnClickListener { + dismiss() + } + } +} diff --git a/app/src/main/java/com/seunggyu/stitch/ui/CreateNewMatch.kt b/app/src/main/java/com/seunggyu/stitch/ui/CreateNewMatch.kt index 33046ef..91f38d5 100644 --- a/app/src/main/java/com/seunggyu/stitch/ui/CreateNewMatch.kt +++ b/app/src/main/java/com/seunggyu/stitch/ui/CreateNewMatch.kt @@ -5,6 +5,7 @@ import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle +import android.service.autofill.FieldClassification.Match import android.util.Log import androidx.activity.viewModels import androidx.core.view.isVisible @@ -55,30 +56,41 @@ class CreateNewMatch : BasicActivity() { btnNewmatchComplete.setOnClickListener { btnNewmatchComplete.isEnabled = true btnNewmatchComplete.setTextColor(getColor(R.color.gray_10)) - viewModel.uploadImage?.let { - val imageName = System.currentTimeMillis().toString() - val imagesRef = Firebase.storage.reference.child("images/$imageName.jpg") - val baos = ByteArrayOutputStream() - viewModel.uploadImage.value?.compress(Bitmap.CompressFormat.JPEG, 100, baos) - val data = baos.toByteArray() - - val uploadTask = imagesRef.putBytes(data) - uploadTask.addOnSuccessListener { - val storageRef = FirebaseStorage.getInstance().getReference("images/$imageName.jpg") - storageRef.downloadUrl.addOnSuccessListener { uri -> - val imageUrl = uri.toString() - viewModel.setImageUrl(imageUrl) - - createMatchProcess() - }.addOnFailureListener { exception -> - SnackBarCustom.make(binding.root,getString(R.string.snackbar_network_error)).show() + viewModel.uploadImage.let { + if (viewModel.imageUploaded) { + val imageName = System.currentTimeMillis().toString() + val imagesRef = Firebase.storage.reference.child("images/$imageName.jpg") + val baos = ByteArrayOutputStream() + viewModel.uploadImage.value?.compress(Bitmap.CompressFormat.JPEG, 100, baos) + val data = baos.toByteArray() + + val uploadTask = imagesRef.putBytes(data) + uploadTask.addOnSuccessListener { + val storageRef = + FirebaseStorage.getInstance().getReference("images/$imageName.jpg") + storageRef.downloadUrl.addOnSuccessListener { uri -> + val imageUrl = uri.toString() + viewModel.setImageUrl(imageUrl) + + createMatchProcess() + }.addOnFailureListener { exception -> + SnackBarCustom.make( + binding.root, + getString(R.string.snackbar_network_error) + ).show() + btnNewmatchComplete.isEnabled = true + btnNewmatchComplete.setTextColor(getColor(R.color.primary)) + } + }.addOnFailureListener { + SnackBarCustom.make( + binding.root, + getString(R.string.snackbar_network_error) + ).show() btnNewmatchComplete.isEnabled = true btnNewmatchComplete.setTextColor(getColor(R.color.primary)) } - }.addOnFailureListener { - SnackBarCustom.make(binding.root,getString(R.string.snackbar_network_error)).show() - btnNewmatchComplete.isEnabled = true - btnNewmatchComplete.setTextColor(getColor(R.color.primary)) + } else { + createMatchProcess() } } @@ -87,6 +99,7 @@ class CreateNewMatch : BasicActivity() { } private fun createMatchProcess() { + Log.e("티치여부 ////////" ,viewModel.isTeach.value.toString()) viewModel.createNewMatch() binding.progressLoadingCreateNewMatch.isVisible = true } @@ -95,15 +108,38 @@ class CreateNewMatch : BasicActivity() { with(viewModel) { createSuccessListener.observe(this@CreateNewMatch) { - if(it) { + if (it) { binding.progressLoadingCreateNewMatch.isVisible = false + val intent = Intent(this@CreateNewMatch, MatchDetailPageActivity::class.java) + viewModel._match.apply { + intent.putExtra("id", this.id) + intent.putExtra("type", this.type) + intent.putExtra("location", this.location) + intent.putExtra("imageUrl", this.imageUrl) + intent.putExtra("name", this.name) + intent.putExtra("detail", this.detail) + intent.putExtra("startTime", this.startTime) + intent.putExtra("duration", this.duration) + intent.putExtra("eventType", this.eventType) + intent.putExtra("hostId", this.hostId) + intent.putExtra("maxCapacity", this.maxCapacity) + intent.putExtra("fee", this.fee) + intent.putExtra("latitude", this.latitude) + intent.putExtra("longitude", this.longitude) + intent.putExtra("teach", this.teach) + intent.putExtra("numOfMembers", this.numOfMembers) + } + startActivity(intent) finish() } } createFailedListener.observe(this@CreateNewMatch) { - if(it) { + if (it) { binding.progressLoadingCreateNewMatch.isVisible = false - SnackBarCustom.make(binding.clCreateNewMatchRoot, getString(R.string.snackbar_network_error)).show() + SnackBarCustom.make( + binding.clCreateNewMatchRoot, + getString(R.string.snackbar_network_error) + ).show() binding.btnNewmatchComplete.isEnabled = true binding.btnNewmatchComplete.setTextColor(getColor(R.color.primary)) Log.e("[Error] createNewMatchFailedListener", "Observed!!!") @@ -157,12 +193,14 @@ class CreateNewMatch : BasicActivity() { val description = getString(R.string.alert_newmatch_clear_description) val negativeText = getString(R.string.alert_quit) val positiveText = getString(R.string.alert_continue) + val color = "primary" val dialog = CustomAlertDialog( this@CreateNewMatch, title, description, negativeText, - positiveText + positiveText, + color ) dialog.setDialogListener { okClicked -> if (!okClicked) { diff --git a/app/src/main/java/com/seunggyu/stitch/ui/MatchDetailPageActivity.kt b/app/src/main/java/com/seunggyu/stitch/ui/MatchDetailPageActivity.kt index 5e07e18..05ef62b 100644 --- a/app/src/main/java/com/seunggyu/stitch/ui/MatchDetailPageActivity.kt +++ b/app/src/main/java/com/seunggyu/stitch/ui/MatchDetailPageActivity.kt @@ -1,49 +1,182 @@ package com.seunggyu.stitch.ui import MatchDetailPageViewModel +import MenuMemberBottomSheetDialog +import android.content.Intent +import android.content.res.Resources import android.os.Bundle +import android.util.Log +import android.util.TypedValue +import android.view.View +import android.view.ViewGroup import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import androidx.core.view.isVisible import androidx.databinding.DataBindingUtil import com.bumptech.glide.Glide +import com.google.android.material.appbar.AppBarLayout +import com.seunggyu.stitch.BasicActivity +import com.seunggyu.stitch.GlobalApplication import com.seunggyu.stitch.R +import com.seunggyu.stitch.Util.SnackBarCustom +import com.seunggyu.stitch.Util.SnackBarLabelCustom import com.seunggyu.stitch.data.model.response.Match import com.seunggyu.stitch.databinding.ActivityMatchDetailPageBinding import java.text.SimpleDateFormat import java.util.* +import kotlin.math.abs import kotlin.math.max class MatchDetailPageActivity : AppCompatActivity() { private lateinit var binding: ActivityMatchDetailPageBinding private val viewModel: MatchDetailPageViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = DataBindingUtil.setContentView(this, R.layout.activity_match_detail_page) - - init() initObserver() + initInsetMargin() + init() + initAppBar() + initClickListener() } private fun init() { + viewModel.setPassedMatchId(intent.getStringExtra("id")!!) + val toolbar = binding.toolbar + (this@MatchDetailPageActivity).setSupportActionBar(toolbar) + + getIntentDataFromHome() viewModel.getMatchDataFromServer() + viewModel.getHostInfo(intent.getStringExtra("hostId").toString()) + } + + private fun initClickListener() { + binding.btnMatchDetailPageBack.setOnClickListener { + finish() + } + + binding.btnMatchDetailPageMenu.setOnClickListener { + val bottomSheet = MenuMemberBottomSheetDialog(0) // 참여자인 경우 + supportFragmentManager.let { it1 -> bottomSheet.show(it1, bottomSheet.tag) } + } + + binding.btnMatchDetailAbled.setOnClickListener { + viewModel.joinMatch() + } + + binding.btnMatchDetailPageSetting.setOnClickListener { + val intent = Intent(this@MatchDetailPageActivity, MatchSettingActivity::class.java) + intent.putExtra("matchId", viewModel.matchData.value?.id) + startActivity(intent) + } + } + private fun getIntentDataFromHome() { + viewModel.setMatchData( + Match( + id = intent.getStringExtra("id"), + type = intent.getStringExtra("type"), + location = intent.getStringExtra("location"), + imageUrl = intent.getStringExtra("imageUrl"), + name = intent.getStringExtra("name"), + detail = intent.getStringExtra("detail"), + startTime = intent.getStringExtra("startTime"), + duration = intent.getIntExtra("duration", 30), + eventType = intent.getStringExtra("eventType"), + hostId = intent.getStringExtra("hostId"), + maxCapacity = intent.getIntExtra("maxCapacity", 2), + fee = intent.getIntExtra("fee", 0), + latitude = intent.getStringExtra("latitude"), + longitude = intent.getStringExtra("longitude"), + teach = intent.getBooleanExtra("teach", false), + numOfMembers = intent.getIntExtra("numOfMembers", 1), + sk = "0") + ) + } private fun initObserver() { with(viewModel) { matchData.observe(this@MatchDetailPageActivity) { initUi(it) } + + hostName.observe(this@MatchDetailPageActivity) { + binding.tvMatchDetailPageHostName.text = it + binding.tvMatchDetailPageHostNameBottom.text = it + } + + hostImageUrl.observe(this@MatchDetailPageActivity) { + if(it != "") { + Glide.with(this@MatchDetailPageActivity).load(it) + .into(binding.cvMatchDetailPageHostProfileImage) + Glide.with(this@MatchDetailPageActivity).load(it) + .into(binding.cvMatchDetailPageHostProfileImageBottom) + Log.e("asdasdasdasd", "asdasdafsjkdhskajvjkadn") + }else { + Glide.with(this@MatchDetailPageActivity).load(R.drawable.default_profile_image) + .into(binding.cvMatchDetailPageHostProfileImage) + Glide.with(this@MatchDetailPageActivity).load(R.drawable.default_profile_image) + .into(binding.cvMatchDetailPageHostProfileImageBottom) + } + } + + isAlreadyMember.observe(this@MatchDetailPageActivity) { + if(it) { + binding.btnMatchDetailDisabled.isVisible = true + binding.btnMatchDetailAbled.isVisible=false + binding.btnMatchDetailPageSetting.isVisible = false + binding.btnMatchDetailPageMenu.isVisible = true + if(viewModel.hostId.value == GlobalApplication.prefs.getCurrentUser().id) { + binding.btnMatchDetailPageSetting.isVisible = true + binding.btnMatchDetailPageMenu.isVisible = false + } + } else { + binding.btnMatchDetailDisabled.isVisible = false + binding.btnMatchDetailAbled.isVisible = true + binding.btnMatchDetailPageSetting.isVisible = false + binding.btnMatchDetailPageMenu.isVisible = true + } + } + + joinSuccess.observe(this@MatchDetailPageActivity) { + if(it) { + SnackBarLabelCustom.make(binding.root, "성공적으로 매치에 참여했습니다") + } + } + + joinedMember.observe(this@MatchDetailPageActivity) { + var tt = false + val uid = GlobalApplication.prefs.getString("userId") + for(i in it){ + if(uid == i.id) { + tt = true + break + } + } + if(tt) { + viewModel.setIsAlreadyMember(true) + } + } } } private fun initUi(match: Match?) { with(binding) { + // 티치매치 여부 확인 + if(match?.teach == true) { + chipClass.root.isVisible = true + ivMatchDetailPageFee.isVisible = true + tvMatchDetailPageFee.isVisible = true + } + Log.e("ImageUrl=============", match?.imageUrl.toString()) + // 이미지 세팅 Glide.with(this@MatchDetailPageActivity) .load(match?.imageUrl) @@ -59,24 +192,30 @@ class MatchDetailPageActivity : AppCompatActivity() { tvMatchDetailPageLocation.text = match?.location // 시간 - tvMatchDetailPageCalendar.text = match?.startTime?.let { t -> match.duration?.let { d -> - getMatchDateFormat(t, d) - } } + tvMatchDetailPageCalendar.text = match?.startTime?.let { t -> + match.duration?.let { d -> + getMatchDateFormat(t, d) + } + } // 참가비 - if(match?.fee != 0) { + if (match?.fee != 0) { tvMatchDetailPageFee.text = String.format("%,d", match?.fee) + "원" } else { - if(match?.teach == true) tvMatchDetailPageFee.text = "0원" + if (match?.teach == true) tvMatchDetailPageFee.text = "0원" else tvMatchDetailPageFee.isVisible = false } // 참가인원 val currentParty = match?.numOfMembers val maxParty = match?.maxCapacity - tvMatchDetailPageParticipant.text = getString(R.string.match_detail_page_detail_participant, currentParty.toString(), maxParty.toString()) - -// Glide.with(this@MatchDetailPageActivity).load(match?.).into(ivRecommendItemBackground) + tvMatchDetailPageParticipant.text = getString( + R.string.match_detail_page_detail_participant, + currentParty.toString(), + maxParty.toString() + ) + tvMatchDetailPageDetail.text = match?.detail +// Glide.with(this@MatchDetailPageActivity).load(match?.ho).into() } } @@ -85,30 +224,51 @@ class MatchDetailPageActivity : AppCompatActivity() { } fun setTopProfileImageAndChips(eventType: String) { - when(eventType) { + when (eventType) { "배드민턴" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_badminton) - binding.chipBadminton.root.isVisible = true} - "야구" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_baseball) - binding.chipBaseball.root.isVisible = true} - "농구" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_basketball) - binding.chipBasketball.root.isVisible = true} - "기타" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_etc) - binding.chipEtc.root.isVisible = true} - "골프" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_golf) - binding.chipGolf.root.isVisible = true} - "헬스" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_health) - binding.chipHealth.root.isVisible = true} - "등산" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_mountain) - binding.chipMountain.root.isVisible = true} - "탁구" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_pingpong) - binding.chipPingpong.root.isVisible = true} - "런닝" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_running) - binding.chipRunning.root.isVisible = true} - "축구" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_soccer) - binding.chipSoccer.root.isVisible = true} - "테니스" -> { binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_tennis) - binding.chipTennis.root.isVisible = true} + binding.chipBadminton.root.isVisible = true + } + "야구" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_baseball) + binding.chipBaseball.root.isVisible = true + } + "농구" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_basketball) + binding.chipBasketball.root.isVisible = true + } + "기타" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_etc) + binding.chipEtc.root.isVisible = true + } + "골프" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_golf) + binding.chipGolf.root.isVisible = true + } + "헬스" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_health) + binding.chipHealth.root.isVisible = true + } + "등산" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_mountain) + binding.chipMountain.root.isVisible = true + } + "탁구" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_pingpong) + binding.chipPingpong.root.isVisible = true + } + "런닝" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_running) + binding.chipRunning.root.isVisible = true + } + "축구" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_soccer) + binding.chipSoccer.root.isVisible = true + } + "테니스" -> { + binding.cvMatchDetailPageProfile.setImageResource(R.drawable.category_tennis) + binding.chipTennis.root.isVisible = true + } } } @@ -135,4 +295,60 @@ class MatchDetailPageActivity : AppCompatActivity() { return sb.toString() } + + private fun initInsetMargin() = with(binding) { + ViewCompat.setOnApplyWindowInsetsListener(coordinator) { v: View, insets: WindowInsetsCompat -> + val params = v.layoutParams as ViewGroup.MarginLayoutParams + params.bottomMargin = insets.systemWindowInsetBottom + toolbarContainer.layoutParams = + (toolbarContainer.layoutParams as ViewGroup.MarginLayoutParams).apply { + setMargins(16.dpToPx(), insets.systemWindowInsetTop, 16.dpToPx(), 0) + } + collapsingToolbarContainer.layoutParams = + (collapsingToolbarContainer.layoutParams as ViewGroup.MarginLayoutParams).apply { + setMargins(0, 0, 0, 0) + } + + insets.consumeSystemWindowInsets() + } + } + + fun Int.dpToPx(): Int { + return TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), + Resources.getSystem().displayMetrics + ).toInt() + } + + private fun initAppBar() { + + binding.appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> + val topPadding = binding.toolbarBackgroundView.height.toFloat() * 3 + val realAlphaScrollHeight = appBarLayout.measuredHeight - appBarLayout.totalScrollRange + val abstractOffset = abs(verticalOffset) + + val realAlphaVerticalOffset = + if (abstractOffset - topPadding < 0) 0f else abstractOffset - topPadding + if (abstractOffset < topPadding) { + binding.toolbarBackgroundView.alpha = 0f + return@OnOffsetChangedListener + } + val percentage = realAlphaVerticalOffset / realAlphaScrollHeight + binding.toolbarBackgroundView.alpha = + 1 - (if (1 - percentage * 2 < 0) 0f else 1 - percentage * 2) + + }) + initActionBar() + } + + private fun initActionBar() = with(binding) { + toolbar.navigationIcon = null + toolbar.setContentInsetsAbsolute(0, 0) + (this@MatchDetailPageActivity).setSupportActionBar(toolbar) + (this@MatchDetailPageActivity).supportActionBar?.let { + it.setHomeButtonEnabled(false) + it.setDisplayHomeAsUpEnabled(false) + it.setDisplayShowHomeEnabled(false) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/ui/MatchSettingActivity.kt b/app/src/main/java/com/seunggyu/stitch/ui/MatchSettingActivity.kt new file mode 100644 index 0000000..1879b30 --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/ui/MatchSettingActivity.kt @@ -0,0 +1,141 @@ +package com.seunggyu.stitch.ui + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.View +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import com.seunggyu.stitch.BasicActivity +import com.seunggyu.stitch.R +import com.seunggyu.stitch.Util.SnackBarCustom +import com.seunggyu.stitch.data.RetrofitApi +import com.seunggyu.stitch.data.model.request.ReportRequest +import com.seunggyu.stitch.databinding.ActivityReportBinding +import com.seunggyu.stitch.dialog.CustomAlertDialog +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class MatchSettingActivity : BasicActivity() { + private lateinit var binding: ActivityReportBinding + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_match_setting) + + init() + initClickListener() + + } + + private fun init() { + intent.getStringExtra("matchId") + + + with(binding) { + btnReportConfirm.setOnClickListener { + report() + + } + + } + } + + private fun report() { + val service = RetrofitApi.retrofitService + + CoroutineScope(Dispatchers.IO).launch { + val response = service.report( + ReportRequest(matchId = intent.getStringExtra("matchId"), + memberId = intent.getStringExtra("memberId"), + reason = binding.etReport.text.toString(), + reporterId = intent.getStringExtra("reporterId") + ) + ) + + withContext(Dispatchers.Main) { + if (response.isSuccessful) { + val result = response.body() + result?.let { + Log.e("result>>>>>>>", result.toString()) + SnackBarCustom.make(binding.clAddressParent, "신고가 정상적으로 접수되었습니다.").show() + finish() + } + } else { + SnackBarCustom.make(binding.clAddressParent, getString(R.string.snackbar_network_error)).show() + } + } + } + } + + private fun initClickListener() { + binding.etReport.addTextChangedListener(object : TextWatcher { + override fun afterTextChanged(s: Editable?) { + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if(s.toString().length > 500) { + binding.tvReportError.visibility = View.VISIBLE + binding.dividerReport.dividerColor = ContextCompat.getColor(this@MatchSettingActivity, R.color.error) + binding.tvReportLength.setTextColor(ContextCompat.getColor(this@MatchSettingActivity,R.color.error)) + } else { + binding.tvReportError.visibility = View.GONE + binding.tvReportLength.visibility = View.VISIBLE + binding.tvReportLength.setTextColor(ContextCompat.getColor(this@MatchSettingActivity,R.color.gray_09)) + binding.dividerReport.dividerColor = ContextCompat.getColor(this@MatchSettingActivity, R.color.gray_07) + } + + if(s.toString().isEmpty()) { + binding.tvReportError.visibility = View.GONE + binding.btnReportConfirm.setBackgroundResource(R.drawable.button_round_disabled) + binding.btnReportConfirm.setTextColor(ContextCompat.getColor(this@MatchSettingActivity, R.color.gray_07)) + binding.btnReportConfirm.isEnabled = false + } else { + binding.btnReportConfirm.setBackgroundResource(R.drawable.button_round) + binding.btnReportConfirm.setTextColor(ContextCompat.getColor(this@MatchSettingActivity, R.color.gray_12)) + binding.btnReportConfirm.isEnabled = true + } + + + binding.tvReportError.text = getString(R.string.newmatch_detail_input_length, s.toString().length.toString(), "500") + } + }) + } + + fun showCloseDialog() { + val title = "신고를 그만두시겠어요?" + val description = "작성된 내용은 사라집니다." + val negativeText = getString(R.string.alert_quit) + val positiveText = getString(R.string.alert_continue) + val color = "primary" + val dialog = CustomAlertDialog( + this@MatchSettingActivity, + title, + description, + negativeText, + positiveText, + color + ) + dialog.setDialogListener { okClicked -> + if (!okClicked) { + finish() + } + } + + // 다이얼로그 테두리 외곽 부분 투명하게 설정 + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)); + + dialog.show() + } + + override fun onBackPressed() { + showCloseDialog() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/ui/ReportMatchActivity.kt b/app/src/main/java/com/seunggyu/stitch/ui/ReportMatchActivity.kt new file mode 100644 index 0000000..ffa1f6d --- /dev/null +++ b/app/src/main/java/com/seunggyu/stitch/ui/ReportMatchActivity.kt @@ -0,0 +1,142 @@ +package com.seunggyu.stitch.ui + +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.util.Log +import android.view.View +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import com.seunggyu.stitch.BasicActivity +import com.seunggyu.stitch.R +import com.seunggyu.stitch.Util.SnackBarCustom +import com.seunggyu.stitch.data.RetrofitApi +import com.seunggyu.stitch.data.model.request.ReportRequest +import com.seunggyu.stitch.databinding.ActivityReportBinding +import com.seunggyu.stitch.dialog.CustomAlertDialog +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class ReportMatchActivity : BasicActivity() { + private lateinit var binding: ActivityReportBinding + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_report) + + init() + initClickListener() + + } + + private fun init() { + intent.getStringExtra("reporterId") + intent.getStringExtra("matchId") + + + with(binding) { + btnReportConfirm.setOnClickListener { + report() + + } + + } + } + + private fun report() { + val service = RetrofitApi.retrofitService + + CoroutineScope(Dispatchers.IO).launch { + val response = service.report( + ReportRequest(matchId = intent.getStringExtra("matchId"), + memberId = intent.getStringExtra("memberId"), + reason = binding.etReport.text.toString(), + reporterId = intent.getStringExtra("reporterId") + ) + ) + + withContext(Dispatchers.Main) { + if (response.isSuccessful) { + val result = response.body() + result?.let { + Log.e("result>>>>>>>", result.toString()) + SnackBarCustom.make(binding.clAddressParent, "신고가 정상적으로 접수되었습니다.").show() + finish() + } + } else { + SnackBarCustom.make(binding.clAddressParent, getString(R.string.snackbar_network_error)).show() + } + } + } + } + + private fun initClickListener() { + binding.etReport.addTextChangedListener(object : TextWatcher { + override fun afterTextChanged(s: Editable?) { + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if(s.toString().length > 500) { + binding.tvReportError.visibility = View.VISIBLE + binding.dividerReport.dividerColor = ContextCompat.getColor(this@ReportMatchActivity, R.color.error) + binding.tvReportLength.setTextColor(ContextCompat.getColor(this@ReportMatchActivity,R.color.error)) + } else { + binding.tvReportError.visibility = View.GONE + binding.tvReportLength.visibility = View.VISIBLE + binding.tvReportLength.setTextColor(ContextCompat.getColor(this@ReportMatchActivity,R.color.gray_09)) + binding.dividerReport.dividerColor = ContextCompat.getColor(this@ReportMatchActivity, R.color.gray_07) + } + + if(s.toString().isEmpty()) { + binding.tvReportError.visibility = View.GONE + binding.btnReportConfirm.setBackgroundResource(R.drawable.button_round_disabled) + binding.btnReportConfirm.setTextColor(ContextCompat.getColor(this@ReportMatchActivity, R.color.gray_07)) + binding.btnReportConfirm.isEnabled = false + } else { + binding.btnReportConfirm.setBackgroundResource(R.drawable.button_round) + binding.btnReportConfirm.setTextColor(ContextCompat.getColor(this@ReportMatchActivity, R.color.gray_12)) + binding.btnReportConfirm.isEnabled = true + } + + + binding.tvReportError.text = getString(R.string.newmatch_detail_input_length, s.toString().length.toString(), "500") + } + }) + } + + fun showCloseDialog() { + val title = "신고를 그만두시겠어요?" + val description = "작성된 내용은 사라집니다." + val negativeText = getString(R.string.alert_quit) + val positiveText = getString(R.string.alert_continue) + val color = "primary" + val dialog = CustomAlertDialog( + this@ReportMatchActivity, + title, + description, + negativeText, + positiveText, + color + ) + dialog.setDialogListener { okClicked -> + if (!okClicked) { + finish() + } + } + + // 다이얼로그 테두리 외곽 부분 투명하게 설정 + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)); + + dialog.show() + } + + override fun onBackPressed() { + showCloseDialog() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/ui/fragment/home/HomeFragment.kt b/app/src/main/java/com/seunggyu/stitch/ui/fragment/home/HomeFragment.kt index 354b3e0..1293f30 100644 --- a/app/src/main/java/com/seunggyu/stitch/ui/fragment/home/HomeFragment.kt +++ b/app/src/main/java/com/seunggyu/stitch/ui/fragment/home/HomeFragment.kt @@ -1,5 +1,6 @@ package com.seunggyu.stitch.ui.fragment.home +import android.content.Context import android.content.Intent import android.content.res.Resources import android.graphics.Rect @@ -34,8 +35,10 @@ import com.seunggyu.stitch.adapter.NewMatchRecyclerViewAdapter import com.seunggyu.stitch.adapter.RecommendMatchRecyclerViewAdapter import com.seunggyu.stitch.data.RetrofitApi import com.seunggyu.stitch.data.model.request.SignupRequest +import com.seunggyu.stitch.data.model.response.Match import com.seunggyu.stitch.databinding.FragMainHomeBinding import com.seunggyu.stitch.ui.AddressSearchActivity +import com.seunggyu.stitch.ui.MatchDetailPageActivity import com.seunggyu.stitch.viewModel.MainViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -45,6 +48,8 @@ import java.util.* import kotlin.math.abs class HomeFragment : Fragment() { + private var mContext: Context? = null + private lateinit var binding: FragMainHomeBinding private lateinit var adapter: BannerPagerAdapter @@ -55,10 +60,30 @@ class HomeFragment : Fragment() { private var timer: Timer? = null private val DELAY_MS: Long = 5000 // (초기 웨이팅 타임) ex) 앱 로딩 후 5초 뒤 플립됨. private val PERIOD_MS: Long = 5000 // 5초 주기로 배너 이동 - +// private lateinit var selectedMatch: Match private val recommendRecyclerViewAdapter: RecommendMatchRecyclerViewAdapter by lazy { - RecommendMatchRecyclerViewAdapter(binding.rvMainContentsRecommend) + RecommendMatchRecyclerViewAdapter(binding.rvMainContentsRecommend) { + val intent = Intent(mContext, MatchDetailPageActivity::class.java) + intent.putExtra("id", it.id) + intent.putExtra("type", it.type) + intent.putExtra("location", it.location) + intent.putExtra("imageUrl", it.imageUrl) + intent.putExtra("name", it.name) + intent.putExtra("detail", it.detail) + intent.putExtra("startTime", it.startTime) + intent.putExtra("duration", it.duration) + intent.putExtra("eventType", it.eventType) + intent.putExtra("hostId", it.hostId) + intent.putExtra("maxCapacity", it.maxCapacity) + intent.putExtra("fee", it.fee) + intent.putExtra("latitude", it.latitude) + intent.putExtra("longitude", it.longitude) + intent.putExtra("teach", it.teach) + intent.putExtra("numOfMembers", it.numOfMembers) + + startActivity(intent) + } } private val matchRecyclerViewAdapter: NewMatchRecyclerViewAdapter by lazy { @@ -88,6 +113,17 @@ class HomeFragment : Fragment() { (activity as BasicActivity).setSupportActionBar(toolbar) } + override fun onAttach(context: Context) { + super.onAttach(context) + mContext = context + Log.e("Attach","attach") + } + + override fun onDetach() { + super.onDetach() + mContext = null + } + private fun initRecyclerView() { binding.rvMainContentsRecommend.apply { @@ -140,19 +176,8 @@ class HomeFragment : Fragment() { timer = null timerStart() } - - - // 페이지가 스크롤(자동스크롤, 사용자 직접 스크롤 모두 포함)될 때마다 페이지 번호를 갱신 -// eventPageDescript = getString( -// R.string.EventViewPagerDescript, -// position % listSize + 1, -// listSize -// ) -// binding.tvPagenum.setText(eventPageDescript) } }) -// binding.dotsIndicator.attachTo(binding.vpBanner) - } else { SnackBarCustom.make(binding.clHomeview, getString(R.string.snackbar_banner_error)) .show() @@ -213,14 +238,16 @@ class HomeFragment : Fragment() { CoroutineScope(Dispatchers.IO).launch { val response = service.update( - SignupRequest(id = user.id, - location = user.location, - imageUrl = user.imageUrl, - name = user.name, - sports = user.sports, - introduce = user.introduce, - type = user.type, - token = user.token) + SignupRequest( + id = user.id, + location = user.location, + imageUrl = user.imageUrl, + name = user.name, + sports = user.sports, + introduce = user.introduce, + type = user.type, + token = user.token + ) ) withContext(Dispatchers.Main) { @@ -232,7 +259,10 @@ class HomeFragment : Fragment() { } } else { Log.e("TAG", response.code().toString()) - SnackBarCustom.make(binding.clHomeview, getString(R.string.snackbar_network_error)) + SnackBarCustom.make( + binding.clHomeview, + getString(R.string.snackbar_network_error) + ) .show() } } diff --git a/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchDetailFragment.kt b/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchDetailFragment.kt index 3d90cbd..77d2c06 100644 --- a/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchDetailFragment.kt +++ b/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchDetailFragment.kt @@ -350,6 +350,8 @@ class MatchDetailFragment : Fragment() { maxCapacity.observe(requireActivity()) { binding.tvMatchParticipantValue.text = getString(R.string.newmatch_detail_Participant_value, it) viewModel.checkAllWritenFlow() + Log.e("티치여부 ////////" ,viewModel.isTeach.value.toString()) + if(viewModel.maxCapacity.value == "1") { binding.btnDetailParticipantMinus.isEnabled = false binding.btnDetailParticipantMinus.imageTintList = ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.gray_11)) @@ -379,9 +381,11 @@ class MatchDetailFragment : Fragment() { } // 업로드 이미지 - uploadImage.observe(requireActivity()) { - binding.ivMatchDetailImage.setImageBitmap(it) - binding.ivMatchImageClear.visibility = View.VISIBLE + uploadImage.observe(requireActivity()) {it1 -> + uploadImage.let { + binding.ivMatchDetailImage.setImageBitmap(it1) + binding.ivMatchImageClear.visibility = View.VISIBLE + } } } } diff --git a/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchTypeFragment.kt b/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchTypeFragment.kt index 94b867e..47b1a3a 100644 --- a/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchTypeFragment.kt +++ b/app/src/main/java/com/seunggyu/stitch/ui/fragment/newmatch/MatchTypeFragment.kt @@ -60,11 +60,14 @@ class MatchTypeFragment : Fragment() { viewModel.setTeach(true) // 버튼 변경 + + Log.e("isTeach", viewModel.isTeach.value.toString()) nextButtonEnable() } btnNewmatchTypeNext.setOnClickListener { viewModel.nextPage() + Log.e("isTeach", viewModel.isTeach.value.toString()) } } } diff --git a/app/src/main/java/com/seunggyu/stitch/viewModel/CreateNewMatchViewModel.kt b/app/src/main/java/com/seunggyu/stitch/viewModel/CreateNewMatchViewModel.kt index eda165f..64cb91a 100644 --- a/app/src/main/java/com/seunggyu/stitch/viewModel/CreateNewMatchViewModel.kt +++ b/app/src/main/java/com/seunggyu/stitch/viewModel/CreateNewMatchViewModel.kt @@ -1,6 +1,7 @@ package com.seunggyu.stitch.viewModel import android.graphics.Bitmap +import android.service.autofill.FieldClassification.Match import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -15,6 +16,7 @@ import com.seunggyu.stitch.data.RetrofitApi import com.seunggyu.stitch.data.RetrofitService import com.seunggyu.stitch.data.model.Location import com.seunggyu.stitch.data.model.request.CreateNewMatchRequest +import com.seunggyu.stitch.data.model.response.CreateNewMatchResponse import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -118,6 +120,11 @@ class CreateNewMatchViewModel : ViewModel() { val teach: Boolean get() = _teach + private var _imageUploaded = false + val imageUploaded: Boolean + get() = _imageUploaded + + lateinit var _match: CreateNewMatchResponse private val _allWritenFlow = flow { val emptySportsType = sportsType.value?.isEmpty() @@ -274,7 +281,9 @@ class CreateNewMatchViewModel : ViewModel() { _imageUrl.value = url } - fun setCreateSuccessListener(success: Boolean) { + fun setCreateSuccessListener(success: Boolean, match: CreateNewMatchResponse) { + _match = match + _createSuccessListener.value = success } @@ -300,7 +309,7 @@ class CreateNewMatchViewModel : ViewModel() { longitude = longitude.value, numOfMembsers = 1, startTime = "${startDate.value} ${startTime.value}", - isTeach = isTeach.value, + teach = isTeach.value, ) @@ -312,7 +321,7 @@ class CreateNewMatchViewModel : ViewModel() { val result = response.body() result?.let { Log.e("result>>>>>>>", result.toString()) - setCreateSuccessListener(true) + setCreateSuccessListener(true, result) } } else { diff --git a/app/src/main/java/com/seunggyu/stitch/viewModel/MainViewModel.kt b/app/src/main/java/com/seunggyu/stitch/viewModel/MainViewModel.kt index dc9b145..fb62e3f 100644 --- a/app/src/main/java/com/seunggyu/stitch/viewModel/MainViewModel.kt +++ b/app/src/main/java/com/seunggyu/stitch/viewModel/MainViewModel.kt @@ -8,10 +8,7 @@ import com.seunggyu.stitch.Util.SnackBarCustom import com.seunggyu.stitch.data.NaverMapApi import com.seunggyu.stitch.data.RetrofitApi import com.seunggyu.stitch.data.model.Location -import com.seunggyu.stitch.data.model.response.HomeDataResponse -import com.seunggyu.stitch.data.model.response.NetworkResponse -import com.seunggyu.stitch.data.model.response.NewMatch -import com.seunggyu.stitch.data.model.response.RecommendedMatch +import com.seunggyu.stitch.data.model.response.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -39,6 +36,11 @@ class MainViewModel : ViewModel() { val newMatchDataSetAvailable: LiveData get() = _newMatchDataSetAvailable + // 매치 클릭시 화면 이동 + private var _selectedMatch = MutableLiveData() + val selectedMatch: LiveData + get() = _selectedMatch + init { getHomeData() } @@ -78,4 +80,8 @@ class MainViewModel : ViewModel() { fun setNewMatchAvailable(boolean: Boolean) { _newMatchDataSetAvailable.value = boolean } + + fun setSelectedMatch(match: Match) { + _selectedMatch.value = match + } } \ No newline at end of file diff --git a/app/src/main/java/com/seunggyu/stitch/viewModel/MatchDetailPageViewModel.kt b/app/src/main/java/com/seunggyu/stitch/viewModel/MatchDetailPageViewModel.kt index 0a73dfa..2f9b4b4 100644 --- a/app/src/main/java/com/seunggyu/stitch/viewModel/MatchDetailPageViewModel.kt +++ b/app/src/main/java/com/seunggyu/stitch/viewModel/MatchDetailPageViewModel.kt @@ -2,9 +2,13 @@ import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.seunggyu.stitch.GlobalApplication import com.seunggyu.stitch.data.NaverMapApi import com.seunggyu.stitch.data.RetrofitApi +import com.seunggyu.stitch.data.model.request.JoinMatchRequest +import com.seunggyu.stitch.data.model.response.JoinedMember import com.seunggyu.stitch.data.model.response.Match +import com.seunggyu.stitch.data.model.response.SignupResponse import kotlinx.coroutines.* @@ -15,75 +19,41 @@ class MatchDetailPageViewModel : ViewModel() { val passedMatchId: LiveData get() = _passedMatchId + // 호스트 Id + private val _hostId = MutableLiveData() + val hostId: LiveData + get() = _hostId + + // 호스트 이름 + private val _hostName = MutableLiveData() + val hostName: LiveData + get() = _hostName + + // 호스트 프로필 이미지 + private val _hostImageUrl = MutableLiveData() + val hostImageUrl: LiveData + get() = _hostImageUrl + + // 참여 여부 + private val _isAlreadyMember = MutableLiveData(false) + val isAlreadyMember: LiveData + get() = _isAlreadyMember + + // 참여 여부 + private val _joinedMember = MutableLiveData>() + val joinedMember: LiveData> + get() = _joinedMember + + // 참여완료 여부 + private val _joinSuccess = MutableLiveData() + val joinSuccess: LiveData + get() = _joinSuccess /***************************** 매치 정보 수신 데이터 ******************************/ -// // 아이디 -// private val _matchId = MutableLiveData() -// val matchId: LiveData -// get() = _matchId -// // 타입 -// private val _matchType = MutableLiveData() -// val matchType: LiveData -// get() = _matchType -// // 주소 -// private val _location = MutableLiveData() -// val location: LiveData -// get() = _location -// // 이미지 url -// private val _imageUrl = MutableLiveData() -// val imageUrl: LiveData -// get() = _imageUrl -// // 제목 -// private val _name = MutableLiveData() -// val name: LiveData -// get() = _name -// // 상세 내용 -// private val _detail = MutableLiveData() -// val detail: LiveData -// get() = _detail -// // 시작 시간 YYYY-MM-DD HH:mm -// private val _startTime = MutableLiveData() -// val startTime: LiveData -// get() = _startTime -// // 진행 시간 (분단위) -// private val _duration = MutableLiveData() -// val duration: LiveData -// get() = _duration -// // 종목 -// private val _eventType = MutableLiveData() -// val eventType: LiveData -// get() = _eventType -// // 호스트 id -// private val _hostId = MutableLiveData() -// val hostId: LiveData -// get() = _hostId -// // 참가정원 -// private val _maxCapacity = MutableLiveData() -// val maxCapacity: LiveData -// get() = _maxCapacity -// // 참가비 -// private val _fee = MutableLiveData() -// val fee: LiveData -// get() = _fee -// // latitude -// private val _latitude = MutableLiveData() -// val latitude: LiveData -// get() = _latitude -// // longitude -// private val _longitude = MutableLiveData() -// val longitude: LiveData -// get() = _longitude -// // Teach여부 -// private val _teach = MutableLiveData() -// val teach: LiveData -// get() = _teach -// // 현재인원 -// private val _numOfMembers = MutableLiveData() -// val numOfMembers: LiveData -// get() = _numOfMembers private val _matchData = MutableLiveData() val matchData: LiveData get() = _matchData + /****************************************************************************/ @@ -100,24 +70,9 @@ class MatchDetailPageViewModel : ViewModel() { val result = response.body() result?.let { Log.e("result>>>>>>>", result.toString()) -// _matchId.value = it.match?.id -// _matchType.value = it.match?.type -// _location.value = it.match?.location -// _imageUrl.value = it.match?.imageUrl -// _name.value = it.match?.name -// _detail.value = it.match?.detail -// _startTime.value = it.match?.startTime -// _duration.value = it.match?.duration -// _eventType.value = it.match?.eventType -// _hostId.value = it.match?.hostId -// _maxCapacity.value = it.match?.maxCapacity -// _fee.value = it.match?.fee -// _latitude.value = it.match?.latitude -// _longitude.value = it.match?.longitude -// _teach.value = it.match?.teach -// _numOfMembers.value = it.match?.numOfMembers _matchData.value = it.match + _joinedMember.value = it.joinedMembers!! } } else { Log.e("TAG", response.code().toString()) @@ -126,4 +81,88 @@ class MatchDetailPageViewModel : ViewModel() { } } + fun getHostInfo(id: String) { + val service = RetrofitApi.retrofitService + + CoroutineScope(Dispatchers.IO).launch { + val response = service.getUserData(id) + + withContext(Dispatchers.Main) { + if (response.isSuccessful) { + val result = response.body() + result?.let { + Log.e("result>>>>>>>", result.toString()) + + _hostId.value = it.id + _hostName.value = it.name + _hostImageUrl.value = it.imageUrl + } + } else { + Log.e("TAG", response.code().toString()) + } + } + } + } + + fun joinMatch() { + val service = RetrofitApi.retrofitService + + CoroutineScope(Dispatchers.IO).launch { + val response = service.joinMatch(GlobalApplication.prefs.getCurrentUser().id, + JoinMatchRequest(matchData.value?.id.toString())) + Log.e("userId", GlobalApplication.prefs.getCurrentUser().id) + Log.e("Id.value", matchData.value?.id.toString()) + withContext(Dispatchers.Main) { + if (response.isSuccessful) { + val result = response.body() + result?.let { + Log.e("result>>>>>>>", result.toString()) + + _isAlreadyMember.value = true + _joinSuccess.value = true + } + } else { + Log.e("TAG", response.code().toString()) + } + } + } + } + + fun quitMatch() { + val service = RetrofitApi.retrofitService + + CoroutineScope(Dispatchers.IO).launch { + val response = service.quitMatch(GlobalApplication.prefs.getCurrentUser().id, + matchData.value?.id!!) + Log.e("userId", GlobalApplication.prefs.getCurrentUser().id) + Log.e("Id.value", matchData.value?.id.toString()) + + withContext(Dispatchers.Main) { + if (response.isSuccessful) { + val result = response.body() + result?.let { + Log.e("result>>>>>>>", result.toString()) + + _isAlreadyMember.value = true + _joinSuccess.value = false + } + } else { + Log.e("TAG", response.code().toString()) + } + } + } + } + + fun setPassedMatchId(id: String) { + _passedMatchId.value = id + } + + fun setMatchData(match: Match) { + _matchData.value = match + } + + fun setIsAlreadyMember(boolean: Boolean) { + _isAlreadyMember.value = boolean + } + } diff --git a/app/src/main/res/drawable/button_round_100_stroke_75_error.xml b/app/src/main/res/drawable/button_round_100_stroke_75_error.xml new file mode 100644 index 0000000..8981dd6 --- /dev/null +++ b/app/src/main/res/drawable/button_round_100_stroke_75_error.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_setting.xml b/app/src/main/res/drawable/ic_setting.xml new file mode 100644 index 0000000..129744c --- /dev/null +++ b/app/src/main/res/drawable/ic_setting.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_verify.xml b/app/src/main/res/drawable/ic_verify.xml new file mode 100644 index 0000000..1879684 --- /dev/null +++ b/app/src/main/res/drawable/ic_verify.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_match_detail_page.xml b/app/src/main/res/layout/activity_match_detail_page.xml index f42c0a7..17ca4e9 100644 --- a/app/src/main/res/layout/activity_match_detail_page.xml +++ b/app/src/main/res/layout/activity_match_detail_page.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools"> @@ -12,8 +13,8 @@ android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_constraintBottom_toTopOf="@+id/cl_match_detail_page_bottom" - android:background="@color/gray_14"> + android:background="@color/gray_14" + app:layout_constraintBottom_toTopOf="@+id/cl_match_detail_page_bottom"> - - - - - - - + app:layout_constraintStart_toStartOf="parent"> + + - + android:ellipsize="end" + android:maxLines="1" + android:textAppearance="@style/Subhead" + android:textColor="@color/gray_02" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/cv_match_detail_page_profile" + app:layout_constraintTop_toTopOf="@id/cv_match_detail_page_profile" + tools:text="이번주 토요일 상급자 레슨" /> - + android:orientation="horizontal" + app:layout_constraintBottom_toBottomOf="@id/cv_match_detail_page_profile" + app:layout_constraintStart_toEndOf="@id/cv_match_detail_page_profile"> - + - + - + - + - + - + - + - + - - + + + + + + + + + + + @@ -373,8 +397,8 @@ + app:layout_constraintTop_toBottomOf="@id/tv_match_detail_page_host_name" /> @@ -567,65 +594,105 @@ android:id="@+id/cl_match_detail_page_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@color/gray_14" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - android:background="@color/gray_14" app:layout_constraintStart_toStartOf="parent"> + + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent"> + + + app:layout_constraintEnd_toStartOf="@id/tv_button_join" + app:layout_constraintHorizontal_chainStyle="packed" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + android:textColor="@color/gray_12" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/iv_button_join" + app:layout_constraintTop_toTopOf="parent" /> - + + + + + + diff --git a/app/src/main/res/layout/activity_match_setting.xml b/app/src/main/res/layout/activity_match_setting.xml new file mode 100644 index 0000000..8158106 --- /dev/null +++ b/app/src/main/res/layout/activity_match_setting.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_report.xml b/app/src/main/res/layout/activity_report.xml new file mode 100644 index 0000000..8ed76c8 --- /dev/null +++ b/app/src/main/res/layout/activity_report.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_bottomsheet_menu_member.xml b/app/src/main/res/layout/dialog_bottomsheet_menu_member.xml new file mode 100644 index 0000000..98adbf3 --- /dev/null +++ b/app/src/main/res/layout/dialog_bottomsheet_menu_member.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/snackbar_custom_label.xml b/app/src/main/res/layout/snackbar_custom_label.xml new file mode 100644 index 0000000..19c7716 --- /dev/null +++ b/app/src/main/res/layout/snackbar_custom_label.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 04f5dc7..4812f4f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ + 1.0.0 ver STITCH 카테고리 @@ -123,6 +124,11 @@ 매치 개설을 그만 두시겠어요? 입력한 정보는 저장되지 않습니다. + 신고하기 + 매치 취소하기 + 취소 + 신고 사유를 적어주세요 +