diff --git a/app/build.gradle b/app/build.gradle index 1d81506..c64892a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ dependencies { //레트로핏 서버 implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' - implementation 'com.google.android.gms:play-services-location:19.0.1' + implementation 'com.google.android.gms:play-services-location:21.0.1' //비동기 implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0" @@ -79,4 +79,7 @@ dependencies { //날씨 implementation 'com.loopj.android:android-async-http:1.4.11' + + // Calendar + implementation 'com.github.prolificinteractive:material-calendarview:1.4.3' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 78937b8..7052703 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,13 @@ + + + + + + + @@ -12,29 +19,28 @@ android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" - android:icon="@mipmap/ic_launcher" + android:icon="@mipmap/ic_launcher1" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.MyApplication" android:usesCleartextTraffic="true" tools:targetApi="31"> - - - + diff --git a/app/src/main/ic_launcher1-playstore.png b/app/src/main/ic_launcher1-playstore.png new file mode 100644 index 0000000..543f1f0 Binary files /dev/null and b/app/src/main/ic_launcher1-playstore.png differ diff --git a/app/src/main/java/com/example/farmmate1/ApiService.kt b/app/src/main/java/com/example/farmmate1/ApiService.kt index c2a3e8a..dd4c800 100644 --- a/app/src/main/java/com/example/farmmate1/ApiService.kt +++ b/app/src/main/java/com/example/farmmate1/ApiService.kt @@ -1,36 +1,141 @@ package com.example.farmmate1 -import com.example.farmmate1.data.TodoItem -import com.example.farmmate1.network.ToDoListInterface import retrofit2.Call -import retrofit2.Response -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.* +import okhttp3.MultipartBody +import okhttp3.RequestBody +import com.example.farmmate1.api.SearchResponse interface ApiService { - @GET("plants") - fun getPlantList(): Call> - // 서버에서 식물 정보를 가져오는 GET 요청을 정의 - @POST("plants") + // 기기 등록 + @POST("device") @Headers("Content-Type: application/json") - fun createPlant(@Body plant: Plant): Call + fun saveDeviceInfo(@Body deviceInfo: DeviceInfo): Call - @GET("plants") - fun getPlant(): Call + //------------------------------------------------------------------------------- + // 식물 전체 GET 요청 + @GET("plant/device/{deviceId}") + fun getPlantList(@Path("deviceId") deviceId: String): Call> + // 서버에서 식물 정보를 가져오는 GET 요청을 정의 - @GET("history") - fun getHistoryList(): Call> - // 서버에서 진단 결과를 가져오는 GET 요청을 정의 + // 식물 POST 요청 + @Multipart + @POST("plant") + fun postPlant( + @PartMap data: HashMap, + @Part image: MultipartBody.Part? // 이미지 파일을 MultipartBody.Part로 전송 + ): Call - @POST("history") - @Headers("Content-Type: application/json") - fun saveResult(@Body history: History): Call + // 식물 개별 GET 요청 + @GET("plant/{plantUuid}") + fun getPlant(@Path("plantUuid") plantUuid: String?): Call + + // 식물 개별 PUT 요청 + @Multipart + @PUT("plant/{plantUuid}") + fun editPlant( + @Path("plantUuid") plantUuid: String, + @PartMap data: HashMap, + @Part image: MultipartBody.Part? // 이미지 파일을 MultipartBody.Part로 전송 + ): Call + + // 북마크 POST 요청 + @POST("plant/{plantUuid}/bookmark") + fun postBookmark(@Path("plantUuid")plantUuid: String): Call + + // 식물 DELETE 요청 + @DELETE("plant/{plantUuid}") + fun deletePlant(@Path("plantUuid")plantUuid: String?): Call + + // 북마크 GET 요청 + @GET("plant/device/{deviceId}/bookmark") + fun getBookmark(@Path("deviceId")deviceId: String): Call> + + //------------------------------------------------------------------------------- + + // 일지 post 요청 + @Multipart + @POST("diary") + fun postDiary( + //@Query("plant_uuid") plantUuid: String?, + //@Path("plantUuid") plantUuid: String, + @PartMap data: HashMap, + @Part image: MultipartBody.Part? // 이미지 파일을 MultipartBody.Part로 전송 + ): Call + + // 일지 개별 GET 요청 + @GET("diary/{diaryUuid}") + fun getDiary(@Path("diaryUuid") diaryUuid: String?): Call + + // 모든 일지 GET 요청 + @GET("diary") + //fun getDiaryList(@Query("plant.plant_name") plantName: String?): Call> + fun getDiaryList(): Call> + + // 일지 개별 PUT 요청 + @Multipart + @PUT("diary/{diaryUuid}") + fun editDiary( + @Path("diaryUuid") diaryUuid: String, + @PartMap data: HashMap, + @Part image: MultipartBody.Part? // 이미지 파일을 MultipartBody.Part로 전송 + ): Call + + // 이미지를 포함하지 않은 PUT 요청 + @Multipart + @PUT("diary/{diaryUuid}") + fun editDiaryWithoutImage( + @Path("diaryUuid") diaryUuid: String, + @PartMap data: HashMap, + ): Call + + + // 일지 개별 DELETE 요청 + @DELETE("diary/{diaryUuid}") + fun deleteDiary(@Path("diaryUuid")diaryUuid: String?): Call + + //------------------------------------------------------------------------------- + + // 진단 POST 요청 + @Multipart + @POST("plant/diagnose") + fun postDiagnosis( + @Part("plantType") plantType: RequestBody, + @Part image: MultipartBody.Part + ): Call + + // 진단 결과 저장 POST 요청 + @POST("plant/diagnose/result") + fun postDiagnosisSave(@Body request: DiagnosisSaveRequest): Call + + // 식물별 진단 결과 GET 요청 + @GET("plant/diagnose/result/plant/{plantUuid}") + fun getSavedResult(@Path("plantUuid") plantUuid: String?): Call> + + // 개별 진단 결과 GET 요청 + @GET("plant/diagnose/result/{plantDiseaseUuid}") + fun getResult(@Path("plantDiseaseUuid") plantDiseaseUuid: String?): Call + +//------------------------------------------------------------------------------- - @GET("history") - fun getHistory(): Call + @GET("service") + fun searchDiseases( + @Query("apiKey") apiKey: String, + @Query("serviceCode") serviceCode: String, + @Query("serviceType") serviceType: String, + @Query("cropName") cropName: String, + @Query("sickNameKor") sickNameKor: String, + @Query("displayCount") displayCount: Int, + @Query("startPoint") startPoint: Int + ): Call + @GET("service") + fun getDetail( + @Query("apiKey") apiKey: String, + @Query("serviceCode") serviceCode: String, + @Query("sickKey") sickKey: String + ): Call } \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/BookmarkAdapter.kt b/app/src/main/java/com/example/farmmate1/BookmarkAdapter.kt new file mode 100644 index 0000000..a7e823b --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/BookmarkAdapter.kt @@ -0,0 +1,74 @@ +package com.example.farmmate1 + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity + +class BookmarkAdapter(private val context: Context, private val bookmarkedPlants: List) : BaseAdapter() { + + override fun getCount(): Int { + return bookmarkedPlants.size + } + + override fun getItem(position: Int): Any { + return bookmarkedPlants[position] + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View = convertView ?: LayoutInflater.from(context).inflate(R.layout.list_item_bookmark, parent, false) + + val plantNameTextView: TextView = view.findViewById(R.id.bookmark_list_item_name) + val plantTypeTextView: TextView = view.findViewById(R.id.bookmark_list_item_type) + val firstPlantingDateTextView: TextView = view.findViewById(R.id.bookmark_list_item_startdate) + val bookmarkImg = view.findViewById(R.id.bookmark_list_item_profile) + + val plant = bookmarkedPlants[position] + plantNameTextView.text = plant.plant_name + plantTypeTextView.text = plant.plant_type + firstPlantingDateTextView.text = plant.first_planting_date + + val imageUrl = plant.image_url + ImageLoaderTask(bookmarkImg).execute(imageUrl) + + view.setOnClickListener { + // 해당 항목의 plant_uuid 가져오기 + val plantUuid = plant.plant_uuid + + // 다음 프래그먼트로 전환하기 위해 번들에 데이터 추가 + val bundle = Bundle() + bundle.putString("plantUuid", plantUuid) + + val plantInfoFragment = PlantInfoFragment() + plantInfoFragment.arguments = bundle +// + // 다음 프래그먼트로 이동하고 번들에 담긴 데이터 전달 + val transaction = (context as AppCompatActivity).supportFragmentManager.beginTransaction() + transaction.replace(R.id.main_fl, plantInfoFragment) + transaction.addToBackStack(null) + transaction.commit() + +// parentFragmentManager +// requireActivity().supportFragmentManager +// .beginTransaction() +// .replace(R.id.main_fl, plantInfoFragment) +// .commit() + +// val transaction = parentFragmentManager +// .beginTransaction() +// .replace(R.id.main_fl, diaryAddFragment) +// transaction.commit() + } + + return view + } +} diff --git a/app/src/main/java/com/example/farmmate1/CustomMultipleDotSpan.kt b/app/src/main/java/com/example/farmmate1/CustomMultipleDotSpan.kt new file mode 100644 index 0000000..4914bd1 --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/CustomMultipleDotSpan.kt @@ -0,0 +1,71 @@ +package com.example.farmmate1 + +import android.graphics.Canvas +import android.graphics.Paint +import android.text.style.LineBackgroundSpan +import android.util.Log + +class CustomMultipleDotSpan(private val radius: Float = DEFAULT_RADIUS, private val colors: IntArray) : LineBackgroundSpan { + + companion object { + private const val DEFAULT_RADIUS = 5f + } + +// override fun drawBackground( +// canvas: Canvas, paint: Paint, left: Int, right: Int, top: Int, baseline: Int, bottom: Int, +// charSequence: CharSequence, start: Int, end: Int, lineNum: Int +// ) { +// val total = if (colors.size > 3) 3 else colors.size +// var leftMost = (total - 1) * -12 +// +// for (i in 0 until total) { +// val oldColor = paint.color +// if (colors[i] != 0) { +// paint.color = colors[i] +// } +// canvas.drawCircle(((left + right) / 2 - leftMost).toFloat(), bottom + radius, radius, paint) +// paint.color = oldColor +// leftMost += 24 +// } +// } +override fun drawBackground( + canvas: Canvas, paint: Paint, left: Int, right: Int, top: Int, baseline: Int, bottom: Int, + charSequence: CharSequence, start: Int, end: Int, lineNum: Int +) { + val total = colors.size + val centerX = (left + right) / 2 // 가운데 x 좌표 + + // 각 점 사이의 간격 계산 + val interval: Float = if (total > 1) { + if (total % 2 == 0) { // 짝수인 경우 + (right - left - radius * 2) / (total*3.3 - 1).toFloat() + } else { // 홀수인 경우 + (right - left - radius * 2) / (total*2).toFloat() + } + } else { + 0f + } + + var currentX = centerX - (interval * (total - 1) / 2) // 첫 번째 점의 x 좌표 계산 + + for (i in 0 until total) { + val oldColor = paint.color + if (colors[i] != 0) { + paint.color = colors[i] + } + + // 각 점의 x 좌표 계산 + val x = currentX.toFloat() + Log.d("CustomMultipleDotSpan", "점 ${i + 1}의 x 좌표: $x") + + canvas.drawCircle(x, bottom + radius, radius, paint) // 점 그리기 + paint.color = oldColor + + currentX += interval.toInt() // 다음 점으로 이동 + } +} + + + + +} diff --git a/app/src/main/java/com/example/farmmate1/DeviceInfo.kt b/app/src/main/java/com/example/farmmate1/DeviceInfo.kt new file mode 100644 index 0000000..5140150 --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DeviceInfo.kt @@ -0,0 +1,3 @@ +package com.example.farmmate1 + +data class DeviceInfo(val deviceId: String) diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisCameraFragment.kt b/app/src/main/java/com/example/farmmate1/DiagnosisCameraFragment.kt new file mode 100644 index 0000000..021b502 --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DiagnosisCameraFragment.kt @@ -0,0 +1,271 @@ +package com.example.farmmate1 + +import android.Manifest +import android.content.pm.PackageManager +import android.os.Bundle +import android.os.Environment +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import android.content.Intent +import android.provider.MediaStore +import android.app.Activity +import java.io.File +import android.graphics.Bitmap +import androidx.core.content.ContextCompat +import com.example.farmmate1.databinding.FragmentDiagnosisCameraBinding +import com.example.farmmate1.DiagnosisResult +import okhttp3.MediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.FileOutputStream +import java.io.IOException +import android.util.Log +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class DiagnosisCameraFragment : Fragment() { + + private val REQUEST_IMAGE_CAPTURE = 101 + private val CAMERA_PERMISSION_CODE = 102 + private val REQUEST_IMAGE_FROM_GALLERY = 103 + private val REQUEST_PERMISSION_CODE = 104 + + private var imagePath: String = "" + + private var _binding: FragmentDiagnosisCameraBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentDiagnosisCameraBinding.inflate(inflater, container, false) + val view = binding.root + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val selectedCrop = arguments?.getString("selectedCrop") + binding.diagnosisCameraTvPlant.text = "진단 할 식물: $selectedCrop" + + binding.diagnosisCameraBtnOpencam.setOnClickListener{ + checkCameraPermission() + } + + binding.diagnosisCameraBtnGallery.setOnClickListener { + getAlbum() + } + + // 초기에 진단하기 버튼 비활성화 + binding.diagnosisCameraBtnNext.visibility = View.INVISIBLE + + binding.diagnosisCameraBackIb.setOnClickListener { + moveToDiagnosisFragment() + } + + binding.diagnosisCameraBtnNext.setOnClickListener { + // 서버에 이미지 보내기 + sendDiagnosisToServer(selectedCrop) + } + + } + + private fun checkPermission(): Boolean { + val cameraPermission = ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.CAMERA + ) == PackageManager.PERMISSION_GRANTED + + val storagePermission = ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.READ_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED + + return cameraPermission && storagePermission + } + + private fun checkCameraPermission() { + // 카메라 권한이 부여되었는지 확인 + if (ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.CAMERA + ) != PackageManager.PERMISSION_GRANTED + ) { + // 권한이 없다면 권한 요청 + requestPermissions( + arrayOf(Manifest.permission.CAMERA), + CAMERA_PERMISSION_CODE + ) + } else { + // 권한이 이미 허용되었다면 사진 촬영 진행 + dispatchTakePictureIntent() + } + } + + // 권한이 없다면 권한 요청 > 요청 결과 처리 + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + if (requestCode == CAMERA_PERMISSION_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // 권한이 허용되면 사진 촬영 진행 + dispatchTakePictureIntent() + } else { + // 권한이 거부되었을 때 처리 + Toast.makeText(requireContext(), "권한이 필요합니다", Toast.LENGTH_SHORT).show() + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + REQUEST_IMAGE_CAPTURE -> { + // 사진 찍기 후 결과 이미지 처리 + saveCapturedImage(data) + } + REQUEST_IMAGE_FROM_GALLERY -> { + // 갤러리에서 이미지 선택 후 처리 + saveGalleryImage(data) + } + } + } + } + + private fun dispatchTakePictureIntent() { + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) + } + + fun getAlbum() { + if (checkPermission()) { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + startActivityForResult(intent, REQUEST_IMAGE_FROM_GALLERY) + } else { + requestPermissions( + arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE + ), + REQUEST_PERMISSION_CODE + ) + } + } + + private fun saveCapturedImage(data: Intent?) { + if (data != null && data.extras != null) { + val imageBitmap = data.extras!!.get("data") as Bitmap + + // 이미지를 파일로 저장 + imagePath = saveImageToFile(imageBitmap) + + // 이미지를 ImageView에 표시 + binding.diagnosisCameraIvImage.setImageBitmap(imageBitmap) + binding.diagnosisCameraBtnNext.visibility = View.VISIBLE + } + } + + private fun saveGalleryImage(data: Intent?) { + val imageUri = data?.data + val imageBitmap = MediaStore.Images.Media.getBitmap(requireActivity().contentResolver, imageUri) + + // 이미지를 파일로 저장 + imagePath = saveImageToFile(imageBitmap) + + // 이미지를 ImageView에 표시 + binding.diagnosisCameraIvImage.setImageBitmap(imageBitmap) + binding.diagnosisCameraBtnNext.visibility = View.VISIBLE + } + + private fun saveImageToFile(bitmap: Bitmap): String { + val filesDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) + val imageFile = File(filesDir, "captured_image.jpg") + + try { + FileOutputStream(imageFile).use { fos -> + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos) + fos.flush() + } + } catch (e: IOException) { + e.printStackTrace() + } + + return imageFile.absolutePath + } + + private fun moveToDiagnosisFragment() { + val transaction = parentFragmentManager + .beginTransaction() + .replace(R.id.main_fl, DiagnosisFragment()) + transaction.commit() + } + + private fun sendDiagnosisToServer(plantType: String?) { + + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + try { + val plantTypeBody = RequestBody.create(MediaType.parse("text/plain"), plantType) + + val imageFile = File(imagePath) + val imageRequestBody = RequestBody.create(MediaType.parse("image/*"), imageFile) + val imageBody = MultipartBody.Part.createFormData("image", imageFile.name, imageRequestBody) + + apiService.postDiagnosis(plantTypeBody, imageBody) + .enqueue(object : Callback { + override fun onResponse( + call: Call, + response: Response + ) { + // 요청 성공 시 처리 + if (response.isSuccessful) { + val diagnosisResult = response.body()?.let { + // 응답 데이터를 DiagnosisResult 객체로 변환 + DiagnosisResult( + it.diseaseUuid, + it.plantName, + it.diseaseName, + it.diseaseCode, + it.diseaseSymptom, + it.diseaseCause, + it.diseaseTreatment, + it.diagnosisCode, + it.plantImg + ) + } + val bundle = Bundle().apply { + putParcelable("diagnosisResult", diagnosisResult) + } + // Fragment 전환 + val diagnosisResultFragment = DiagnosisResultFragment() + diagnosisResultFragment.arguments = bundle + parentFragmentManager.beginTransaction() + .replace(R.id.main_fl, diagnosisResultFragment) + .commit() + } else { + // API 요청 실패 처리 + Log.e("CameraFragment", "Failed to fetch plant list: ${response.message()}") + } + } + + override fun onFailure(call: Call, t: Throwable) { + // 통신 오류 처리 + Log.e("CameraFragment", "Network error: ${t.message}") + } + }) + } catch (e: Exception) { + e.printStackTrace() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisFragment.kt b/app/src/main/java/com/example/farmmate1/DiagnosisFragment.kt index 2dc6f25..c406228 100644 --- a/app/src/main/java/com/example/farmmate1/DiagnosisFragment.kt +++ b/app/src/main/java/com/example/farmmate1/DiagnosisFragment.kt @@ -1,66 +1,212 @@ package com.example.farmmate1 +import android.content.Context +import android.graphics.Color import android.os.Bundle import android.util.Log +import android.view.Gravity import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.* import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.appcompat.app.AlertDialog import com.example.farmmate1.databinding.FragmentDiagnosisBinding +import com.prolificinteractive.materialcalendarview.CalendarDay import retrofit2.Call import retrofit2.Callback import retrofit2.Response - +import java.util.ArrayList class DiagnosisFragment : Fragment() { private var _binding: FragmentDiagnosisBinding? = null private val binding get() = _binding!! + private var selectedDate: CalendarDay? = null + private var selectedPlantName: String? = "" + private var selectedPlantUuid: String? = "" + private var historyList: ArrayList? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = FragmentDiagnosisBinding.inflate(inflater, container, false) val view = binding.root + + // 상단바 get + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + // SharedPreferences에서 디바이스 ID 가져오기 + val sharedPreferences = requireActivity().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + val deviceId: String = sharedPreferences.getString(DEVICE_ID_KEY, "") ?: "" + + val plantInfoName = arguments?.getString("plantInfoName") + + apiService.getPlantList(deviceId).enqueue(object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + val plantList = response.body() as? ArrayList + if (plantList != null) { + + setButtonTextForLinearLayout(plantList) + + // 이미 있는 버튼에 데이터 할당 + for (i in 0 until 5) { + val button = binding.diagnosisLinearlayout.getChildAt(i) as? Button + button?.setOnClickListener { + // 클릭된 버튼을 강조하기 위해 색상 변경 + onButtonClicked(button) + selectedPlantName = button?.text.toString() + selectedPlantUuid = plantList[i].plant_uuid + fetchDiaryListFromServer(selectedPlantUuid) + } + } + + // 동적으로 생성된 버튼 + for (i in 5 until binding.diagnosisLinearlayout.childCount) { + val button = binding.diagnosisLinearlayout.getChildAt(i) as? Button + button?.setOnClickListener { + // 클릭된 버튼을 강조하기 위해 색상 변경 + onButtonClicked(button) + selectedPlantName = button?.text.toString() + selectedPlantUuid = plantList[i].plant_uuid + fetchDiaryListFromServer(selectedPlantUuid) + } + } + + plantInfoName?.let { plantName -> + for (i in 0 until binding.diagnosisLinearlayout.childCount) { + val button = binding.diagnosisLinearlayout.getChildAt(i) as? Button + if (button?.text.toString() == plantName) { + button?.isSelected = true + selectedPlantName = plantName + selectedPlantUuid = plantList.find { it.plant_name == plantName }?.plant_uuid + fetchDiaryListFromServer(selectedPlantUuid) + break + } + } + } ?: run { + // 넘겨준 값이 없을 경우에는 맨 처음 버튼을 선택 상태로 지정 + val firstButton = binding.diagnosisLinearlayout.getChildAt(0) as? Button + firstButton?.isSelected = true + selectedPlantName = firstButton?.text.toString() + selectedPlantUuid = plantList[0].plant_uuid + fetchDiaryListFromServer(selectedPlantUuid) + } + } else { + // API 요청 실패 처리 + Log.e("DiagnosisFragment", "Failed to fetch plant list: ${response.message()}") + } + } + + override fun onFailure(call: Call>, t: Throwable) { + // 통신 오류 처리 + Log.e("DiaryFragment", "Network error: ${t.message}") + } + }) + return view } -// var HistoryList = arrayListOf( -// History(R.drawable.number_one, "2023-06-01", "정상"), -// History(R.drawable.number_two, "2023-06-01", "정상"), -// History(R.drawable.number_three, "2023-06-01", "정상"), -// History(R.drawable.number_four, "2023-06-01", "정상"), -// History(R.drawable.number_five, "2023-06-01", "정상"), -// History(R.drawable.number_six, "2023-06-01", "정상"), -// History(R.drawable.number_seven, "2023-06-01", "정상"), -// History(R.drawable.number_eight, "2023-06-01", "정상"), -// History(R.drawable.number_nine, "2023-06-01", "정상"), -// History(R.drawable.number_ten, "2023-06-01", "정상") -// ) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + // 진단하기 버튼 클릭 시 알림창 (진단할 작물 선택) + binding.diagnosisBtnDiagnosis.setOnClickListener{ + showCropSelectionDialog() + } + + // 리스트 객체 클릭 시 진단 결과 페이지로 이동.. + binding.diagnosisListLvHistory.setOnItemClickListener { parent, view, position, id -> + historyList?.let { list -> + if (position < list.size) { + val selectedHistory = list[position] + val bundle = Bundle().apply { + putString("plantDiseaseUuid", selectedHistory.plantDiseaseUuid) + } + val diagnosisSavedFragment = DiagnosisSavedFragment() + diagnosisSavedFragment.arguments = bundle + + val transaction = parentFragmentManager + .beginTransaction() + .replace(R.id.main_fl, diagnosisSavedFragment) + transaction.commit() + } + } + } + + } + + override fun onDestroyView() { + super.onDestroyView() + + // 메모리 누수를 방지하기 위해 Fragment View에 대한 참조를 제거하여 가비지 컬렉터가 수거 + _binding = null + } + + // LinearLayout에 버튼을 추가하는 함수 + fun setButtonTextForLinearLayout(plantList: List) { + for (i in 0 until plantList.size) { + val plantName = plantList[i].plant_name + if (i < 5) { + // 처음 다섯 개의 버튼에 텍스트만 할당 + val button = binding.diagnosisLinearlayout.getChildAt(i) as? Button + button?.text = plantName ?: "" + } else { + // 여섯 번째 요소부터 동적으로 버튼을 추가하며 텍스트 할당 + val button = Button(requireContext()) + button.text = plantName ?: "" + val layoutParams = LinearLayout.LayoutParams( + resources.getDimensionPixelSize(R.dimen.button_width), + resources.getDimensionPixelSize(R.dimen.button_height) + ) + val marginHorizontalPx = resources.getDimensionPixelSize(R.dimen.button_margin_horizontal) + layoutParams.setMargins(marginHorizontalPx, 0, marginHorizontalPx, 0) // 좌우 마진과 상단 마진을 dimens.xml에서 가져온 값으로 설정 + button.layoutParams = layoutParams + button.setTextColor(Color.BLACK) // 텍스트 색상 설정 + button.setBackgroundResource(R.drawable.rounded_btn) + button.gravity = Gravity.CENTER + + button.setPadding(0, -3, 0, 0) + layoutParams.weight = 1f + + button.setOnClickListener { + // 버튼이 클릭되었을 때 수행할 작업 추가 + } + binding.diagnosisLinearlayout.addView(button) + } + } + } + + // 모든 버튼을 클릭했을 때 호출되는 메서드 + fun onButtonClicked(clickedButton: Button) { + // 모든 버튼을 탐색하면서 클릭된 버튼인지 확인하고 상태를 변경합니다. + for (i in 0 until binding.diagnosisLinearlayout.childCount) { + val button = binding.diagnosisLinearlayout.getChildAt(i) as? Button + button?.isSelected = (button == clickedButton) + } + } + + private fun fetchDiaryListFromServer(plantUuid: String?){ val retrofit = RetrofitClient.instance val apiService = retrofit.create(ApiService::class.java) - // 데이터 요청 - apiService.getHistoryList().enqueue(object : Callback> { + apiService.getSavedResult(plantUuid).enqueue(object : Callback> { override fun onResponse(call: Call>, response: Response>) { if (response.isSuccessful) { - val historyList = response.body() as? ArrayList + historyList = response.body() as? ArrayList if (historyList != null) { - val adapter = HistoryAdapter(requireContext(), historyList) + // history 어댑터 연결 + val adapter = HistoryAdapter(requireContext(), historyList!!) binding.diagnosisListLvHistory.adapter = adapter } } else { @@ -75,51 +221,50 @@ class DiagnosisFragment : Fragment() { } }) - // history 어댑터 연결 -// val Adapter = HistoryAdapter(requireContext(),HistoryList) -// binding.diagnosisListLvHistory.adapter = Adapter + } - // 진단하기 버튼 클릭 시 페이지 이동 (진단할 작물 선택) - binding.diagnosisHistoryBtnDiagnosis.setOnClickListener{ - moveToDiagnosisSelectFragment() + private fun moveToDiagnosisCameraFragment(selectedCrop: String?) { + val bundle = Bundle().apply { + putString("selectedCrop", selectedCrop) // 선택한 작물을 번들에 저장 } - // 리스트 객체 클릭 시 진단 결과 페이지로 이동.. - binding.diagnosisListLvHistory.setOnItemClickListener { parent, view, position, id -> - moveToDiagnosisResultFragment()} - - } + val fragment = DiagnosisCameraFragment().apply { + arguments = bundle // 번들을 프래그먼트에 전달 + } - private fun moveToDiagnosisSelectFragment() { val transaction = parentFragmentManager .beginTransaction() - .replace(R.id.main_fl, DiagnosisSelectFragment()) + .replace(R.id.main_fl, fragment) transaction.commit() } - private fun moveToDiagnosisResultFragment() { - val transaction = parentFragmentManager - .beginTransaction() - .replace(R.id.main_fl, DiagnosisResultFragment()) - transaction.commit() - } + private var selectedCrop: String? = null // 선택한 작물을 저장할 변수 - override fun onDestroyView() { - super.onDestroyView() + private fun showCropSelectionDialog() { + val crops = arrayOf("가지", "고추", "단호박", "딸기", "상추", "수박", "애호박", "오이", "쥬키니호박", "참외", "토마토", "포도") + val checkedItem = -1 - // 메모리 누수를 방지하기 위해 Fragment View에 대한 참조를 제거하여 가비지 컬렉터가 수거 - _binding = null + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle("작물 종류를 선택하세요") + .setSingleChoiceItems(crops, checkedItem) { dialog, which -> + // 라디오 버튼을 클릭한 경우의 동작 설정 + selectedCrop = crops[which] // 선택한 작물 저장 + } + .setPositiveButton("다음") { dialog, which -> + // "다음" 버튼을 클릭한 경우의 동작 설정 + if (selectedCrop != null) { + moveToDiagnosisCameraFragment(selectedCrop!!) + dialog.dismiss() // 다이얼로그 닫기 + } else { + Toast.makeText(requireContext(), "진단할 작물을 선택하세요", Toast.LENGTH_SHORT).show() + // 왜 알림창이 닫힐까 ^^ + } + } + .setNegativeButton("취소") { dialog, which -> + // "취소" 버튼을 클릭한 경우의 동작 설정 + dialog.dismiss() // 다이얼로그 닫기 + } + .show() // 다이얼로그 표시 } - class MainViewModel : ViewModel() { - - private val _count = MutableLiveData() - val count : LiveData get() = _count - init { - _count.value = 5 - } - fun getUpdatedCount(plusCount: Int){ - _count.value = (_count.value)?.plus(plusCount) - } - } } diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisPost.kt b/app/src/main/java/com/example/farmmate1/DiagnosisPost.kt new file mode 100644 index 0000000..09f8e8d --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DiagnosisPost.kt @@ -0,0 +1,9 @@ +package com.example.farmmate1 + +import okhttp3.MultipartBody +import okhttp3.RequestBody + +class DiagnosisPost ( + val plantType: String, + var diagnosisImg: RequestBody +) \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisResult.kt b/app/src/main/java/com/example/farmmate1/DiagnosisResult.kt new file mode 100644 index 0000000..f28ac99 --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DiagnosisResult.kt @@ -0,0 +1,54 @@ +package com.example.farmmate1 + +import android.os.Parcel +import android.os.Parcelable + +data class DiagnosisResult( + val diseaseUuid: String, + val plantName: String, + val diseaseName: String, + val diseaseCode: Int, + val diseaseSymptom: String?, + val diseaseCause: String?, + val diseaseTreatment: String?, + val diagnosisCode: Int, + val plantImg: String? // 추가된 필드 +) : Parcelable { + constructor(parcel: Parcel) : this( + parcel.readString()!!, + parcel.readString()!!, + parcel.readString()!!, + parcel.readInt(), + parcel.readString(), + parcel.readString(), + parcel.readString(), + parcel.readInt(), + parcel.readString() // 추가된 필드 읽기 + ) + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeString(diseaseUuid) + parcel.writeString(plantName) + parcel.writeString(diseaseName) + parcel.writeInt(diseaseCode) + parcel.writeString(diseaseSymptom) + parcel.writeString(diseaseCause) + parcel.writeString(diseaseTreatment) + parcel.writeInt(diagnosisCode) + parcel.writeString(plantImg) // 추가된 필드 쓰기 + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): DiagnosisResult { + return DiagnosisResult(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } +} diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisResultFragment.kt b/app/src/main/java/com/example/farmmate1/DiagnosisResultFragment.kt index b15d20d..4f5a599 100644 --- a/app/src/main/java/com/example/farmmate1/DiagnosisResultFragment.kt +++ b/app/src/main/java/com/example/farmmate1/DiagnosisResultFragment.kt @@ -1,11 +1,15 @@ package com.example.farmmate1 +import android.app.AlertDialog +import android.content.Context import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.TextView import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -14,15 +18,12 @@ import com.example.farmmate1.databinding.FragmentDiagnosisResultBinding import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import java.util.ArrayList class DiagnosisResultFragment : Fragment() { private var _binding: FragmentDiagnosisResultBinding? = null private val binding get() = _binding!! - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -32,33 +33,91 @@ class DiagnosisResultFragment : Fragment() { return view } + private var selectedButtonId: Int = R.id.diagnosis_result_btn_symptom + private var plantList: ArrayList? = null + private var plantData: List> = emptyList() + private var diseaseUuid: String = "" + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val retrofit = RetrofitClient.instance - val apiService = retrofit.create(ApiService::class.java) + val diagnosisResult = arguments?.getParcelable("diagnosisResult") + + var diseaseName: String? = "" + var symptom: String? = "" + var cause: String? = "" + var treatment: String? = "" + var plantType: String? = "" + + if (diagnosisResult != null) { + diseaseUuid = diagnosisResult.diseaseUuid + + // 사진 + val plantImg = binding.diagnosisResultIvPhoto + + val imageUrl = diagnosisResult?.plantImg + ImageLoaderTask(plantImg).execute(imageUrl) + + // 결과 + diseaseName = diagnosisResult.diseaseName + binding.diagnosisResultTvName.text = diseaseName + // 처음에는 증상 + binding.diagnosisResultTvDetail.text = diagnosisResult.diseaseSymptom + + plantType = diagnosisResult.plantName + symptom = diagnosisResult.diseaseSymptom + cause = diagnosisResult.diseaseCause + treatment = diagnosisResult.diseaseTreatment + + if (diseaseName == "정상") { + binding.diagnosisResultBtnSymptom.visibility = View.GONE + binding.diagnosisResultBtnCause.visibility = View.GONE + binding.diagnosisResultBtnCure.visibility = View.GONE + binding.diagnosisResultTvDetail.text = "$plantType 진단 결과 정상 작물로 예측됩니다." + } + + } else { + Log.e("DiagnosisResultFragment", "DiagnosisResult object is null") + } + + selectButton(binding.diagnosisResultBtnSymptom) - // 데이터 요청 -// apiService.getHistoryList().enqueue(object : Callback> { -// override fun onResponse(call: Call>, response: Response>) { -// if (response.isSuccessful) { -// val historyList = response.body() as? ArrayList -// if (historyList != null) { -// val adapter = HistoryAdapter(requireContext(), historyList) -// binding.diagnosisListLvHistory.adapter = adapter -// } -// } else { -// // API 요청 실패 처리 -// Log.e("DiagnosisResultFragment", "Failed to fetch plant list: ${response.message()}") -// } -// } -// -// override fun onFailure(call: Call>, t: Throwable) { -// // 통신 오류 처리 -// Log.e("DiagnosisResultFragment", "Network error: ${t.message}") -// } -// }) + // 증상 + binding.diagnosisResultBtnSymptom.setOnClickListener { + selectButton(it) + binding.diagnosisResultTvDetail.text = symptom + } + + // 원인 + binding.diagnosisResultBtnCause.setOnClickListener { + selectButton(it) + binding.diagnosisResultTvDetail.text = cause + } + + // 치료법 + binding.diagnosisResultBtnCure.setOnClickListener { + selectButton(it) + binding.diagnosisResultTvDetail.text = treatment + } + + + // back button + binding.diagnosisResultBackIb.setOnClickListener { + moveToDiagnosisFragment() + } + // plantList GET + getPlantList() + + // 저장 + binding.diagnosisResultBtnSave.setOnClickListener { + showPlantSelectionDialog() + } + + // 재측정 + binding.diagnosisResultBtnRecheck.setOnClickListener { + moveToDiagnosisCameraFragment(plantType) + } } override fun onDestroyView() { @@ -68,15 +127,121 @@ class DiagnosisResultFragment : Fragment() { _binding = null } - class MainViewModel : ViewModel() { + private fun moveToDiagnosisFragment() { + val transaction = parentFragmentManager + .beginTransaction() + .replace(R.id.main_fl, DiagnosisFragment()) + transaction.commit() + } + + private fun moveToDiagnosisCameraFragment(plantType: String?) { + val transaction = parentFragmentManager.beginTransaction() + val fragment = DiagnosisCameraFragment() + + // 번들에 데이터 추가 + val bundle = Bundle() + bundle.putString("selectedCrop", plantType) + fragment.arguments = bundle - private val _count = MutableLiveData() - val count : LiveData get() = _count - init { - _count.value = 5 + transaction.replace(R.id.main_fl, fragment) + transaction.commit() + } + + + // 버튼을 선택 상태로 변경하는 함수 + private fun selectButton(button: View) { + // 이전에 선택된 버튼의 isSelected 속성을 false로 설정하여 선택 해제 + binding.diagnosisResultBtnSymptom.isSelected = false + binding.diagnosisResultBtnCause.isSelected = false + binding.diagnosisResultBtnCure.isSelected = false + + // 현재 선택된 버튼의 isSelected 속성을 true로 설정하여 선택 + button.isSelected = true + + // 선택된 버튼의 ID를 추적 + selectedButtonId = button.id + } + + private fun getPlantList(){ + // Retrofit 인스턴스 생성 + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + // SharedPreferences에서 디바이스 ID 가져오기 + val sharedPreferences = requireActivity().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + val deviceId: String = sharedPreferences.getString(DEVICE_ID_KEY, "") ?: "" + + apiService.getPlantList(deviceId).enqueue(object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + val plantList = response.body() as? ArrayList + if (plantList != null) { + // 작물 이름과 plant_uuid를 매핑하여 리스트에 저장 + plantData = plantList.map { (it.plant_name ?: "Unknown") to it.plant_uuid } + } else { + Log.e("DiaryResultFragment", "Failed to fetch user crops: ${response.message()}") + } + } + + override fun onFailure(call: Call>, t: Throwable) { + Log.e("DiaryResultFragment", "Network error: ${t.message}") + } + }) + } + + private fun showPlantSelectionDialog() { + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle("작물 선택") + + val plantNames = plantData.map { it.first }.toTypedArray() + var selectedPlantIndex = 0 // 초기 선택된 항목의 인덱스를 추적 + + // 라디오 버튼으로 작물 목록 표시 + builder.setSingleChoiceItems(plantNames, selectedPlantIndex) { dialog, which -> + selectedPlantIndex = which // 선택한 항목의 인덱스 업데이트 } - fun getUpdatedCount(plusCount: Int){ - _count.value = (_count.value)?.plus(plusCount) + + // 다음 버튼 + builder.setPositiveButton("다음") { dialog, _ -> + val selectedPlantUuid = plantData[selectedPlantIndex].second + val request = DiagnosisSaveRequest(selectedPlantUuid, diseaseUuid) + Log.d("DiagnosisResultFragment", "$selectedPlantUuid, $diseaseUuid") + postDiagnosisSave(request) + + dialog.dismiss() } + + // 취소 버튼 + builder.setNegativeButton("취소") { dialog, _ -> + dialog.dismiss() + } + + builder.show() + } + + private fun postDiagnosisSave(request: DiagnosisSaveRequest) { + // Retrofit 인스턴스 생성 + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + // POST 요청 보내기 + apiService.postDiagnosisSave(request).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + // 요청이 성공적으로 처리된 경우의 처리 로직 + Log.d("DiagnosisResultFragment", "Diagnosis saved successfully.") + moveToDiagnosisFragment() + } else { + // 요청이 실패한 경우의 처리 로직 + Log.e("DiagnosisResultFragment", "Failed to save diagnosis: ${response.message()}") + } + } + + override fun onFailure(call: Call, t: Throwable) { + // 네트워크 오류 또는 예외 발생 시의 처리 로직 + Log.e("DiagnosisResultFragment", "Network error: ${t.message}") + } + }) } + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisSaveRequest.kt b/app/src/main/java/com/example/farmmate1/DiagnosisSaveRequest.kt new file mode 100644 index 0000000..0678214 --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DiagnosisSaveRequest.kt @@ -0,0 +1,6 @@ +package com.example.farmmate1 + +data class DiagnosisSaveRequest( + val plantUuid: String, + val diseaseUuid: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisSavedFragment.kt b/app/src/main/java/com/example/farmmate1/DiagnosisSavedFragment.kt new file mode 100644 index 0000000..933255e --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DiagnosisSavedFragment.kt @@ -0,0 +1,144 @@ +package com.example.farmmate1 + +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.example.farmmate1.databinding.FragmentDiagnosisSavedBinding +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import java.text.SimpleDateFormat +import java.util.* + +class DiagnosisSavedFragment : Fragment() { + + private var _binding: FragmentDiagnosisSavedBinding? = null + private val binding get() = _binding!! + + private lateinit var plantDiseaseUuid: String + + private var symptom: String? = "" + private var cause: String? = "" + private var treatment: String? = "" + private var selectedButtonId: Int = R.id.diagnosis_result_btn_symptom + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + } + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentDiagnosisSavedBinding.inflate(inflater, container, false) + val view = binding.root + + plantDiseaseUuid = arguments?.getString("plantDiseaseUuid") ?: "" + plantDiseaseUuid?.let { uuid -> + + // Retrofit 인스턴스 생성 + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + Log.d("DiagnosisSavedFragment", "Uuid: $plantDiseaseUuid") + + apiService.getResult(plantDiseaseUuid).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + val historyget = response.body() + // 데이터를 받아온 후에 해당 데이터를 View에 설정해주는 작업을 수행 + + Log.d("DiagnosisSavedFragment", "$historyget") + + binding.diagnosisSavedTvName.text = historyget?.disease?.diseaseName + binding.diagnosisSavedTvDetail.text = historyget?.disease?.diseaseSymptom + + // 사진 + val plantImg = binding.diagnosisSavedIvPhoto + + val imageUrl = historyget?.disease?.plantImg + ImageLoaderTask(plantImg).execute(imageUrl) + + symptom = historyget?.disease?.diseaseSymptom + cause = historyget?.disease?.diseaseCause + treatment = historyget?.disease?.diseaseTreatment + val plantType = historyget?.disease?.plantName + + if (historyget?.disease?.diseaseName == "정상") { + binding.diagnosisSavedBtnSymptom.visibility = View.GONE + binding.diagnosisSavedBtnCause.visibility = View.GONE + binding.diagnosisSavedBtnCure.visibility = View.GONE + binding.diagnosisSavedTvDetail.text = "$plantType 진단 결과 정상 작물로 예측됩니다." + } + } else { + // API 요청 실패 처리 + Log.e("DiagnosisSavedFragment", "Failed to fetch plant: ${response.message()}") + } + } + + override fun onFailure(call: Call, t: Throwable) { + // 통신 오류 처리 + Log.e("DiagnosisSavedFragment", "Network error: ${t.message}") + } + }) + } + + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + selectButton(binding.diagnosisSavedBtnSymptom) + + // 증상 + binding.diagnosisSavedBtnSymptom.setOnClickListener { + selectButton(it) + binding.diagnosisSavedTvDetail.text = symptom + } + + // 원인 + binding.diagnosisSavedBtnCause.setOnClickListener { + selectButton(it) + binding.diagnosisSavedTvDetail.text = cause + } + + // 치료법 + binding.diagnosisSavedBtnCure.setOnClickListener { + selectButton(it) + binding.diagnosisSavedTvDetail.text = treatment + } + + + // back button + binding.diagnosisSavedBackIb.setOnClickListener { + moveToDiagnosisFragment() + } + } + + private fun selectButton(button: View) { + // 이전에 선택된 버튼의 isSelected 속성을 false로 설정하여 선택 해제 + binding.diagnosisSavedBtnSymptom.isSelected = false + binding.diagnosisSavedBtnCause.isSelected = false + binding.diagnosisSavedBtnCure.isSelected = false + + // 현재 선택된 버튼의 isSelected 속성을 true로 설정하여 선택 + button.isSelected = true + + // 선택된 버튼의 ID를 추적 + selectedButtonId = button.id + } + + private fun moveToDiagnosisFragment() { + val transaction = parentFragmentManager + .beginTransaction() + .replace(R.id.main_fl, DiagnosisFragment()) + transaction.commit() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/DiagnosisSelectFragment.kt b/app/src/main/java/com/example/farmmate1/DiagnosisSelectFragment.kt deleted file mode 100644 index 072adc6..0000000 --- a/app/src/main/java/com/example/farmmate1/DiagnosisSelectFragment.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.example.farmmate1 - -import android.os.Bundle -import androidx.fragment.app.Fragment -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ArrayAdapter -import com.example.farmmate1.databinding.FragmentDiagnosisSelectBinding -import com.example.farmmate1.databinding.FragmentPlantAddBinding - - -class DiagnosisSelectFragment : Fragment() { - - private var _binding: FragmentDiagnosisSelectBinding? = null - private val binding get() = _binding!! - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - } - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - _binding = FragmentDiagnosisSelectBinding.inflate(inflater, container, false) - val view = binding.root - return view - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val retrofit = RetrofitClient.instance - val apiService = retrofit.create(ApiService::class.java) - - // 데이터 요청 -// apiService.getHistoryList().enqueue(object : Callback> { -// override fun onResponse(call: Call>, response: Response>) { -// if (response.isSuccessful) { -// val historyList = response.body() as? ArrayList -// if (historyList != null) { -// val adapter = HistoryAdapter(requireContext(), historyList) -// binding.diagnosisListLvHistory.adapter = adapter -// } -// } else { -// // API 요청 실패 처리 -// Log.e("DiagnosisResultFragment", "Failed to fetch plant list: ${response.message()}") -// } -// } -// -// override fun onFailure(call: Call>, t: Throwable) { -// // 통신 오류 처리 -// Log.e("DiagnosisResultFragment", "Network error: ${t.message}") -// } -// }) - - // 작물 종류 선택 (등록한 작물) - setUpSpinnerMyplants() - - // 작물 종류 선택 (등록하지 않은 작물) - setUpSpinnerAnyplants() - - // 뒤로 가기 버튼 클릭 후 진단 메인 페이지로 이동 - binding.diagnosisSelectBackIb.setOnClickListener{ - moveToDiagnosisFragment() - } - } - - private fun setUpSpinnerMyplants() { - val myplants = resources.getStringArray(R.array.myplants) - val adapter = ArrayAdapter(requireContext(),R.layout.spinner_item_myplant, myplants) - val spinner = binding.diagnosisSelectSpinnerMyplant - spinner.adapter = adapter - } - - private fun setUpSpinnerAnyplants() { - val anyplants = resources.getStringArray(R.array.anyplants) - val adapter = ArrayAdapter(requireContext(),R.layout.spinner_item_anyplant, anyplants) - val spinner = binding.diagnosisSelectSpinnerAnyplant - spinner.adapter = adapter - } - - private fun moveToDiagnosisFragment() { - val transaction = parentFragmentManager - .beginTransaction() - .replace(R.id.main_fl, DiagnosisFragment()) - transaction.commit() - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/Diary b/app/src/main/java/com/example/farmmate1/Diary new file mode 100644 index 0000000..7e0974e --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/Diary @@ -0,0 +1,18 @@ +package com.example.farmmate1 + +data class Diary( + val plantName: String, + val diaryDate: String, + val plantWeather: String, + val temperature: String, + val humidity: String, + val waterFlag: Boolean, + val fertilizeFlag: Boolean, + val fertilizeName: String, + val fertilizeUsage: String, + val pesticideFlag: Boolean, + val pesticideName: String, + val pesticideUsage: String, + val memo: String, + val imageData: ByteArray? = null +) diff --git a/app/src/main/java/com/example/farmmate1/DiaryAddFragment.kt b/app/src/main/java/com/example/farmmate1/DiaryAddFragment.kt new file mode 100644 index 0000000..3185388 --- /dev/null +++ b/app/src/main/java/com/example/farmmate1/DiaryAddFragment.kt @@ -0,0 +1,375 @@ +package com.example.farmmate1 + +import android.Manifest +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Bundle +import android.provider.MediaStore +import android.provider.OpenableColumns +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.* +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.example.farmmate1.data.* +import com.example.farmmate1.databinding.FragmentDiaryAddBinding +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import java.text.SimpleDateFormat +import java.util.* +import com.prolificinteractive.materialcalendarview.* +import okhttp3.MediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody + +class DiaryAddFragment : Fragment() { + + // 날짜 데이터 전달받아 인스턴스 생성 + companion object { + private const val ARG_DATE = "arg_date" + + fun newInstance(date: Calendar): DiaryAddFragment { + val args = Bundle().apply { + putSerializable(ARG_DATE, date) + } + val fragment = DiaryAddFragment() + fragment.arguments = args + return fragment + } + } + + private val REQUEST_IMAGE_FROM_GALLERY = 103 + private val REQUEST_PERMISSION_CODE = 104 + + private var selectedPlantUuid: String = "" + private var plantList: ArrayList? = null + + private var _binding: FragmentDiaryAddBinding? = null + private val binding get() = _binding!! // !! -> non-null assertion + + private var imageData: ByteArray? = null + private var image: MultipartBody.Part? = null + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentDiaryAddBinding.inflate(inflater, container, false) + val view = binding.root + + return view + } + + private var checkedItems = mutableSetOf() // 체크된 항목 기록 + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // 스피너에 사용자 작물 목록 설정 + loadUserCropsToSpinner() + + // 스피너에서 항목을 선택할 때마다 선택한 작물의 plant_uuid를 저장 + binding.diaryAddSpinnerSelect.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + // 선택한 작물의 plant_uuid 저장 + selectedPlantUuid = (binding.diaryAddSpinnerSelect.selectedItem as? Pair)?.second ?: "" + Log.d("DiaryAdd-- plant_uuid", "$selectedPlantUuid") + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + // 아무것도 선택하지 않았을 때, 첫 번째 항목을 기본값으로 설정 + selectedPlantUuid = (binding.diaryAddSpinnerSelect.getItemAtPosition(0) as? Pair)?.second ?: "" + + } + } + + // Post 요청할 때 selectedPlantUuid 사용 + // 예: saveDiaryEntry(selectedPlantUuid, ...) + + // 일지 작성 페이지 상단에 기록하는 날짜 표시 + val selectedDate = arguments?.getSerializable(ARG_DATE) as? Calendar + selectedDate?.let { + val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + val formattedDate = dateFormat.format(it.time) + binding.diaryAddTvDate.text = formattedDate + } ?: run { + binding.diaryAddTvDate.text = "에러 발생" // 날짜가 없을 경우에 대한 처리 (빈 문자열로 표시) + } + + binding.diaryAddIbImage.setOnClickListener { + openGallery() + } + + binding.diaryAddBtnEnroll.setOnClickListener { + val selectedPlant = binding.diaryAddSpinnerSelect.selectedItem.toString() + val temperatureText = binding.diaryAddEtTemperature.text.toString() + val humidityText = binding.diaryAddEtHumidity.text.toString() + + if (validateTemperature(temperatureText) && validateHumidity(humidityText)) { + postDiary() + } + } + + //back button + binding.diaryAddBackIb.setOnClickListener { + moveToDiaryFragment() + } + } + + // 스피너에 사용자 작물 목록 설정 + private fun loadUserCropsToSpinner() { + // Retrofit 인스턴스 생성 + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + // SharedPreferences에서 디바이스 ID 가져오기 + val sharedPreferences = requireActivity().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + val deviceId: String = sharedPreferences.getString(DEVICE_ID_KEY, "") ?: "" + + apiService.getPlantList(deviceId).enqueue(object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + val plantList = response.body() as? ArrayList + if (plantList != null) { + // 작물 이름과 plant_uuid를 매핑하여 리스트에 저장 + val plantData = plantList.map { (it.plant_name ?: "Unknown") to it.plant_uuid } + val spinnerAdapter = object : ArrayAdapter>( + requireContext(), + android.R.layout.simple_spinner_item, + plantData + ) { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = super.getView(position, convertView, parent) + val plantName = getItem(position)?.first + val textView = view.findViewById(android.R.id.text1) + textView.text = plantName + return view + } + override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = super.getDropDownView(position, convertView, parent) + val plantName = getItem(position)?.first + val textView = view.findViewById(android.R.id.text1) + textView.text = plantName + return view + } + } + spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + binding.diaryAddSpinnerSelect.adapter = spinnerAdapter + } else { + Log.e("DiaryAddFragment", "Failed to fetch user crops: ${response.message()}") + } + } + + override fun onFailure(call: Call>, t: Throwable) { + Log.e("DiaryAddFragment", "Network error: ${t.message}") + } + }) + } + + private fun postDiary() { + + Log.d("DiaryAdd-- Post plant_uuid","$selectedPlantUuid") + val diaryDate = binding.diaryAddTvDate.text.toString() + val plantUuid = selectedPlantUuid + val plantWeather = binding.diaryAddEtWeather.text.toString() + val temperature = binding.diaryAddEtTemperature.text.toString() + val humidity = binding.diaryAddEtHumidity.text.toString() + val waterFlag = binding.diaryAddCbWater.isChecked.toString() + val fertilizeFlag = binding.diaryAddCbFert.isChecked.toString() + val fertilizeName = binding.diaryAddEtFert.text.toString() + val fertilizeUsage = binding.diaryAddEtFertuse.text.toString() + val pesticideFlag = binding.diaryAddCbPes.isChecked.toString() + val pesticideName = binding.diaryAddEtPes.text.toString() + val pesticideUsage = binding.diaryAddEtPesuse.text.toString() + val memo = binding.diaryAddEtMemo.text.toString() + + val requestBodyMap = hashMapOf() + requestBodyMap["plantUuid"] = createPartFromString(plantUuid) + requestBodyMap["diaryDate"] = createPartFromString(diaryDate) + requestBodyMap["plantWeather"] = createPartFromString(plantWeather) + requestBodyMap["temperature"] = createPartFromString(temperature) + requestBodyMap["humidity"] = createPartFromString(humidity) + requestBodyMap["waterFlag"] = createPartFromString(waterFlag) + requestBodyMap["fertilizeFlag"] = createPartFromString(fertilizeFlag) + requestBodyMap["fertilizeName"] = createPartFromString(fertilizeName) + requestBodyMap["fertilizeUsage"] = createPartFromString(fertilizeUsage) + requestBodyMap["pesticideFlag"] = createPartFromString(pesticideFlag) + requestBodyMap["pesticideName"] = createPartFromString(pesticideName) + requestBodyMap["pesticideUsage"] = createPartFromString(pesticideUsage) + requestBodyMap["memo"] = createPartFromString(memo) + + // 이미지 데이터를 MultipartBody.Part로 변환 + val imagePart = image + + // Retrofit 인스턴스 생성 + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + plantUuid?.let { + apiService.postDiary(requestBodyMap, imagePart).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + Log.d("전송성공", "전송성공") + moveToDiaryFragment() + } else { + // 전송 실패 + Log.d("전송실패", "전송실패") + } + } + + override fun onFailure(call: Call, t: Throwable) { + // 전송 실패 + Log.d("전송실패who", "전송실who패") + } + }) + } ?: Log.d("전송실패", "플랜트 UUID가 null입니다.") + } + + private fun createPartFromString(string: String): RequestBody { + return RequestBody.create(MediaType.parse("text/plain"), string) + } + + private fun validateTemperature(temperatureText: String): Boolean { + if (temperatureText.isEmpty()) { + // 온도가 비어있는 경우 + Toast.makeText(requireContext(), "온도를 입력하세요.", Toast.LENGTH_SHORT).show() + return false + } + + val temperature = temperatureText.toIntOrNull() + if (temperature == null) { + // 온도가 숫자로 변환할 수 없는 경우 + Toast.makeText(requireContext(), "온도는 숫자로 입력하세요.", Toast.LENGTH_SHORT).show() + return false + } + + if (temperature < -40 || temperature > 40) { + // 온도가 범위를 벗어난 경우 + Toast.makeText(requireContext(), "온도는 -40도에서 50도 사이로 입력하세요.", Toast.LENGTH_SHORT).show() + return false + } + + return true + } + + private fun validateHumidity(humidityText: String): Boolean { + if (humidityText.isEmpty()) { + // 습도가 비어있는 경우 + Toast.makeText(requireContext(), "습도를 입력하세요.", Toast.LENGTH_SHORT).show() + return false + } + + val humidity = humidityText.toIntOrNull() + if (humidity == null) { + // 습도가 숫자로 변환할 수 없는 경우 + Toast.makeText(requireContext(), "습도는 숫자로 입력하세요.", Toast.LENGTH_SHORT).show() + return false + } + + if (humidity < 50 || humidity > 100) { + // 습도가 범위를 벗어난 경우 + Toast.makeText(requireContext(), "습도는 50에서 100 사이로 입력하세요.", Toast.LENGTH_SHORT).show() + return false + } + + return true + } + + private fun openGallery() { + if (checkStoragePermission()) { + val galleryIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + startActivityForResult(galleryIntent, REQUEST_IMAGE_FROM_GALLERY) + } else { + requestStoragePermission() + } + } + + private fun checkStoragePermission(): Boolean { + return ContextCompat.checkSelfPermission( + requireContext(), + Manifest.permission.READ_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED + } + + private fun requestStoragePermission() { + requestPermissions( + arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), + REQUEST_PERMISSION_CODE + ) + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == REQUEST_PERMISSION_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + openGallery() + } else { + Toast.makeText(requireContext(), "저장소 권한이 필요합니다.", Toast.LENGTH_SHORT).show() + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + REQUEST_IMAGE_FROM_GALLERY -> { + data?.data?.let { uri -> + val inputStream = requireActivity().contentResolver.openInputStream(uri) + val bytes = inputStream?.readBytes() + inputStream?.close() + imageData = bytes + + // 이미지 파일의 MIME 타입 가져오기 + val contentType = requireActivity().contentResolver.getType(uri) + //파일명 + val fileName = getFileNameFromUri(uri) + binding.diaryAddTvUploadFileinfo.text = "파일 선택됨: $fileName" + + // 이미지 파일을 MultipartBody.Part로 변환 + val requestBody = RequestBody.create(MediaType.parse(contentType), bytes) + val multipart = MultipartBody.Part.createFormData("image", fileName, requestBody) + image = multipart + } + } + } + } + } + + private fun getFileNameFromUri(uri: Uri): String { + var fileName = "" + val cursor = requireActivity().contentResolver.query(uri, null, null, null, null) + cursor?.use { + if (it.moveToFirst()) { + val displayNameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (displayNameIndex >= 0) { + fileName = it.getString(displayNameIndex) + } + } + } + return fileName + } + + private fun moveToDiaryFragment() { + val transaction = parentFragmentManager + .beginTransaction() + .replace(R.id.main_fl, DiaryFragment()) + transaction.commit() + } + + + +// fun getCheckedItems(): Set { +// return checkedItems +// } +// +// fun getSelectedDate(): CalendarDay? { +// return (requireArguments().getSerializable(ARG_DATE) as? CalendarDay) +// } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/farmmate1/DiaryDataListener.kt b/app/src/main/java/com/example/farmmate1/DiaryDataListener.kt deleted file mode 100644 index addc9d8..0000000 --- a/app/src/main/java/com/example/farmmate1/DiaryDataListener.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.example.farmmate1 - -import java.util.Calendar - -interface DiaryDataListener { - fun onDiaryDataReceived(date: Calendar, data: String){ - - - } -} diff --git a/app/src/main/java/com/example/farmmate1/DiaryFragment.kt b/app/src/main/java/com/example/farmmate1/DiaryFragment.kt index 5e32878..f984e7e 100644 --- a/app/src/main/java/com/example/farmmate1/DiaryFragment.kt +++ b/app/src/main/java/com/example/farmmate1/DiaryFragment.kt @@ -1,147 +1,387 @@ package com.example.farmmate1 +import android.content.Context +import android.graphics.Color import android.os.Bundle +import android.util.Log +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ArrayAdapter -import android.widget.Button -import android.widget.CalendarView -import android.widget.ListView +import android.widget.* import androidx.fragment.app.Fragment -import java.text.SimpleDateFormat +import com.example.farmmate1.databinding.FragmentDiaryBinding import java.util.* +import com.prolificinteractive.materialcalendarview.* +import com.prolificinteractive.materialcalendarview.format.TitleFormatter +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class DiaryFragment : Fragment() { + + private var _binding: FragmentDiaryBinding? = null + private val binding get() = _binding!! + + private var diaryList: ArrayList? = null + private lateinit var calendarView: MaterialCalendarView + private var selectedDate: CalendarDay? = null + private var selectedPlantName: String? = null + //private var filteredDiaryList: List? = null + + private lateinit var diaryUuid: String + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentDiaryBinding.inflate(inflater, container, false) + val view = binding.root + + calendarView = binding.diaryFragmentCal + + val today = CalendarDay.today() + val oneDayDecorator = OneDayDecorator() + + calendarView.selectedDate = today + calendarView.setDateSelected(today, true) + calendarView.addDecorators( + SundayDecorator(), + SaturdayDecorator(), + oneDayDecorator + ) + + calendarView.setTitleFormatter(object : TitleFormatter { + override fun format(day: CalendarDay): CharSequence { + // 원하는 형식으로 제목을 지정 + return "${day.year}년 ${day.month + 1}월" // month는 0부터 시작하므로 +1 해줍니다. + } + }) + + // 상단바 get + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) + + // SharedPreferences에서 디바이스 ID 가져오기 + val sharedPreferences = requireActivity().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) + val deviceId: String = sharedPreferences.getString(DEVICE_ID_KEY, "") ?: "" + + val plantInfoName = arguments?.getString("plantInfoName") + + apiService.getPlantList(deviceId).enqueue(object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + val plantList = response.body() as? ArrayList + if (plantList != null) { + Log.d("DiaryFragment", "$plantList") + + setButtonTextForLinearLayout(plantList) + // 동적으로 버튼 추가 + for (plant in plantList) { + Log.d("DiaryFragment", "${plant.plant_name}") + } + + for (i in 0 until 5) { + val button = binding.diaryLinearlayout.getChildAt(i) as? Button + button?.setOnClickListener { + // 클릭된 버튼을 강조하기 위해 색상 변경 + onButtonClicked(button) + selectedPlantName = button?.text.toString() + Log.d("DiaryPlantName","$selectedPlantName") + fetchDiaryListFromServer() + } + } + + // 동적으로 생성된 버튼에 클릭 이벤트 처리기 추가 + for (i in 5 until binding.diaryLinearlayout.childCount) { + val button = binding.diaryLinearlayout.getChildAt(i) as? Button + button?.setOnClickListener { + // 클릭된 버튼을 강조하기 위해 색상 변경 + onButtonClicked(button) + selectedPlantName = button?.text.toString() + Log.d("DiaryPlantName","$selectedPlantName") + fetchDiaryListFromServer() + } + } + + // plantInfo에서 넘어온 경우 + plantInfoName?.let { plantName -> + for (i in 0 until binding.diaryLinearlayout.childCount) { + val button = binding.diaryLinearlayout.getChildAt(i) as? Button + if (button?.text.toString() == plantName) { + button?.isSelected = true + selectedPlantName = plantName + Log.d("DiaryPlantName", "$selectedPlantName") + fetchDiaryListFromServer() + break + } + } + } ?: run { + // 넘겨준 값이 없을 경우에는 맨 처음 버튼을 선택 상태로 지정 + val firstButton = binding.diaryLinearlayout.getChildAt(0) as? Button + firstButton?.isSelected = true + selectedPlantName = firstButton?.text.toString() + Log.d("DiaryPlantName", "$selectedPlantName") + fetchDiaryListFromServer() + } + + } else { + // API 요청 실패 처리 + Log.e("DiaryFragment", "Failed to fetch plant list: ${response.message()}") + } + } -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" + override fun onFailure(call: Call>, t: Throwable) { + // 통신 오류 처리 + Log.e("DiaryFragment", "Network error: ${t.message}") + } + }) + return view + } -/** - * A simple [Fragment] subclass. - * Use the [DiaryFragment.newInstance] factory method to - * create an instance of this fragment. - */ -class DiaryFragment : Fragment(), DiaryDataListener { + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - private lateinit var fragment2: WriteDiaryFragment - private lateinit var calendarView: CalendarView - private lateinit var writeButton: Button - private lateinit var listView : ListView + binding.diaryRegitstBtn.setOnClickListener { + // selectedDate가 null이 아닌 경우에만 DiaryAddFragment를 생성하고 전환 + Log.d("-------","$selectedDate") + selectedDate?.let { date -> + moveToAddDiaryFragment(date) + } + } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_diary, container, false) + binding.diaryContentLayout.setOnClickListener { + val bundle = Bundle() + bundle.putString("diaryUuid", diaryUuid) + bundle.putString("selectedPlantName", selectedPlantName) - calendarView = view.findViewById(R.id.diary_calview) - listView = view.findViewById(R.id.diary_todo_list_view) + val diaryInfoFragment = DiaryInfoFragment() + diaryInfoFragment.arguments = bundle + requireActivity().supportFragmentManager + .beginTransaction() + .replace(R.id.main_fl, diaryInfoFragment) + .commit() + } - // 프래그먼트 인스턴스 생성 - fragment2 = WriteDiaryFragment() - calendarView = view.findViewById(R.id.diary_calview) - writeButton = view.findViewById(R.id.diary_regitst_btn) + } - //캘린더 날짜 선택 이벤트 처리 - calendarView.setOnDateChangeListener{_, year, month, dayOfMonth -> - val selectDate = Calendar.getInstance().apply{ - set(year, month, dayOfMonth) - } - val todoList = getTodoList(selectDate) - val adapter = ArrayAdapter(requireContext(),android.R.layout.simple_list_item_1, todoList) - listView.adapter=adapter - } + override fun onDestroyView() { + super.onDestroyView() + // 메모리 누수를 방지하기 위해 Fragment View에 대한 참조를 제거하여 가비지 컬렉터가 수거 + _binding = null + } - //버튼 클릭시 이벤트 처리 - writeButton.setOnClickListener { - val selectDate = Calendar.getInstance().apply{ - timeInMillis = calendarView.date + // LinearLayout에 버튼을 추가하는 함수 + fun setButtonTextForLinearLayout(plantList: List) { + for (i in 0 until plantList.size) { + val plantName = plantList[i].plant_name + if (i < 5) { + // 처음 다섯 개의 버튼에 텍스트만 할당 + val button = binding.diaryLinearlayout.getChildAt(i) as? Button + button?.text = plantName ?: "" + } else { + // 여섯 번째 요소부터 동적으로 버튼을 추가하며 텍스트 할당 + val button = Button(requireContext()) + button.text = plantName ?: "" + val layoutParams = LinearLayout.LayoutParams( + resources.getDimensionPixelSize(R.dimen.button_width), + resources.getDimensionPixelSize(R.dimen.button_height) + ) + val marginHorizontalPx = resources.getDimensionPixelSize(R.dimen.button_margin_horizontal) + layoutParams.setMargins(marginHorizontalPx, 0, marginHorizontalPx, 0) // 좌우 마진과 상단 마진을 dimens.xml에서 가져온 값으로 설정 + button.layoutParams = layoutParams + button.setTextColor(Color.BLACK) // 텍스트 색상 설정 + button.setBackgroundResource(R.drawable.rounded_btn) + button.gravity = Gravity.CENTER + + button.setPadding(0, -3, 0, 0) + layoutParams.weight = 1f + + button.setOnClickListener { + // 버튼이 클릭되었을 때 수행할 작업 추가 + } + binding.diaryLinearlayout.addView(button) } - //TODO: 선택된 날짜에 데이터 저장 } + } - //캘린더 날짜 선택 이벤트 처리 - calendarView.setOnDateChangeListener{_, year, month, dayOfMonth-> - val selectedDate = Calendar.getInstance().apply{ - set(year,month,dayOfMonth) - } - val todoList = getTodoList(selectedDate) - val adapter = ArrayAdapter(requireContext(),android.R.layout.simple_list_item_1, todoList ) - listView.adapter = adapter + // 모든 버튼을 클릭했을 때 호출되는 메서드 + fun onButtonClicked(clickedButton: Button) { + // 모든 버튼을 탐색하면서 클릭된 버튼인지 확인하고 상태를 변경합니다. + for (i in 0 until binding.diaryLinearlayout.childCount) { + val button = binding.diaryLinearlayout.getChildAt(i) as? Button + button?.isSelected = (button == clickedButton) + } - /* val hasData = checkDataExist(selectedDate) - if (hasData){ + // 일지 요약 초기화 + binding.diaryContentDate.text = "" + binding.diaryContentWeather.text = "일지를 등록하세요" + binding.diaryContentMemo.text = "" + } - }*/ + private fun moveToAddDiaryFragment(selectedDate: CalendarDay?) { + selectedDate?.let { date -> + val diaryAddFragment = DiaryAddFragment.newInstance(date.calendar) + val transaction = parentFragmentManager + .beginTransaction() + .replace(R.id.main_fl, diaryAddFragment) + transaction.commit() } + } + private fun fetchDiaryListFromServer() { + val retrofit = RetrofitClient.instance + val apiService = retrofit.create(ApiService::class.java) - // 버튼 클릭 시 Fragment2로 전환 - view.findViewById