diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cc2a809..6f7cc88 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -82,4 +82,7 @@ dependencies { //recyclerview implementation("androidx.recyclerview:recyclerview:1.3.2") + //image upload + implementation("com.github.bumptech.glide:glide:4.16.0") + } diff --git a/app/src/main/java/com/example/energy/data/repository/community/CommunityPost.kt b/app/src/main/java/com/example/energy/data/repository/community/CommunityPost.kt new file mode 100644 index 0000000..6af4e1b --- /dev/null +++ b/app/src/main/java/com/example/energy/data/repository/community/CommunityPost.kt @@ -0,0 +1,14 @@ +package com.example.energy.data.repository.community + +import android.net.Uri + +data class CommunityPost( + val userProfile: Int, //프로필 사진 + val userName: String, //사용자 이름 + val title: String, //제목 + val content: String, //내용 + val category: List, //카테고리 리스트 + val imageUrl: List, //사진 리스트 + val likes: String, //좋아요 수 + val comments: String, //댓글 수 +) diff --git a/app/src/main/java/com/example/energy/data/repository/community/WritingCommunityImage.kt b/app/src/main/java/com/example/energy/data/repository/community/WritingCommunityImage.kt new file mode 100644 index 0000000..06ab35a --- /dev/null +++ b/app/src/main/java/com/example/energy/data/repository/community/WritingCommunityImage.kt @@ -0,0 +1,8 @@ +package com.example.energy.data.repository.community + +import android.net.Uri + +data class WritingCommunityImage( + val imageUrl: Uri, // 선택한 이미지 + var isRepresentative: Boolean = false, // 대표 이미지 여부를 나타내는 속성 추가 +) diff --git a/app/src/main/java/com/example/energy/presentation/view/community/CommunityWholeFragment.kt b/app/src/main/java/com/example/energy/presentation/view/community/CommunityWholeFragment.kt index be2e5e8..c131203 100644 --- a/app/src/main/java/com/example/energy/presentation/view/community/CommunityWholeFragment.kt +++ b/app/src/main/java/com/example/energy/presentation/view/community/CommunityWholeFragment.kt @@ -1,17 +1,42 @@ package com.example.energy.presentation.view.community +import android.net.Uri import android.os.Bundle import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager import com.example.energy.R +import com.example.energy.data.repository.community.CommunityPost +import com.example.energy.data.repository.community.WritingCommunityImage import com.example.energy.databinding.FragmentCommunityWholeBinding import com.example.energy.presentation.view.base.BaseFragment class CommunityWholeFragment : BaseFragment({ FragmentCommunityWholeBinding.inflate(it)}) { + var postInfo = ArrayList() //선택한 이미지 데이터 리스트 + val categoriesList = listOf("도와줘요", "요청 중") //임시 카테고리 리스트 + val imageUrlsList: List = emptyList() // 임시 이미지 리스트 + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + // RecyclerView 연결 및 초기화 + binding.wholeCommunityPostRv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + val postCommunityAdapter = PostCommunityRVAdapter(postInfo) + binding.wholeCommunityPostRv.adapter = postCommunityAdapter + + // 더미데이터 + postInfo.apply{ + add(CommunityPost(R.drawable.user_profile, "김규리", "연희동 급 SOS", "혹시 지금 연희동 쪽으로 도움 주러 오실 수 있는 분 계신가요? 멈춰서 움직일수가 없어요ㅠㅠ", + categoriesList, imageUrlsList, "1", "3")) + add(CommunityPost(R.drawable.user_profile, "김규리", "연희동 급 SOS", "혹시 지금 연희동 쪽으로 도움 주러 오실 수 있는 분 계신가요? 멈춰서 움직일수가 없어요ㅠㅠ", + categoriesList, imageUrlsList, "1", "3")) + add(CommunityPost(R.drawable.user_profile, "김규리", "연희동 급 SOS", "혹시 지금 연희동 쪽으로 도움 주러 오실 수 있는 분 계신가요? 멈춰서 움직일수가 없어요ㅠㅠ", + categoriesList, imageUrlsList, "1", "3")) + add(CommunityPost(R.drawable.user_profile, "김규리", "연희동 급 SOS", "혹시 지금 연희동 쪽으로 도움 주러 오실 수 있는 분 계신가요? 멈춰서 움직일수가 없어요ㅠㅠ", + categoriesList, imageUrlsList, "1", "3")) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/energy/presentation/view/community/CommunityWritingActivity.kt b/app/src/main/java/com/example/energy/presentation/view/community/CommunityWritingActivity.kt index ebfe2cc..a30f0bd 100644 --- a/app/src/main/java/com/example/energy/presentation/view/community/CommunityWritingActivity.kt +++ b/app/src/main/java/com/example/energy/presentation/view/community/CommunityWritingActivity.kt @@ -1,23 +1,27 @@ package com.example.energy.presentation.view.community -import android.app.Activity +import android.app.Dialog import android.content.Intent -import android.content.Intent.ACTION_GET_CONTENT +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.net.Uri import android.os.Bundle -import android.provider.MediaStore -import android.widget.ImageView -import android.widget.LinearLayout +import android.view.ViewGroup +import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager +import com.example.energy.R +import com.example.energy.data.repository.community.WritingCommunityImage import com.example.energy.databinding.ActivityCommunityWritingBinding +import com.example.energy.databinding.DialogSelectCategoryBinding +import com.google.android.material.bottomsheet.BottomSheetDialog -class CommunityWritingActivity : AppCompatActivity(), WritingCommunityImageRVAdapter.MyItemClickListener { +class CommunityWritingActivity : AppCompatActivity(), GalleryAdapter.MyItemClickListener { private lateinit var binding: ActivityCommunityWritingBinding - var list = ArrayList() //선택한 이미지 데이터 리스트 - val adapter = WritingCommunityImageRVAdapter(list) //Recycler View Adapter + var imageList = ArrayList() //선택한 이미지 데이터 리스트 + val adapter = GalleryAdapter(imageList) //Recycler View Adapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -32,52 +36,73 @@ class CommunityWritingActivity : AppCompatActivity(), WritingCommunityImageRVAda // 어댑터에 클릭 리스너 설정 adapter.setMyItemClickListener(this) - // 이미지 업로드 - val selectImagesActivityResult = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode == Activity.RESULT_OK) { - val data: Intent? = result.data - // 다중 이미지 선택 - if (data?.clipData != null) { - val count = data.clipData?.itemCount ?: 0 - for (i in 0 until count) { - val imageUri = data.clipData!!.getItemAt(i).uri - addImageToList(imageUri) - } - } - // 단일 이미지 선택 - else if (data?.data != null) { - val imageUri: Uri? = data.data - if(imageUri !=null) { - addImageToList(imageUri) - } - } - } - adapter.notifyDataSetChanged() - - } - // 뒤로가기 버튼 binding.communityWritingBackIcon.setOnClickListener { finish() // 현재 액티비티 종료 } - // 이미지 업로드 버튼 클릭 시 + // 카테고리 선택 버튼 클릭 리스너 설정 + binding.communityWritingCategoryUnderBtn.setOnClickListener { + showCategoryDialog() + } + + // 이미지 업로드 사진 클릭 시 binding.communityWritingImageSelect.setOnClickListener { - val intent = Intent(ACTION_GET_CONTENT) - intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) - intent.type = "*/*" - selectImagesActivityResult.launch(intent) + val intent = Intent(Intent.ACTION_PICK) //갤러리 호출 + intent.type = "image/*" + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) //멀티 선택 기능 + activityResult.launch(intent) + } + } + private fun showCategoryDialog() { //카테고리 선택 화면 + val dialog = Dialog(this) + val binding = DialogSelectCategoryBinding.inflate(layoutInflater) + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) // 기존 다이어그램 배경 투명으로 적용(커스텀한 배경이 보이게 하기 위함) + dialog.window?.setLayout( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + dialog.setContentView(binding.root) + dialog.setCancelable(true) // 바깥 영역 터치하면 닫힘 + + // 다이얼로그 표시 + dialog.show() + } + + // 이미지 가져오기 + private var activityResult: ActivityResultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ){ + //결과 코드 OK, 결과값 null 아니면 (이미지를 선택하면..) + if (it.resultCode == RESULT_OK){ + //멀티 선택은 clip Data + if (it.data!!.clipData != null) { //멀티 이미지 + val count = it.data!!.clipData!!.itemCount //선택한 이미지 갯수 + for(index in 0 until count){ + val imageUri = it.data!!.clipData!!.getItemAt(index).uri //이미지 담기 + addImageToList(imageUri) //이미지 추가 + } + } else{ //싱글 이미지 + val imageUri = it.data!!.data + addImageToList(imageUri!!) + } + adapter.notifyDataSetChanged() } } private fun addImageToList(imageUri: Uri) { //데이터 리스트에 업로드하는 이미지 저장 - list.add(WritingCommunityImage(imageUri)) - adapter.notifyItemInserted(list.size - 1) + val isRepresentative = imageList.isEmpty() // 첫 번째 이미지인 경우 대표 이미지로 설정 + imageList.add(WritingCommunityImage(imageUri, isRepresentative)) + adapter.notifyItemInserted(imageList.size - 1) } override fun onRemoveImage(position: Int) { //이미지 삭제 adapter.removeImage(position) + // 대표 이미지가 삭제된 경우 새로운 대표 이미지 설정 + if (imageList.isNotEmpty() && !imageList.any { it.isRepresentative }) { + imageList[0].isRepresentative = true + adapter.notifyItemChanged(0) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/energy/presentation/view/community/WritingCommunityImageRVAdapter.kt b/app/src/main/java/com/example/energy/presentation/view/community/GalleryAdapter.kt similarity index 57% rename from app/src/main/java/com/example/energy/presentation/view/community/WritingCommunityImageRVAdapter.kt rename to app/src/main/java/com/example/energy/presentation/view/community/GalleryAdapter.kt index e39bb55..3721a05 100644 --- a/app/src/main/java/com/example/energy/presentation/view/community/WritingCommunityImageRVAdapter.kt +++ b/app/src/main/java/com/example/energy/presentation/view/community/GalleryAdapter.kt @@ -1,34 +1,44 @@ package com.example.energy.presentation.view.community import android.annotation.SuppressLint -import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.example.energy.data.repository.community.WritingCommunityImage import com.example.energy.databinding.ItemWritingCommunityImageBinding -class WritingCommunityImageRVAdapter (private val imageUrl: ArrayList): RecyclerView.Adapter() { + +class GalleryAdapter (private val imageUrl: ArrayList): RecyclerView.Adapter() { interface MyItemClickListener{ fun onRemoveImage(position: Int) } - // 외부에서 전달받은 Listener 객체를 Adapter에서 사용할 수 있도록 따로 저장할 변수 선언 + // Listener 객체를 Adapter에서 사용할 수 있도록 따로 저장할 변수 선언 private lateinit var mItemClickListener: MyItemClickListener fun setMyItemClickListener(itemClickListener: MyItemClickListener){ mItemClickListener = itemClickListener } - override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): WritingCommunityImageRVAdapter.ViewHolder { + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): GalleryAdapter.ViewHolder { // itemview 객체 생성 val binding: ItemWritingCommunityImageBinding = ItemWritingCommunityImageBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false) return ViewHolder(binding) } - override fun onBindViewHolder(holder: WritingCommunityImageRVAdapter.ViewHolder, position: Int) { - holder.bind(imageUrl[position]) + override fun onBindViewHolder(holder: GalleryAdapter.ViewHolder, position: Int) { + val currentImage = imageUrl[position] + + Glide.with(holder.itemView.context) + .load(imageUrl[position].imageUrl) //이미지 위치 + .into(holder.galleryView) //보여줄 위치 + + // 대표 이미지 표시 + holder.binding.representativeLabel.visibility = if (currentImage.isRepresentative) View.VISIBLE else View.GONE // X 아이콘 클릭 시 해당데이터 삭제 holder.binding.writingCommunityImageCancel.setOnClickListener { @@ -46,9 +56,10 @@ class WritingCommunityImageRVAdapter (private val imageUrl: ArrayList): RecyclerView.Adapter() { + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): PostCommunityRVAdapter.ViewHolder { + // itemview 객체 생성 + val binding: ItemCommunityPostBinding = ItemCommunityPostBinding.inflate( + LayoutInflater.from(viewGroup.context), viewGroup, false) + return ViewHolder(binding) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + holder.bind(postInfo[position]) + } + + + override fun getItemCount(): Int = postInfo.size + + inner class ViewHolder(val binding: ItemCommunityPostBinding): RecyclerView.ViewHolder(binding.root) { + fun bind(postInfo: CommunityPost) { + binding.itemCommunityPostUserProfile.setImageResource(postInfo.userProfile) + binding.itemCommunityPostUserName.text = postInfo.userName + binding.itemCommunityPostTitle.text = postInfo.title + binding.itemCommunityPostContent.text = postInfo.content + binding.itemCommunityPostLikeNum.text = postInfo.likes + binding.itemCommunityPostCommentNum.text = postInfo.comments + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/energy/presentation/view/community/WritingCommunityImage.kt b/app/src/main/java/com/example/energy/presentation/view/community/WritingCommunityImage.kt deleted file mode 100644 index 4248fa2..0000000 --- a/app/src/main/java/com/example/energy/presentation/view/community/WritingCommunityImage.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.example.energy.presentation.view.community - -import android.net.Uri - -data class WritingCommunityImage( - val imageUrl: Uri // 선택한 이미지 -) diff --git a/app/src/main/res/drawable/btn_sort_selected.xml b/app/src/main/res/drawable/btn_sort_selected.xml new file mode 100644 index 0000000..fdabe17 --- /dev/null +++ b/app/src/main/res/drawable/btn_sort_selected.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_sort_unselected.xml b/app/src/main/res/drawable/btn_sort_unselected.xml new file mode 100644 index 0000000..e3b0729 --- /dev/null +++ b/app/src/main/res/drawable/btn_sort_unselected.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/check_box.png b/app/src/main/res/drawable/check_box.png new file mode 100644 index 0000000..4184236 Binary files /dev/null and b/app/src/main/res/drawable/check_box.png differ diff --git a/app/src/main/res/drawable/comment_icon.png b/app/src/main/res/drawable/comment_icon.png new file mode 100644 index 0000000..16d2dd4 Binary files /dev/null and b/app/src/main/res/drawable/comment_icon.png differ diff --git a/app/src/main/res/drawable/dialog_style.xml b/app/src/main/res/drawable/dialog_style.xml new file mode 100644 index 0000000..be99c78 --- /dev/null +++ b/app/src/main/res/drawable/dialog_style.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/drawable/like_icon.png b/app/src/main/res/drawable/like_icon.png new file mode 100644 index 0000000..961d6cc Binary files /dev/null and b/app/src/main/res/drawable/like_icon.png differ diff --git a/app/src/main/res/drawable/representative_label_background.xml b/app/src/main/res/drawable/representative_label_background.xml new file mode 100644 index 0000000..e1fd5ab --- /dev/null +++ b/app/src/main/res/drawable/representative_label_background.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/drawable/tag_curious.png b/app/src/main/res/drawable/tag_curious.png new file mode 100644 index 0000000..0502f68 Binary files /dev/null and b/app/src/main/res/drawable/tag_curious.png differ diff --git a/app/src/main/res/drawable/tag_daily.png b/app/src/main/res/drawable/tag_daily.png new file mode 100644 index 0000000..6457fea Binary files /dev/null and b/app/src/main/res/drawable/tag_daily.png differ diff --git a/app/src/main/res/drawable/tag_help.png b/app/src/main/res/drawable/tag_help.png new file mode 100644 index 0000000..a203722 Binary files /dev/null and b/app/src/main/res/drawable/tag_help.png differ diff --git a/app/src/main/res/drawable/tag_scooter.png b/app/src/main/res/drawable/tag_scooter.png new file mode 100644 index 0000000..e20835a Binary files /dev/null and b/app/src/main/res/drawable/tag_scooter.png differ diff --git a/app/src/main/res/drawable/tag_wheelchair.png b/app/src/main/res/drawable/tag_wheelchair.png new file mode 100644 index 0000000..4be9a59 Binary files /dev/null and b/app/src/main/res/drawable/tag_wheelchair.png differ diff --git a/app/src/main/res/drawable/uncheck_box.png b/app/src/main/res/drawable/uncheck_box.png new file mode 100644 index 0000000..6ffd9cc Binary files /dev/null and b/app/src/main/res/drawable/uncheck_box.png differ diff --git a/app/src/main/res/drawable/under_vector.png b/app/src/main/res/drawable/under_vector.png new file mode 100644 index 0000000..e62492f Binary files /dev/null and b/app/src/main/res/drawable/under_vector.png differ diff --git a/app/src/main/res/drawable/user_profile.png b/app/src/main/res/drawable/user_profile.png new file mode 100644 index 0000000..219ffc1 Binary files /dev/null and b/app/src/main/res/drawable/user_profile.png differ diff --git a/app/src/main/res/drawable/writing_community_btn.png b/app/src/main/res/drawable/writing_community_btn.png new file mode 100644 index 0000000..a43f92a Binary files /dev/null and b/app/src/main/res/drawable/writing_community_btn.png differ diff --git a/app/src/main/res/layout/activity_community_writing.xml b/app/src/main/res/layout/activity_community_writing.xml index 5d9a17c..99b2960 100644 --- a/app/src/main/res/layout/activity_community_writing.xml +++ b/app/src/main/res/layout/activity_community_writing.xml @@ -40,7 +40,7 @@ android:text="완료" android:textSize="16sp" android:textStyle="bold" - android:textColor="#888886" + android:textColor="@color/gray_scale5" android:layout_marginTop="15dp" android:layout_marginEnd="20dp" app:layout_constraintTop_toTopOf="parent" @@ -50,7 +50,7 @@ android:id="@+id/divider1" android:layout_width="wrap_content" android:layout_height="2dp" - android:background="#D7D7D5" + android:background="@color/gray_scale4" android:layout_marginTop="15dp" app:layout_constraintTop_toBottomOf="@id/community_writing_name_tv" app:layout_constraintStart_toStartOf="parent"/> @@ -59,32 +59,60 @@ android:id="@+id/community_writing_category_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="게시글의 카테고리를 선택해주세요" + android:text="게시글의 카테고리를 선택해주세요." android:textSize="16sp" android:textStyle="bold" - android:textColor="#888886" + android:textColor="@color/gray_scale5" android:layout_marginTop="15dp" android:layout_marginStart="20dp" app:layout_constraintTop_toBottomOf="@id/divider1" app:layout_constraintStart_toStartOf="parent"/> + + + + + + + + - @@ -123,7 +151,7 @@ android:id="@+id/divider4" android:layout_width="wrap_content" android:layout_height="2dp" - android:background="#D7D7D5" + android:background="@color/gray_scale4" android:layout_marginTop="15dp" app:layout_constraintTop_toBottomOf="@id/community_writing_image_select" app:layout_constraintStart_toStartOf="parent"/> diff --git a/app/src/main/res/layout/dialog_select_category.xml b/app/src/main/res/layout/dialog_select_category.xml new file mode 100644 index 0000000..3ba7479 --- /dev/null +++ b/app/src/main/res/layout/dialog_select_category.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_community.xml b/app/src/main/res/layout/fragment_community.xml index 3766a29..4cd6c29 100644 --- a/app/src/main/res/layout/fragment_community.xml +++ b/app/src/main/res/layout/fragment_community.xml @@ -39,6 +39,7 @@ android:id="@+id/community_category_tab_layout" android:layout_width="match_parent" android:layout_height="60dp" + android:background="@android:color/white" android:gravity="center" app:tabMaxWidth="0dp" app:tabGravity="start" @@ -52,56 +53,75 @@ app:tabIndicatorGravity="bottom" app:tabSelectedTextColor="@color/black"/> - - + + + + + + - + app:layout_constraintStart_toEndOf="@id/community_recommended_layout" > + + + + -