Added accessibility tags and small ui fix

This commit is contained in:
Pau 2025-05-27 05:32:34 +02:00
parent 3177d74a82
commit 8d314c9192
74 changed files with 1885 additions and 742 deletions

View File

@ -35,8 +35,6 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Objects;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -248,7 +246,7 @@ public class AddNewPlaceActivity extends AppCompatActivity implements View.OnCli
entity.setAddress(Helper.getStringFromInput(etAddress)); entity.setAddress(Helper.getStringFromInput(etAddress));
entity.setLatitude(Helper.getStringFromInput(etLatitude)); entity.setLatitude(Helper.getStringFromInput(etLatitude));
entity.setLongitude(Helper.getStringFromInput(etLongitude)); entity.setLongitude(Helper.getStringFromInput(etLongitude));
entity.setCreatedBy(SharedPref.getUserUid(context)); entity.setCreatedBy(SharedPref.getUserUuid(context));
entity.setUuid(place_uuid); entity.setUuid(place_uuid);
entity.setImage(jsonString); entity.setImage(jsonString);
} }

View File

@ -6,37 +6,46 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat; 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.api.LocationApiClient;
import com.example.acloc.model.Place; import com.example.acloc.model.Place;
import com.example.acloc.model.Report; 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.ReportService;
import com.example.acloc.service.ReportTypeService;
import com.example.acloc.utility.Constants; import com.example.acloc.utility.Constants;
import com.example.acloc.utility.DialogUtils; import com.example.acloc.utility.DialogUtils;
import com.example.acloc.utility.Helper; import com.example.acloc.utility.Helper;
import com.example.acloc.utility.SharedPref; import com.example.acloc.utility.SharedPref;
import com.example.acloc.utility.UploadManager; 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.android.material.textfield.TextInputEditText;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.ieslamar.acloc.R;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -44,179 +53,382 @@ import retrofit2.Response;
public class AddReportActivity extends AppCompatActivity implements View.OnClickListener { public class AddReportActivity extends AppCompatActivity implements View.OnClickListener {
public static final String TAG = AddReportActivity.class.getSimpleName(); 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; 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 Place placeEntity;
private Report reportEntity; private Report reportEntity;
private String report_type_uuid, place_uuid; private String place_uuid;
private int reportRating; private int reportRating = 0;
private String report_uuid; private String report_uuid;
private boolean isEditMode = false;
// Report Types - Now supporting multiple selection
private ReportTypeAdapter reportTypeAdapter;
private List<ReportType> reportTypesList = new ArrayList<>();
private List<String> selectedReportTypeUuids = new ArrayList<>();
// Multiple Images handling
private static final int PICK_IMAGE_REQUEST = 100; private static final int PICK_IMAGE_REQUEST = 100;
private List<String> imageUrls = new ArrayList<>();
private Uri selectedImageUri; private int currentImageIndex = 0;
private String imageUrl; private String jsonString = "[]";
private String jsonString;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_report); setContentView(R.layout.activity_add_report);
initToolbar();
initUI(); initUI();
resetThumbsColors();
loadIntentData(); loadIntentData();
initListener(); initListener();
initObj(); initObj();
} loadReportTypes();
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);
}
} }
private void initUI() { private void initUI() {
rlAddReport = findViewById(R.id.rlAddReport); // Text inputs
ivReportPhoto = findViewById(R.id.ivReportPhoto);
etPlaceName = findViewById(R.id.etPlaceName);
etDescription = findViewById(R.id.etDescription); etDescription = findViewById(R.id.etDescription);
// Place info
tvPlaceName = findViewById(R.id.tvPlaceName);
tvPlaceAddress = findViewById(R.id.tvPlaceAddress);
// Rating thumbs
ivThumbsUp = findViewById(R.id.ivThumbsUp); ivThumbsUp = findViewById(R.id.ivThumbsUp);
ivThumbsAverage = findViewById(R.id.ivThumbsAverage); ivThumbsAverage = findViewById(R.id.ivThumbsAverage);
ivThumbsDown = findViewById(R.id.ivThumbsDown); 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<ReportType> selectedReportTypes) {
// Update selected UUIDs list
selectedReportTypeUuids.clear();
for (ReportType reportType : selectedReportTypes) {
selectedReportTypeUuids.add(reportType.getUuid());
}
}
});
rvReportTypes.setAdapter(reportTypeAdapter);
} }
private void loadIntentData() { 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) { if (placeEntity != null) {
place_uuid = placeEntity.getUuid(); 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) { if (reportEntity != null) {
report_uuid = reportEntity.getUuid(); // setting place uuid first isEditMode = true;
report_uuid = reportEntity.getUuid();
place_uuid = reportEntity.getPlaceUuid(); place_uuid = reportEntity.getPlaceUuid();
Log.d(TAG, "" +
"place uuid: " + reportEntity.getPlaceUuid() +
"\n fkplace " + reportEntity.getFkPlace());
setDataToEditText(); 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<JsonObject> call = placeService.getPlaceFromUuid(token, placeUuid);
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> 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<JsonObject> 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() { private void setDataToEditText() {
etPlaceName.setText(reportEntity.getPlaceName()); if (reportEntity != null) {
etDescription.setText(reportEntity.getDescription()); etDescription.setText(reportEntity.getDescription());
int rating = reportEntity.getReportRating();
if (rating == 1) { // Reset colors first
ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN); resetThumbsColors();
ivThumbsUp.setColorFilter(null); // reset the other
ivThumbsAverage.setColorFilter(null); // Set rating using constants
reportRating = Constants.BAD_RATING; //1 int rating = reportEntity.getReportRating();
} else if (rating == 2) { if (rating == Constants.BAD_RATING) { // 1
ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN); onClickThumbsDown();
ivThumbsUp.setColorFilter(null); // reset the others } else if (rating == Constants.AVERAGE_RATING) { // 2
ivThumbsDown.setColorFilter(null); onClickThumbsAverage();
reportRating = Constants.AVERAGE_RATING; //2 } else if (rating == Constants.GOOD_RATING) { // 3
} else if (rating == 3) { onClickThumbsUp();
ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN); }
ivThumbsDown.setColorFilter(null); // reset the other
ivThumbsAverage.setColorFilter(null); // Load existing images
reportRating = Constants.GOOD_RATING; //3 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()) { if (reportEntity.getImage() != null && !reportEntity.getImage().isEmpty()) {
String rawImg = reportEntity.getImage(); String rawImg = reportEntity.getImage();
try { try {
JSONArray array = new JSONArray(rawImg); JSONArray array = new JSONArray(rawImg);
String imageUrl = array.getString(0); // Get first element in the array imageUrls.clear();
Picasso.get()
.load(imageUrl)
.into(ivReportPhoto, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
Picasso.get().load(imageUrl).into(ivReportPhoto);
}
@Override for (int i = 0; i < array.length(); i++) {
public void onError(Exception e) { String imageUrl = array.getString(i);
// Error loading image 404 -- load default imageUrls.add(imageUrl);
Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto); }
}
}); // 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) { } catch (JSONException e) {
Log.e(TAG, "ERROR: " + e.toString()); 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 } else {
Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto); 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<JsonObject> call = reportTypeService.getReportTypes(token, null, null);
call.enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> 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<JsonObject> 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() { private void initListener() {
ivReportPhoto.setOnClickListener(this);
ivThumbsUp.setOnClickListener(this); ivThumbsUp.setOnClickListener(this);
ivThumbsAverage.setOnClickListener(this); ivThumbsAverage.setOnClickListener(this);
ivThumbsDown.setOnClickListener(this); ivThumbsDown.setOnClickListener(this);
ivReportPhoto.setOnClickListener(this); btnSubmitReport.setOnClickListener(this);
btnSubmit.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() { private void initObj() {
context = this; context = this;
reportEntity = new Report(); if (reportEntity == null) {
reportEntity = new Report();
}
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
int id = v.getId(); int id = v.getId();
if (id == R.id.ivThumbsUp) { if (id == R.id.ivReportPhoto) {
onClickIvReportPhoto();
} else if (id == R.id.ivThumbsUp) {
onClickThumbsUp(); onClickThumbsUp();
} else if (id == R.id.ivThumbsAverage) { } else if (id == R.id.ivThumbsAverage) {
onClickThumbsAverage(); onClickThumbsAverage();
} else if (id == R.id.ivThumbsDown) { } else if (id == R.id.ivThumbsDown) {
onClickThumbsDown(); onClickThumbsDown();
} else if (id == R.id.ivReportPhoto) { } else if (id == R.id.btnSubmitReport) {
onClickIvReportPhoto();
} else if (id == R.id.btnSubmit) {
onClickBtnSubmit(); onClickBtnSubmit();
} }
} }
private void onClickIvReportPhoto() { private void onClickIvReportPhoto() {
// Open the gallery to select an image
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 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); startActivityForResult(intent, PICK_IMAGE_REQUEST);
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) { if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
selectedImageUri = data.getData();
// Upload the image
uploadImageToServer(selectedImageUri);
// Load image using Picasso
Picasso.get().load(selectedImageUri).into(ivReportPhoto);
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) { private void uploadImageToServer(Uri imageUri) {
btnSubmitReport.setClickable(false);
UploadManager.uploadImage(this, imageUri, new UploadManager.UploadCallback() { UploadManager.uploadImage(this, imageUri, new UploadManager.UploadCallback() {
@Override @Override
public void onSuccess(String response) { public void onSuccess(String response) {
@ -224,54 +436,83 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
JSONObject json = new JSONObject(response); JSONObject json = new JSONObject(response);
if (json.getBoolean("success")) { if (json.getBoolean("success")) {
String filename = json.getJSONObject("file").getString("filename"); String filename = json.getJSONObject("file").getString("filename");
imageUrl = BASE_URL + "public/" + filename; String imageUrl = BASE_URL + "public/" + filename;
jsonString = "[\"" + imageUrl + "\"]";
Helper.makeSnackBar(rlAddReport, getString(R.string.image_uploaded_successfully)); // Add to images list
btnSubmit.setClickable(true); 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 { } else {
Helper.makeSnackBar(rlAddReport, getString(R.string.upload_failed)); Helper.makeSnackBar(findViewById(android.R.id.content),
btnSubmit.setClickable(true); getString(R.string.upload_failed));
} }
} catch (JSONException e) { } catch (JSONException e) {
Helper.makeSnackBar(rlAddReport, getString(R.string.response_parsing_error)); Helper.makeSnackBar(findViewById(android.R.id.content),
btnSubmit.setClickable(true); getString(R.string.response_parsing_error));
Log.e(TAG, "Failed to parse JSON", e); Log.e(TAG, "Failed to parse JSON", e);
} }
btnSubmitReport.setClickable(true);
} }
@Override @Override
public void onError(String message) { public void onError(String message) {
Helper.makeSnackBar(rlAddReport, "Upload failed: " + message); Helper.makeSnackBar(findViewById(android.R.id.content),
Log.e(TAG, "Upload error:" + message); "Upload failed: " + message);
btnSubmit.setClickable(true); 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() { private void onClickThumbsUp() {
resetThumbsColors();
ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN); ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN);
ivThumbsDown.setColorFilter(null); // reset the other reportRating = Constants.GOOD_RATING; // 3
ivThumbsAverage.setColorFilter(null);
reportRating = Constants.GOOD_RATING; //3
} }
private void onClickThumbsAverage() { private void onClickThumbsAverage() {
resetThumbsColors();
ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN); ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN);
ivThumbsUp.setColorFilter(null); // reset the others reportRating = Constants.AVERAGE_RATING; // 2
ivThumbsDown.setColorFilter(null);
reportRating = Constants.AVERAGE_RATING; //2
} }
private void onClickThumbsDown() { private void onClickThumbsDown() {
resetThumbsColors();
ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN); ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN);
ivThumbsUp.setColorFilter(null); // reset the other reportRating = Constants.BAD_RATING; // 1
ivThumbsAverage.setColorFilter(null); }
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() { private void onClickBtnSubmit() {
View[] views = {etPlaceName, etDescription}; View[] views = {etDescription};
if (Helper.isEmptyFieldValidation(context, views) && isValidateRating()) { if (Helper.isEmptyFieldValidation(context, views) && isValidateRating()) {
setInputDataToEntity(); setInputDataToEntity();
@ -280,20 +521,23 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
updateReportRetrofit( updateReportRetrofit(
report_uuid, report_uuid,
place_uuid, place_uuid,
SharedPref.getUserUid(context), SharedPref.getUserUuid(context),
String.valueOf(reportEntity.getReportRating()), String.valueOf(reportEntity.getReportRating()),
reportEntity.getDescription(), reportEntity.getDescription(),
reportEntity.getCreatedBy(), reportEntity.getCreatedBy(),
reportEntity.getImage() reportEntity.getImage(),
selectedReportTypeUuids // Now passing array
); );
} else { } else {
// Create new report
insertReportRetrofit( insertReportRetrofit(
placeEntity.getUuid(), place_uuid,
SharedPref.getUserUid(context), SharedPref.getUserUuid(context),
String.valueOf(reportEntity.getReportRating()), String.valueOf(reportEntity.getReportRating()),
reportEntity.getDescription(), reportEntity.getDescription(),
reportEntity.getCreatedBy(), 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() { private void setInputDataToEntity() {
reportEntity.setDescription(Helper.getStringFromInput(etDescription)); reportEntity.setDescription(Helper.getStringFromInput(etDescription));
reportEntity.setReportRating(reportRating); reportEntity.setReportRating(reportRating);
reportEntity.setCreatedBy(SharedPref.getUserUid(context)); reportEntity.setCreatedBy(SharedPref.getUserUuid(context));
reportEntity.setImage(jsonString); reportEntity.setImage(jsonString);
reportEntity.setReportTypeUuids(new ArrayList<>(selectedReportTypeUuids)); // Set multiple UUIDs
reportEntity.setPlaceUuid(place_uuid);
} }
private boolean isValidateRating() { private boolean isValidateRating() {
if (reportRating != 0) { if (reportRating != 0) {
return true; return true;
} else { } 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; return false;
} }
} }
private void insertReportRetrofit(String placeUuid, String userUuid, String rating, private void insertReportRetrofit(String placeUuid, String userUuid, String rating,
String description, String createdBy, String jsonString) { String description, String createdBy, String jsonString,
List<String> reportTypeUuids) {
DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait)); 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("createdBy", createdBy);
reportBody.addProperty("images", jsonString); 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); String token = "Bearer " + SharedPref.getAccessToken(context);
ReportService reportService = LocationApiClient.getInstance().getReportService(); 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(); JsonObject reportObject = data.getAsJsonArray("reports").get(0).getAsJsonObject();
String report_uuid = reportObject.get("uuid").getAsString(); String report_uuid = reportObject.get("uuid").getAsString();
Log.d(TAG, "Report UUID: " + report_uuid); 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(); finish();
}, 500); }, 500);
} else { } else {
Log.d(TAG, "Failed to extract report UUID."); 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 { } 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()); Log.e(TAG, "Insert Report Error: " + response.code());
} }
} }
@ -362,13 +622,14 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
public void onFailure(Call<JsonObject> call, Throwable t) { public void onFailure(Call<JsonObject> call, Throwable t) {
DialogUtils.dismissDialog(); DialogUtils.dismissDialog();
Log.e(TAG, "Insert Report Failure: ", t); 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, private void updateReportRetrofit(String uuid, String placeUuid, String userUuid, String rating,
String description, String createdBy, String jsonString) { String description, String createdBy, String jsonString,
List<String> reportTypeUuids) {
DialogUtils.showLoadingDialog(context, getString(R.string.Updating_report)); 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("createdBy", createdBy);
reportBody.addProperty("images", jsonString); 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); String token = "Bearer " + SharedPref.getAccessToken(context);
// Using the new ReportService through LocationApiClient
ReportService reportService = LocationApiClient.getInstance().getReportService(); ReportService reportService = LocationApiClient.getInstance().getReportService();
Call<JsonObject> call = reportService.updateReport(token, uuid, reportBody); Call<JsonObject> call = reportService.updateReport(token, uuid, reportBody);
@ -391,20 +660,23 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) { public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
DialogUtils.dismissDialog(); DialogUtils.dismissDialog();
if (response.isSuccessful()) { if (response.isSuccessful()) {
Helper.makeSnackBar(rlAddReport, getString(R.string.Report_updated_successfully)); String message = getString(R.string.Report_updated_successfully);
rlAddReport.postDelayed(() -> {
finish(); //to go back to the previous activity Helper.makeSnackBar(findViewById(android.R.id.content), message);
findViewById(android.R.id.content).postDelayed(() -> {
setResult(RESULT_OK);
finish();
}, 500); }, 500);
} else { } 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 @Override
public void onFailure(Call<JsonObject> call, Throwable t) { public void onFailure(Call<JsonObject> call, Throwable t) {
DialogUtils.dismissDialog(); DialogUtils.dismissDialog();
Log.e(TAG, "Update Place Error: ", t); Log.e(TAG, "Update Report Error: ", 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));
} }
}); });
} }

