From d92cbacbf05d848eace3ce576ca6ea4305f8a738 Mon Sep 17 00:00:00 2001 From: vavali08 Date: Thu, 25 Apr 2024 12:55:54 -0400 Subject: [PATCH] edit sublet route --- .../{ => Subletting}/NewListingsFragment.kt | 18 +- .../Subletting/SubletDetailsFragment.kt | 19 + .../Subletting/SubletEditFragment.kt | 316 +++++++++ .../SubletterDraftListingsFragment.kt | 1 - .../SubletterPostedListingsFragment.kt | 1 - .../labs/pennmobile/api/StudentLife.java | 10 + .../pennmobile/classes/SublettingViewModel.kt | 34 + ...ml => fragment_subletter_edit_listing.xml} | 0 .../layout/fragment_subletter_new_listing.xml | 665 ++++++++++++++++++ 9 files changed, 1053 insertions(+), 11 deletions(-) rename PennMobile/src/main/java/com/pennapps/labs/pennmobile/{ => Subletting}/NewListingsFragment.kt (95%) create mode 100644 PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletEditFragment.kt rename PennMobile/src/main/res/layout/{fragment_new_listings.xml => fragment_subletter_edit_listing.xml} (100%) create mode 100644 PennMobile/src/main/res/layout/fragment_subletter_new_listing.xml diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewListingsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/NewListingsFragment.kt similarity index 95% rename from PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewListingsFragment.kt rename to PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/NewListingsFragment.kt index fce861c2..776429e0 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/NewListingsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/NewListingsFragment.kt @@ -1,4 +1,4 @@ -package com.pennapps.labs.pennmobile +package com.pennapps.labs.pennmobile.Subletting import android.graphics.BitmapFactory import android.os.Bundle @@ -15,20 +15,19 @@ import android.widget.Toast import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment +import com.pennapps.labs.pennmobile.MainActivity import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.AmenitiesItem import com.pennapps.labs.pennmobile.classes.MultipartUtil import com.pennapps.labs.pennmobile.classes.Sublet import com.pennapps.labs.pennmobile.classes.SublettingViewModel -import com.pennapps.labs.pennmobile.databinding.FragmentNewListingsBinding -import okhttp3.MediaType.Companion.toMediaType +import com.pennapps.labs.pennmobile.databinding.FragmentSubletterNewListingBinding import okhttp3.MultipartBody -import okhttp3.RequestBody.Companion.toRequestBody import java.io.IOException class NewListingsFragment(private val dataModel: SublettingViewModel) : Fragment() { - private var _binding: FragmentNewListingsBinding? = null + private var _binding: FragmentSubletterNewListingBinding? = null private val binding get() = _binding!! private lateinit var mStudentLife: StudentLife @@ -100,7 +99,7 @@ class NewListingsFragment(private val dataModel: SublettingViewModel) : Fragment override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - _binding = FragmentNewListingsBinding.inflate(inflater, container, false) + _binding = FragmentSubletterNewListingBinding.inflate(inflater, container, false) val view = binding.root super.onViewCreated(view, savedInstanceState) @@ -253,9 +252,10 @@ class NewListingsFragment(private val dataModel: SublettingViewModel) : Fragment } } - val subletPart = MultipartUtil.createSubletPart(subletId) - - + if (multipartImage != null) { + val subletPart = MultipartUtil.createSubletPart(subletId) + dataModel.postImage(mActivity, subletId, subletPart, multipartImage!!) + } diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletDetailsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletDetailsFragment.kt index 6d18cb99..6c865657 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletDetailsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletDetailsFragment.kt @@ -5,10 +5,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentTransaction import androidx.viewpager2.widget.ViewPager2 import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.pennapps.labs.pennmobile.MainActivity +import com.pennapps.labs.pennmobile.R import com.pennapps.labs.pennmobile.api.StudentLife import com.pennapps.labs.pennmobile.classes.Sublet import com.pennapps.labs.pennmobile.classes.SublettingViewModel @@ -51,9 +53,26 @@ class SubletDetailsFragment(private val dataModel: SublettingViewModel, private dataModel.deleteSublet(mActivity, subletNumber) } + binding.editText.setOnClickListener(){ + navigateEditListing() + } + return binding.root } + + private fun navigateEditListing() { + val mainActivity = context as MainActivity + + val fragment = SubletEditFragment(dataModel, subletNumber) + + val fragmentManager = mainActivity.supportFragmentManager + fragmentManager.beginTransaction() + .replace(R.id.content_frame, fragment, "NEW_LISTING_FRAGMENT") + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .addToBackStack(null) + .commitAllowingStateLoss() + } } \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletEditFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletEditFragment.kt new file mode 100644 index 00000000..56e6c8af --- /dev/null +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletEditFragment.kt @@ -0,0 +1,316 @@ +package com.pennapps.labs.pennmobile.Subletting + +import android.graphics.BitmapFactory +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.CheckBox +import android.widget.EditText +import android.widget.ImageView +import android.widget.Spinner +import android.widget.TextView +import android.widget.Toast +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.Fragment +import com.bumptech.glide.Glide +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.pennapps.labs.pennmobile.MainActivity +import com.pennapps.labs.pennmobile.api.StudentLife +import com.pennapps.labs.pennmobile.classes.AmenitiesItem +import com.pennapps.labs.pennmobile.classes.MultipartUtil +import com.pennapps.labs.pennmobile.classes.Sublet +import com.pennapps.labs.pennmobile.classes.SublettingViewModel +import com.pennapps.labs.pennmobile.databinding.FragmentSubletterEditListingBinding +import com.pennapps.labs.pennmobile.databinding.FragmentSubletterNewListingBinding +import okhttp3.MultipartBody +import java.io.IOException + +class SubletEditFragment (private val dataModel: SublettingViewModel, private val subletNumber: Int) : Fragment() { + private var _binding: FragmentSubletterEditListingBinding? = null + private val binding get() = _binding!! + + private lateinit var mStudentLife: StudentLife + + internal lateinit var titleEt : EditText + internal lateinit var priceEt : EditText + internal lateinit var streetAddressEt : EditText + internal lateinit var apartmentEt : EditText + internal lateinit var zipCodeEt : EditText + internal lateinit var startEt : EditText + internal lateinit var endEt : EditText + internal lateinit var bedsSpinner : Spinner + internal lateinit var bathsSpinner : Spinner + internal lateinit var descriptionEt : EditText + internal lateinit var bathroomCheck : CheckBox + internal lateinit var laundryCheck : CheckBox + internal lateinit var gymCheck : CheckBox + internal lateinit var wifiCheck : CheckBox + internal lateinit var furnishedCheck : CheckBox + internal lateinit var closetCheck : CheckBox + internal lateinit var utilitiesCheck : CheckBox + internal lateinit var poolCheck : CheckBox + internal lateinit var loungeCheck : CheckBox + internal lateinit var parkingCheck : CheckBox + internal lateinit var patioCheck : CheckBox + internal lateinit var kitchenCheck : CheckBox + internal lateinit var dogCheck : CheckBox + internal lateinit var catCheck : CheckBox + internal lateinit var imageView: ImageView + internal lateinit var imageIcon: ImageView + internal lateinit var imageText: TextView + + //Sublet variables + private lateinit var title : String + private lateinit var price : String + private var streetAddress : String? = null + private var apartment : String? = null + private var zipCode : String? = null + private lateinit var startDate : String + private lateinit var endDate : String + private var beds : Int? = null + private var baths : Int? = null + private var description: String? = null + private lateinit var amenities: List + + private var image: String? = null + var multipartImage: MultipartBody.Part? = null + + private lateinit var mActivity: MainActivity + + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mStudentLife = MainActivity.studentLifeInstance + mActivity = activity as MainActivity + mActivity.hideBottomBar() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + _binding = FragmentSubletterEditListingBinding.inflate(inflater, container, false) + val view = binding.root + super.onViewCreated(view, savedInstanceState) + + titleEt = binding.listingNameInput + priceEt = binding.priceInput + streetAddressEt = binding.streetAddressInput + apartmentEt = binding.apartmentInput + zipCodeEt = binding.postalCodeInput + startEt = binding.startDateInput + endEt = binding.endDateInput + bedsSpinner = binding.bedInput + bathsSpinner = binding.bathInput + descriptionEt = binding.descriptionInput + bathroomCheck = binding.bathroomCheck + laundryCheck = binding.laundryCheck + gymCheck = binding.gymCheck + wifiCheck = binding.wifiCheck + furnishedCheck = binding.furnishedCheck + closetCheck = binding.closetCheck + utilitiesCheck = binding.utilitiesCheck + poolCheck = binding.poolCheck + loungeCheck = binding.loungeCheck + parkingCheck = binding.parkingCheck + patioCheck = binding.patioCheck + kitchenCheck = binding.kitchenCheck + dogCheck = binding.dogCheck + catCheck = binding.catCheck + imageView = binding.mainImage + imageIcon = binding.mainImageIcon + imageText = binding.addPhotosText + + val sublet : Sublet = dataModel.getSublet(subletNumber) + titleEt.setText(sublet.title) + priceEt.setText(sublet.price.toString()) + + if (sublet.address != null) { + val addressComponents = sublet.address.split(", ") + streetAddressEt.setText(addressComponents.getOrElse(0) { "" }) + apartmentEt.setText(addressComponents.getOrElse(1) { "" }) + zipCodeEt.setText(addressComponents.getOrElse(2) { "" }) + } + + startEt.setText(sublet.startDate) + endEt.setText(sublet.endDate) + descriptionEt.setText(sublet.description) + + + context?.let { + Glide.with(it) + .load(sublet.images?.get(0)?.imageUrl) + .centerCrop() // optional - adjust as needed + .transition(DrawableTransitionOptions.withCrossFade()) + .into(binding.mainImage) + } + + val amenitiesList = sublet.amenities ?: emptyList() + + for (amenity in amenitiesList) { + when (amenity) { + "Private Bathroom" -> bathroomCheck.isChecked = true + "In-unit Laundry" -> laundryCheck.isChecked = true + "In-Unit Laundry" -> laundryCheck.isChecked = true + "Gym" -> gymCheck.isChecked = true + "Wifi" -> wifiCheck.isChecked = true + "Furnished" -> furnishedCheck.isChecked = true + "Walk-in Closet" -> closetCheck.isChecked = true + "Utilities Included" -> utilitiesCheck.isChecked = true + "Swimming Pool" -> poolCheck.isChecked = true + "Resident Lounge" -> loungeCheck.isChecked = true + "Parking" -> parkingCheck.isChecked = true + "Patio" -> patioCheck.isChecked = true + "Kitchen" -> kitchenCheck.isChecked = true + "Dog-Friendly" -> dogCheck.isChecked = true + "Cat-Friendly" -> catCheck.isChecked = true + } + } + + + val pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> + // Callback is invoked after the user selects a media item or closes the + // photo picker. + if (uri != null) { + Log.d("PhotoPicker", "Selected URI: $uri") + try { + // Load the selected image into the ImageView + val inputStream = context?.contentResolver?.openInputStream(uri) + val bitmap = BitmapFactory.decodeStream(inputStream) + image = bitmap.toString() + imageView.setImageBitmap(bitmap) + imageIcon.visibility = View.GONE + imageText.visibility = View.GONE + multipartImage = MultipartUtil.createPartFromBitmap(bitmap) + + + + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + Toast.makeText(context, "Failed to load image", Toast.LENGTH_SHORT).show() + } + } else { + Log.d("PhotoPicker", "No media selected") + } + } + + imageView.setOnClickListener{ + pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) + } + + + val dateRegex = Regex("""^(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])/\d{2}$""") + + binding.postButton.setOnClickListener{ + if (titleEt.text.toString().matches("".toRegex()) + || priceEt.text.toString().matches("".toRegex()) + || startEt.text.toString().matches("".toRegex()) + || endEt.text.toString().matches("".toRegex())) { + Toast.makeText(activity, "Please fill in all required fields", + Toast.LENGTH_LONG).show() + } else if (!startEt.text.toString().matches(dateRegex) || !endEt.text.toString().matches(dateRegex)) { + Toast.makeText(activity, "Please follow formatting instructions for date", + Toast.LENGTH_LONG).show() + } else { + title = titleEt.text.toString() + price = priceEt.text.toString() + streetAddress = streetAddressEt.text.toString() + ", " + apartmentEt.text.toString() + + ", " + zipCodeEt.text.toString() + if (streetAddress.equals(", , ")) { + streetAddress = null + } + startDate = startEt.text.toString() + endDate = endEt.text.toString() + + beds = bedsSpinner.selectedItemPosition + 1 + baths = bathsSpinner.selectedItemPosition + 1 + + val amenitiesList = mutableListOf() + if(bathroomCheck.isChecked) { amenitiesList.add("Private Bathroom") } + if(laundryCheck.isChecked) { amenitiesList.add("In-Unit Laundry") } + if(gymCheck.isChecked) { amenitiesList.add("Gym") } + if(wifiCheck.isChecked) { amenitiesList.add("Wifi") } + if(furnishedCheck.isChecked) { amenitiesList.add("Furnished") } + if(closetCheck.isChecked) { amenitiesList.add("Walk-in Closet") } + if(utilitiesCheck.isChecked) { amenitiesList.add("Utilities Included") } + if(poolCheck.isChecked) { amenitiesList.add("Swimming Pool") } + if(loungeCheck.isChecked) { amenitiesList.add("Resident Lounge") } + if(parkingCheck.isChecked) { amenitiesList.add("Parking") } + if(patioCheck.isChecked) { amenitiesList.add("Patio") } + if(kitchenCheck.isChecked) { amenitiesList.add("Kitchen") } + if(dogCheck.isChecked) { amenitiesList.add("Dog-Friendly") } + if(catCheck.isChecked) { amenitiesList.add("Cat-Friendly") } + + description = descriptionEt.text.toString() + if (description.equals("")) { + description = null; + } + + editSublet(title, Integer.parseInt(price), streetAddress, startDate, endDate, beds, + baths, amenitiesList, description) + + } + + } + return view + } + + private fun editSublet(title : String, price : Int, address : String?, startDate: String, + endDate : String, beds: Int?, baths: Int?, amenities: List?, + description: String?) { + val convertedEnd = convertToYYYYMMDD(endDate) + val convertedStart = convertToYYYYMMDD(startDate) + var subletId = -1 + + + val newSublet = Sublet( + endDate = convertedEnd, + baths = baths, + address = address, + price = price,//fix + expiresAt = "3000-02-01T10:48:02-05:00", //? + description = description, + title = title, + beds = beds, + amenities = amenities, + externalLink = "https://pennlabs.org/", // fix + startDate = convertedStart + ) + + dataModel.editSublet(mActivity, newSublet, subletNumber) { postedSublet -> + if (postedSublet != null) { + Log.i("MainActivity", "Posted sublet ID: ${postedSublet.id}") + subletId = postedSublet.id!! + } else { + // Handle failure to post sublet + Log.e("MainActivity", "Failed to post sublet") + } + } + + if (multipartImage != null) { + val subletPart = MultipartUtil.createSubletPart(subletId) + dataModel.postImage(mActivity, subletId, subletPart, multipartImage!!) + } + + + + + + } + + private fun convertToYYYYMMDD(mmddyy: String): String { + val components = mmddyy.split("/") + val month = components[0].toInt() + val day = components[1].toInt() + val year = components[2].toInt() + 2000 + + return String.format("%04d-%02d-%02d", year, month, day) + } + + + + +} \ No newline at end of file diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterDraftListingsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterDraftListingsFragment.kt index abd9a7c1..713f823a 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterDraftListingsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterDraftListingsFragment.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.pennapps.labs.pennmobile.MainActivity -import com.pennapps.labs.pennmobile.NewListingsFragment import com.pennapps.labs.pennmobile.R import com.pennapps.labs.pennmobile.classes.SublettingViewModel import com.pennapps.labs.pennmobile.databinding.FragmentSubletterDraftListingsBinding diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterPostedListingsFragment.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterPostedListingsFragment.kt index 6684f8c5..f1cd4306 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterPostedListingsFragment.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/Subletting/SubletterPostedListingsFragment.kt @@ -10,7 +10,6 @@ import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.pennapps.labs.pennmobile.MainActivity -import com.pennapps.labs.pennmobile.NewListingsFragment import com.pennapps.labs.pennmobile.R import com.pennapps.labs.pennmobile.adapters.PostedSubletsListAdapter import com.pennapps.labs.pennmobile.api.StudentLife diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/api/StudentLife.java b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/api/StudentLife.java index 6410c0b7..af5a1081 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/api/StudentLife.java +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/api/StudentLife.java @@ -41,6 +41,7 @@ import retrofit.http.Header; import retrofit.http.Headers; import retrofit.http.POST; +import retrofit.http.PUT; import retrofit.http.Part; import retrofit.http.Path; import retrofit.http.Query; @@ -253,6 +254,15 @@ void deleteSublet( @Path("sublet_id") int id, Callback callback); + @Headers({"Content-Type: application/json"}) + @PUT("/sublet/properties/{sublet_id}") + void editSublet( + @Header("Authorization") String bearerToken, + @Path("sublet_id") int id, + @Body Sublet sublet, + Callback callback + ); + @Headers({"Content-Type: application/json"}) @GET("/sublet/properties/") Observable> getSublets( diff --git a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/classes/SublettingViewModel.kt b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/classes/SublettingViewModel.kt index 3e11839b..be4f0fe3 100644 --- a/PennMobile/src/main/java/com/pennapps/labs/pennmobile/classes/SublettingViewModel.kt +++ b/PennMobile/src/main/java/com/pennapps/labs/pennmobile/classes/SublettingViewModel.kt @@ -140,6 +140,40 @@ class SublettingViewModel (private val activity: Activity, private val studentLi } } + fun editSublet(mActivity : MainActivity, sublet : Sublet, id: Int, callback: (Sublet?) -> Unit) { + + val context = activity.applicationContext + val sp = PreferenceManager.getDefaultSharedPreferences(activity) + + + OAuth2NetworkManager(mActivity).getAccessToken { + + val bearerToken = + "Bearer " + sp.getString(context.getString(R.string.access_token), "").toString() + + + studentLife.editSublet(bearerToken, id, sublet, + object : Callback { + override fun success(t: Sublet?, response: Response?) { + Log.i("Subletting View Model", "sublet edited") + callback(sublet) + } + + override fun failure(error: RetrofitError?) { + Log.e("Subletting View Model", "Error editing sublet " + + "$error", error + ) + Toast.makeText(activity, "An error has occurred. Please try again.", Toast.LENGTH_LONG).show() + + + } + + }) + } + + + } + diff --git a/PennMobile/src/main/res/layout/fragment_new_listings.xml b/PennMobile/src/main/res/layout/fragment_subletter_edit_listing.xml similarity index 100% rename from PennMobile/src/main/res/layout/fragment_new_listings.xml rename to PennMobile/src/main/res/layout/fragment_subletter_edit_listing.xml diff --git a/PennMobile/src/main/res/layout/fragment_subletter_new_listing.xml b/PennMobile/src/main/res/layout/fragment_subletter_new_listing.xml new file mode 100644 index 00000000..83cc8f58 --- /dev/null +++ b/PennMobile/src/main/res/layout/fragment_subletter_new_listing.xml @@ -0,0 +1,665 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +