diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a626c27..c000d11 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -60,4 +60,4 @@ android:value="AIzaSyCzcuZhHd-GqadewAiCbh4NuaBhO2AcPOY" /> - \ No newline at end of file + diff --git a/app/src/main/java/com/example/acloc/activity/AddNewPlaceActivity.java b/app/src/main/java/com/example/acloc/activity/AddNewPlaceActivity.java index 3568a5e..4411315 100644 --- a/app/src/main/java/com/example/acloc/activity/AddNewPlaceActivity.java +++ b/app/src/main/java/com/example/acloc/activity/AddNewPlaceActivity.java @@ -35,8 +35,6 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.util.Objects; - import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -248,7 +246,7 @@ public class AddNewPlaceActivity extends AppCompatActivity implements View.OnCli entity.setAddress(Helper.getStringFromInput(etAddress)); entity.setLatitude(Helper.getStringFromInput(etLatitude)); entity.setLongitude(Helper.getStringFromInput(etLongitude)); - entity.setCreatedBy(SharedPref.getUserUid(context)); + entity.setCreatedBy(SharedPref.getUserUuid(context)); entity.setUuid(place_uuid); entity.setImage(jsonString); } diff --git a/app/src/main/java/com/example/acloc/activity/AddReportActivity.java b/app/src/main/java/com/example/acloc/activity/AddReportActivity.java index 2bb9cdb..29b428e 100644 --- a/app/src/main/java/com/example/acloc/activity/AddReportActivity.java +++ b/app/src/main/java/com/example/acloc/activity/AddReportActivity.java @@ -6,37 +6,46 @@ import android.content.Context; import android.content.Intent; import android.graphics.PorterDuff; import android.net.Uri; - import android.os.Bundle; import android.provider.MediaStore; import android.util.Log; import android.view.View; import android.widget.ImageView; -import android.widget.RelativeLayout; +import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.AppCompatButton; -import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import com.example.acloc.adapter.ReportTypeAdapter; import com.example.acloc.api.LocationApiClient; import com.example.acloc.model.Place; import com.example.acloc.model.Report; +import com.example.acloc.model.ReportType; +import com.example.acloc.service.PlaceService; import com.example.acloc.service.ReportService; +import com.example.acloc.service.ReportTypeService; import com.example.acloc.utility.Constants; import com.example.acloc.utility.DialogUtils; import com.example.acloc.utility.Helper; import com.example.acloc.utility.SharedPref; import com.example.acloc.utility.UploadManager; -import com.ieslamar.acloc.R; +import com.google.android.material.button.MaterialButton; import com.google.android.material.textfield.TextInputEditText; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.ieslamar.acloc.R; import com.squareup.picasso.Picasso; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.ArrayList; +import java.util.List; + import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -44,179 +53,382 @@ import retrofit2.Response; public class AddReportActivity extends AppCompatActivity implements View.OnClickListener { public static final String TAG = AddReportActivity.class.getSimpleName(); - private RelativeLayout rlAddReport; - private TextInputEditText etDescription, etPlaceName; - private ImageView ivReportPhoto; - private ImageView ivThumbsUp, ivThumbsAverage, ivThumbsDown; - private AppCompatButton btnSubmit; private Context context; + + // UI Components + private TextInputEditText etDescription; + private TextView tvPlaceName, tvPlaceAddress; + private ImageView ivReportPhoto, ivThumbsUp, ivThumbsAverage, ivThumbsDown; + private MaterialButton btnSubmitReport; + private RecyclerView rvReportTypes; + + // Data private Place placeEntity; private Report reportEntity; - private String report_type_uuid, place_uuid; - private int reportRating; + private String place_uuid; + private int reportRating = 0; private String report_uuid; + private boolean isEditMode = false; + // Report Types - Now supporting multiple selection + private ReportTypeAdapter reportTypeAdapter; + private List reportTypesList = new ArrayList<>(); + private List selectedReportTypeUuids = new ArrayList<>(); + + // Multiple Images handling private static final int PICK_IMAGE_REQUEST = 100; - - private Uri selectedImageUri; - private String imageUrl; - private String jsonString; - + private List imageUrls = new ArrayList<>(); + private int currentImageIndex = 0; + private String jsonString = "[]"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_report); - initToolbar(); initUI(); + resetThumbsColors(); loadIntentData(); initListener(); initObj(); - } - - private void initToolbar() { - try { - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - if (getSupportActionBar() != null) { - getSupportActionBar().setDisplayHomeAsUpEnabled(false); - getSupportActionBar().setTitle(getString(R.string.Add_Report)); - } - } catch (Exception e) { - Log.e(TAG, "Error in AddReportActivity", e); - } + loadReportTypes(); } private void initUI() { - rlAddReport = findViewById(R.id.rlAddReport); - ivReportPhoto = findViewById(R.id.ivReportPhoto); - etPlaceName = findViewById(R.id.etPlaceName); + // Text inputs etDescription = findViewById(R.id.etDescription); + + // Place info + tvPlaceName = findViewById(R.id.tvPlaceName); + tvPlaceAddress = findViewById(R.id.tvPlaceAddress); + + // Rating thumbs ivThumbsUp = findViewById(R.id.ivThumbsUp); ivThumbsAverage = findViewById(R.id.ivThumbsAverage); ivThumbsDown = findViewById(R.id.ivThumbsDown); - btnSubmit = findViewById(R.id.btnSubmit); + + // Photo and submit + ivReportPhoto = findViewById(R.id.ivReportPhoto); + btnSubmitReport = findViewById(R.id.btnSubmitReport); + + // Report types + rvReportTypes = findViewById(R.id.rvReportTypes); + + // Setup RecyclerView for report types + rvReportTypes.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + reportTypeAdapter = new ReportTypeAdapter(this, reportTypesList); + reportTypeAdapter.setOnReportTypeClickListener(new ReportTypeAdapter.OnReportTypeClickListener() { + @Override + public void onReportTypeClick(ReportType reportType, int position, boolean isSelected) { + // Individual click handling if needed + Log.d(TAG, "Report type " + reportType.getName() + " " + (isSelected ? "selected" : "deselected")); + } + + @Override + public void onSelectionChanged(List selectedReportTypes) { + // Update selected UUIDs list + selectedReportTypeUuids.clear(); + for (ReportType reportType : selectedReportTypes) { + selectedReportTypeUuids.add(reportType.getUuid()); + } + } + }); + rvReportTypes.setAdapter(reportTypeAdapter); } private void loadIntentData() { - placeEntity = (Place) getIntent().getSerializableExtra(Constants.PLACE); + Intent intent = getIntent(); + + // Get place data (if available) + placeEntity = (Place) intent.getSerializableExtra(Constants.PLACE); if (placeEntity != null) { place_uuid = placeEntity.getUuid(); - etPlaceName.setText(placeEntity.getName()); //Just to display place name in report + populatePlaceInfo(); } - reportEntity = (Report) getIntent().getSerializableExtra(Constants.REPORT); + // Get report data (for editing existing reports) + reportEntity = (Report) intent.getSerializableExtra(Constants.REPORT); if (reportEntity != null) { - report_uuid = reportEntity.getUuid(); // setting place uuid first + isEditMode = true; + report_uuid = reportEntity.getUuid(); place_uuid = reportEntity.getPlaceUuid(); - Log.d(TAG, "" + - "place uuid: " + reportEntity.getPlaceUuid() + - "\n fkplace " + reportEntity.getFkPlace()); setDataToEditText(); + + // If we don't have place entity but have place_uuid, fetch place data + if (placeEntity == null && place_uuid != null) { + fetchPlaceData(place_uuid); + } + } + + // Get place UUID directly (if passed without Place object) + String passedPlaceUuid = intent.getStringExtra("place_uuid"); + if (passedPlaceUuid != null && place_uuid == null) { + place_uuid = passedPlaceUuid; + fetchPlaceData(place_uuid); + } + + // Validate that we have the necessary data + if (place_uuid == null || place_uuid.isEmpty()) { + Helper.makeSnackBar(findViewById(android.R.id.content), + getString(R.string.error_no_place_selected)); + finish(); + } + } + + private void fetchPlaceData(String placeUuid) { + String token = "Bearer " + SharedPref.getAccessToken(this); + PlaceService placeService = LocationApiClient.getInstance().getPlaceService(); + + Call call = placeService.getPlaceFromUuid(token, placeUuid); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { + parsePlaceResponse(response.body()); + } else { + Log.e(TAG, "Failed to load place data: " + response.code()); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e(TAG, "Failed to load place data", t); + } + }); + } + + private void parsePlaceResponse(JsonObject responseBody) { + JsonObject data = responseBody.getAsJsonObject("_data"); + if (data != null && data.has("places")) { + JsonArray placesArray = data.getAsJsonArray("places"); + if (placesArray.size() > 0) { + JsonObject placeObject = placesArray.get(0).getAsJsonObject(); + + // Create place entity from response + placeEntity = new Place(); + placeEntity.setUuid(placeObject.get("uuid").getAsString()); + placeEntity.setName(placeObject.get("name").getAsString()); + if (placeObject.has("address") && !placeObject.get("address").isJsonNull()) { + placeEntity.setAddress(placeObject.get("address").getAsString()); + } + + populatePlaceInfo(); + } + } + } + + private void populatePlaceInfo() { + if (placeEntity != null) { + tvPlaceName.setText(placeEntity.getName()); + if (placeEntity.getAddress() != null && !placeEntity.getAddress().isEmpty()) { + tvPlaceAddress.setText(placeEntity.getAddress()); + } else { + tvPlaceAddress.setText(getString(R.string.address_not_available)); + } } } private void setDataToEditText() { - etPlaceName.setText(reportEntity.getPlaceName()); - etDescription.setText(reportEntity.getDescription()); - int rating = reportEntity.getReportRating(); - if (rating == 1) { - ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN); - ivThumbsUp.setColorFilter(null); // reset the other - ivThumbsAverage.setColorFilter(null); - reportRating = Constants.BAD_RATING; //1 - } else if (rating == 2) { - ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN); - ivThumbsUp.setColorFilter(null); // reset the others - ivThumbsDown.setColorFilter(null); - reportRating = Constants.AVERAGE_RATING; //2 - } else if (rating == 3) { - ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN); - ivThumbsDown.setColorFilter(null); // reset the other - ivThumbsAverage.setColorFilter(null); - reportRating = Constants.GOOD_RATING; //3 + if (reportEntity != null) { + etDescription.setText(reportEntity.getDescription()); + + // Reset colors first + resetThumbsColors(); + + // Set rating using constants + int rating = reportEntity.getReportRating(); + if (rating == Constants.BAD_RATING) { // 1 + onClickThumbsDown(); + } else if (rating == Constants.AVERAGE_RATING) { // 2 + onClickThumbsAverage(); + } else if (rating == Constants.GOOD_RATING) { // 3 + onClickThumbsUp(); + } + + // Load existing images + loadReportImages(); + + // Set place info from report if available + if (reportEntity.getPlaceName() != null) { + tvPlaceName.setText(reportEntity.getPlaceName()); + } + + // Set selected report types (multiple) + selectedReportTypeUuids.clear(); + selectedReportTypeUuids.addAll(reportEntity.getReportTypeUuids()); } + } + + private void loadReportImages() { if (reportEntity.getImage() != null && !reportEntity.getImage().isEmpty()) { String rawImg = reportEntity.getImage(); try { JSONArray array = new JSONArray(rawImg); - String imageUrl = array.getString(0); // Get first element in the array - Picasso.get() - .load(imageUrl) - .into(ivReportPhoto, new com.squareup.picasso.Callback() { - @Override - public void onSuccess() { - Picasso.get().load(imageUrl).into(ivReportPhoto); - } + imageUrls.clear(); - @Override - public void onError(Exception e) { - // Error loading image 404 -- load default - Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto); - } - }); + for (int i = 0; i < array.length(); i++) { + String imageUrl = array.getString(i); + imageUrls.add(imageUrl); + } + + // Load first image in the ImageView + if (!imageUrls.isEmpty()) { + String imageUrl = imageUrls.get(0); + Picasso.get() + .load(imageUrl) + .into(ivReportPhoto, new com.squareup.picasso.Callback() { + @Override + public void onSuccess() { + Picasso.get().load(imageUrl).into(ivReportPhoto); + } + + @Override + public void onError(Exception e) { + Picasso.get().load(R.drawable.ic_add_light).into(ivReportPhoto); + } + }); + + jsonString = rawImg; // Keep original JSON string + updateImageCounter(); + } } catch (JSONException e) { Log.e(TAG, "ERROR: " + e.toString()); - Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto); + Picasso.get().load(R.drawable.ic_add_light).into(ivReportPhoto); } - } else { //if image is null - Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto); + } else { + Picasso.get().load(R.drawable.ic_add_light).into(ivReportPhoto); + } + } + + private void updateImageCounter() { + if (imageUrls.size() > 1) { + Log.d(TAG, "Images: " + (currentImageIndex + 1) + " of " + imageUrls.size()); + } + } + + private void loadReportTypes() { + String token = "Bearer " + SharedPref.getAccessToken(this); + ReportTypeService reportTypeService = LocationApiClient.getInstance().getReportTypeService(); + + Call call = reportTypeService.getReportTypes(token, null, null); + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful() && response.body() != null) { + parseReportTypesResponse(response.body()); + } else { + Log.e(TAG, "Failed to load report types: " + response.code()); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e(TAG, "Failed to load report types", t); + } + }); + } + + private void parseReportTypesResponse(JsonObject responseBody) { + JsonObject data = responseBody.getAsJsonObject("_data"); + if (data != null && data.has("report_types")) { + reportTypesList.clear(); + JsonArray reportTypesArray = data.getAsJsonArray("report_types"); + + for (JsonElement element : reportTypesArray) { + JsonObject typeObject = element.getAsJsonObject(); + ReportType reportType = new ReportType(); + reportType.setUuid(typeObject.get("uuid").getAsString()); + reportType.setName(typeObject.get("name").getAsString()); + reportTypesList.add(reportType); + } + + // If editing existing report, mark selected types + if (isEditMode && reportEntity != null && !reportEntity.getReportTypeUuids().isEmpty()) { + reportTypeAdapter.setSelectedReportTypes(reportEntity.getReportTypeUuids()); + } + + reportTypeAdapter.notifyDataSetChanged(); } } private void initListener() { + ivReportPhoto.setOnClickListener(this); ivThumbsUp.setOnClickListener(this); ivThumbsAverage.setOnClickListener(this); ivThumbsDown.setOnClickListener(this); - ivReportPhoto.setOnClickListener(this); - btnSubmit.setOnClickListener(this); + btnSubmitReport.setOnClickListener(this); + + // Long click to cycle through multiple images + ivReportPhoto.setOnLongClickListener(v -> { + if (imageUrls.size() > 1) { + currentImageIndex = (currentImageIndex + 1) % imageUrls.size(); + Picasso.get() + .load(imageUrls.get(currentImageIndex)) + .placeholder(R.drawable.ic_add_light) + .error(R.drawable.ic_add_light) + .into(ivReportPhoto); + updateImageCounter(); + Helper.makeSnackBar(findViewById(android.R.id.content), + "Imagen " + (currentImageIndex + 1) + " de " + imageUrls.size()); + return true; + } + return false; + }); } private void initObj() { context = this; - reportEntity = new Report(); + if (reportEntity == null) { + reportEntity = new Report(); + } } @Override public void onClick(View v) { int id = v.getId(); - if (id == R.id.ivThumbsUp) { + if (id == R.id.ivReportPhoto) { + onClickIvReportPhoto(); + } else if (id == R.id.ivThumbsUp) { onClickThumbsUp(); } else if (id == R.id.ivThumbsAverage) { onClickThumbsAverage(); } else if (id == R.id.ivThumbsDown) { onClickThumbsDown(); - } else if (id == R.id.ivReportPhoto) { - onClickIvReportPhoto(); - } else if (id == R.id.btnSubmit) { + } else if (id == R.id.btnSubmitReport) { onClickBtnSubmit(); } } private void onClickIvReportPhoto() { - // Open the gallery to select an image Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); - intent.setType("image/*"); // Restrict to images only + intent.setType("image/*"); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); startActivityForResult(intent, PICK_IMAGE_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) { - selectedImageUri = data.getData(); - - // Upload the image - uploadImageToServer(selectedImageUri); - - // Load image using Picasso - Picasso.get().load(selectedImageUri).into(ivReportPhoto); + if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) { + if (data.getClipData() != null) { + // Multiple images selected + int count = data.getClipData().getItemCount(); + for (int i = 0; i < count; i++) { + Uri imageUri = data.getClipData().getItemAt(i).getUri(); + uploadImageToServer(imageUri); + } + } else if (data.getData() != null) { + // Single image selected + Uri selectedImageUri = data.getData(); + uploadImageToServer(selectedImageUri); + Picasso.get().load(selectedImageUri).into(ivReportPhoto); + } } } private void uploadImageToServer(Uri imageUri) { + btnSubmitReport.setClickable(false); UploadManager.uploadImage(this, imageUri, new UploadManager.UploadCallback() { @Override public void onSuccess(String response) { @@ -224,54 +436,83 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick JSONObject json = new JSONObject(response); if (json.getBoolean("success")) { String filename = json.getJSONObject("file").getString("filename"); - imageUrl = BASE_URL + "public/" + filename; - jsonString = "[\"" + imageUrl + "\"]"; - Helper.makeSnackBar(rlAddReport, getString(R.string.image_uploaded_successfully)); - btnSubmit.setClickable(true); + String imageUrl = BASE_URL + "public/" + filename; + + // Add to images list + imageUrls.add(imageUrl); + + // Update JSON string + updateJsonString(); + + // Load first image if this is the first one + if (imageUrls.size() == 1) { + Picasso.get().load(imageUrl).into(ivReportPhoto); + } + + updateImageCounter(); + Helper.makeSnackBar(findViewById(android.R.id.content), + getString(R.string.image_uploaded_successfully) + " (" + imageUrls.size() + ")"); } else { - Helper.makeSnackBar(rlAddReport, getString(R.string.upload_failed)); - btnSubmit.setClickable(true); + Helper.makeSnackBar(findViewById(android.R.id.content), + getString(R.string.upload_failed)); } } catch (JSONException e) { - Helper.makeSnackBar(rlAddReport, getString(R.string.response_parsing_error)); - btnSubmit.setClickable(true); + Helper.makeSnackBar(findViewById(android.R.id.content), + getString(R.string.response_parsing_error)); Log.e(TAG, "Failed to parse JSON", e); } + btnSubmitReport.setClickable(true); } @Override public void onError(String message) { - Helper.makeSnackBar(rlAddReport, "Upload failed: " + message); - Log.e(TAG, "Upload error:" + message); - btnSubmit.setClickable(true); + Helper.makeSnackBar(findViewById(android.R.id.content), + "Upload failed: " + message); + Log.e(TAG, "Upload error: " + message); + btnSubmitReport.setClickable(true); } }); } + private void updateJsonString() { + try { + JSONArray jsonArray = new JSONArray(); + for (String imageUrl : imageUrls) { + jsonArray.put(imageUrl); + } + jsonString = jsonArray.toString(); + } catch (Exception e) { + Log.e(TAG, "Error creating images JSON", e); + jsonString = "[]"; + } + } + private void onClickThumbsUp() { + resetThumbsColors(); ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN); - ivThumbsDown.setColorFilter(null); // reset the other - ivThumbsAverage.setColorFilter(null); - reportRating = Constants.GOOD_RATING; //3 + reportRating = Constants.GOOD_RATING; // 3 } private void onClickThumbsAverage() { + resetThumbsColors(); ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN); - ivThumbsUp.setColorFilter(null); // reset the others - ivThumbsDown.setColorFilter(null); - reportRating = Constants.AVERAGE_RATING; //2 + reportRating = Constants.AVERAGE_RATING; // 2 } private void onClickThumbsDown() { + resetThumbsColors(); ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN); - ivThumbsUp.setColorFilter(null); // reset the other - ivThumbsAverage.setColorFilter(null); - reportRating = Constants.BAD_RATING; //1 + reportRating = Constants.BAD_RATING; // 1 + } + private void resetThumbsColors() { + ivThumbsUp.setColorFilter(ContextCompat.getColor(this, android.R.color.transparent), PorterDuff.Mode.SRC_IN); + ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, android.R.color.transparent), PorterDuff.Mode.SRC_IN); + ivThumbsDown.setColorFilter(ContextCompat.getColor(this, android.R.color.transparent), PorterDuff.Mode.SRC_IN); } private void onClickBtnSubmit() { - View[] views = {etPlaceName, etDescription}; + View[] views = {etDescription}; if (Helper.isEmptyFieldValidation(context, views) && isValidateRating()) { setInputDataToEntity(); @@ -280,20 +521,23 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick updateReportRetrofit( report_uuid, place_uuid, - SharedPref.getUserUid(context), + SharedPref.getUserUuid(context), String.valueOf(reportEntity.getReportRating()), reportEntity.getDescription(), reportEntity.getCreatedBy(), - reportEntity.getImage() + reportEntity.getImage(), + selectedReportTypeUuids // Now passing array ); } else { + // Create new report insertReportRetrofit( - placeEntity.getUuid(), - SharedPref.getUserUid(context), + place_uuid, + SharedPref.getUserUuid(context), String.valueOf(reportEntity.getReportRating()), reportEntity.getDescription(), reportEntity.getCreatedBy(), - reportEntity.getImage() + reportEntity.getImage(), + selectedReportTypeUuids // Now passing array ); } } @@ -302,21 +546,24 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick private void setInputDataToEntity() { reportEntity.setDescription(Helper.getStringFromInput(etDescription)); reportEntity.setReportRating(reportRating); - reportEntity.setCreatedBy(SharedPref.getUserUid(context)); + reportEntity.setCreatedBy(SharedPref.getUserUuid(context)); reportEntity.setImage(jsonString); + reportEntity.setReportTypeUuids(new ArrayList<>(selectedReportTypeUuids)); // Set multiple UUIDs + reportEntity.setPlaceUuid(place_uuid); } private boolean isValidateRating() { if (reportRating != 0) { return true; } else { - Helper.makeSnackBar(rlAddReport, getString(R.string.Please_select_rating)); + Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Please_select_rating)); return false; } } private void insertReportRetrofit(String placeUuid, String userUuid, String rating, - String description, String createdBy, String jsonString) { + String description, String createdBy, String jsonString, + List reportTypeUuids) { DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait)); @@ -328,6 +575,15 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick reportBody.addProperty("createdBy", createdBy); reportBody.addProperty("images", jsonString); + // Add report type UUIDs as array (if any selected) + if (reportTypeUuids != null && !reportTypeUuids.isEmpty()) { + JsonArray reportTypesArray = new JsonArray(); + for (String uuid : reportTypeUuids) { + reportTypesArray.add(uuid); + } + reportBody.add("report_type_uuid", reportTypesArray); + } + String token = "Bearer " + SharedPref.getAccessToken(context); ReportService reportService = LocationApiClient.getInstance().getReportService(); @@ -344,16 +600,20 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick JsonObject reportObject = data.getAsJsonArray("reports").get(0).getAsJsonObject(); String report_uuid = reportObject.get("uuid").getAsString(); Log.d(TAG, "Report UUID: " + report_uuid); - Helper.makeSnackBar(rlAddReport, getString(R.string.Report_submitted_successfully)); - rlAddReport.postDelayed(() -> { + + String message = getString(R.string.Report_submitted_successfully); + + Helper.makeSnackBar(findViewById(android.R.id.content), message); + findViewById(android.R.id.content).postDelayed(() -> { + setResult(RESULT_OK); finish(); }, 500); } else { Log.d(TAG, "Failed to extract report UUID."); - Helper.makeSnackBar(rlAddReport, getString(R.string.Something_went_wrong_Try_again)); + Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Something_went_wrong_Try_again)); } } else { - Helper.makeSnackBar(rlAddReport, getString(R.string.Report_submission_failed_Try_again)); + Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Report_submission_failed_Try_again)); Log.e(TAG, "Insert Report Error: " + response.code()); } } @@ -362,13 +622,14 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick public void onFailure(Call call, Throwable t) { DialogUtils.dismissDialog(); Log.e(TAG, "Insert Report Failure: ", t); - Helper.makeSnackBar(rlAddReport, context.getString(R.string.Network_error_Try_again)); + Helper.makeSnackBar(findViewById(android.R.id.content), context.getString(R.string.Network_error_Try_again)); } }); } private void updateReportRetrofit(String uuid, String placeUuid, String userUuid, String rating, - String description, String createdBy, String jsonString) { + String description, String createdBy, String jsonString, + List reportTypeUuids) { DialogUtils.showLoadingDialog(context, getString(R.string.Updating_report)); @@ -380,9 +641,17 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick reportBody.addProperty("createdBy", createdBy); reportBody.addProperty("images", jsonString); + // Add report type UUIDs as array (if any selected) + if (reportTypeUuids != null && !reportTypeUuids.isEmpty()) { + JsonArray reportTypesArray = new JsonArray(); + for (String reportUuid : reportTypeUuids) { + reportTypesArray.add(reportUuid); + } + reportBody.add("report_type_uuid", reportTypesArray); + } + String token = "Bearer " + SharedPref.getAccessToken(context); - // Using the new ReportService through LocationApiClient ReportService reportService = LocationApiClient.getInstance().getReportService(); Call call = reportService.updateReport(token, uuid, reportBody); @@ -391,20 +660,23 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick public void onResponse(Call call, Response response) { DialogUtils.dismissDialog(); if (response.isSuccessful()) { - Helper.makeSnackBar(rlAddReport, getString(R.string.Report_updated_successfully)); - rlAddReport.postDelayed(() -> { - finish(); //to go back to the previous activity + String message = getString(R.string.Report_updated_successfully); + + Helper.makeSnackBar(findViewById(android.R.id.content), message); + findViewById(android.R.id.content).postDelayed(() -> { + setResult(RESULT_OK); + finish(); }, 500); } else { - Helper.makeSnackBar(rlAddReport, getString(R.string.Update_failed_Server_error_Try_again)); + Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Update_failed_Server_error_Try_again)); } } @Override public void onFailure(Call call, Throwable t) { DialogUtils.dismissDialog(); - Log.e(TAG, "Update Place Error: ", t); - Helper.makeSnackBar(rlAddReport, context.getString(R.string.Network_error_Try_again)); + Log.e(TAG, "Update Report Error: ", t); + Helper.makeSnackBar(findViewById(android.R.id.content), context.getString(R.string.Network_error_Try_again)); } }); } diff --git a/app/src/main/java/com/example/acloc/activity/PlaceDetailActivity.java b/app/src/main/java/com/example/acloc/activity/PlaceDetailActivity.java index d1ff42b..a3fe5f4 100644 --- a/app/src/main/java/com/example/acloc/activity/PlaceDetailActivity.java +++ b/app/src/main/java/com/example/acloc/activity/PlaceDetailActivity.java @@ -130,7 +130,7 @@ public class PlaceDetailActivity extends AppCompatActivity implements View.OnCli private void initObj() { context = this; - checkIfPlaceIsFavorite(SharedPref.getUserUid(context), place_uuid); + checkIfPlaceIsFavorite(SharedPref.getUserUuid(context), place_uuid); } private void loadIntentData() { @@ -235,9 +235,9 @@ public class PlaceDetailActivity extends AppCompatActivity implements View.OnCli private void onClickFavorite() { if (isFavorite) { - removePlaceFromFavorites(SharedPref.getUserUid(context), place_uuid); + removePlaceFromFavorites(SharedPref.getUserUuid(context), place_uuid); } else { - addPlaceToFavorites(SharedPref.getUserUid(context), place_uuid); + addPlaceToFavorites(SharedPref.getUserUuid(context), place_uuid); } } diff --git a/app/src/main/java/com/example/acloc/activity/RegisterActivity.java b/app/src/main/java/com/example/acloc/activity/RegisterActivity.java index 190e49b..5b6a3bf 100644 --- a/app/src/main/java/com/example/acloc/activity/RegisterActivity.java +++ b/app/src/main/java/com/example/acloc/activity/RegisterActivity.java @@ -97,7 +97,7 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL View[] views = {etName, etEmail, etPassword}; if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail) && Helper.isPasswordValid(context, etPassword)) { setInputDataToEntity(); - registerUserWithRetrofit(); + registerUser(); } } @@ -107,17 +107,10 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL entity.setPassword(Helper.getStringFromInput(etPassword)); } - private void registerUserWithRetrofit() { + private void registerUser() { DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait)); - JsonObject jsonParam = new JsonObject(); - jsonParam.addProperty("username", entity.getUsername()); - jsonParam.addProperty("email", entity.getEmail()); - jsonParam.addProperty("password", entity.getPassword()); - jsonParam.addProperty("fk_role", Constants.ADMIN); //Default Admin for now (BUT acc to api it will be Viewer) - - AuthService authService = LocationApiClient.getInstance().getAuthService(); - Call call = authService.registerUser(jsonParam); + Call call = getJsonObjectCall(); call.enqueue(new Callback() { @Override @@ -162,4 +155,16 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL } }); } + + private Call getJsonObjectCall() { + JsonObject jsonParam = new JsonObject(); + jsonParam.addProperty("username", entity.getUsername()); + jsonParam.addProperty("email", entity.getEmail()); + jsonParam.addProperty("password", entity.getPassword()); + jsonParam.addProperty("fk_role", Constants.ADMIN); //Default Admin for now (BUT acc to api it will be Viewer) + + AuthService authService = LocationApiClient.getInstance().getAuthService(); + Call call = authService.registerUser(jsonParam); + return call; + } } diff --git a/app/src/main/java/com/example/acloc/adapter/FavoriteAdapter.java b/app/src/main/java/com/example/acloc/adapter/FavoriteAdapter.java index 597bfea..112ceaa 100644 --- a/app/src/main/java/com/example/acloc/adapter/FavoriteAdapter.java +++ b/app/src/main/java/com/example/acloc/adapter/FavoriteAdapter.java @@ -74,7 +74,7 @@ public class FavoriteAdapter extends RecyclerView.Adapter removePlaceFromFavorites(SharedPref.getUserUid(context), favorite.getPlaceUuid(), favorite.getUuid())); + holder.ivFavorite.setOnClickListener(v -> removePlaceFromFavorites(SharedPref.getUserUuid(context), favorite.getPlaceUuid(), favorite.getUuid())); holder.itemView.setOnClickListener(v -> getPlaceByUuid(favorite.getPlaceUuid())); } diff --git a/app/src/main/java/com/example/acloc/adapter/PlaceReportsAdapter.java b/app/src/main/java/com/example/acloc/adapter/PlaceReportsAdapter.java index 0deb8bc..a4ae145 100644 --- a/app/src/main/java/com/example/acloc/adapter/PlaceReportsAdapter.java +++ b/app/src/main/java/com/example/acloc/adapter/PlaceReportsAdapter.java @@ -10,11 +10,15 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.ieslamar.acloc.R; import com.example.acloc.model.Report; +import com.example.acloc.utility.Constants; +import com.example.acloc.utility.AccessibilityHelper; +import com.ieslamar.acloc.R; +import java.util.ArrayList; import java.util.List; public class PlaceReportsAdapter extends RecyclerView.Adapter { @@ -27,68 +31,155 @@ public class PlaceReportsAdapter extends RecyclerView.Adapter reportList) { + if (reportList != null) { + this.reportList = reportList; + notifyDataSetChanged(); + } } @SuppressLint("NotifyDataSetChanged") - public void updateReportsList(List reportList) { - try { - if (reportList != null) { - this.reportList = reportList; - notifyDataSetChanged(); - } - } catch (Exception exception) { - Log.e(TAG, "Error in PlaceReportsAdapter", exception); + public void clearReports() { + if (this.reportList != null) { + this.reportList.clear(); + notifyDataSetChanged(); } } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - LayoutInflater inflater = LayoutInflater.from(context); - View detailItem = inflater.inflate(R.layout.list_view_place_reports, parent, false); - return new ViewHolder(detailItem); + View view = LayoutInflater.from(context).inflate(R.layout.list_view_place_reports, parent, false); + return new ViewHolder(view); } - @SuppressLint("SetTextI18n") @Override - public void onBindViewHolder(@NonNull PlaceReportsAdapter.ViewHolder holder, int position) { + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { try { - if (!reportList.isEmpty()) { - Report report = reportList.get(position); - holder.tvDescription.setText(report.getDescription()); - if (report.getReportRating() == 1) { - holder.tvRating.setText(context.getString(R.string.Rating_BAD)); - holder.ivRating.setImageResource(R.drawable.ic_thumbs_down); - } else if (report.getReportRating() == 2) { - holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE)); - holder.ivRating.setImageResource(R.drawable.ic_thumb_up_average); - } else if (report.getReportRating() == 3) { - holder.tvRating.setText(context.getString(R.string.Rating_GOOD)); - holder.ivRating.setImageResource(R.drawable.ic_thumbs_up); - } - } + Report report = reportList.get(position); + holder.tvDescription.setText(report.getDescription()); + + // Set rating + setRatingDisplay(holder, report.getReportRating()); + + // Setup accessibility tags for multiple report types + setupAccessibilityTags(holder.rvAccessibilityTags, report, position); + } catch (Exception e) { - Log.e(TAG, "Error in PlaceReportsAdapter", e); + Log.e(TAG, "Error binding report", e); } } + private void setRatingDisplay(ViewHolder holder, int rating) { + switch (rating) { + case Constants.BAD_RATING: + holder.tvRating.setText(context.getString(R.string.Rating_BAD)); + holder.ivRating.setImageResource(R.drawable.ic_thumbs_down); + break; + case Constants.AVERAGE_RATING: + holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE)); + holder.ivRating.setImageResource(R.drawable.ic_thumb_up_average); + break; + case Constants.GOOD_RATING: + holder.tvRating.setText(context.getString(R.string.Rating_GOOD)); + holder.ivRating.setImageResource(R.drawable.ic_thumbs_up); + break; + } + } + + private void setupAccessibilityTags(RecyclerView rvTags, Report report, int position) { + // Clear any existing adapter first to avoid conflicts + rvTags.setAdapter(null); + + // Get report type names - support both single and multiple + List reportTypeNames = new ArrayList<>(); + + if (report.getReportTypeNames() != null && !report.getReportTypeNames().isEmpty()) { + reportTypeNames.addAll(report.getReportTypeNames()); + } + + // Only show tags if we have report type names + if (reportTypeNames.isEmpty()) { + rvTags.setVisibility(View.GONE); + return; + } + + // Create tag data for each report type + List tagDataList = new ArrayList<>(); + + for (String reportTypeName : reportTypeNames) { + // Use AccessibilityHelper to get proper display name + String displayName = AccessibilityHelper.getDisplayName(context, reportTypeName); + + // Skip if display name is unknown or empty + if (!displayName.equals(context.getString(R.string.accessibility_unknown)) && + !displayName.trim().isEmpty()) { + + tagDataList.add(new AccessibilityTagsAdapter.TagData( + displayName, + report.getReportRating() + )); + } + } + + // Hide tags if no valid display names + if (tagDataList.isEmpty()) { + rvTags.setVisibility(View.GONE); + return; + } + + // Setup RecyclerView with unique configuration + LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); + rvTags.setLayoutManager(layoutManager); + + // Create new adapter instance for each item + AccessibilityTagsAdapter adapter = new AccessibilityTagsAdapter(context, tagDataList); + rvTags.setAdapter(adapter); + + // Set unique tag to avoid recycling conflicts + rvTags.setTag("accessibility_tags_" + position); + + // Disable nested scrolling to avoid conflicts + rvTags.setNestedScrollingEnabled(false); + + rvTags.setVisibility(View.VISIBLE); + + // Force layout update + rvTags.post(() -> { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + }); + } + @Override public int getItemCount() { return reportList.size(); } + // Add this to ensure proper recycling + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemViewType(int position) { + return position; + } + public static class ViewHolder extends RecyclerView.ViewHolder { - private final TextView tvDescription, tvRating; - private final ImageView ivRating; + final TextView tvDescription, tvRating; + final ImageView ivRating; + final RecyclerView rvAccessibilityTags; public ViewHolder(@NonNull View itemView) { super(itemView); tvDescription = itemView.findViewById(R.id.tvDescription); tvRating = itemView.findViewById(R.id.tvRating); ivRating = itemView.findViewById(R.id.ivRating); + rvAccessibilityTags = itemView.findViewById(R.id.rvAccessibilityTags); } } } diff --git a/app/src/main/java/com/example/acloc/api/LocationApiClient.java b/app/src/main/java/com/example/acloc/api/LocationApiClient.java index 4f04e0f..a39c71e 100644 --- a/app/src/main/java/com/example/acloc/api/LocationApiClient.java +++ b/app/src/main/java/com/example/acloc/api/LocationApiClient.java @@ -4,11 +4,13 @@ import com.example.acloc.service.AuthService; import com.example.acloc.service.FavoriteService; import com.example.acloc.service.PlaceService; import com.example.acloc.service.ReportService; +import com.example.acloc.service.ReportTypeService; import com.example.acloc.service.RoleService; import com.example.acloc.service.UploadService; import com.example.acloc.service.UserService; import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; /** * Centralized API client that manages Retrofit instance and provides access to all service interfaces @@ -22,6 +24,7 @@ public class LocationApiClient { private FavoriteService favoriteService; private PlaceService placeService; private ReportService reportService; + private ReportTypeService reportTypeService; private RoleService roleService; private UserService userService; private UploadService uploadService; @@ -86,6 +89,17 @@ public class LocationApiClient { return reportService; } + /** + * Gets the ReportTypeService interface + * @return ReportTypeService implementation + */ + public ReportTypeService getReportTypeService() { + if (reportTypeService == null) { + reportTypeService = retrofit.create(ReportTypeService.class); + } + return reportTypeService; + } + /** * Gets the RoleService interface * @return RoleService implementation @@ -114,4 +128,4 @@ public class LocationApiClient { } return uploadService; } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/acloc/dialog/AlertChangePasswordDialog.java b/app/src/main/java/com/example/acloc/dialog/AlertChangePasswordDialog.java index 5f2707f..6579ec9 100644 --- a/app/src/main/java/com/example/acloc/dialog/AlertChangePasswordDialog.java +++ b/app/src/main/java/com/example/acloc/dialog/AlertChangePasswordDialog.java @@ -95,7 +95,7 @@ public class AlertChangePasswordDialog implements View.OnClickListener { String username = SharedPref.getUserName(context); String oldPassword = Helper.getStringFromInput(etOldPassword); String newPassword = Helper.getStringFromInput(etNewPassword); - String uuid = SharedPref.getUserUid(context); + String uuid = SharedPref.getUserUuid(context); verifyOldPasswordRetrofit(uuid, username, oldPassword, newPassword); } diff --git a/app/src/main/java/com/example/acloc/dialog/AlertViewAddNewPlaceDialog.java b/app/src/main/java/com/example/acloc/dialog/AlertViewAddNewPlaceDialog.java index 4d5cf03..e71abf5 100644 --- a/app/src/main/java/com/example/acloc/dialog/AlertViewAddNewPlaceDialog.java +++ b/app/src/main/java/com/example/acloc/dialog/AlertViewAddNewPlaceDialog.java @@ -136,7 +136,7 @@ public class AlertViewAddNewPlaceDialog implements View.OnClickListener { entity.setAddress(Helper.getStringFromInput(etAddress)); entity.setLatitude(Helper.getStringFromInput(etLatitude)); entity.setLongitude(Helper.getStringFromInput(etLongitude)); - entity.setCreatedBy(SharedPref.getUserUid(context)); + entity.setCreatedBy(SharedPref.getUserUuid(context)); entity.setUuid(place_uuid); } diff --git a/app/src/main/java/com/example/acloc/dialog/AlertViewOrUpdateProfileDialog.java b/app/src/main/java/com/example/acloc/dialog/AlertViewOrUpdateProfileDialog.java index dcb29fd..586bbe5 100644 --- a/app/src/main/java/com/example/acloc/dialog/AlertViewOrUpdateProfileDialog.java +++ b/app/src/main/java/com/example/acloc/dialog/AlertViewOrUpdateProfileDialog.java @@ -117,7 +117,7 @@ public class AlertViewOrUpdateProfileDialog implements View.OnClickListener { View[] views = {etUsername, etEmail}; if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail)) { setInputDataToEntity(); - String uuid = SharedPref.getUserUid(context); + String uuid = SharedPref.getUserUuid(context); updateUserWithRetrofit(uuid, entity.getUsername(), entity.getEmail()); } } diff --git a/app/src/main/java/com/example/acloc/dialog/PlaceBottomSheetDialog.java b/app/src/main/java/com/example/acloc/dialog/PlaceBottomSheetDialog.java index b585dad..8e10821 100644 --- a/app/src/main/java/com/example/acloc/dialog/PlaceBottomSheetDialog.java +++ b/app/src/main/java/com/example/acloc/dialog/PlaceBottomSheetDialog.java @@ -20,6 +20,7 @@ import com.example.acloc.activity.AddNewPlaceActivity; import com.example.acloc.activity.AddReportActivity; import com.example.acloc.activity.PlaceDetailActivity; import com.example.acloc.adapter.PlaceReportsAdapter; +import com.example.acloc.adapter.AccessibilityTagsAdapter; import com.example.acloc.api.LocationApiClient; import com.example.acloc.model.Place; import com.example.acloc.model.Report; @@ -29,6 +30,7 @@ import com.example.acloc.utility.Constants; import com.example.acloc.utility.DialogUtils; import com.example.acloc.utility.Helper; import com.example.acloc.utility.SharedPref; +import com.example.acloc.utility.AccessibilityHelper; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; @@ -36,11 +38,17 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.ieslamar.acloc.R; +import com.squareup.picasso.Picasso; + +import org.json.JSONArray; +import org.json.JSONException; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import retrofit2.Call; import retrofit2.Callback; @@ -54,9 +62,9 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { private boolean isFavorite = false; private TextView tvPlaceName, tvAddress, tvDescription, tvNoReports; - private ImageView ivFavorite, ivEdit, ivExpand; + private ImageView ivFavorite, ivEdit, ivExpand, ivPlaceImage; private AppCompatButton btnAddReport; - private RecyclerView rvReports; + private RecyclerView rvReports, rvAccessibilityOverview; private PlaceReportsAdapter adapter; private final List reportList = new ArrayList<>(); private BottomSheetBehavior behavior; @@ -76,11 +84,9 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { if (bottomSheet != null) { behavior = BottomSheetBehavior.from(bottomSheet); - //Set initial state to half expanded behavior.setPeekHeight(getResources().getDisplayMetrics().heightPixels / 2); behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED); - //Add callback to update expand/collapse icon behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { @@ -93,7 +99,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { - // animation based on slide position - do nothing for now + // Do nothing for now } }); } @@ -111,7 +117,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { initUI(view); setPlaceData(); initListeners(); - checkIfPlaceIsFavorite(SharedPref.getUserUid(context), place.getUuid()); + checkIfPlaceIsFavorite(SharedPref.getUserUuid(context), place.getUuid()); loadReports(); return view; @@ -125,24 +131,70 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { ivFavorite = view.findViewById(R.id.ivFavorite); ivEdit = view.findViewById(R.id.ivEdit); ivExpand = view.findViewById(R.id.ivExpand); + ivPlaceImage = view.findViewById(R.id.ivPlaceImage); btnAddReport = view.findViewById(R.id.btnAddReport); rvReports = view.findViewById(R.id.rvReports); + rvAccessibilityOverview = view.findViewById(R.id.rvAccessibilityOverview); rvReports.setLayoutManager(new LinearLayoutManager(context)); + rvAccessibilityOverview.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); } private void setPlaceData() { tvPlaceName.setText(place.getName()); tvAddress.setText(place.getAddress()); tvDescription.setText(place.getDescription()); + + // Load place image with better error handling + loadPlaceImage(); + } + + private void loadPlaceImage() { + if (place.getImage() != null && !place.getImage().isEmpty()) { + try { + JSONArray imageArray = new JSONArray(place.getImage()); + if (imageArray.length() > 0) { + String imageUrl = imageArray.getString(0); + + // Ensure the URL is properly formatted + if (!imageUrl.startsWith("http")) { + // Assume it's a relative path and prepend base URL + imageUrl = Constants.BASE_URL + imageUrl; + } + + ivPlaceImage.setVisibility(View.VISIBLE); + Picasso.get() + .load(imageUrl) + .placeholder(R.drawable.place_header) + .error(R.drawable.place_header) + .fit() + .centerCrop() + .into(ivPlaceImage); + + Log.d(TAG, "Loading place image: " + imageUrl); + } else { + setDefaultPlaceImage(); + } + } catch (JSONException e) { + Log.e(TAG, "Error parsing place images", e); + setDefaultPlaceImage(); + } + } else { + setDefaultPlaceImage(); + } + } + + private void setDefaultPlaceImage() { + ivPlaceImage.setVisibility(View.VISIBLE); + ivPlaceImage.setImageResource(R.drawable.place_header); } private void initListeners() { ivFavorite.setOnClickListener(v -> { if (isFavorite) { - removePlaceFromFavorites(SharedPref.getUserUid(context), place.getUuid()); + removePlaceFromFavorites(SharedPref.getUserUuid(context), place.getUuid()); } else { - addPlaceToFavorites(SharedPref.getUserUid(context), place.getUuid()); + addPlaceToFavorites(SharedPref.getUserUuid(context), place.getUuid()); } }); @@ -166,7 +218,6 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { dismiss(); }); - // Open full screen details on click View.OnClickListener fullScreenListener = v -> { Helper.goTo(context, PlaceDetailActivity.class, Constants.PLACE, place); dismiss(); @@ -175,6 +226,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { tvPlaceName.setOnClickListener(fullScreenListener); tvAddress.setOnClickListener(fullScreenListener); tvDescription.setOnClickListener(fullScreenListener); + ivPlaceImage.setOnClickListener(fullScreenListener); } private void loadReports() { @@ -194,16 +246,15 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { for (JsonElement element : data.getAsJsonArray("reports")) { Report report = getReport(element); - reportList.add(report); } - // Show latest reports first Collections.reverse(reportList); List latestReports = reportList.size() > 3 ? reportList.subList(0, 3) : reportList; updateReportsUI(latestReports); + calculateAndShowAccessibilityStats(reportList); } else { showNoReports(); } @@ -228,9 +279,118 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { report.setDescription(reportObject.get("description").getAsString()); report.setPlaceName(reportObject.get("place_name").getAsString()); report.setPlaceUuid(reportObject.get("place_uuid").getAsString()); + + List reportTypeUuids = new ArrayList<>(); + List reportTypeNames = new ArrayList<>(); + + processReportTypeField(reportObject, "report_type_uuids", reportTypeUuids); + processReportTypeField(reportObject, "report_type_names", reportTypeNames); + + // Fallback for legacy fields (singular) + if (reportTypeUuids.isEmpty() && reportObject.has("report_type_uuid") && !reportObject.get("report_type_uuid").isJsonNull()) { + reportTypeUuids.add(reportObject.get("report_type_uuid").getAsString()); + } + + if (reportTypeNames.isEmpty() && reportObject.has("report_type_name") && !reportObject.get("report_type_name").isJsonNull()) { + reportTypeNames.add(reportObject.get("report_type_name").getAsString()); + } + + report.setReportTypeUuids(reportTypeUuids); + report.setReportTypeNames(reportTypeNames); + return report; } + private static void processReportTypeField(JsonObject reportObject, String fieldName, List resultList) { + try { + if (!reportObject.has(fieldName) || reportObject.get(fieldName).isJsonNull()) { + return; // null + } + + JsonElement element = reportObject.get(fieldName); + + if (element.isJsonArray()) { + // array JSON + JsonArray array = element.getAsJsonArray(); + for (JsonElement item : array) { + String value = item.getAsString().trim(); + if (!value.isEmpty()) { + resultList.add(value); + } + } + Log.d(TAG, fieldName + " processed as array: " + resultList.size() + " items"); + + } else if (element.isJsonPrimitive()) { + // string (GROUP_CONCAT) + String stringValue = element.getAsString(); + if (!stringValue.isEmpty()) { + // Split (GROUP_CONCAT) + String[] values = stringValue.split(","); + for (String value : values) { + String cleanValue = value.trim(); + if (!cleanValue.isEmpty()) { + resultList.add(cleanValue); + } + } + Log.d(TAG, fieldName + " processed as string: " + resultList.size() + " items from '" + stringValue + "'"); + } + } else { + Log.w(TAG, fieldName + " is neither array nor primitive: " + element.getClass().getSimpleName()); + } + + } catch (Exception e) { + Log.e(TAG, "Error processing " + fieldName, e); + } + } + + private void calculateAndShowAccessibilityStats(List allReports) { + if (allReports.isEmpty()) { + rvAccessibilityOverview.setVisibility(View.GONE); + return; + } + + // Calculate statistics for each accessibility type + Map statsMap = new HashMap<>(); + int totalReports = allReports.size(); + + for (Report report : allReports) { + List reportTypeNames = report.getReportTypeNames(); + if (reportTypeNames != null) { + for (String typeName : reportTypeNames) { + String displayName = AccessibilityHelper.getDisplayName(context, typeName); + if (!displayName.equals(context.getString(R.string.accessibility_unknown))) { + AccessibilityStats stats = statsMap.getOrDefault(displayName, new AccessibilityStats(displayName)); + stats.addRating(report.getReportRating()); + statsMap.put(displayName, stats); + } + } + } + } + + // Show overall statistics + showAccessibilityOverview(new ArrayList<>(statsMap.values())); + } + + private void showAccessibilityOverview(List statsList) { + if (statsList.isEmpty()) { + rvAccessibilityOverview.setVisibility(View.GONE); + return; + } + + // Convert stats to tag data for display + List tagDataList = new ArrayList<>(); + for (AccessibilityStats stats : statsList) { + tagDataList.add(new AccessibilityTagsAdapter.TagData( + stats.typeName + " (" + stats.count + ")", + stats.getAverageRating() + )); + } + + AccessibilityTagsAdapter overviewAdapter = new AccessibilityTagsAdapter(context, tagDataList); + rvAccessibilityOverview.setAdapter(overviewAdapter); + rvAccessibilityOverview.setVisibility(View.VISIBLE); + } + private void updateReportsUI(List reports) { if (reports != null && !reports.isEmpty()) { adapter = new PlaceReportsAdapter(context, reports); @@ -244,9 +404,35 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { private void showNoReports() { rvReports.setVisibility(View.GONE); + rvAccessibilityOverview.setVisibility(View.GONE); tvNoReports.setVisibility(View.VISIBLE); } + // Helper class for accessibility statistics + private static class AccessibilityStats { + String typeName; + int count = 0; + int totalRating = 0; + + AccessibilityStats(String typeName) { + this.typeName = typeName; + } + + void addRating(int rating) { + count++; + totalRating += rating; + } + + int getAverageRating() { + if (count == 0) return Constants.AVERAGE_RATING; + + double average = (double) totalRating / count; + if (average <= 1.5) return Constants.BAD_RATING; + if (average <= 2.5) return Constants.AVERAGE_RATING; + return Constants.GOOD_RATING; + } + } + private void checkIfPlaceIsFavorite(String userUuid, String placeUuid) { String token = "Bearer " + SharedPref.getAccessToken(context); FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService(); @@ -314,7 +500,6 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment { if (response.errorBody() != null) { String errorBody = response.errorBody().string(); - // Try restoring if it's a duplicate (409 Conflict) or it isn't found (deleted) if ((response.code() == 409 && errorBody.contains("ER_DUP_ENTRY"))|| response.code() == 404 ) { restorePlaceToFavorites(userUuid, placeUuid); return; diff --git a/app/src/main/java/com/example/acloc/fragments/FavoriteFragment.java b/app/src/main/java/com/example/acloc/fragments/FavoriteFragment.java index a30e501..d450aa1 100644 --- a/app/src/main/java/com/example/acloc/fragments/FavoriteFragment.java +++ b/app/src/main/java/com/example/acloc/fragments/FavoriteFragment.java @@ -103,7 +103,7 @@ public class FavoriteFragment extends Fragment { if (favoriteList == null) { favoriteList = new ArrayList<>(); } - String userUuid = SharedPref.getUserUid(context); + String userUuid = SharedPref.getUserUuid(context); getFavoriteByUserUuid(userUuid); } catch (Exception e) { Log.e(TAG, "Error in FavoriteFragment", e); diff --git a/app/src/main/java/com/example/acloc/fragments/MyReportsFragment.java b/app/src/main/java/com/example/acloc/fragments/MyReportsFragment.java index c55c388..57a02fb 100644 --- a/app/src/main/java/com/example/acloc/fragments/MyReportsFragment.java +++ b/app/src/main/java/com/example/acloc/fragments/MyReportsFragment.java @@ -107,7 +107,7 @@ public class MyReportsFragment extends Fragment implements View.OnClickListener if (reportList == null) { reportList = new ArrayList<>(); } - String userUuid = SharedPref.getUserUid(context); + String userUuid = SharedPref.getUserUuid(context); getReportsByUserUuid(userUuid); } catch (Exception e) { Log.e(TAG, "Error in MyReportsFragment", e); diff --git a/app/src/main/java/com/example/acloc/model/Report.java b/app/src/main/java/com/example/acloc/model/Report.java index 1a84b34..255ee75 100644 --- a/app/src/main/java/com/example/acloc/model/Report.java +++ b/app/src/main/java/com/example/acloc/model/Report.java @@ -1,13 +1,33 @@ package com.example.acloc.model; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; public class Report implements Serializable { - String uuid, fkUser, fkPlace, fkReportType, description, createdBy; + String uuid, fkUser, fkPlace, description, createdBy; String placeName, placeUuid; int reportRating; String image; + private List reportTypeUuids = new ArrayList<>(); + private List reportTypeNames = new ArrayList<>(); + + public List getReportTypeUuids() { + return reportTypeUuids; + } + + public void setReportTypeUuids(List reportTypeUuids) { + this.reportTypeUuids = reportTypeUuids; + } + + public List getReportTypeNames() { + return reportTypeNames; + } + + public void setReportTypeNames(List reportTypeNames) { + this.reportTypeNames = reportTypeNames; + } public String getUuid() { return uuid; } @@ -32,14 +52,6 @@ public class Report implements Serializable { this.fkPlace = fkPlace; } - public String getFkReportType() { - return fkReportType; - } - - public void setFkReportType(String fkReportType) { - this.fkReportType = fkReportType; - } - public String getDescription() { return description; } diff --git a/app/src/main/java/com/example/acloc/model/ReportType.java b/app/src/main/java/com/example/acloc/model/ReportType.java new file mode 100644 index 0000000..a31d6bd --- /dev/null +++ b/app/src/main/java/com/example/acloc/model/ReportType.java @@ -0,0 +1,42 @@ +package com.example.acloc.model; + +import java.io.Serializable; + +public class ReportType implements Serializable { + private String uuid; + private String name; + private boolean selected; + + public ReportType() { + } + + public ReportType(String uuid, String name) { + this.uuid = uuid; + this.name = name; + this.selected = false; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } +} diff --git a/app/src/main/java/com/example/acloc/service/ReportService.java b/app/src/main/java/com/example/acloc/service/ReportService.java index 9dd4590..12f5fc2 100644 --- a/app/src/main/java/com/example/acloc/service/ReportService.java +++ b/app/src/main/java/com/example/acloc/service/ReportService.java @@ -67,7 +67,7 @@ public interface ReportService { * @param reportData Report data containing parameters to modify * @return JsonObject containing updated report information */ - @PUT("/reports/{uuid}") + @PUT("reports/{uuid}") Call updateReport( @Header("Authorization") String token, @Path("uuid") String uuid, diff --git a/app/src/main/java/com/example/acloc/service/ReportTypeService.java b/app/src/main/java/com/example/acloc/service/ReportTypeService.java new file mode 100644 index 0000000..2a923b6 --- /dev/null +++ b/app/src/main/java/com/example/acloc/service/ReportTypeService.java @@ -0,0 +1,48 @@ +package com.example.acloc.service; + +import com.google.gson.JsonObject; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.DELETE; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Path; +import retrofit2.http.Query; + +public interface ReportTypeService { + + @GET("report_types") + Call getReportTypes( + @Header("Authorization") String token, + @Query("uuid") String uuid, + @Query("name") String name + ); + + @GET("report_types/{uuid}") + Call getReportTypeByUuid( + @Header("Authorization") String token, + @Path("uuid") String uuid + ); + + @POST("report_types") + Call createReportType( + @Header("Authorization") String token, + @Body JsonObject body + ); + + @PUT("report_types/{uuid}") + Call updateReportType( + @Header("Authorization") String token, + @Path("uuid") String uuid, + @Body JsonObject body + ); + + @DELETE("report_types/{uuid}") + Call deleteReportType( + @Header("Authorization") String token, + @Path("uuid") String uuid + ); +} diff --git a/app/src/main/java/com/example/acloc/utility/AccessibilityHelper.java b/app/src/main/java/com/example/acloc/utility/AccessibilityHelper.java new file mode 100644 index 0000000..b5c2275 --- /dev/null +++ b/app/src/main/java/com/example/acloc/utility/AccessibilityHelper.java @@ -0,0 +1,164 @@ +package com.example.acloc.utility; + +import android.content.Context; + +import com.ieslamar.acloc.R; + +public class AccessibilityHelper { + + public static class AccessibilityInfo { + public final String displayName; + public final int iconResource; + public final int backgroundColorRes; + public final int textColorRes; + public final int borderColorRes; + + public AccessibilityInfo(String displayName, int iconResource, + int backgroundColorRes, int textColorRes, int borderColorRes) { + this.displayName = displayName; + this.iconResource = iconResource; + this.backgroundColorRes = backgroundColorRes; + this.textColorRes = textColorRes; + this.borderColorRes = borderColorRes; + } + } + + public static AccessibilityInfo getAccessibilityInfo(String reportTypeName, int rating) { + // Get icon based on report type name + int iconResource = getIconForReportType(reportTypeName); + + // Get colors based on rating + int[] colors = getColorsForRating(rating); + + return new AccessibilityInfo( + reportTypeName, + iconResource, + colors[0], // background + colors[1], // text + colors[2] // border + ); + } + + // Made public for ReportTypeAdapter + public static int getIconForReportType(String reportTypeName) { + if (reportTypeName == null) return R.drawable.ic_accessible; + + String name = reportTypeName.toLowerCase(); + + // Map based on common accessibility type names + if (name.contains("silla") || name.contains("wheelchair") || name.contains("rueda")) { + return R.drawable.ic_accessible; + } else if (name.contains("visual") || name.contains("vista") || name.contains("ciego")) { + return R.drawable.ic_visibility; + } else if (name.contains("auditivo") || name.contains("hearing") || name.contains("sordo")) { + return com.ieslamar.acloc.R.drawable.ic_hearing; + } else if (name.contains("cognitivo") || name.contains("mental") || name.contains("cognitive")) { + return R.drawable.ic_psychology; + } else if (name.contains("movilidad") || name.contains("mobility") || name.contains("caminar")) { + return R.drawable.ic_directions_walk; + } else if (name.contains("estacionamiento") || name.contains("parking") || name.contains("aparcamiento")) { + return R.drawable.ic_local_parking; + } else if (name.contains("entrada") || name.contains("entrance") || name.contains("puerta")) { + return R.drawable.ic_door_front; + } else if (name.contains("baño") || name.contains("bathroom") || name.contains("aseo")) { + return R.drawable.ic_wc; + } else if (name.contains("ascensor") || name.contains("elevator")) { + return R.drawable.ic_elevator; + } else if (name.contains("rampa") || name.contains("ramp")) { + return R.drawable.ic_trending_up; + } else { + return R.drawable.ic_accessible; // Default accessibility icon + } + } + + // New method for getting display name + public static String getDisplayName(Context context, String reportTypeName) { + if (reportTypeName == null || reportTypeName.trim().isEmpty()) { + return context.getString(R.string.accessibility_unknown); + } + + // Clean up the name first - remove timestamps and weird suffixes + String cleanName = cleanReportTypeName(reportTypeName); + String name = cleanName.toLowerCase(); + + // Return localized display names + if (name.contains("silla") || name.contains("wheelchair") || name.contains("rueda")) { + return context.getString(R.string.accessibility_wheelchair); + } else if (name.contains("visual") || name.contains("vista") || name.contains("ciego")) { + return context.getString(R.string.accessibility_visual); + } else if (name.contains("auditivo") || name.contains("hearing") || name.contains("sordo")) { + return context.getString(R.string.accessibility_hearing); + } else if (name.contains("cognitivo") || name.contains("mental") || name.contains("cognitive")) { + return context.getString(R.string.accessibility_cognitive); + } else if (name.contains("movilidad") || name.contains("mobility") || name.contains("caminar")) { + return context.getString(R.string.accessibility_mobility); + } else if (name.contains("estacionamiento") || name.contains("parking") || name.contains("aparcamiento")) { + return context.getString(R.string.accessibility_parking); + } else if (name.contains("entrada") || name.contains("entrance") || name.contains("puerta")) { + return context.getString(R.string.accessibility_entrance); + } else if (name.contains("baño") || name.contains("bathroom") || name.contains("aseo")) { + return context.getString(R.string.accessibility_bathroom); + } else if (name.contains("ascensor") || name.contains("elevator")) { + return context.getString(R.string.accessibility_elevator); + } else if (name.contains("rampa") || name.contains("ramp")) { + return context.getString(R.string.accessibility_ramp); + } else { + // If no mapping found, return the cleaned name + return capitalizeFirstLetter(cleanName); + } + } + + // Add this new method to clean report type names + private static String cleanReportTypeName(String reportTypeName) { + if (reportTypeName == null) return ""; + + // Remove timestamp patterns like "20250418155930234_" + String cleaned = reportTypeName.replaceAll("\\d{17}_", ""); + + // Remove random suffixes like "_a1kzpr9q" + cleaned = cleaned.replaceAll("_[a-z0-9]{8}$", ""); + + // Remove any remaining underscores and replace with spaces + cleaned = cleaned.replace("_", " "); + + // Trim whitespace + cleaned = cleaned.trim(); + + return cleaned; + } + + private static String capitalizeFirstLetter(String text) { + if (text == null || text.isEmpty()) return text; + return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase(); + } + + private static int[] getColorsForRating(int rating) { + // Returns [background, text, border] colors + switch (rating) { + case Constants.GOOD_RATING: // 3 + return new int[]{ + R.color.accessibility_good_bg, + R.color.accessibility_good_text, + R.color.accessibility_good_border + }; + case Constants.AVERAGE_RATING: // 2 + return new int[]{ + R.color.accessibility_average_bg, + R.color.accessibility_average_text, + R.color.accessibility_average_border + }; + case Constants.BAD_RATING: // 1 + return new int[]{ + R.color.accessibility_poor_bg, + R.color.accessibility_poor_text, + R.color.accessibility_poor_border + }; + default: + return new int[]{ + R.color.accessibility_default_bg, + R.color.accessibility_default_text, + R.color.accessibility_default_border + }; + } + } +} diff --git a/app/src/main/java/com/example/acloc/utility/FileUtils.java b/app/src/main/java/com/example/acloc/utility/FileUtils.java index a255d03..647e216 100644 --- a/app/src/main/java/com/example/acloc/utility/FileUtils.java +++ b/app/src/main/java/com/example/acloc/utility/FileUtils.java @@ -1 +1 @@ -package com.example.acloc.utility; \ No newline at end of file +package com.example.acloc.utility; diff --git a/app/src/main/java/com/example/acloc/utility/Helper.java b/app/src/main/java/com/example/acloc/utility/Helper.java index 0832931..378b52a 100644 --- a/app/src/main/java/com/example/acloc/utility/Helper.java +++ b/app/src/main/java/com/example/acloc/utility/Helper.java @@ -249,7 +249,7 @@ public class Helper { } // Regex for strong password validation - String passwordPattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{6,}$"; + String passwordPattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&.])[A-Za-z\\d@$!%*?&.]{6,}$"; if (!passwordText.matches(passwordPattern)) { if (textInputLayout != null) { @@ -360,4 +360,3 @@ public class Helper { return new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); } } - diff --git a/app/src/main/java/com/example/acloc/utility/ImageLoaderUtil.java b/app/src/main/java/com/example/acloc/utility/ImageLoaderUtil.java index 3826db4..ab76e57 100644 --- a/app/src/main/java/com/example/acloc/utility/ImageLoaderUtil.java +++ b/app/src/main/java/com/example/acloc/utility/ImageLoaderUtil.java @@ -44,4 +44,4 @@ public class ImageLoaderUtil { .into(targetView); } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/acloc/utility/ImagePicker.java b/app/src/main/java/com/example/acloc/utility/ImagePicker.java index f67bdcd..4e7881a 100644 --- a/app/src/main/java/com/example/acloc/utility/ImagePicker.java +++ b/app/src/main/java/com/example/acloc/utility/ImagePicker.java @@ -103,4 +103,4 @@ public class ImagePicker { // MultipartBody.Part is used to send the actual file return MultipartBody.Part.createFormData(partName, file.getName(), requestFile); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/acloc/utility/KeyGeneratorUtils.java b/app/src/main/java/com/example/acloc/utility/KeyGeneratorUtils.java index 28b1b6d..65fd0cd 100644 --- a/app/src/main/java/com/example/acloc/utility/KeyGeneratorUtils.java +++ b/app/src/main/java/com/example/acloc/utility/KeyGeneratorUtils.java @@ -29,4 +29,4 @@ public class KeyGeneratorUtils { // Combine timestamp and random string return timeStamp + "_" + randomStr.toString(); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/acloc/utility/SharedPref.java b/app/src/main/java/com/example/acloc/utility/SharedPref.java index 7cf1ecc..36b89fb 100644 --- a/app/src/main/java/com/example/acloc/utility/SharedPref.java +++ b/app/src/main/java/com/example/acloc/utility/SharedPref.java @@ -44,7 +44,7 @@ public class SharedPref { editor.apply(); } - public static String getUserUid(Context con) { + public static String getUserUuid(Context con) { return sharedPreferences(con).getString(USER_UUID, ""); } diff --git a/app/src/main/res/anim/slide_in_left.xml b/app/src/main/res/anim/slide_in_left.xml index 07d168b..451f652 100644 --- a/app/src/main/res/anim/slide_in_left.xml +++ b/app/src/main/res/anim/slide_in_left.xml @@ -8,4 +8,4 @@ android:duration="300" android:fromAlpha="0.0" android:toAlpha="1.0" /> - \ No newline at end of file + diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml index bf44111..782b3db 100644 --- a/app/src/main/res/anim/slide_in_right.xml +++ b/app/src/main/res/anim/slide_in_right.xml @@ -8,4 +8,4 @@ android:duration="300" android:fromAlpha="0.0" android:toAlpha="1.0" /> - \ No newline at end of file + diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml index c8baf6f..a70e2dd 100644 --- a/app/src/main/res/anim/slide_out_left.xml +++ b/app/src/main/res/anim/slide_out_left.xml @@ -8,4 +8,4 @@ android:duration="300" android:fromAlpha="1.0" android:toAlpha="0.0" /> - \ No newline at end of file + diff --git a/app/src/main/res/anim/slide_out_right.xml b/app/src/main/res/anim/slide_out_right.xml index 9448105..0553877 100644 --- a/app/src/main/res/anim/slide_out_right.xml +++ b/app/src/main/res/anim/slide_out_right.xml @@ -8,4 +8,4 @@ android:duration="300" android:fromAlpha="1.0" android:toAlpha="0.0" /> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_accessible.xml b/app/src/main/res/drawable/ic_accessible.xml new file mode 100644 index 0000000..8c87bd3 --- /dev/null +++ b/app/src/main/res/drawable/ic_accessible.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_check_circle.xml b/app/src/main/res/drawable/ic_check_circle.xml new file mode 100644 index 0000000..9a125bc --- /dev/null +++ b/app/src/main/res/drawable/ic_check_circle.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_directions_walk.xml b/app/src/main/res/drawable/ic_directions_walk.xml new file mode 100644 index 0000000..0efb20b --- /dev/null +++ b/app/src/main/res/drawable/ic_directions_walk.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_door_front.xml b/app/src/main/res/drawable/ic_door_front.xml new file mode 100644 index 0000000..d28fcf9 --- /dev/null +++ b/app/src/main/res/drawable/ic_door_front.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_elevator.xml b/app/src/main/res/drawable/ic_elevator.xml new file mode 100644 index 0000000..a4e6cab --- /dev/null +++ b/app/src/main/res/drawable/ic_elevator.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_hearing.xml b/app/src/main/res/drawable/ic_hearing.xml new file mode 100644 index 0000000..fc8fac1 --- /dev/null +++ b/app/src/main/res/drawable/ic_hearing.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_help.xml b/app/src/main/res/drawable/ic_help.xml new file mode 100644 index 0000000..814f522 --- /dev/null +++ b/app/src/main/res/drawable/ic_help.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 2b068d1..7706ab9 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -27,4 +27,4 @@ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" android:strokeWidth="1" android:strokeColor="#00000000" /> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_local_parking.xml b/app/src/main/res/drawable/ic_local_parking.xml new file mode 100644 index 0000000..6399ade --- /dev/null +++ b/app/src/main/res/drawable/ic_local_parking.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_psychology.xml b/app/src/main/res/drawable/ic_psychology.xml new file mode 100644 index 0000000..6fea75f --- /dev/null +++ b/app/src/main/res/drawable/ic_psychology.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_trending_up.xml b/app/src/main/res/drawable/ic_trending_up.xml new file mode 100644 index 0000000..1f89d11 --- /dev/null +++ b/app/src/main/res/drawable/ic_trending_up.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_visibility.xml b/app/src/main/res/drawable/ic_visibility.xml new file mode 100644 index 0000000..4e41f67 --- /dev/null +++ b/app/src/main/res/drawable/ic_visibility.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_wc.xml b/app/src/main/res/drawable/ic_wc.xml new file mode 100644 index 0000000..82187a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_wc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/rating.xml b/app/src/main/res/drawable/rating.xml index 1482ff0..b5da2ce 100644 --- a/app/src/main/res/drawable/rating.xml +++ b/app/src/main/res/drawable/rating.xml @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/drawable/rectangle.xml b/app/src/main/res/drawable/rectangle.xml index 36e5733..d772662 100644 --- a/app/src/main/res/drawable/rectangle.xml +++ b/app/src/main/res/drawable/rectangle.xml @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_add_new_place.xml b/app/src/main/res/layout/activity_add_new_place.xml index 43a8cd8..6e9fc72 100644 --- a/app/src/main/res/layout/activity_add_new_place.xml +++ b/app/src/main/res/layout/activity_add_new_place.xml @@ -141,4 +141,4 @@ android:text="@string/SUBMIT" android:textColor="?attr/colorOnPrimary" tools:ignore="HardcodedText" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_add_report.xml b/app/src/main/res/layout/activity_add_report.xml index 28e75e8..5c9b783 100644 --- a/app/src/main/res/layout/activity_add_report.xml +++ b/app/src/main/res/layout/activity_add_report.xml @@ -1,321 +1,324 @@ - + android:fillViewport="true"> - - - - + + android:layout_marginTop="16dp" + app:cardCornerRadius="12dp" + app:cardElevation="4dp"> - - + android:orientation="vertical" + android:padding="16dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + android:baselineAligned="false" + android:orientation="horizontal" + android:gravity="center"> - - - - - + android:layout_weight="1" + android:orientation="vertical" + android:gravity="center"> - + android:id="@+id/ivThumbsDown" + android:layout_width="60dp" + android:layout_height="60dp" + android:layout_margin="8dp" + android:src="@drawable/ic_thumbs_down" + android:background="?attr/selectableItemBackgroundBorderless" + android:padding="12dp" + android:contentDescription="@string/BAD" /> - - - - - - - + android:text="@string/BAD" + android:textSize="12sp" + android:textColor="?attr/colorOnSurfaceVariant"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file + android:backgroundTint="@color/primaryColor_dark" + app:cornerRadius="12dp" + android:padding="16dp" /> + + + + diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index a37e232..27822a3 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -173,4 +173,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a986a67..e0aed1d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -31,4 +31,4 @@ app:itemIconTint="?attr/colorOnBackground" app:itemTextColor="?attr/colorOnBackground" app:menu="@menu/menu_bottom_navigation" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_manage_roles.xml b/app/src/main/res/layout/activity_manage_roles.xml index 08b14ed..2e8cc14 100644 --- a/app/src/main/res/layout/activity_manage_roles.xml +++ b/app/src/main/res/layout/activity_manage_roles.xml @@ -44,4 +44,4 @@ tools:listitem="@layout/list_view_users" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/activity_place_detail.xml b/app/src/main/res/layout/activity_place_detail.xml index 67519fb..215e59c 100644 --- a/app/src/main/res/layout/activity_place_detail.xml +++ b/app/src/main/res/layout/activity_place_detail.xml @@ -242,4 +242,4 @@ android:text="@string/ADD_REPORT" android:textColor="?attr/colorOnPrimary" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/alert_dialog_add_new_place.xml b/app/src/main/res/layout/alert_dialog_add_new_place.xml index 23e7df7..751de8e 100644 --- a/app/src/main/res/layout/alert_dialog_add_new_place.xml +++ b/app/src/main/res/layout/alert_dialog_add_new_place.xml @@ -216,4 +216,4 @@ tools:ignore="HardcodedText" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/alert_dialog_change_password.xml b/app/src/main/res/layout/alert_dialog_change_password.xml index 98fa1d6..362a3f8 100644 --- a/app/src/main/res/layout/alert_dialog_change_password.xml +++ b/app/src/main/res/layout/alert_dialog_change_password.xml @@ -85,4 +85,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/alert_dialog_profile.xml b/app/src/main/res/layout/alert_dialog_profile.xml index aa8a405..fb7b2fc 100644 --- a/app/src/main/res/layout/alert_dialog_profile.xml +++ b/app/src/main/res/layout/alert_dialog_profile.xml @@ -83,4 +83,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/bottom_sheet_place_detail.xml b/app/src/main/res/layout/bottom_sheet_place_detail.xml index ea34e1a..247b2fe 100644 --- a/app/src/main/res/layout/bottom_sheet_place_detail.xml +++ b/app/src/main/res/layout/bottom_sheet_place_detail.xml @@ -12,6 +12,17 @@ android:orientation="vertical" android:padding="16dp"> + + + + + + + + + + - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml index dcdda39..d8b4246 100644 --- a/app/src/main/res/layout/fragment_map.xml +++ b/app/src/main/res/layout/fragment_map.xml @@ -51,4 +51,4 @@ android:elevation="4dp" android:visibility="gone" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_my_reports.xml b/app/src/main/res/layout/fragment_my_reports.xml index 80751de..24b87bb 100644 --- a/app/src/main/res/layout/fragment_my_reports.xml +++ b/app/src/main/res/layout/fragment_my_reports.xml @@ -42,4 +42,4 @@ app:iconTint="?attr/colorOnPrimary"/> - \ No newline at end of file + diff --git a/app/src/main/res/layout/item_report_type_selector.xml b/app/src/main/res/layout/item_report_type_selector.xml new file mode 100644 index 0000000..a871d28 --- /dev/null +++ b/app/src/main/res/layout/item_report_type_selector.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_view_place_reports.xml b/app/src/main/res/layout/list_view_place_reports.xml index 8ce7f14..3c35562 100644 --- a/app/src/main/res/layout/list_view_place_reports.xml +++ b/app/src/main/res/layout/list_view_place_reports.xml @@ -14,6 +14,7 @@ android:orientation="vertical" android:padding="12dp"> + + android:textColor="@android:color/black" + tools:text="Este lugar tiene buena accesibilidad para sillas de ruedas y personas con discapacidad visual." /> + + android:orientation="vertical"> - - - + + android:gravity="center_vertical" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml index f2516df..e32cc2c 100644 --- a/app/src/main/res/layout/toolbar.xml +++ b/app/src/main/res/layout/toolbar.xml @@ -8,4 +8,4 @@ android:textColor="?attr/colorOnPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.DayNight" - app:titleTextColor="?attr/colorOnPrimary" /> \ No newline at end of file + app:titleTextColor="?attr/colorOnPrimary" /> diff --git a/app/src/main/res/menu/menu_bottom_navigation.xml b/app/src/main/res/menu/menu_bottom_navigation.xml index 608d269..afe7e9b 100644 --- a/app/src/main/res/menu/menu_bottom_navigation.xml +++ b/app/src/main/res/menu/menu_bottom_navigation.xml @@ -15,4 +15,4 @@ android:icon="@drawable/ic_favorite" android:title="@string/Favorite" /> - \ No newline at end of file + diff --git a/app/src/main/res/menu/menu_dashboard.xml b/app/src/main/res/menu/menu_dashboard.xml index a33bc4a..1ead551 100644 --- a/app/src/main/res/menu/menu_dashboard.xml +++ b/app/src/main/res/menu/menu_dashboard.xml @@ -32,4 +32,4 @@ android:title="@string/Logout" app:iconTint="?attr/colorError" /> - \ No newline at end of file + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 036d09b..80b730f 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 036d09b..80b730f 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index fcedf0f..6a66a1d 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -174,6 +174,46 @@ Por favor Vacío La contraseña debe tener al menos 6 caracteres, incluir 1 mayúscula, 1 minúscula, 1 dígito y 1 carácter especial. + Puntúa este sitio + Mala accessibilidad + Accesibilidad regular + Buena accessibilidad + Selecciona el tipo de discapacidad relacionado + Localización actual + Introduzca una locación + Localización + Puntuación + Características accesibles + Selecciona el tipo de discapacidad relacionada con el comentario + Enviar comentario + Titulo del comentario + Cuerpo del comentario + Selected + Bad accessibility + Rate the accessibility experience of this location + Location info + Accessibility info + Report type icon + Accessibility icon + Place image + + Silla de ruedas + Acceso visual + Acceso auditivo + Acceso cognitivo + Movilidad + Estacionamiento + Entrada + Baño + Ascensor + Rampa + Accesibilidad - \ No newline at end of file + + toca para seleccionar + Add images to your comment + Error: no place selected + Address not available + Accessibility overview + diff --git a/app/src/main/res/values-es/themes.xml b/app/src/main/res/values-es/themes.xml index 4aaebcd..71b80ea 100644 --- a/app/src/main/res/values-es/themes.xml +++ b/app/src/main/res/values-es/themes.xml @@ -1,4 +1,4 @@ 50% - \ No newline at end of file + diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index a425c03..a934dae 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -22,4 +22,4 @@ 50% - \ No newline at end of file + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 3b639ea..6097075 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -4,11 +4,11 @@ #FFFFFFFF - #0D47A1 + #0D47A1 #4D8EF4 - #42A5F5 + #42A5F5 #5AB1F6 @@ -17,12 +17,12 @@ #C62828 - #FAFAFA - #121212 + #FAFAFA + #121212 - #FFFFFF - #040404 + #FFFFFF + #040404 #FFFFFF @@ -31,20 +31,19 @@ #000000 #FFFFFF - #212121 - + #212121 #E0E0E0 - #212121 - #F5F5F5 + #212121 + #F5F5F5 - #C62828 - #F44336 + #C62828 + #F44336 - #FF4081 - #C51162 + #FF4081 + #C51162 #e8edf6 #232324 @@ -56,4 +55,25 @@ #F44336 #e8edf6 - \ No newline at end of file + + + #E8F5E8 + #2E7D32 + #4CAF50 + + + #FFF8E1 + #F57C00 + #FF9800 + + + #FFEBEE + #C62828 + #F44336 + + + #F5F5F5 + #757575 + #BDBDBD + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 7766af4..e93ce1d 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -48,4 +48,4 @@ 16dp 8dp - \ No newline at end of file + diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml index c5d5899..f42ada6 100644 --- a/app/src/main/res/values/ic_launcher_background.xml +++ b/app/src/main/res/values/ic_launcher_background.xml @@ -1,4 +1,4 @@ #FFFFFF - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9ce168f..a43197c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,182 +1,224 @@ - AcLoc - Accessible Locations Application + AcLoc - Accessible Locations Application - - LOGIN - REGISTER - SAVE PLACE - UPDATE - CANCEL - SUBMIT - ADD REPORT + + LOGIN + REGISTER + SAVE PLACE + UPDATE + CANCEL + SUBMIT + ADD REPORT - - Add Report - Place Details - Add Place + + Add Report + Place Details + Add Place - - Enter Username - Enter Password - Enter Email - Enter Name - Enter Location - Enter Contact - "Already have an Account? - Please login - Please register - Don\'t have an Account? - Favorite - My Report - Map - Profile - Change Password - Manage Roles - Change Language - Logout - Enter Place Name - Enter Latitude - Enter Longitude - Enter Address - Enter Place Description - Search Place - Enter Old Password - Enter New Password - Place Name - Address - Place Description - Enter Description - Report Description - Reports - Search User - User - Role - Change Role + + Enter Username + Enter Password + Enter Email + Enter Name + Enter Location + Enter Contact + "Already have an Account? + Please login + Please register + Don\'t have an Account? + Favorite + My Report + Map + Profile + Change Password + Manage Roles + Change Language + Logout + Enter Place Name + Enter Latitude + Enter Longitude + Enter Address + Enter Place Description + Search Place + Enter Old Password + Enter New Password + Place Name + Address + Place Description + Enter Description + Report Description + Reports + Search User + User + Role + Change Role - - GOOD - AVERAGE - BAD + + GOOD + AVERAGE + BAD - - change language to Spanish - Are you sure you want to logout? - Are you sure you want to %1$s?\nWARNING: This action cannot be undone - Yes - No - Location permission required - This app requires location permission to function properly. Please enable it in Settings. - Go to Settings - Exit App + + change language to Spanish + Are you sure you want to logout? + Are you sure you want to %1$s?\nWARNING: This action cannot be undone + Yes + No + Location permission required + This app requires location permission to function properly. Please enable it in Settings. + Go to Settings + Exit App - - Something went wrong!!! - Login failed - Invalid Credentials. Please try again. - Login Successful - Please wait… - "User already exists. Please login. - Profile Updated Successfully! - Registration Successful - Try again later - Update Failed - Something went wrong. Try again. - Updating… - Invalid old password - Network error. Try again. - Changing password… - Password updated successfully! - Password update failed. - Verifying old password… - change Role to - Updating Roles… - User Role updated successfully! - Update failed. Server error. Try again - Rating: BAD - Rating: AVERAGE - Rating: GOOD - Delete report - Removing Report… - Report removed! - Failed to remove report - Removing from favorites… - Favorite removed - Failed to remove Favorite - Loading favorites… - No Favorite found. - Failed to load favorite. Try again. - Location permission is required - Failed to load places - Loading reports… - No reports found. - Failed to load reports. Try again. - Place updated successfully! - Updating place… - Place inserted successfully! - Failed to extract place.Try again - Insert failed. Server error. - Report submission failed. Try again - Report submitted successfully! - Please select rating! - Updating report… - Report updated successfully! - Failed to load users. Try again. - No users found - Loading users… - Adding to favorites… - Place added to favorites! - Failed to add favorite. Server error. - Restoring favorite… - Place restored to favorites! - Failed to restore favorite. - Removed from favorites - Failed to remove from favorites - Checking favorite status… - - - - - + + Something went wrong!!! + Login failed + Invalid Credentials. Please try again. + Login Successful + Please wait… + "User already exists. Please login. + Profile Updated Successfully! + Registration Successful + Try again later + Update Failed + Something went wrong. Try again. + Updating… + Invalid old password + Network error. Try again. + Changing password… + Password updated successfully! + Password update failed. + Verifying old password… + change Role to + Updating Roles… + User Role updated successfully! + Update failed. Server error. Try again + Rating: BAD + Rating: AVERAGE + Rating: GOOD + Delete report + Removing Report… + Report removed! + Failed to remove report + Removing from favorites… + Favorite removed + Failed to remove Favorite + Loading favorites… + No Favorite found. + Failed to load favorite. Try again. + Location permission is required + Failed to load places + Loading reports… + No reports found. + Failed to load reports. Try again. + Place updated successfully! + Updating place… + Place inserted successfully! + Failed to extract place.Try again + Insert failed. Server error. + Report submission failed. Try again + Report submitted successfully! + Updating report… + Report updated successfully! + Failed to load users. Try again. + No users found + Loading users… + Adding to favorites… + Place added to favorites! + Failed to add favorite. Server error. + Restoring favorite… + Place restored to favorites! + Failed to restore favorite. + Removed from favorites + Failed to remove from favorites + Checking favorite status… + + + + + - - - - - - - - - + + + + + + + + + - Add New Location - Tap to add photo - Location Details - Additional Information - Rate this place! - How would you rate the accessibility of this place? - Welcome Back - Sign in to continue - Expand - Address - Description - Edit - Recent Reports - No reports about this place yet - Details - Add to favorites - Image uploaded successfully - Upload failed - Response parsing error - No places found near this location - Location not found - Invalid email address - Please - Empty - Password must be at least 6 characters, include 1 uppercase, 1 lowercase, 1 digit, and 1 special character. + Add New Location + Tap to add photo + Location Details + Additional Information + Rate this place! + How would you rate the accessibility of this place? + Welcome Back + Sign in to continue + Expand + Address + Description + Edit + Recent Reports + No reports about this place yet + Details + Add to favorites + Image uploaded successfully + Upload failed + Response parsing error + No places found near this location + Location not found + Invalid email address + Please + Empty + Password must be at least 6 characters, include 1 uppercase, 1 lowercase, 1 digit, and 1 special character. - \ No newline at end of file + Rate the accessibility of this place + Bad accessibility + Average accessibility + Good accessibility + Please select an accessibility type + Please select a rating + Get Current Location + Enter location + Location + Rating + Accessibility Features + Select the accessibility feature you want to report + Submit Report + Report Title + Report Description + Selected + Bad accessibility + Rate the accessibility experience of this location + Location info + Accessibility info + Report type icon + Accessibility icon + Place image + + Wheelchair accessible + Visually accessible + Hearing accessible + Neurodivergent accessible + Mobility accessible + Parking + Entrance + WC + Elevator + Ramp + Accessibility + + + Touch to select + Add images to your comment + Help other users + Error: no place selected + Address not available + Accessibility overview + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 67961ed..1975928 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -33,4 +33,4 @@ 50% - \ No newline at end of file + diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml index fa0f996..148c18b 100644 --- a/app/src/main/res/xml/backup_rules.xml +++ b/app/src/main/res/xml/backup_rules.xml @@ -10,4 +10,4 @@ --> - \ No newline at end of file + diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml index 9ee9997..0c4f95c 100644 --- a/app/src/main/res/xml/data_extraction_rules.xml +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -16,4 +16,4 @@ --> - \ No newline at end of file +