View File

@ -130,7 +130,7 @@ public class PlaceDetailActivity extends AppCompatActivity implements View.OnCli
private void initObj() { private void initObj() {
context = this; context = this;
checkIfPlaceIsFavorite(SharedPref.getUserUid(context), place_uuid); checkIfPlaceIsFavorite(SharedPref.getUserUuid(context), place_uuid);
} }
private void loadIntentData() { private void loadIntentData() {
@ -235,9 +235,9 @@ public class PlaceDetailActivity extends AppCompatActivity implements View.OnCli
private void onClickFavorite() { private void onClickFavorite() {
if (isFavorite) { if (isFavorite) {
removePlaceFromFavorites(SharedPref.getUserUid(context), place_uuid); removePlaceFromFavorites(SharedPref.getUserUuid(context), place_uuid);
} else { } else {
addPlaceToFavorites(SharedPref.getUserUid(context), place_uuid); addPlaceToFavorites(SharedPref.getUserUuid(context), place_uuid);
} }
} }

View File

@ -97,7 +97,7 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL
View[] views = {etName, etEmail, etPassword}; View[] views = {etName, etEmail, etPassword};
if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail) && Helper.isPasswordValid(context, etPassword)) { if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail) && Helper.isPasswordValid(context, etPassword)) {
setInputDataToEntity(); setInputDataToEntity();
registerUserWithRetrofit(); registerUser();
} }
} }
@ -107,17 +107,10 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL
entity.setPassword(Helper.getStringFromInput(etPassword)); entity.setPassword(Helper.getStringFromInput(etPassword));
} }
private void registerUserWithRetrofit() { private void registerUser() {
DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait)); DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait));
JsonObject jsonParam = new JsonObject(); Call<JsonObject> call = getJsonObjectCall();
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<JsonObject> call = authService.registerUser(jsonParam);
call.enqueue(new Callback<JsonObject>() { call.enqueue(new Callback<JsonObject>() {
@Override @Override
@ -162,4 +155,16 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL
} }
}); });
} }
private Call<JsonObject> 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<JsonObject> call = authService.registerUser(jsonParam);
return call;
}
} }

View File

@ -74,7 +74,7 @@ public class FavoriteAdapter extends RecyclerView.Adapter<FavoriteAdapter.ViewHo
holder.tvDescription.setText(favorite.getPlaceDescription()); holder.tvDescription.setText(favorite.getPlaceDescription());
// handle favorite on click // handle favorite on click
holder.ivFavorite.setOnClickListener(v -> 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())); holder.itemView.setOnClickListener(v -> getPlaceByUuid(favorite.getPlaceUuid()));
} }

View File

@ -10,11 +10,15 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.ieslamar.acloc.R;
import com.example.acloc.model.Report; 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; import java.util.List;
public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapter.ViewHolder> { public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapter.ViewHolder> {
@ -27,68 +31,155 @@ public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapte
this.reportList = reportList; this.reportList = reportList;
} }
public void clearReports() { @SuppressLint("NotifyDataSetChanged")
reportList.clear(); public void updateReportsList(List<Report> reportList) {
notifyDataSetChanged(); if (reportList != null) {
this.reportList = reportList;
notifyDataSetChanged();
}
} }
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
public void updateReportsList(List<Report> reportList) { public void clearReports() {
try { if (this.reportList != null) {
if (reportList != null) { this.reportList.clear();
this.reportList = reportList; notifyDataSetChanged();
notifyDataSetChanged();
}
} catch (Exception exception) {
Log.e(TAG, "Error in PlaceReportsAdapter", exception);
} }
} }
@NonNull @NonNull
@Override @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context); View view = LayoutInflater.from(context).inflate(R.layout.list_view_place_reports, parent, false);
View detailItem = inflater.inflate(R.layout.list_view_place_reports, parent, false); return new ViewHolder(view);
return new ViewHolder(detailItem);
} }
@SuppressLint("SetTextI18n")
@Override @Override
public void onBindViewHolder(@NonNull PlaceReportsAdapter.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
try { try {
if (!reportList.isEmpty()) { Report report = reportList.get(position);
Report report = reportList.get(position); holder.tvDescription.setText(report.getDescription());
holder.tvDescription.setText(report.getDescription());
if (report.getReportRating() == 1) { // Set rating
holder.tvRating.setText(context.getString(R.string.Rating_BAD)); setRatingDisplay(holder, report.getReportRating());
holder.ivRating.setImageResource(R.drawable.ic_thumbs_down);
} else if (report.getReportRating() == 2) { // Setup accessibility tags for multiple report types
holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE)); setupAccessibilityTags(holder.rvAccessibilityTags, report, position);
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);
}
}
} catch (Exception e) { } 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<String> 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<AccessibilityTagsAdapter.TagData> 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 @Override
public int getItemCount() { public int getItemCount() {
return reportList.size(); 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 { public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView tvDescription, tvRating; final TextView tvDescription, tvRating;
private final ImageView ivRating; final ImageView ivRating;
final RecyclerView rvAccessibilityTags;
public ViewHolder(@NonNull View itemView) { public ViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
tvDescription = itemView.findViewById(R.id.tvDescription); tvDescription = itemView.findViewById(R.id.tvDescription);
tvRating = itemView.findViewById(R.id.tvRating); tvRating = itemView.findViewById(R.id.tvRating);
ivRating = itemView.findViewById(R.id.ivRating); ivRating = itemView.findViewById(R.id.ivRating);
rvAccessibilityTags = itemView.findViewById(R.id.rvAccessibilityTags);
} }
} }
} }

View File

@ -4,11 +4,13 @@ import com.example.acloc.service.AuthService;
import com.example.acloc.service.FavoriteService; import com.example.acloc.service.FavoriteService;
import com.example.acloc.service.PlaceService; import com.example.acloc.service.PlaceService;
import com.example.acloc.service.ReportService; import com.example.acloc.service.ReportService;
import com.example.acloc.service.ReportTypeService;
import com.example.acloc.service.RoleService; import com.example.acloc.service.RoleService;
import com.example.acloc.service.UploadService; import com.example.acloc.service.UploadService;
import com.example.acloc.service.UserService; import com.example.acloc.service.UserService;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/** /**
* Centralized API client that manages Retrofit instance and provides access to all service interfaces * 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 FavoriteService favoriteService;
private PlaceService placeService; private PlaceService placeService;
private ReportService reportService; private ReportService reportService;
private ReportTypeService reportTypeService;
private RoleService roleService; private RoleService roleService;
private UserService userService; private UserService userService;
private UploadService uploadService; private UploadService uploadService;
@ -86,6 +89,17 @@ public class LocationApiClient {
return reportService; 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 * Gets the RoleService interface
* @return RoleService implementation * @return RoleService implementation

View File

@ -95,7 +95,7 @@ public class AlertChangePasswordDialog implements View.OnClickListener {
String username = SharedPref.getUserName(context); String username = SharedPref.getUserName(context);
String oldPassword = Helper.getStringFromInput(etOldPassword); String oldPassword = Helper.getStringFromInput(etOldPassword);
String newPassword = Helper.getStringFromInput(etNewPassword); String newPassword = Helper.getStringFromInput(etNewPassword);
String uuid = SharedPref.getUserUid(context); String uuid = SharedPref.getUserUuid(context);
verifyOldPasswordRetrofit(uuid, username, oldPassword, newPassword); verifyOldPasswordRetrofit(uuid, username, oldPassword, newPassword);
} }

View File

@ -136,7 +136,7 @@ public class AlertViewAddNewPlaceDialog implements View.OnClickListener {
entity.setAddress(Helper.getStringFromInput(etAddress)); entity.setAddress(Helper.getStringFromInput(etAddress));
entity.setLatitude(Helper.getStringFromInput(etLatitude)); entity.setLatitude(Helper.getStringFromInput(etLatitude));
entity.setLongitude(Helper.getStringFromInput(etLongitude)); entity.setLongitude(Helper.getStringFromInput(etLongitude));
entity.setCreatedBy(SharedPref.getUserUid(context)); entity.setCreatedBy(SharedPref.getUserUuid(context));
entity.setUuid(place_uuid); entity.setUuid(place_uuid);
} }

View File

@ -117,7 +117,7 @@ public class AlertViewOrUpdateProfileDialog implements View.OnClickListener {
View[] views = {etUsername, etEmail}; View[] views = {etUsername, etEmail};
if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail)) { if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail)) {
setInputDataToEntity(); setInputDataToEntity();
String uuid = SharedPref.getUserUid(context); String uuid = SharedPref.getUserUuid(context);
updateUserWithRetrofit(uuid, entity.getUsername(), entity.getEmail()); updateUserWithRetrofit(uuid, entity.getUsername(), entity.getEmail());
} }
} }

View File

@ -20,6 +20,7 @@ import com.example.acloc.activity.AddNewPlaceActivity;
import com.example.acloc.activity.AddReportActivity; import com.example.acloc.activity.AddReportActivity;
import com.example.acloc.activity.PlaceDetailActivity; import com.example.acloc.activity.PlaceDetailActivity;
import com.example.acloc.adapter.PlaceReportsAdapter; import com.example.acloc.adapter.PlaceReportsAdapter;
import com.example.acloc.adapter.AccessibilityTagsAdapter;
import com.example.acloc.api.LocationApiClient; import com.example.acloc.api.LocationApiClient;
import com.example.acloc.model.Place; import com.example.acloc.model.Place;
import com.example.acloc.model.Report; 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.DialogUtils;
import com.example.acloc.utility.Helper; import com.example.acloc.utility.Helper;
import com.example.acloc.utility.SharedPref; 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.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; 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.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.ieslamar.acloc.R; import com.ieslamar.acloc.R;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -54,9 +62,9 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
private boolean isFavorite = false; private boolean isFavorite = false;
private TextView tvPlaceName, tvAddress, tvDescription, tvNoReports; private TextView tvPlaceName, tvAddress, tvDescription, tvNoReports;
private ImageView ivFavorite, ivEdit, ivExpand; private ImageView ivFavorite, ivEdit, ivExpand, ivPlaceImage;
private AppCompatButton btnAddReport; private AppCompatButton btnAddReport;
private RecyclerView rvReports; private RecyclerView rvReports, rvAccessibilityOverview;
private PlaceReportsAdapter adapter; private PlaceReportsAdapter adapter;
private final List<Report> reportList = new ArrayList<>(); private final List<Report> reportList = new ArrayList<>();
private BottomSheetBehavior<View> behavior; private BottomSheetBehavior<View> behavior;
@ -76,11 +84,9 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
if (bottomSheet != null) { if (bottomSheet != null) {
behavior = BottomSheetBehavior.from(bottomSheet); behavior = BottomSheetBehavior.from(bottomSheet);
//Set initial state to half expanded
behavior.setPeekHeight(getResources().getDisplayMetrics().heightPixels / 2); behavior.setPeekHeight(getResources().getDisplayMetrics().heightPixels / 2);
behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED); behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
//Add callback to update expand/collapse icon
behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override @Override
public void onStateChanged(@NonNull View bottomSheet, int newState) { public void onStateChanged(@NonNull View bottomSheet, int newState) {
@ -93,7 +99,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
@Override @Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) { 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); initUI(view);
setPlaceData(); setPlaceData();
initListeners(); initListeners();
checkIfPlaceIsFavorite(SharedPref.getUserUid(context), place.getUuid()); checkIfPlaceIsFavorite(SharedPref.getUserUuid(context), place.getUuid());
loadReports(); loadReports();
return view; return view;
@ -125,24 +131,70 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
ivFavorite = view.findViewById(R.id.ivFavorite); ivFavorite = view.findViewById(R.id.ivFavorite);
ivEdit = view.findViewById(R.id.ivEdit); ivEdit = view.findViewById(R.id.ivEdit);
ivExpand = view.findViewById(R.id.ivExpand); ivExpand = view.findViewById(R.id.ivExpand);
ivPlaceImage = view.findViewById(R.id.ivPlaceImage);
btnAddReport = view.findViewById(R.id.btnAddReport); btnAddReport = view.findViewById(R.id.btnAddReport);
rvReports = view.findViewById(R.id.rvReports); rvReports = view.findViewById(R.id.rvReports);
rvAccessibilityOverview = view.findViewById(R.id.rvAccessibilityOverview);
rvReports.setLayoutManager(new LinearLayoutManager(context)); rvReports.setLayoutManager(new LinearLayoutManager(context));
rvAccessibilityOverview.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
} }
private void setPlaceData() { private void setPlaceData() {
tvPlaceName.setText(place.getName()); tvPlaceName.setText(place.getName());
tvAddress.setText(place.getAddress()); tvAddress.setText(place.getAddress());
tvDescription.setText(place.getDescription()); 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() { private void initListeners() {
ivFavorite.setOnClickListener(v -> { ivFavorite.setOnClickListener(v -> {
if (isFavorite) { if (isFavorite) {
removePlaceFromFavorites(SharedPref.getUserUid(context), place.getUuid()); removePlaceFromFavorites(SharedPref.getUserUuid(context), place.getUuid());
} else { } else {
addPlaceToFavorites(SharedPref.getUserUid(context), place.getUuid()); addPlaceToFavorites(SharedPref.getUserUuid(context), place.getUuid());
} }
}); });
@ -166,7 +218,6 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
dismiss(); dismiss();
}); });
// Open full screen details on click
View.OnClickListener fullScreenListener = v -> { View.OnClickListener fullScreenListener = v -> {
Helper.goTo(context, PlaceDetailActivity.class, Constants.PLACE, place); Helper.goTo(context, PlaceDetailActivity.class, Constants.PLACE, place);
dismiss(); dismiss();
@ -175,6 +226,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
tvPlaceName.setOnClickListener(fullScreenListener); tvPlaceName.setOnClickListener(fullScreenListener);
tvAddress.setOnClickListener(fullScreenListener); tvAddress.setOnClickListener(fullScreenListener);
tvDescription.setOnClickListener(fullScreenListener); tvDescription.setOnClickListener(fullScreenListener);
ivPlaceImage.setOnClickListener(fullScreenListener);
} }
private void loadReports() { private void loadReports() {
@ -194,16 +246,15 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
for (JsonElement element : data.getAsJsonArray("reports")) { for (JsonElement element : data.getAsJsonArray("reports")) {
Report report = getReport(element); Report report = getReport(element);
reportList.add(report); reportList.add(report);
} }
// Show latest reports first
Collections.reverse(reportList); Collections.reverse(reportList);
List<Report> latestReports = reportList.size() > 3 ? List<Report> latestReports = reportList.size() > 3 ?
reportList.subList(0, 3) : reportList; reportList.subList(0, 3) : reportList;
updateReportsUI(latestReports); updateReportsUI(latestReports);
calculateAndShowAccessibilityStats(reportList);
} else { } else {
showNoReports(); showNoReports();
} }
@ -228,9 +279,118 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
report.setDescription(reportObject.get("description").getAsString()); report.setDescription(reportObject.get("description").getAsString());
report.setPlaceName(reportObject.get("place_name").getAsString()); report.setPlaceName(reportObject.get("place_name").getAsString());
report.setPlaceUuid(reportObject.get("place_uuid").getAsString()); report.setPlaceUuid(reportObject.get("place_uuid").getAsString());
List<String> reportTypeUuids = new ArrayList<>();
List<String> 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; return report;
} }
private static void processReportTypeField(JsonObject reportObject, String fieldName, List<String> 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<Report> allReports) {
if (allReports.isEmpty()) {
rvAccessibilityOverview.setVisibility(View.GONE);
return;
}
// Calculate statistics for each accessibility type
Map<String, AccessibilityStats> statsMap = new HashMap<>();
int totalReports = allReports.size();
for (Report report : allReports) {
List<String> 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<AccessibilityStats> statsList) {
if (statsList.isEmpty()) {
rvAccessibilityOverview.setVisibility(View.GONE);
return;
}
// Convert stats to tag data for display
List<AccessibilityTagsAdapter.TagData> 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<Report> reports) { private void updateReportsUI(List<Report> reports) {
if (reports != null && !reports.isEmpty()) { if (reports != null && !reports.isEmpty()) {
adapter = new PlaceReportsAdapter(context, reports); adapter = new PlaceReportsAdapter(context, reports);
@ -244,9 +404,35 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
private void showNoReports() { private void showNoReports() {
rvReports.setVisibility(View.GONE); rvReports.setVisibility(View.GONE);
rvAccessibilityOverview.setVisibility(View.GONE);
tvNoReports.setVisibility(View.VISIBLE); 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) { private void checkIfPlaceIsFavorite(String userUuid, String placeUuid) {
String token = "Bearer " + SharedPref.getAccessToken(context); String token = "Bearer " + SharedPref.getAccessToken(context);
FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService(); FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService();
@ -314,7 +500,6 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
if (response.errorBody() != null) { if (response.errorBody() != null) {
String errorBody = response.errorBody().string(); 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 ) { if ((response.code() == 409 && errorBody.contains("ER_DUP_ENTRY"))|| response.code() == 404 ) {
restorePlaceToFavorites(userUuid, placeUuid); restorePlaceToFavorites(userUuid, placeUuid);
return; return;

View File

@ -103,7 +103,7 @@ public class FavoriteFragment extends Fragment {
if (favoriteList == null) { if (favoriteList == null) {
favoriteList = new ArrayList<>(); favoriteList = new ArrayList<>();
} }
String userUuid = SharedPref.getUserUid(context); String userUuid = SharedPref.getUserUuid(context);
getFavoriteByUserUuid(userUuid); getFavoriteByUserUuid(userUuid);
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error in FavoriteFragment", e); Log.e(TAG, "Error in FavoriteFragment", e);

View File

@ -107,7 +107,7 @@ public class MyReportsFragment extends Fragment implements View.OnClickListener
if (reportList == null) { if (reportList == null) {
reportList = new ArrayList<>(); reportList = new ArrayList<>();
} }
String userUuid = SharedPref.getUserUid(context); String userUuid = SharedPref.getUserUuid(context);
getReportsByUserUuid(userUuid); getReportsByUserUuid(userUuid);
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error in MyReportsFragment", e); Log.e(TAG, "Error in MyReportsFragment", e);

View File

@ -1,13 +1,33 @@
package com.example.acloc.model; package com.example.acloc.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Report implements Serializable { public class Report implements Serializable {
String uuid, fkUser, fkPlace, fkReportType, description, createdBy; String uuid, fkUser, fkPlace, description, createdBy;
String placeName, placeUuid; String placeName, placeUuid;
int reportRating; int reportRating;
String image; String image;
private List<String> reportTypeUuids = new ArrayList<>();
private List<String> reportTypeNames = new ArrayList<>();
public List<String> getReportTypeUuids() {
return reportTypeUuids;
}
public void setReportTypeUuids(List<String> reportTypeUuids) {
this.reportTypeUuids = reportTypeUuids;
}
public List<String> getReportTypeNames() {
return reportTypeNames;
}
public void setReportTypeNames(List<String> reportTypeNames) {
this.reportTypeNames = reportTypeNames;
}
public String getUuid() { public String getUuid() {
return uuid; return uuid;
} }
@ -32,14 +52,6 @@ public class Report implements Serializable {
this.fkPlace = fkPlace; this.fkPlace = fkPlace;
} }
public String getFkReportType() {
return fkReportType;
}
public void setFkReportType(String fkReportType) {
this.fkReportType = fkReportType;
}
public String getDescription() { public String getDescription() {
return description; return description;
} }

View File

@ -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;
}
}

View File

@ -67,7 +67,7 @@ public interface ReportService {
* @param reportData Report data containing parameters to modify * @param reportData Report data containing parameters to modify
* @return JsonObject containing updated report information * @return JsonObject containing updated report information
*/ */
@PUT("/reports/{uuid}") @PUT("reports/{uuid}")
Call<JsonObject> updateReport( Call<JsonObject> updateReport(
@Header("Authorization") String token, @Header("Authorization") String token,
@Path("uuid") String uuid, @Path("uuid") String uuid,

View File

@ -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<JsonObject> getReportTypes(
@Header("Authorization") String token,
@Query("uuid") String uuid,
@Query("name") String name
);
@GET("report_types/{uuid}")
Call<JsonObject> getReportTypeByUuid(
@Header("Authorization") String token,
@Path("uuid") String uuid
);
@POST("report_types")
Call<JsonObject> createReportType(
@Header("Authorization") String token,
@Body JsonObject body
);
@PUT("report_types/{uuid}")
Call<JsonObject> updateReportType(
@Header("Authorization") String token,
@Path("uuid") String uuid,
@Body JsonObject body
);
@DELETE("report_types/{uuid}")
Call<Void> deleteReportType(
@Header("Authorization") String token,
@Path("uuid") String uuid
);
}

View File

@ -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
};
}
}
}

View File

@ -249,7 +249,7 @@ public class Helper {
} }
// Regex for strong password validation // 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 (!passwordText.matches(passwordPattern)) {
if (textInputLayout != null) { if (textInputLayout != null) {
@ -360,4 +360,3 @@ public class Helper {
return new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); return new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
} }
} }

View File

@ -44,7 +44,7 @@ public class SharedPref {
editor.apply(); editor.apply();
} }
public static String getUserUid(Context con) { public static String getUserUuid(Context con) {
return sharedPreferences(con).getString(USER_UUID, ""); return sharedPreferences(con).getString(USER_UUID, "");
} }

View File

@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path android:fillColor="@android:color/white" android:pathData="M19,13v-2c-1.54,0.02 -3.09,-0.75 -4.07,-1.83l-1.29,-1.43c-0.17,-0.19 -0.38,-0.34 -0.61,-0.45 -0.01,0 -0.01,-0.01 -0.02,-0.01L13,7.28c-0.35,-0.2 -0.75,-0.3 -1.19,-0.26C10.76,7.11 10,8.04 10,9.09L10,15c0,1.1 0.9,2 2,2h5v5h2v-5.5c0,-1.1 -0.9,-2 -2,-2h-3v-3.45c1.29,1.07 3.25,1.94 5,1.95zM12.83,18c-0.41,1.16 -1.52,2 -2.83,2 -1.66,0 -3,-1.34 -3,-3 0,-1.31 0.84,-2.41 2,-2.83L9,12.1c-2.28,0.46 -4,2.48 -4,4.9 0,2.76 2.24,5 5,5 2.42,0 4.44,-1.72 4.9,-4h-2.07z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M13.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM9.8,8.9L7,23h2.1l1.8,-8 2.1,2v6h2v-7.5l-2.1,-2 0.6,-3C14.8,12 16.8,13 19,13v-2c-1.9,0 -3.5,-1 -4.3,-2.4l-1,-1.6c-0.4,-0.6 -1,-1 -1.7,-1 -0.3,0 -0.5,0.1 -0.8,0.1L6,8.3V13h2V9.6l1.8,-0.7"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19,19V5c0,-1.1 -0.9,-2 -2,-2H7C5.9,3 5,3.9 5,5v14H3v2h18v-2H19zM15,13h-2v-2h2V13z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM8.5,6c0.69,0 1.25,0.56 1.25,1.25c0,0.69 -0.56,1.25 -1.25,1.25S7.25,7.94 7.25,7.25C7.25,6.56 7.81,6 8.5,6zM11,14h-1v4H7v-4H6v-2.5c0,-1.1 0.9,-2 2,-2h1c1.1,0 2,0.9 2,2V14zM15.5,17L13,13h5L15.5,17zM13,11l2.5,-4l2.5,4H13z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5s5,2.2 5,5h2c0,-3.93 -3.07,-7 -7,-7S7,5.07 7,9c0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 2.21,0 4,-1.79 4,-4h-2c0,1.1 -0.9,2 -2,2zM7.64,2.64L6.22,1.22C4.23,3.21 3,5.96 3,9s1.23,5.79 3.22,7.78l1.41,-1.41C6.01,13.74 5,11.49 5,9s1.01,-4.74 2.64,-6.36zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M13,3L6,3v18h4v-6h3c3.31,0 6,-2.69 6,-6s-2.69,-6 -6,-6zM13.2,11L10,11L10,7h3.2c1.1,0 2,0.9 2,2s-0.9,2 -2,2z"/>
</vector>

View File

@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M13,8.57c-0.79,0 -1.43,0.64 -1.43,1.43s0.64,1.43 1.43,1.43s1.43,-0.64 1.43,-1.43S13.79,8.57 13,8.57z"/>
<path android:fillColor="@android:color/white" android:pathData="M13,3C9.25,3 6.2,5.94 6.02,9.64L4.1,12.2C3.85,12.53 4.09,13 4.5,13H6v3c0,1.1 0.9,2 2,2h1v3h7v-4.68c2.36,-1.12 4,-3.53 4,-6.32C20,6.13 16.87,3 13,3zM16,10c0,0.13 -0.01,0.26 -0.02,0.39l0.83,0.66c0.08,0.06 0.1,0.16 0.05,0.25l-0.8,1.39c-0.05,0.09 -0.16,0.12 -0.24,0.09l-0.99,-0.4c-0.21,0.16 -0.43,0.29 -0.67,0.39L14,13.83c-0.01,0.1 -0.1,0.17 -0.2,0.17h-1.6c-0.1,0 -0.18,-0.07 -0.2,-0.17l-0.15,-1.06c-0.25,-0.1 -0.47,-0.23 -0.68,-0.39l-0.99,0.4c-0.09,0.03 -0.2,0 -0.25,-0.09l-0.8,-1.39c-0.05,-0.08 -0.03,-0.19 0.05,-0.25l0.84,-0.66C10.01,10.26 10,10.13 10,10c0,-0.13 0.02,-0.27 0.04,-0.39L9.19,8.95c-0.08,-0.06 -0.1,-0.16 -0.05,-0.26l0.8,-1.38c0.05,-0.09 0.15,-0.12 0.24,-0.09l1,0.4c0.2,-0.15 0.43,-0.29 0.67,-0.39l0.15,-1.06C12.02,6.07 12.1,6 12.2,6h1.6c0.1,0 0.18,0.07 0.2,0.17l0.15,1.06c0.24,0.1 0.46,0.23 0.67,0.39l1,-0.4c0.09,-0.03 0.2,0 0.24,0.09l0.8,1.38c0.05,0.09 0.03,0.2 -0.05,0.26l-0.85,0.66C15.99,9.73 16,9.86 16,10z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M17.66,17.66l-1.06,1.06l-0.71,-0.71l1.06,-1.06l-1.94,-1.94l-1.06,1.06l-0.71,-0.71l1.06,-1.06l-1.94,-1.94l-1.06,1.06l-0.71,-0.71l1.06,-1.06L9.7,9.7l-1.06,1.06l-0.71,-0.71l1.06,-1.06L7.05,7.05L5.99,8.11L5.28,7.4l1.06,-1.06L4,4v14c0,1.1 0.9,2 2,2h14L17.66,17.66zM7,17v-5.76L12.76,17H7z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M5.5,22v-7.5L4,14.5L4,9c0,-1.1 0.9,-2 2,-2h3c1.1,0 2,0.9 2,2v5.5L9.5,14.5L9.5,22h-4zM18,22v-6h3l-2.54,-7.63C18.18,7.55 17.42,7 16.56,7h-0.12c-0.86,0 -1.63,0.55 -1.9,1.37L12,16h3v6h3zM7.5,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2 -2,0.89 -2,2 0.89,2 2,2zM16.5,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2 -2,0.89 -2,2 0.89,2 2,2z"/>
</vector>

View File

@ -1,321 +1,324 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rlAddReport"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="com.example.acloc.activity.AddReportActivity"> android:fillViewport="true">
<include <LinearLayout
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_above="@id/btnSubmitContainer" android:orientation="vertical"
android:layout_below="@id/toolbar"
android:fillViewport="true"
android:fitsSystemWindows="true"
android:clipToPadding="false"
android:padding="16dp"> android:padding="16dp">
<LinearLayout <!-- Place Info Card -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:layout_marginTop="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<!-- Report Form Card --> <LinearLayout
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:orientation="vertical"
app:cardCornerRadius="12dp" android:padding="16dp">
app:cardElevation="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/place_info"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primaryColor_dark" />
<TextView
android:id="@+id/tvPlaceName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textSize="16sp"
android:textStyle="bold"
tools:text="Biblioteca Central" />
<TextView
android:id="@+id/tvPlaceAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"
tools:text="Calle Principal 123, Ciudad" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Report Type Selection -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/select_accessibility_features"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primaryColor_dark" />
<!-- Report Types RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvReportTypes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:nestedScrollingEnabled="false"
tools:itemCount="3"
tools:listitem="@layout/item_report_type_selector" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Rating Selection -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Rating Header -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/rating"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?attr/colorPrimary"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/rate_accessibility_experience"
android:textSize="14sp"
android:textColor="?attr/colorOnBackground"
android:layout_marginBottom="16dp"/>
<!-- Rating Thumbs -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:baselineAligned="false"
android:padding="16dp"> android:orientation="horizontal"
android:gravity="center">
<!-- Header --> <LinearLayout
<TextView android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/add_report" android:layout_weight="1"
android:textSize="20sp" android:orientation="vertical"
android:textStyle="bold" android:gravity="center">
android:textColor="?attr/colorPrimary"
android:layout_marginBottom="16dp"/>
<!-- Image Container -->
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardCornerRadius="8dp"
app:strokeWidth="1dp"
app:strokeColor="?attr/colorPrimary"
app:cardElevation="0dp">
<ImageView <ImageView
android:id="@+id/ivReportPhoto" android:id="@+id/ivThumbsDown"
android:layout_width="@dimen/image_view_width" android:layout_width="60dp"
android:layout_height="@dimen/image_view_height" android:layout_height="60dp"
android:padding="@dimen/content_padding" android:layout_margin="8dp"
android:background="@drawable/rectangle" android:src="@drawable/ic_thumbs_down"
android:importantForAccessibility="no" android:background="?attr/selectableItemBackgroundBorderless"
android:importantForAutofill="no" android:padding="12dp"
android:src="@drawable/logo_add_location" /> android:contentDescription="@string/BAD" />
</com.google.android.material.card.MaterialCardView>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tap_to_add_photo"
android:textSize="12sp"
android:gravity="center"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"/>
<!-- Place Name Field -->
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:startIconDrawable="@drawable/ic_location"
app:startIconTint="?attr/colorPrimary"
app:boxStrokeColor="?attr/colorPrimary"
app:hintTextColor="?attr/colorPrimary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPlaceName"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="false" android:text="@string/BAD"
android:focusable="false" android:textSize="12sp"
android:hint="@string/Enter_Place_Name" android:textColor="?attr/colorOnSurfaceVariant"/>
android:importantForAutofill="no"
android:inputType="text"
tools:ignore="HardcodedText" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Description Field -->
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:startIconDrawable="@drawable/ic_location"
app:startIconTint="?attr/colorPrimary"
app:boxStrokeColor="?attr/colorPrimary"
app:hintTextColor="?attr/colorPrimary"
app:counterEnabled="true"
app:counterMaxLength="200">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/Enter_Description"
android:importantForAutofill="no"
android:inputType="textImeMultiLine"
android:minLines="3"
android:maxLines="5"
tools:ignore="HardcodedText" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Rating Card -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Rating Header -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/how_would_you_rate_this_place"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?attr/colorPrimary"
android:textAlignment="center"
android:layout_marginBottom="16dp"/>
<!-- Rating Options -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center"
android:orientation="horizontal">
<!-- Good Rating -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="8dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="24dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@android:color/transparent">
<ImageView
android:id="@+id/ivThumbsUp"
android:layout_width="@dimen/image_icon_width"
android:layout_height="@dimen/image_icon_height"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="Thumbs Up"
android:focusable="true"
android:padding="12dp"
app:tint="?attr/colorOnBackground"
android:src="@drawable/ic_thumb_up_border" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/GOOD"
android:textColor="?attr/colorPrimary"
android:textSize="@dimen/textSizeInEditText"
android:textStyle="bold" />
</LinearLayout>
<!-- Average Rating -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="8dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="24dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@android:color/transparent">
<ImageView
android:id="@+id/ivThumbsAverage"
android:layout_width="@dimen/image_icon_width"
android:layout_height="@dimen/image_icon_height"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="Thumbs Average"
android:focusable="true"
android:rotation="260"
android:padding="12dp"
app:tint="?attr/colorOnBackground"
android:src="@drawable/ic_thumb_up_border" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/AVERAGE"
android:textColor="?attr/colorPrimary"
android:textSize="@dimen/textSizeInEditText"
android:textStyle="bold" />
</LinearLayout>
<!-- Bad Rating -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="8dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="24dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@android:color/transparent">
<ImageView
android:id="@+id/ivThumbsDown"
android:layout_width="@dimen/image_icon_width"
android:layout_height="@dimen/image_icon_height"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="Thumbs Down"
android:focusable="true"
android:padding="12dp"
app:tint="?attr/colorOnBackground"
android:src="@drawable/ic_thumb_down_border" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/BAD"
android:textColor="?attr/colorPrimary"
android:textSize="@dimen/textSizeInEditText"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/ivThumbsAverage"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="8dp"
android:src="@drawable/ic_thumb_up_average"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="12dp"
android:contentDescription="@string/AVERAGE" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/AVERAGE"
android:textSize="12sp"
android:textColor="?attr/colorOnSurfaceVariant"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/ivThumbsUp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="8dp"
android:src="@drawable/ic_thumbs_up"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="12dp"
android:contentDescription="@string/GOOD" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/GOOD"
android:textSize="12sp"
android:textColor="?attr/colorOnSurfaceVariant"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</ScrollView>
<!-- Submit Button Container --> </LinearLayout>
<FrameLayout
android:id="@+id/btnSubmitContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@android:color/white"
android:elevation="8dp"
android:padding="16dp">
<com.google.android.material.button.MaterialButton </com.google.android.material.card.MaterialCardView>
android:id="@+id/btnSubmit"
<!-- Description -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="12dp" android:layout_marginTop="16dp"
android:paddingBottom="12dp" app:cardCornerRadius="12dp"
android:text="@string/SUBMIT" app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/description"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primaryColor_dark" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:hint="@string/describe_accessibility"
app:boxStrokeColor="@color/primaryColor_dark"
app:hintTextColor="@color/primaryColor_dark">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minLines="3"
android:maxLines="5"
android:gravity="top"
android:inputType="textMultiLine|textCapSentences" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Photo Upload Card -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_photo"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primaryColor_dark" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/photo_helps_others"
android:textSize="14sp"
android:textColor="@android:color/darker_gray" />
<ImageView
android:id="@+id/ivReportPhoto"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:layout_marginTop="12dp"
android:src="@drawable/ic_add_light"
android:background="?attr/selectableItemBackgroundBorderless"
android:scaleType="centerCrop"
android:contentDescription="@string/add_photo" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Submit Button -->
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSubmitReport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="16dp"
android:text="@string/submit_report"
android:textSize="16sp"
android:textStyle="bold" android:textStyle="bold"
app:cornerRadius="8dp" android:backgroundTint="@color/primaryColor_dark"
tools:ignore="HardcodedText" /> app:cornerRadius="12dp"
</FrameLayout> android:padding="16dp" />
</RelativeLayout>
</LinearLayout>
</ScrollView>

View File

@ -12,6 +12,17 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
<!-- Place Image -->
<ImageView
android:id="@+id/ivPlaceImage"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginBottom="16dp"
android:scaleType="centerCrop"
android:background="@drawable/rectangle"
android:contentDescription="@string/place_image"
tools:src="@drawable/place_header" />
<!-- Header section --> <!-- Header section -->
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -90,6 +101,29 @@
android:text="@string/Add_Report" /> android:text="@string/Add_Report" />
</RelativeLayout> </RelativeLayout>
<!-- Accessibility Overview Section -->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#DDDDDD" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
android:text="@string/accessibility_overview" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvAccessibilityOverview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone"
tools:visibility="visible" />
<!-- Reports section --> <!-- Reports section -->
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/reportTypeCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:strokeWidth="2dp"
app:strokeColor="@color/neutralGrey"
app:cardBackgroundColor="@android:color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="16dp">
<!-- Icon -->
<ImageView
android:id="@+id/reportTypeIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="12dp"
android:contentDescription="@string/report_type_icon"
app:tint="@color/neutralGrey"
tools:src="@drawable/ic_accessible" />
<!-- Report Type Info -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tvReportTypeName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@android:color/black"
tools:text="Accesibilidad para sillas de ruedas" />
</LinearLayout>
<!-- Selection Indicator -->
<ImageView
android:id="@+id/ivSelected"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_check_circle"
android:visibility="gone"
app:tint="@color/primaryColor_dark"
tools:visibility="visible" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -14,6 +14,7 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="12dp"> android:padding="12dp">
<!-- Report Description -->
<TextView <TextView
android:id="@+id/tvDescription" android:id="@+id/tvDescription"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -21,30 +22,70 @@
android:ellipsize="end" android:ellipsize="end"
android:maxLines="3" android:maxLines="3"
android:textSize="14sp" android:textSize="14sp"
tools:text="This is a report description that might be multiple lines long. It describes the accessibility features or issues at this location." /> android:textColor="@android:color/black"
tools:text="Este lugar tiene buena accesibilidad para sillas de ruedas y personas con discapacidad visual." />
<!-- Rating and Accessibility Tags Container -->
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:gravity="center_vertical" android:orientation="vertical">
android:orientation="horizontal">
<ImageView <!-- Rating Row -->
android:id="@+id/ivRating" <LinearLayout
android:layout_width="16dp" android:layout_width="match_parent"
android:layout_height="16dp"
android:layout_marginEnd="4dp"
android:src="@drawable/ic_thumbs_up"
app:tint="@color/primaryColor_dark" />
<TextView
android:id="@+id/tvRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="12sp" android:gravity="center_vertical"
android:textStyle="bold" android:orientation="horizontal">
tools:text="GOOD" />
<ImageView
android:id="@+id/ivRating"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginEnd="4dp"
android:src="@drawable/ic_thumbs_up"
app:tint="@color/green" />
<TextView
android:id="@+id/tvRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textStyle="bold"
android:textColor="@color/green"
tools:text="BUENO" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<!-- Report Date -->
<TextView
android:id="@+id/tvReportDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="11sp"
android:textColor="@android:color/darker_gray"
tools:text="12/01/2024" />
</LinearLayout>
<!-- Accessibility Tags -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvAccessibilityTags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible"
tools:itemCount="2"
tools:listitem="@layout/item_accessibility_tag" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View File

@ -174,6 +174,46 @@
<string name="please">Por favor</string> <string name="please">Por favor</string>
<string name="empty">Vacío</string> <string name="empty">Vacío</string>
<string name="password_validation_requirement">La contraseña debe tener al menos 6 caracteres, incluir 1 mayúscula, 1 minúscula, 1 dígito y 1 carácter especial.</string> <string name="password_validation_requirement">La contraseña debe tener al menos 6 caracteres, incluir 1 mayúscula, 1 minúscula, 1 dígito y 1 carácter especial.</string>
<string name="rate_accessibility">Puntúa este sitio</string>
<string name="bad_rating">Mala accessibilidad</string>
<string name="average_rating">Accesibilidad regular</string>
<string name="good_rating">Buena accessibilidad</string>
<string name="please_select_accessibility_type">Selecciona el tipo de discapacidad relacionado</string>
<string name="get_current_location">Localización actual</string>
<string name="enter_location">Introduzca una locación</string>
<string name="location">Localización</string>
<string name="rating">Puntuación</string>
<string name="accessibility_features">Características accesibles</string>
<string name="select_accessibility_features">Selecciona el tipo de discapacidad relacionada con el comentario</string>
<string name="submit_report">Enviar comentario</string>
<string name="report_title">Titulo del comentario</string>
<string name="report_description">Cuerpo del comentario</string>
<string name="selected">Selected</string>
<string name="bad_accessibility">Bad accessibility</string>
<string name="rate_accessibility_experience">Rate the accessibility experience of this location</string>
<string name="place_info">Location info</string>
<string name="describe_accessibility">Accessibility info</string>
<string name="report_type_icon">Report type icon</string>
<string name="accessibility_icon">Accessibility icon</string>
<string name="place_image">Place image</string>
<!-- Accessibility Types -->
<string name="accessibility_wheelchair">Silla de ruedas</string>
<string name="accessibility_visual">Acceso visual</string>
<string name="accessibility_hearing">Acceso auditivo</string>
<string name="accessibility_cognitive">Acceso cognitivo</string>
<string name="accessibility_mobility">Movilidad</string>
<string name="accessibility_parking">Estacionamiento</string>
<string name="accessibility_entrance">Entrada</string>
<string name="accessibility_bathroom">Baño</string>
<string name="accessibility_elevator">Ascensor</string>
<string name="accessibility_ramp">Rampa</string>
<string name="accessibility_unknown">Accesibilidad</string>
<!-- Selection states -->
<string name="tap_to_select">toca para seleccionar</string>
<string name="add_photo">Add images to your comment</string>
<string name="error_no_place_selected">Error: no place selected</string>
<string name="address_not_available">Address not available</string>
<string name="accessibility_overview">Accessibility overview</string>
</resources> </resources>

View File

@ -4,11 +4,11 @@
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<!-- Primary Colors --> <!-- Primary Colors -->
<color name="primaryColor_light">#0D47A1</color> <!-- Deep Blue: trustworthy, strong (main actions or headers) --> <color name="primaryColor_light">#0D47A1</color>
<color name="primaryColor_dark">#4D8EF4</color> <color name="primaryColor_dark">#4D8EF4</color>
<!-- Primary Variant --> <!-- Primary Variant -->
<color name="primaryVariant_light">#42A5F5</color> <!-- Light Blue: fresh, friendly (backgrounds, buttons, accents) --> <color name="primaryVariant_light">#42A5F5</color>
<color name="primaryVariant_dark">#5AB1F6</color> <color name="primaryVariant_dark">#5AB1F6</color>
<!-- Accessibility Status Colors --> <!-- Accessibility Status Colors -->
@ -17,12 +17,12 @@
<color name="notAccessibleColor">#C62828</color> <color name="notAccessibleColor">#C62828</color>
<!-- Background Colors --> <!-- Background Colors -->
<color name="backgroundColor_light">#FAFAFA</color> <!-- Light background for bright theme --> <color name="backgroundColor_light">#FAFAFA</color>
<color name="backgroundColor_dark">#121212</color> <!-- Dark background for dark mode --> <color name="backgroundColor_dark">#121212</color>
<!-- Surface Colors --> <!-- Surface Colors -->
<color name="surfaceColor_light">#FFFFFF</color> <!-- Surface for light theme --> <color name="surfaceColor_light">#FFFFFF</color>
<color name="surfaceColor_dark">#040404</color> <!-- Surface for dark theme --> <!--changed --> <color name="surfaceColor_dark">#040404</color>
<!-- Text & Icon Colors --> <!-- Text & Icon Colors -->
<color name="onPrimaryColor_light">#FFFFFF</color> <color name="onPrimaryColor_light">#FFFFFF</color>
@ -31,20 +31,19 @@
<color name="onSecondaryColor_light">#000000</color> <color name="onSecondaryColor_light">#000000</color>
<color name="onSecondaryColor_dark">#FFFFFF</color> <color name="onSecondaryColor_dark">#FFFFFF</color>
<color name="onBackgroundColor_light">#212121 <color name="onBackgroundColor_light">#212121</color>
</color> <!-- Light Gray: soft background (cards/app bg) -->
<color name="onBackgroundColor_dark">#E0E0E0</color> <color name="onBackgroundColor_dark">#E0E0E0</color>
<color name="onSurfaceColor_light">#212121</color> <!-- Dark text on surface --> <color name="onSurfaceColor_light">#212121</color>
<color name="onSurfaceColor_dark">#F5F5F5</color> <!-- Light Gray for dark surfaces --> <color name="onSurfaceColor_dark">#F5F5F5</color>
<!-- Error Colors --> <!-- Error Colors -->
<color name="errorColor_light">#C62828</color> <!-- Error red in light mode --> <color name="errorColor_light">#C62828</color>
<color name="errorColor_dark">#F44336</color> <!-- Error red in dark mode --> <color name="errorColor_dark">#F44336</color>
<!-- Accent / Highlight --> <!-- Accent / Highlight -->
<color name="accentColor_light">#FF4081</color> <!-- Bright pink: attention-grabbing --> <color name="accentColor_light">#FF4081</color>
<color name="accentColor_dark">#C51162</color> <!-- Darker pink for dark mode --> <color name="accentColor_dark">#C51162</color>
<color name="colorTertiary_light">#e8edf6</color> <color name="colorTertiary_light">#e8edf6</color>
<color name="colorTertiary_dark">#232324</color> <color name="colorTertiary_dark">#232324</color>
@ -56,4 +55,25 @@
<color name="red">#F44336</color> <color name="red">#F44336</color>
<color name="light_blue">#e8edf6</color> <color name="light_blue">#e8edf6</color>
<!-- Accessibility Tag Colors -->
<!-- Good Rating (3) -->
<color name="accessibility_good_bg">#E8F5E8</color>
<color name="accessibility_good_text">#2E7D32</color>
<color name="accessibility_good_border">#4CAF50</color>
<!-- Average Rating (2) -->
<color name="accessibility_average_bg">#FFF8E1</color>
<color name="accessibility_average_text">#F57C00</color>
<color name="accessibility_average_border">#FF9800</color>
<!-- Poor Rating (1) -->
<color name="accessibility_poor_bg">#FFEBEE</color>
<color name="accessibility_poor_text">#C62828</color>
<color name="accessibility_poor_border">#F44336</color>
<!-- Default/Unrated -->
<color name="accessibility_default_bg">#F5F5F5</color>
<color name="accessibility_default_text">#757575</color>
<color name="accessibility_default_border">#BDBDBD</color>
</resources> </resources>

View File

@ -1,182 +1,224 @@
<resources> <resources>
<string name="app_name">AcLoc - Accessible Locations Application</string> <string name="app_name">AcLoc - Accessible Locations Application</string>
<!-- BUTTON TITLE --> <!-- BUTTON TITLE -->
<string name="LOGIN">LOGIN</string> <string name="LOGIN">LOGIN</string>
<string name="REGISTER">REGISTER</string> <string name="REGISTER">REGISTER</string>
<string name="SAVE_PLACE">SAVE PLACE</string> <string name="SAVE_PLACE">SAVE PLACE</string>
<string name="UPDATE">UPDATE</string> <string name="UPDATE">UPDATE</string>
<string name="CANCEL">CANCEL</string> <string name="CANCEL">CANCEL</string>
<string name="SUBMIT">SUBMIT</string> <string name="SUBMIT">SUBMIT</string>
<string name="ADD_REPORT">ADD REPORT</string> <string name="ADD_REPORT">ADD REPORT</string>
<!-- toolbar --> <!-- toolbar -->
<string name="Add_Report">Add Report</string> <string name="Add_Report">Add Report</string>
<string name="Place_Details">Place Details</string> <string name="Place_Details">Place Details</string>
<string name="Add_Place">Add Place</string> <string name="Add_Place">Add Place</string>
<!-- edittext --> <!-- edittext -->
<string name="Enter_Username">Enter Username</string> <string name="Enter_Username">Enter Username</string>
<string name="Enter_Password">Enter Password</string> <string name="Enter_Password">Enter Password</string>
<string name="Enter_Email">Enter Email</string> <string name="Enter_Email">Enter Email</string>
<string name="Enter_Name">Enter Name</string> <string name="Enter_Name">Enter Name</string>
<string name="Enter_Location">Enter Location</string> <string name="Enter_Location">Enter Location</string>
<string name="Enter_Contact">Enter Contact</string> <string name="Enter_Contact">Enter Contact</string>
<string name="Already_have_an_Account">"Already have an Account? </string> <string name="Already_have_an_Account">"Already have an Account? </string>
<string name="Please_login">Please login</string> <string name="Please_login">Please login</string>
<string name="Please_register">Please register</string> <string name="Please_register">Please register</string>
<string name="Dont_have_an_Account">Don\'t have an Account? </string> <string name="Dont_have_an_Account">Don\'t have an Account? </string>
<string name="Favorite">Favorite</string> <string name="Favorite">Favorite</string>
<string name="My_Report">My Report</string> <string name="My_Report">My Report</string>
<string name="Map">Map</string> <string name="Map">Map</string>
<string name="Profile">Profile</string> <string name="Profile">Profile</string>
<string name="Change_Password">Change Password</string> <string name="Change_Password">Change Password</string>
<string name="Manage_Roles">Manage Roles</string> <string name="Manage_Roles">Manage Roles</string>
<string name="Change_Language">Change Language</string> <string name="Change_Language">Change Language</string>
<string name="Logout">Logout</string> <string name="Logout">Logout</string>
<string name="Enter_Place_Name">Enter Place Name</string> <string name="Enter_Place_Name">Enter Place Name</string>
<string name="Enter_Latitude">Enter Latitude</string> <string name="Enter_Latitude">Enter Latitude</string>
<string name="Enter_Longitude">Enter Longitude</string> <string name="Enter_Longitude">Enter Longitude</string>
<string name="Enter_Address">Enter Address</string> <string name="Enter_Address">Enter Address</string>
<string name="Enter_Place_Description">Enter Place Description</string> <string name="Enter_Place_Description">Enter Place Description</string>
<string name="Search_Place">Search Place</string> <string name="Search_Place">Search Place</string>
<string name="Enter_Old_Password">Enter Old Password</string> <string name="Enter_Old_Password">Enter Old Password</string>
<string name="Enter_New_Password">Enter New Password</string> <string name="Enter_New_Password">Enter New Password</string>
<string name="Place_Name">Place Name</string> <string name="Place_Name">Place Name</string>
<string name="Address">Address</string> <string name="Address">Address</string>
<string name="Place_Description">Place Description</string> <string name="Place_Description">Place Description</string>
<string name="Enter_Description">Enter Description</string> <string name="Enter_Description">Enter Description</string>
<string name="Report_Description">Report Description</string> <string name="Report_Description">Report Description</string>
<string name="Report">Reports</string> <string name="Report">Reports</string>
<string name="Search_User">Search User</string> <string name="Search_User">Search User</string>
<string name="User">User</string> <string name="User">User</string>
<string name="Role">Role</string> <string name="Role">Role</string>
<string name="Change_Role">Change Role</string> <string name="Change_Role">Change Role</string>
<!--TextView--> <!--TextView-->
<string name="GOOD">GOOD</string> <string name="GOOD">GOOD</string>
<string name="AVERAGE">AVERAGE</string> <string name="AVERAGE">AVERAGE</string>
<string name="BAD">BAD</string> <string name="BAD">BAD</string>
<!-- Alert dialog --> <!-- Alert dialog -->
<string name="change_language_confirmation">change language to Spanish</string> <string name="change_language_confirmation">change language to Spanish</string>
<string name="Are_you_sure_you_want_to_logout">Are you sure you want to logout?</string> <string name="Are_you_sure_you_want_to_logout">Are you sure you want to logout?</string>
<string name="confirmation_message">Are you sure you want to %1$s?\nWARNING: This action cannot be undone</string> <string name="confirmation_message">Are you sure you want to %1$s?\nWARNING: This action cannot be undone</string>
<string name="yes">Yes</string> <string name="yes">Yes</string>
<string name="no">No</string> <string name="no">No</string>
<string name="Location_Permission_Required">Location permission required</string> <string name="Location_Permission_Required">Location permission required</string>
<string name="Location_permission_rationale">This app requires location permission to function properly. Please enable it in Settings.</string> <string name="Location_permission_rationale">This app requires location permission to function properly. Please enable it in Settings.</string>
<string name="Go_to_Settings">Go to Settings</string> <string name="Go_to_Settings">Go to Settings</string>
<string name="Exit_App">Exit App</string> <string name="Exit_App">Exit App</string>
<!-- Snackbar text --> <!-- Snackbar text -->
<string name="Something_went_wrong">Something went wrong!!!</string> <string name="Something_went_wrong">Something went wrong!!!</string>
<string name="Login_failed">Login failed</string> <string name="Login_failed">Login failed</string>
<string name="Invalid_Credentials_Please_try_again">Invalid Credentials. Please try again.</string> <string name="Invalid_Credentials_Please_try_again">Invalid Credentials. Please try again.</string>
<string name="Login_Successful">Login Successful</string> <string name="Login_Successful">Login Successful</string>
<string name="Please_wait">Please wait…</string> <string name="Please_wait">Please wait…</string>
<string name="User_already_exists_Please_login">"User already exists. Please login.</string> <string name="User_already_exists_Please_login">"User already exists. Please login.</string>
<string name="Profile_Updated_Successfully">Profile Updated Successfully!</string> <string name="Profile_Updated_Successfully">Profile Updated Successfully!</string>
<string name="Registration_Successful">Registration Successful</string> <string name="Registration_Successful">Registration Successful</string>
<string name="Try_again_later">Try again later</string> <string name="Try_again_later">Try again later</string>
<string name="Update_Failed">Update Failed </string> <string name="Update_Failed">Update Failed </string>
<string name="Something_went_wrong_Try_again">Something went wrong. Try again.</string> <string name="Something_went_wrong_Try_again">Something went wrong. Try again.</string>
<string name="Updating">Updating…</string> <string name="Updating">Updating…</string>
<string name="Invalid_old_password">Invalid old password</string> <string name="Invalid_old_password">Invalid old password</string>
<string name="Network_error_Try_again">Network error. Try again.</string> <string name="Network_error_Try_again">Network error. Try again.</string>
<string name="Changing_password">Changing password…</string> <string name="Changing_password">Changing password…</string>
<string name="Password_updated_successfully">Password updated successfully!</string> <string name="Password_updated_successfully">Password updated successfully!</string>
<string name="Password_update_failed">Password update failed.</string> <string name="Password_update_failed">Password update failed.</string>
<string name="Verifying_old_password">Verifying old password…</string> <string name="Verifying_old_password">Verifying old password…</string>
<string name="Change_Role_to">change Role to </string> <string name="Change_Role_to">change Role to </string>
<string name="Updating_Role">Updating Roles…</string> <string name="Updating_Role">Updating Roles…</string>
<string name="User_Role_update_successfully">User Role updated successfully!</string> <string name="User_Role_update_successfully">User Role updated successfully!</string>
<string name="Update_failed_Server_error_Try_again">Update failed. Server error. Try again</string> <string name="Update_failed_Server_error_Try_again">Update failed. Server error. Try again</string>
<string name="Rating_BAD">Rating: BAD</string> <string name="Rating_BAD">Rating: BAD</string>
<string name="Rating_AVERAGE">Rating: AVERAGE</string> <string name="Rating_AVERAGE">Rating: AVERAGE</string>
<string name="Rating_GOOD">Rating: GOOD</string> <string name="Rating_GOOD">Rating: GOOD</string>
<string name="Delete_report">Delete report</string> <string name="Delete_report">Delete report</string>
<string name="Removing_Report">Removing Report…</string> <string name="Removing_Report">Removing Report…</string>
<string name="Report_removed">Report removed!</string> <string name="Report_removed">Report removed!</string>
<string name="Failed_to_remove_report">Failed to remove report</string> <string name="Failed_to_remove_report">Failed to remove report</string>
<string name="Removing_from_favorites">Removing from favorites…</string> <string name="Removing_from_favorites">Removing from favorites…</string>
<string name="Favorite_removed">Favorite removed</string> <string name="Favorite_removed">Favorite removed</string>
<string name="Failed_to_remove_Favorite">Failed to remove Favorite</string> <string name="Failed_to_remove_Favorite">Failed to remove Favorite</string>
<string name="Loading_Favorites">Loading favorites…</string> <string name="Loading_Favorites">Loading favorites…</string>
<string name="No_Favorite_found">No Favorite found.</string> <string name="No_Favorite_found">No Favorite found.</string>
<string name="Failed_to_load_favorite_Try_again">Failed to load favorite. Try again.</string> <string name="Failed_to_load_favorite_Try_again">Failed to load favorite. Try again.</string>
<string name="Location_permission_is_required">Location permission is required</string> <string name="Location_permission_is_required">Location permission is required</string>
<string name="Failed_to_load_places">Failed to load places</string> <string name="Failed_to_load_places">Failed to load places</string>
<string name="Loading_reports">Loading reports…</string> <string name="Loading_reports">Loading reports…</string>
<string name="No_reports_found">No reports found.</string> <string name="No_reports_found">No reports found.</string>
<string name="Failed_to_load_reports_Try_again.">Failed to load reports. Try again.</string> <string name="Failed_to_load_reports_Try_again.">Failed to load reports. Try again.</string>
<string name="Place_updated_successfully">Place updated successfully!</string> <string name="Place_updated_successfully">Place updated successfully!</string>
<string name="Updating_place">Updating place…</string> <string name="Updating_place">Updating place…</string>
<string name="Place_inserted_successfully">Place inserted successfully!</string> <string name="Place_inserted_successfully">Place inserted successfully!</string>
<string name="Failed_to_extract_place_Try_again">Failed to extract place.Try again</string> <string name="Failed_to_extract_place_Try_again">Failed to extract place.Try again</string>
<string name="Insert_failed_Server_error">Insert failed. Server error.</string> <string name="Insert_failed_Server_error">Insert failed. Server error.</string>
<string name="Report_submission_failed_Try_again">Report submission failed. Try again</string> <string name="Report_submission_failed_Try_again">Report submission failed. Try again</string>
<string name="Report_submitted_successfully">Report submitted successfully!</string> <string name="Report_submitted_successfully">Report submitted successfully!</string>
<string name="Please_select_rating">Please select rating!</string> <string name="Updating_report">Updating report…</string>
<string name="Updating_report">Updating report…</string> <string name="Report_updated_successfully">Report updated successfully!</string>
<string name="Report_updated_successfully">Report updated successfully!</string> <string name="Failed_to_load_users_Try_again">Failed to load users. Try again.</string>
<string name="Failed_to_load_users_Try_again">Failed to load users. Try again.</string> <string name="No_users_found">No users found</string>
<string name="No_users_found">No users found</string> <string name="Loading_users">Loading users…</string>
<string name="Loading_users">Loading users…</string> <string name="Adding_to_favorites">Adding to favorites…</string>
<string name="Adding_to_favorites">Adding to favorites…</string> <string name="Place_added_to_favorites">Place added to favorites!</string>
<string name="Place_added_to_favorites">Place added to favorites!</string> <string name="Failed_to_add_favorite_Server_error">Failed to add favorite. Server error.</string>
<string name="Failed_to_add_favorite_Server_error">Failed to add favorite. Server error.</string> <string name="Restoring_favorite">Restoring favorite…</string>
<string name="Restoring_favorite">Restoring favorite…</string> <string name="Place_restored_to_favorites">Place restored to favorites!</string>
<string name="Place_restored_to_favorites">Place restored to favorites!</string> <string name="Failed_to_restore_favorite">Failed to restore favorite.</string>
<string name="Failed_to_restore_favorite">Failed to restore favorite.</string> <string name="Removed_from_favorites">Removed from favorites</string>
<string name="Removed_from_favorites">Removed from favorites</string> <string name="Failed_to_remove_from_favorites">Failed to remove from favorites</string>
<string name="Failed_to_remove_from_favorites">Failed to remove from favorites</string> <string name="Checking_favorite_status">Checking favorite status…</string>
<string name="Checking_favorite_status">Checking favorite status…</string> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>--> <!-- <string name="Logout">Logout</string>-->
<string name="add_new_location">Add New Location</string> <string name="add_new_location">Add New Location</string>
<string name="tap_to_add_photo">Tap to add photo</string> <string name="tap_to_add_photo">Tap to add photo</string>
<string name="location_details">Location Details</string> <string name="location_details">Location Details</string>
<string name="additional_information">Additional Information</string> <string name="additional_information">Additional Information</string>
<string name="add_report">Rate this place!</string> <string name="add_report">Rate this place!</string>
<string name="how_would_you_rate_this_place">How would you rate the accessibility of this place?</string> <string name="how_would_you_rate_this_place">How would you rate the accessibility of this place?</string>
<string name="welcome_back">Welcome Back</string> <string name="welcome_back">Welcome Back</string>
<string name="sign_in_to_continue">Sign in to continue</string> <string name="sign_in_to_continue">Sign in to continue</string>
<string name="expand">Expand</string> <string name="expand">Expand</string>
<string name="address">Address</string> <string name="address">Address</string>
<string name="description">Description</string> <string name="description">Description</string>
<string name="edit">Edit</string> <string name="edit">Edit</string>
<string name="recent_reports">Recent Reports</string> <string name="recent_reports">Recent Reports</string>
<string name="no_reports_yet">No reports about this place yet</string> <string name="no_reports_yet">No reports about this place yet</string>
<string name="details">Details</string> <string name="details">Details</string>
<string name="add_to_favorites">Add to favorites</string> <string name="add_to_favorites">Add to favorites</string>
<string name="image_uploaded_successfully">Image uploaded successfully</string> <string name="image_uploaded_successfully">Image uploaded successfully</string>
<string name="upload_failed">Upload failed</string> <string name="upload_failed">Upload failed</string>
<string name="response_parsing_error">Response parsing error</string> <string name="response_parsing_error">Response parsing error</string>
<string name="no_places_found_near_this_location">No places found near this location</string> <string name="no_places_found_near_this_location">No places found near this location</string>
<string name="location_not_found">Location not found</string> <string name="location_not_found">Location not found</string>
<string name="invalid_email_address">Invalid email address</string> <string name="invalid_email_address">Invalid email address</string>
<string name="please">Please</string> <string name="please">Please</string>
<string name="empty">Empty</string> <string name="empty">Empty</string>
<string name="password_validation_requirement">Password must be at least 6 characters, include 1 uppercase, 1 lowercase, 1 digit, and 1 special character.</string> <string name="password_validation_requirement">Password must be at least 6 characters, include 1 uppercase, 1 lowercase, 1 digit, and 1 special character.</string>
<string name="rate_accessibility">Rate the accessibility of this place</string>
<string name="bad_rating">Bad accessibility</string>
<string name="average_rating">Average accessibility</string>
<string name="good_rating">Good accessibility</string>
<string name="please_select_accessibility_type">Please select an accessibility type</string>
<string name="Please_select_rating">Please select a rating</string>
<string name="get_current_location">Get Current Location</string>
<string name="enter_location">Enter location</string>
<string name="location">Location</string>
<string name="rating">Rating</string>
<string name="accessibility_features">Accessibility Features</string>
<string name="select_accessibility_features">Select the accessibility feature you want to report</string>
<string name="submit_report">Submit Report</string>
<string name="report_title">Report Title</string>
<string name="report_description">Report Description</string>
<string name="selected">Selected</string>
<string name="bad_accessibility">Bad accessibility</string>
<string name="rate_accessibility_experience">Rate the accessibility experience of this location</string>
<string name="place_info">Location info</string>
<string name="describe_accessibility">Accessibility info</string>
<string name="report_type_icon">Report type icon</string>
<string name="accessibility_icon">Accessibility icon</string>
<string name="place_image">Place image</string>
<!-- Accessibility Types -->
<string name="accessibility_wheelchair">Wheelchair accessible</string>
<string name="accessibility_visual">Visually accessible</string>
<string name="accessibility_hearing">Hearing accessible</string>
<string name="accessibility_cognitive">Neurodivergent accessible</string>
<string name="accessibility_mobility">Mobility accessible</string>
<string name="accessibility_parking">Parking</string>
<string name="accessibility_entrance">Entrance</string>
<string name="accessibility_bathroom">WC</string>
<string name="accessibility_elevator">Elevator</string>
<string name="accessibility_ramp">Ramp</string>
<string name="accessibility_unknown">Accessibility</string>
<!-- Selection states -->
<string name="tap_to_select">Touch to select</string>
<string name="add_photo">Add images to your comment</string>
<string name="photo_helps_others">Help other users</string>
<string name="error_no_place_selected">Error: no place selected</string>
<string name="address_not_available">Address not available</string>
<string name="accessibility_overview">Accessibility overview</string>
</resources> </resources>