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

@ -60,4 +60,4 @@
android:value="AIzaSyCzcuZhHd-GqadewAiCbh4NuaBhO2AcPOY" />
</application>
</manifest>
</manifest>

View File

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

View File

@ -6,37 +6,46 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.acloc.adapter.ReportTypeAdapter;
import com.example.acloc.api.LocationApiClient;
import com.example.acloc.model.Place;
import com.example.acloc.model.Report;
import com.example.acloc.model.ReportType;
import com.example.acloc.service.PlaceService;
import com.example.acloc.service.ReportService;
import com.example.acloc.service.ReportTypeService;
import com.example.acloc.utility.Constants;
import com.example.acloc.utility.DialogUtils;
import com.example.acloc.utility.Helper;
import com.example.acloc.utility.SharedPref;
import com.example.acloc.utility.UploadManager;
import com.ieslamar.acloc.R;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.textfield.TextInputEditText;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.ieslamar.acloc.R;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@ -44,179 +53,382 @@ import retrofit2.Response;
public class AddReportActivity extends AppCompatActivity implements View.OnClickListener {
public static final String TAG = AddReportActivity.class.getSimpleName();
private RelativeLayout rlAddReport;
private TextInputEditText etDescription, etPlaceName;
private ImageView ivReportPhoto;
private ImageView ivThumbsUp, ivThumbsAverage, ivThumbsDown;
private AppCompatButton btnSubmit;
private Context context;
// UI Components
private TextInputEditText etDescription;
private TextView tvPlaceName, tvPlaceAddress;
private ImageView ivReportPhoto, ivThumbsUp, ivThumbsAverage, ivThumbsDown;
private MaterialButton btnSubmitReport;
private RecyclerView rvReportTypes;
// Data
private Place placeEntity;
private Report reportEntity;
private String report_type_uuid, place_uuid;
private int reportRating;
private String place_uuid;
private int reportRating = 0;
private String report_uuid;
private boolean isEditMode = false;
// Report Types - Now supporting multiple selection
private ReportTypeAdapter reportTypeAdapter;
private List<ReportType> reportTypesList = new ArrayList<>();
private List<String> selectedReportTypeUuids = new ArrayList<>();
// Multiple Images handling
private static final int PICK_IMAGE_REQUEST = 100;
private Uri selectedImageUri;
private String imageUrl;
private String jsonString;
private List<String> imageUrls = new ArrayList<>();
private int currentImageIndex = 0;
private String jsonString = "[]";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_report);
initToolbar();
initUI();
resetThumbsColors();
loadIntentData();
initListener();
initObj();
}
private void initToolbar() {
try {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setTitle(getString(R.string.Add_Report));
}
} catch (Exception e) {
Log.e(TAG, "Error in AddReportActivity", e);
}
loadReportTypes();
}
private void initUI() {
rlAddReport = findViewById(R.id.rlAddReport);
ivReportPhoto = findViewById(R.id.ivReportPhoto);
etPlaceName = findViewById(R.id.etPlaceName);
// Text inputs
etDescription = findViewById(R.id.etDescription);
// Place info
tvPlaceName = findViewById(R.id.tvPlaceName);
tvPlaceAddress = findViewById(R.id.tvPlaceAddress);
// Rating thumbs
ivThumbsUp = findViewById(R.id.ivThumbsUp);
ivThumbsAverage = findViewById(R.id.ivThumbsAverage);
ivThumbsDown = findViewById(R.id.ivThumbsDown);
btnSubmit = findViewById(R.id.btnSubmit);
// Photo and submit
ivReportPhoto = findViewById(R.id.ivReportPhoto);
btnSubmitReport = findViewById(R.id.btnSubmitReport);
// Report types
rvReportTypes = findViewById(R.id.rvReportTypes);
// Setup RecyclerView for report types
rvReportTypes.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
reportTypeAdapter = new ReportTypeAdapter(this, reportTypesList);
reportTypeAdapter.setOnReportTypeClickListener(new ReportTypeAdapter.OnReportTypeClickListener() {
@Override
public void onReportTypeClick(ReportType reportType, int position, boolean isSelected) {
// Individual click handling if needed
Log.d(TAG, "Report type " + reportType.getName() + " " + (isSelected ? "selected" : "deselected"));
}
@Override
public void onSelectionChanged(List<ReportType> selectedReportTypes) {
// Update selected UUIDs list
selectedReportTypeUuids.clear();
for (ReportType reportType : selectedReportTypes) {
selectedReportTypeUuids.add(reportType.getUuid());
}
}
});
rvReportTypes.setAdapter(reportTypeAdapter);
}
private void loadIntentData() {
placeEntity = (Place) getIntent().getSerializableExtra(Constants.PLACE);
Intent intent = getIntent();
// Get place data (if available)
placeEntity = (Place) intent.getSerializableExtra(Constants.PLACE);
if (placeEntity != null) {
place_uuid = placeEntity.getUuid();
etPlaceName.setText(placeEntity.getName()); //Just to display place name in report
populatePlaceInfo();
}
reportEntity = (Report) getIntent().getSerializableExtra(Constants.REPORT);
// Get report data (for editing existing reports)
reportEntity = (Report) intent.getSerializableExtra(Constants.REPORT);
if (reportEntity != null) {
report_uuid = reportEntity.getUuid(); // setting place uuid first
isEditMode = true;
report_uuid = reportEntity.getUuid();
place_uuid = reportEntity.getPlaceUuid();
Log.d(TAG, "" +
"place uuid: " + reportEntity.getPlaceUuid() +
"\n fkplace " + reportEntity.getFkPlace());
setDataToEditText();
// If we don't have place entity but have place_uuid, fetch place data
if (placeEntity == null && place_uuid != null) {
fetchPlaceData(place_uuid);
}
}
// Get place UUID directly (if passed without Place object)
String passedPlaceUuid = intent.getStringExtra("place_uuid");
if (passedPlaceUuid != null && place_uuid == null) {
place_uuid = passedPlaceUuid;
fetchPlaceData(place_uuid);
}
// Validate that we have the necessary data
if (place_uuid == null || place_uuid.isEmpty()) {
Helper.makeSnackBar(findViewById(android.R.id.content),
getString(R.string.error_no_place_selected));
finish();
}
}
private void fetchPlaceData(String placeUuid) {
String token = "Bearer " + SharedPref.getAccessToken(this);
PlaceService placeService = LocationApiClient.getInstance().getPlaceService();
Call<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() {
etPlaceName.setText(reportEntity.getPlaceName());
etDescription.setText(reportEntity.getDescription());
int rating = reportEntity.getReportRating();
if (rating == 1) {
ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN);
ivThumbsUp.setColorFilter(null); // reset the other
ivThumbsAverage.setColorFilter(null);
reportRating = Constants.BAD_RATING; //1
} else if (rating == 2) {
ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN);
ivThumbsUp.setColorFilter(null); // reset the others
ivThumbsDown.setColorFilter(null);
reportRating = Constants.AVERAGE_RATING; //2
} else if (rating == 3) {
ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN);
ivThumbsDown.setColorFilter(null); // reset the other
ivThumbsAverage.setColorFilter(null);
reportRating = Constants.GOOD_RATING; //3
if (reportEntity != null) {
etDescription.setText(reportEntity.getDescription());
// Reset colors first
resetThumbsColors();
// Set rating using constants
int rating = reportEntity.getReportRating();
if (rating == Constants.BAD_RATING) { // 1
onClickThumbsDown();
} else if (rating == Constants.AVERAGE_RATING) { // 2
onClickThumbsAverage();
} else if (rating == Constants.GOOD_RATING) { // 3
onClickThumbsUp();
}
// Load existing images
loadReportImages();
// Set place info from report if available
if (reportEntity.getPlaceName() != null) {
tvPlaceName.setText(reportEntity.getPlaceName());
}
// Set selected report types (multiple)
selectedReportTypeUuids.clear();
selectedReportTypeUuids.addAll(reportEntity.getReportTypeUuids());
}
}
private void loadReportImages() {
if (reportEntity.getImage() != null && !reportEntity.getImage().isEmpty()) {
String rawImg = reportEntity.getImage();
try {
JSONArray array = new JSONArray(rawImg);
String imageUrl = array.getString(0); // Get first element in the array
Picasso.get()
.load(imageUrl)
.into(ivReportPhoto, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
Picasso.get().load(imageUrl).into(ivReportPhoto);
}
imageUrls.clear();
@Override
public void onError(Exception e) {
// Error loading image 404 -- load default
Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto);
}
});
for (int i = 0; i < array.length(); i++) {
String imageUrl = array.getString(i);
imageUrls.add(imageUrl);
}
// Load first image in the ImageView
if (!imageUrls.isEmpty()) {
String imageUrl = imageUrls.get(0);
Picasso.get()
.load(imageUrl)
.into(ivReportPhoto, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
Picasso.get().load(imageUrl).into(ivReportPhoto);
}
@Override
public void onError(Exception e) {
Picasso.get().load(R.drawable.ic_add_light).into(ivReportPhoto);
}
});
jsonString = rawImg; // Keep original JSON string
updateImageCounter();
}
} catch (JSONException e) {
Log.e(TAG, "ERROR: " + e.toString());
Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto);
Picasso.get().load(R.drawable.ic_add_light).into(ivReportPhoto);
}
} else { //if image is null
Picasso.get().load(R.drawable.logo_add_location).into(ivReportPhoto);
} else {
Picasso.get().load(R.drawable.ic_add_light).into(ivReportPhoto);
}
}
private void updateImageCounter() {
if (imageUrls.size() > 1) {
Log.d(TAG, "Images: " + (currentImageIndex + 1) + " of " + imageUrls.size());
}
}
private void loadReportTypes() {
String token = "Bearer " + SharedPref.getAccessToken(this);
ReportTypeService reportTypeService = LocationApiClient.getInstance().getReportTypeService();
Call<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() {
ivReportPhoto.setOnClickListener(this);
ivThumbsUp.setOnClickListener(this);
ivThumbsAverage.setOnClickListener(this);
ivThumbsDown.setOnClickListener(this);
ivReportPhoto.setOnClickListener(this);
btnSubmit.setOnClickListener(this);
btnSubmitReport.setOnClickListener(this);
// Long click to cycle through multiple images
ivReportPhoto.setOnLongClickListener(v -> {
if (imageUrls.size() > 1) {
currentImageIndex = (currentImageIndex + 1) % imageUrls.size();
Picasso.get()
.load(imageUrls.get(currentImageIndex))
.placeholder(R.drawable.ic_add_light)
.error(R.drawable.ic_add_light)
.into(ivReportPhoto);
updateImageCounter();
Helper.makeSnackBar(findViewById(android.R.id.content),
"Imagen " + (currentImageIndex + 1) + " de " + imageUrls.size());
return true;
}
return false;
});
}
private void initObj() {
context = this;
reportEntity = new Report();
if (reportEntity == null) {
reportEntity = new Report();
}
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.ivThumbsUp) {
if (id == R.id.ivReportPhoto) {
onClickIvReportPhoto();
} else if (id == R.id.ivThumbsUp) {
onClickThumbsUp();
} else if (id == R.id.ivThumbsAverage) {
onClickThumbsAverage();
} else if (id == R.id.ivThumbsDown) {
onClickThumbsDown();
} else if (id == R.id.ivReportPhoto) {
onClickIvReportPhoto();
} else if (id == R.id.btnSubmit) {
} else if (id == R.id.btnSubmitReport) {
onClickBtnSubmit();
}
}
private void onClickIvReportPhoto() {
// Open the gallery to select an image
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*"); // Restrict to images only
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(intent, PICK_IMAGE_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
selectedImageUri = data.getData();
// Upload the image
uploadImageToServer(selectedImageUri);
// Load image using Picasso
Picasso.get().load(selectedImageUri).into(ivReportPhoto);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
if (data.getClipData() != null) {
// Multiple images selected
int count = data.getClipData().getItemCount();
for (int i = 0; i < count; i++) {
Uri imageUri = data.getClipData().getItemAt(i).getUri();
uploadImageToServer(imageUri);
}
} else if (data.getData() != null) {
// Single image selected
Uri selectedImageUri = data.getData();
uploadImageToServer(selectedImageUri);
Picasso.get().load(selectedImageUri).into(ivReportPhoto);
}
}
}
private void uploadImageToServer(Uri imageUri) {
btnSubmitReport.setClickable(false);
UploadManager.uploadImage(this, imageUri, new UploadManager.UploadCallback() {
@Override
public void onSuccess(String response) {
@ -224,54 +436,83 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
JSONObject json = new JSONObject(response);
if (json.getBoolean("success")) {
String filename = json.getJSONObject("file").getString("filename");
imageUrl = BASE_URL + "public/" + filename;
jsonString = "[\"" + imageUrl + "\"]";
Helper.makeSnackBar(rlAddReport, getString(R.string.image_uploaded_successfully));
btnSubmit.setClickable(true);
String imageUrl = BASE_URL + "public/" + filename;
// Add to images list
imageUrls.add(imageUrl);
// Update JSON string
updateJsonString();
// Load first image if this is the first one
if (imageUrls.size() == 1) {
Picasso.get().load(imageUrl).into(ivReportPhoto);
}
updateImageCounter();
Helper.makeSnackBar(findViewById(android.R.id.content),
getString(R.string.image_uploaded_successfully) + " (" + imageUrls.size() + ")");
} else {
Helper.makeSnackBar(rlAddReport, getString(R.string.upload_failed));
btnSubmit.setClickable(true);
Helper.makeSnackBar(findViewById(android.R.id.content),
getString(R.string.upload_failed));
}
} catch (JSONException e) {
Helper.makeSnackBar(rlAddReport, getString(R.string.response_parsing_error));
btnSubmit.setClickable(true);
Helper.makeSnackBar(findViewById(android.R.id.content),
getString(R.string.response_parsing_error));
Log.e(TAG, "Failed to parse JSON", e);
}
btnSubmitReport.setClickable(true);
}
@Override
public void onError(String message) {
Helper.makeSnackBar(rlAddReport, "Upload failed: " + message);
Log.e(TAG, "Upload error:" + message);
btnSubmit.setClickable(true);
Helper.makeSnackBar(findViewById(android.R.id.content),
"Upload failed: " + message);
Log.e(TAG, "Upload error: " + message);
btnSubmitReport.setClickable(true);
}
});
}
private void updateJsonString() {
try {
JSONArray jsonArray = new JSONArray();
for (String imageUrl : imageUrls) {
jsonArray.put(imageUrl);
}
jsonString = jsonArray.toString();
} catch (Exception e) {
Log.e(TAG, "Error creating images JSON", e);
jsonString = "[]";
}
}
private void onClickThumbsUp() {
resetThumbsColors();
ivThumbsUp.setColorFilter(ContextCompat.getColor(this, R.color.green), PorterDuff.Mode.SRC_IN);
ivThumbsDown.setColorFilter(null); // reset the other
ivThumbsAverage.setColorFilter(null);
reportRating = Constants.GOOD_RATING; //3
reportRating = Constants.GOOD_RATING; // 3
}
private void onClickThumbsAverage() {
resetThumbsColors();
ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, R.color.yellow), PorterDuff.Mode.SRC_IN);
ivThumbsUp.setColorFilter(null); // reset the others
ivThumbsDown.setColorFilter(null);
reportRating = Constants.AVERAGE_RATING; //2
reportRating = Constants.AVERAGE_RATING; // 2
}
private void onClickThumbsDown() {
resetThumbsColors();
ivThumbsDown.setColorFilter(ContextCompat.getColor(this, R.color.red), PorterDuff.Mode.SRC_IN);
ivThumbsUp.setColorFilter(null); // reset the other
ivThumbsAverage.setColorFilter(null);
reportRating = Constants.BAD_RATING; //1
reportRating = Constants.BAD_RATING; // 1
}
private void resetThumbsColors() {
ivThumbsUp.setColorFilter(ContextCompat.getColor(this, android.R.color.transparent), PorterDuff.Mode.SRC_IN);
ivThumbsAverage.setColorFilter(ContextCompat.getColor(this, android.R.color.transparent), PorterDuff.Mode.SRC_IN);
ivThumbsDown.setColorFilter(ContextCompat.getColor(this, android.R.color.transparent), PorterDuff.Mode.SRC_IN);
}
private void onClickBtnSubmit() {
View[] views = {etPlaceName, etDescription};
View[] views = {etDescription};
if (Helper.isEmptyFieldValidation(context, views) && isValidateRating()) {
setInputDataToEntity();
@ -280,20 +521,23 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
updateReportRetrofit(
report_uuid,
place_uuid,
SharedPref.getUserUid(context),
SharedPref.getUserUuid(context),
String.valueOf(reportEntity.getReportRating()),
reportEntity.getDescription(),
reportEntity.getCreatedBy(),
reportEntity.getImage()
reportEntity.getImage(),
selectedReportTypeUuids // Now passing array
);
} else {
// Create new report
insertReportRetrofit(
placeEntity.getUuid(),
SharedPref.getUserUid(context),
place_uuid,
SharedPref.getUserUuid(context),
String.valueOf(reportEntity.getReportRating()),
reportEntity.getDescription(),
reportEntity.getCreatedBy(),
reportEntity.getImage()
reportEntity.getImage(),
selectedReportTypeUuids // Now passing array
);
}
}
@ -302,21 +546,24 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
private void setInputDataToEntity() {
reportEntity.setDescription(Helper.getStringFromInput(etDescription));
reportEntity.setReportRating(reportRating);
reportEntity.setCreatedBy(SharedPref.getUserUid(context));
reportEntity.setCreatedBy(SharedPref.getUserUuid(context));
reportEntity.setImage(jsonString);
reportEntity.setReportTypeUuids(new ArrayList<>(selectedReportTypeUuids)); // Set multiple UUIDs
reportEntity.setPlaceUuid(place_uuid);
}
private boolean isValidateRating() {
if (reportRating != 0) {
return true;
} else {
Helper.makeSnackBar(rlAddReport, getString(R.string.Please_select_rating));
Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Please_select_rating));
return false;
}
}
private void insertReportRetrofit(String placeUuid, String userUuid, String rating,
String description, String createdBy, String jsonString) {
String description, String createdBy, String jsonString,
List<String> reportTypeUuids) {
DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait));
@ -328,6 +575,15 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
reportBody.addProperty("createdBy", createdBy);
reportBody.addProperty("images", jsonString);
// Add report type UUIDs as array (if any selected)
if (reportTypeUuids != null && !reportTypeUuids.isEmpty()) {
JsonArray reportTypesArray = new JsonArray();
for (String uuid : reportTypeUuids) {
reportTypesArray.add(uuid);
}
reportBody.add("report_type_uuid", reportTypesArray);
}
String token = "Bearer " + SharedPref.getAccessToken(context);
ReportService reportService = LocationApiClient.getInstance().getReportService();
@ -344,16 +600,20 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
JsonObject reportObject = data.getAsJsonArray("reports").get(0).getAsJsonObject();
String report_uuid = reportObject.get("uuid").getAsString();
Log.d(TAG, "Report UUID: " + report_uuid);
Helper.makeSnackBar(rlAddReport, getString(R.string.Report_submitted_successfully));
rlAddReport.postDelayed(() -> {
String message = getString(R.string.Report_submitted_successfully);
Helper.makeSnackBar(findViewById(android.R.id.content), message);
findViewById(android.R.id.content).postDelayed(() -> {
setResult(RESULT_OK);
finish();
}, 500);
} else {
Log.d(TAG, "Failed to extract report UUID.");
Helper.makeSnackBar(rlAddReport, getString(R.string.Something_went_wrong_Try_again));
Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Something_went_wrong_Try_again));
}
} else {
Helper.makeSnackBar(rlAddReport, getString(R.string.Report_submission_failed_Try_again));
Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Report_submission_failed_Try_again));
Log.e(TAG, "Insert Report Error: " + response.code());
}
}
@ -362,13 +622,14 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
public void onFailure(Call<JsonObject> call, Throwable t) {
DialogUtils.dismissDialog();
Log.e(TAG, "Insert Report Failure: ", t);
Helper.makeSnackBar(rlAddReport, context.getString(R.string.Network_error_Try_again));
Helper.makeSnackBar(findViewById(android.R.id.content), context.getString(R.string.Network_error_Try_again));
}
});
}
private void updateReportRetrofit(String uuid, String placeUuid, String userUuid, String rating,
String description, String createdBy, String jsonString) {
String description, String createdBy, String jsonString,
List<String> reportTypeUuids) {
DialogUtils.showLoadingDialog(context, getString(R.string.Updating_report));
@ -380,9 +641,17 @@ public class AddReportActivity extends AppCompatActivity implements View.OnClick
reportBody.addProperty("createdBy", createdBy);
reportBody.addProperty("images", jsonString);
// Add report type UUIDs as array (if any selected)
if (reportTypeUuids != null && !reportTypeUuids.isEmpty()) {
JsonArray reportTypesArray = new JsonArray();
for (String reportUuid : reportTypeUuids) {
reportTypesArray.add(reportUuid);
}
reportBody.add("report_type_uuid", reportTypesArray);
}
String token = "Bearer " + SharedPref.getAccessToken(context);
// Using the new ReportService through LocationApiClient
ReportService reportService = LocationApiClient.getInstance().getReportService();
Call<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) {
DialogUtils.dismissDialog();
if (response.isSuccessful()) {
Helper.makeSnackBar(rlAddReport, getString(R.string.Report_updated_successfully));
rlAddReport.postDelayed(() -> {
finish(); //to go back to the previous activity
String message = getString(R.string.Report_updated_successfully);
Helper.makeSnackBar(findViewById(android.R.id.content), message);
findViewById(android.R.id.content).postDelayed(() -> {
setResult(RESULT_OK);
finish();
}, 500);
} else {
Helper.makeSnackBar(rlAddReport, getString(R.string.Update_failed_Server_error_Try_again));
Helper.makeSnackBar(findViewById(android.R.id.content), getString(R.string.Update_failed_Server_error_Try_again));
}
}
@Override
public void onFailure(Call<JsonObject> call, Throwable t) {
DialogUtils.dismissDialog();
Log.e(TAG, "Update Place Error: ", t);
Helper.makeSnackBar(rlAddReport, context.getString(R.string.Network_error_Try_again));
Log.e(TAG, "Update Report Error: ", t);
Helper.makeSnackBar(findViewById(android.R.id.content), context.getString(R.string.Network_error_Try_again));
}
});
}

View File

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

View File

@ -97,7 +97,7 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL
View[] views = {etName, etEmail, etPassword};
if (Helper.isEmptyFieldValidation(context, views) && Helper.isEmailValid(context, etEmail) && Helper.isPasswordValid(context, etPassword)) {
setInputDataToEntity();
registerUserWithRetrofit();
registerUser();
}
}
@ -107,17 +107,10 @@ public class RegisterActivity extends AppCompatActivity implements View.OnClickL
entity.setPassword(Helper.getStringFromInput(etPassword));
}
private void registerUserWithRetrofit() {
private void registerUser() {
DialogUtils.showLoadingDialog(context, getString(R.string.Please_wait));
JsonObject jsonParam = new JsonObject();
jsonParam.addProperty("username", entity.getUsername());
jsonParam.addProperty("email", entity.getEmail());
jsonParam.addProperty("password", entity.getPassword());
jsonParam.addProperty("fk_role", Constants.ADMIN); //Default Admin for now (BUT acc to api it will be Viewer)
AuthService authService = LocationApiClient.getInstance().getAuthService();
Call<JsonObject> call = authService.registerUser(jsonParam);
Call<JsonObject> call = getJsonObjectCall();
call.enqueue(new Callback<JsonObject>() {
@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());
// 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()));
}

View File

@ -10,11 +10,15 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.ieslamar.acloc.R;
import com.example.acloc.model.Report;
import com.example.acloc.utility.Constants;
import com.example.acloc.utility.AccessibilityHelper;
import com.ieslamar.acloc.R;
import java.util.ArrayList;
import java.util.List;
public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapter.ViewHolder> {
@ -27,68 +31,155 @@ public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapte
this.reportList = reportList;
}
public void clearReports() {
reportList.clear();
notifyDataSetChanged();
@SuppressLint("NotifyDataSetChanged")
public void updateReportsList(List<Report> reportList) {
if (reportList != null) {
this.reportList = reportList;
notifyDataSetChanged();
}
}
@SuppressLint("NotifyDataSetChanged")
public void updateReportsList(List<Report> reportList) {
try {
if (reportList != null) {
this.reportList = reportList;
notifyDataSetChanged();
}
} catch (Exception exception) {
Log.e(TAG, "Error in PlaceReportsAdapter", exception);
public void clearReports() {
if (this.reportList != null) {
this.reportList.clear();
notifyDataSetChanged();
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View detailItem = inflater.inflate(R.layout.list_view_place_reports, parent, false);
return new ViewHolder(detailItem);
View view = LayoutInflater.from(context).inflate(R.layout.list_view_place_reports, parent, false);
return new ViewHolder(view);
}
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(@NonNull PlaceReportsAdapter.ViewHolder holder, int position) {
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
try {
if (!reportList.isEmpty()) {
Report report = reportList.get(position);
holder.tvDescription.setText(report.getDescription());
if (report.getReportRating() == 1) {
holder.tvRating.setText(context.getString(R.string.Rating_BAD));
holder.ivRating.setImageResource(R.drawable.ic_thumbs_down);
} else if (report.getReportRating() == 2) {
holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE));
holder.ivRating.setImageResource(R.drawable.ic_thumb_up_average);
} else if (report.getReportRating() == 3) {
holder.tvRating.setText(context.getString(R.string.Rating_GOOD));
holder.ivRating.setImageResource(R.drawable.ic_thumbs_up);
}
}
Report report = reportList.get(position);
holder.tvDescription.setText(report.getDescription());
// Set rating
setRatingDisplay(holder, report.getReportRating());
// Setup accessibility tags for multiple report types
setupAccessibilityTags(holder.rvAccessibilityTags, report, position);
} catch (Exception e) {
Log.e(TAG, "Error in PlaceReportsAdapter", e);
Log.e(TAG, "Error binding report", e);
}
}
private void setRatingDisplay(ViewHolder holder, int rating) {
switch (rating) {
case Constants.BAD_RATING:
holder.tvRating.setText(context.getString(R.string.Rating_BAD));
holder.ivRating.setImageResource(R.drawable.ic_thumbs_down);
break;
case Constants.AVERAGE_RATING:
holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE));
holder.ivRating.setImageResource(R.drawable.ic_thumb_up_average);
break;
case Constants.GOOD_RATING:
holder.tvRating.setText(context.getString(R.string.Rating_GOOD));
holder.ivRating.setImageResource(R.drawable.ic_thumbs_up);
break;
}
}
private void setupAccessibilityTags(RecyclerView rvTags, Report report, int position) {
// Clear any existing adapter first to avoid conflicts
rvTags.setAdapter(null);
// Get report type names - support both single and multiple
List<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
public int getItemCount() {
return reportList.size();
}
// Add this to ensure proper recycling
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView tvDescription, tvRating;
private final ImageView ivRating;
final TextView tvDescription, tvRating;
final ImageView ivRating;
final RecyclerView rvAccessibilityTags;
public ViewHolder(@NonNull View itemView) {
super(itemView);
tvDescription = itemView.findViewById(R.id.tvDescription);
tvRating = itemView.findViewById(R.id.tvRating);
ivRating = itemView.findViewById(R.id.ivRating);
rvAccessibilityTags = itemView.findViewById(R.id.rvAccessibilityTags);
}
}
}

View File

@ -4,11 +4,13 @@ import com.example.acloc.service.AuthService;
import com.example.acloc.service.FavoriteService;
import com.example.acloc.service.PlaceService;
import com.example.acloc.service.ReportService;
import com.example.acloc.service.ReportTypeService;
import com.example.acloc.service.RoleService;
import com.example.acloc.service.UploadService;
import com.example.acloc.service.UserService;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Centralized API client that manages Retrofit instance and provides access to all service interfaces
@ -22,6 +24,7 @@ public class LocationApiClient {
private FavoriteService favoriteService;
private PlaceService placeService;
private ReportService reportService;
private ReportTypeService reportTypeService;
private RoleService roleService;
private UserService userService;
private UploadService uploadService;
@ -86,6 +89,17 @@ public class LocationApiClient {
return reportService;
}
/**
* Gets the ReportTypeService interface
* @return ReportTypeService implementation
*/
public ReportTypeService getReportTypeService() {
if (reportTypeService == null) {
reportTypeService = retrofit.create(ReportTypeService.class);
}
return reportTypeService;
}
/**
* Gets the RoleService interface
* @return RoleService implementation
@ -114,4 +128,4 @@ public class LocationApiClient {
}
return uploadService;
}
}
}

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@ import com.example.acloc.activity.AddNewPlaceActivity;
import com.example.acloc.activity.AddReportActivity;
import com.example.acloc.activity.PlaceDetailActivity;
import com.example.acloc.adapter.PlaceReportsAdapter;
import com.example.acloc.adapter.AccessibilityTagsAdapter;
import com.example.acloc.api.LocationApiClient;
import com.example.acloc.model.Place;
import com.example.acloc.model.Report;
@ -29,6 +30,7 @@ import com.example.acloc.utility.Constants;
import com.example.acloc.utility.DialogUtils;
import com.example.acloc.utility.Helper;
import com.example.acloc.utility.SharedPref;
import com.example.acloc.utility.AccessibilityHelper;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
@ -36,11 +38,17 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.ieslamar.acloc.R;
import com.squareup.picasso.Picasso;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
@ -54,9 +62,9 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
private boolean isFavorite = false;
private TextView tvPlaceName, tvAddress, tvDescription, tvNoReports;
private ImageView ivFavorite, ivEdit, ivExpand;
private ImageView ivFavorite, ivEdit, ivExpand, ivPlaceImage;
private AppCompatButton btnAddReport;
private RecyclerView rvReports;
private RecyclerView rvReports, rvAccessibilityOverview;
private PlaceReportsAdapter adapter;
private final List<Report> reportList = new ArrayList<>();
private BottomSheetBehavior<View> behavior;
@ -76,11 +84,9 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
if (bottomSheet != null) {
behavior = BottomSheetBehavior.from(bottomSheet);
//Set initial state to half expanded
behavior.setPeekHeight(getResources().getDisplayMetrics().heightPixels / 2);
behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
//Add callback to update expand/collapse icon
behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
@ -93,7 +99,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// animation based on slide position - do nothing for now
// Do nothing for now
}
});
}
@ -111,7 +117,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
initUI(view);
setPlaceData();
initListeners();
checkIfPlaceIsFavorite(SharedPref.getUserUid(context), place.getUuid());
checkIfPlaceIsFavorite(SharedPref.getUserUuid(context), place.getUuid());
loadReports();
return view;
@ -125,24 +131,70 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
ivFavorite = view.findViewById(R.id.ivFavorite);
ivEdit = view.findViewById(R.id.ivEdit);
ivExpand = view.findViewById(R.id.ivExpand);
ivPlaceImage = view.findViewById(R.id.ivPlaceImage);
btnAddReport = view.findViewById(R.id.btnAddReport);
rvReports = view.findViewById(R.id.rvReports);
rvAccessibilityOverview = view.findViewById(R.id.rvAccessibilityOverview);
rvReports.setLayoutManager(new LinearLayoutManager(context));
rvAccessibilityOverview.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
}
private void setPlaceData() {
tvPlaceName.setText(place.getName());
tvAddress.setText(place.getAddress());
tvDescription.setText(place.getDescription());
// Load place image with better error handling
loadPlaceImage();
}
private void loadPlaceImage() {
if (place.getImage() != null && !place.getImage().isEmpty()) {
try {
JSONArray imageArray = new JSONArray(place.getImage());
if (imageArray.length() > 0) {
String imageUrl = imageArray.getString(0);
// Ensure the URL is properly formatted
if (!imageUrl.startsWith("http")) {
// Assume it's a relative path and prepend base URL
imageUrl = Constants.BASE_URL + imageUrl;
}
ivPlaceImage.setVisibility(View.VISIBLE);
Picasso.get()
.load(imageUrl)
.placeholder(R.drawable.place_header)
.error(R.drawable.place_header)
.fit()
.centerCrop()
.into(ivPlaceImage);
Log.d(TAG, "Loading place image: " + imageUrl);
} else {
setDefaultPlaceImage();
}
} catch (JSONException e) {
Log.e(TAG, "Error parsing place images", e);
setDefaultPlaceImage();
}
} else {
setDefaultPlaceImage();
}
}
private void setDefaultPlaceImage() {
ivPlaceImage.setVisibility(View.VISIBLE);
ivPlaceImage.setImageResource(R.drawable.place_header);
}
private void initListeners() {
ivFavorite.setOnClickListener(v -> {
if (isFavorite) {
removePlaceFromFavorites(SharedPref.getUserUid(context), place.getUuid());
removePlaceFromFavorites(SharedPref.getUserUuid(context), place.getUuid());
} else {
addPlaceToFavorites(SharedPref.getUserUid(context), place.getUuid());
addPlaceToFavorites(SharedPref.getUserUuid(context), place.getUuid());
}
});
@ -166,7 +218,6 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
dismiss();
});
// Open full screen details on click
View.OnClickListener fullScreenListener = v -> {
Helper.goTo(context, PlaceDetailActivity.class, Constants.PLACE, place);
dismiss();
@ -175,6 +226,7 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
tvPlaceName.setOnClickListener(fullScreenListener);
tvAddress.setOnClickListener(fullScreenListener);
tvDescription.setOnClickListener(fullScreenListener);
ivPlaceImage.setOnClickListener(fullScreenListener);
}
private void loadReports() {
@ -194,16 +246,15 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
for (JsonElement element : data.getAsJsonArray("reports")) {
Report report = getReport(element);
reportList.add(report);
}
// Show latest reports first
Collections.reverse(reportList);
List<Report> latestReports = reportList.size() > 3 ?
reportList.subList(0, 3) : reportList;
updateReportsUI(latestReports);
calculateAndShowAccessibilityStats(reportList);
} else {
showNoReports();
}
@ -228,9 +279,118 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
report.setDescription(reportObject.get("description").getAsString());
report.setPlaceName(reportObject.get("place_name").getAsString());
report.setPlaceUuid(reportObject.get("place_uuid").getAsString());
List<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;
}
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) {
if (reports != null && !reports.isEmpty()) {
adapter = new PlaceReportsAdapter(context, reports);
@ -244,9 +404,35 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
private void showNoReports() {
rvReports.setVisibility(View.GONE);
rvAccessibilityOverview.setVisibility(View.GONE);
tvNoReports.setVisibility(View.VISIBLE);
}
// Helper class for accessibility statistics
private static class AccessibilityStats {
String typeName;
int count = 0;
int totalRating = 0;
AccessibilityStats(String typeName) {
this.typeName = typeName;
}
void addRating(int rating) {
count++;
totalRating += rating;
}
int getAverageRating() {
if (count == 0) return Constants.AVERAGE_RATING;
double average = (double) totalRating / count;
if (average <= 1.5) return Constants.BAD_RATING;
if (average <= 2.5) return Constants.AVERAGE_RATING;
return Constants.GOOD_RATING;
}
}
private void checkIfPlaceIsFavorite(String userUuid, String placeUuid) {
String token = "Bearer " + SharedPref.getAccessToken(context);
FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService();
@ -314,7 +500,6 @@ public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
if (response.errorBody() != null) {
String errorBody = response.errorBody().string();
// Try restoring if it's a duplicate (409 Conflict) or it isn't found (deleted)
if ((response.code() == 409 && errorBody.contains("ER_DUP_ENTRY"))|| response.code() == 404 ) {
restorePlaceToFavorites(userUuid, placeUuid);
return;

View File

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

View File

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

View File

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

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
* @return JsonObject containing updated report information
*/
@PUT("/reports/{uuid}")
@PUT("reports/{uuid}")
Call<JsonObject> updateReport(
@Header("Authorization") String token,
@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

@ -1 +1 @@
package com.example.acloc.utility;
package com.example.acloc.utility;

View File

@ -249,7 +249,7 @@ public class Helper {
}
// Regex for strong password validation
String passwordPattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{6,}$";
String passwordPattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&.])[A-Za-z\\d@$!%*?&.]{6,}$";
if (!passwordText.matches(passwordPattern)) {
if (textInputLayout != null) {
@ -360,4 +360,3 @@ public class Helper {
return new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
}
}

View File

@ -44,4 +44,4 @@ public class ImageLoaderUtil {
.into(targetView);
}
}
}
}

View File

@ -103,4 +103,4 @@ public class ImagePicker {
// MultipartBody.Part is used to send the actual file
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}
}
}

View File

@ -29,4 +29,4 @@ public class KeyGeneratorUtils {
// Combine timestamp and random string
return timeStamp + "_" + randomStr.toString();
}
}
}

View File

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

View File

@ -8,4 +8,4 @@
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
</set>

View File

@ -8,4 +8,4 @@
android:duration="300"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
</set>

View File

@ -8,4 +8,4 @@
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
</set>

View File

@ -8,4 +8,4 @@
android:duration="300"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
</set>

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

@ -27,4 +27,4 @@
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
</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

@ -3,4 +3,4 @@
<solid android:color="?attr/colorPrimary"/>
<corners android:radius="50px"/>
<stroke android:width="1dip" android:color="?attr/colorPrimary"/>
</shape>
</shape>

View File

@ -3,4 +3,4 @@
<solid android:color="@android:color/transparent"/>
<corners android:radius="1px"/>
<stroke android:width="1dip" android:color="?attr/colorPrimary"/>
</shape>
</shape>

View File

@ -141,4 +141,4 @@
android:text="@string/SUBMIT"
android:textColor="?attr/colorOnPrimary"
tools:ignore="HardcodedText" />
</RelativeLayout>
</RelativeLayout>

View File

@ -1,321 +1,324 @@
<?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:tools="http://schemas.android.com/tools"
android:id="@+id/rlAddReport"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.acloc.activity.AddReportActivity">
android:fillViewport="true">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<ScrollView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/btnSubmitContainer"
android:layout_below="@id/toolbar"
android:fillViewport="true"
android:fitsSystemWindows="true"
android:clipToPadding="false"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
<!-- Place Info Card -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_marginTop="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<!-- Report Form Card -->
<com.google.android.material.card.MaterialCardView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
android:orientation="vertical"
android:padding="16dp">
<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
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
android:baselineAligned="false"
android:orientation="horizontal"
android:gravity="center">
<!-- Header -->
<TextView
android:layout_width="match_parent"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/add_report"
android:textSize="20sp"
android:textStyle="bold"
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">
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/ivReportPhoto"
android:layout_width="@dimen/image_view_width"
android:layout_height="@dimen/image_view_height"
android:padding="@dimen/content_padding"
android:background="@drawable/rectangle"
android:importantForAccessibility="no"
android:importantForAutofill="no"
android:src="@drawable/logo_add_location" />
</com.google.android.material.card.MaterialCardView>
android:id="@+id/ivThumbsDown"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_margin="8dp"
android:src="@drawable/ic_thumbs_down"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="12dp"
android:contentDescription="@string/BAD" />
<TextView
android:layout_width="match_parent"
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"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:hint="@string/Enter_Place_Name"
android:importantForAutofill="no"
android:inputType="text"
tools:ignore="HardcodedText" />
</com.google.android.material.textfield.TextInputLayout>
android:text="@string/BAD"
android:textSize="12sp"
android:textColor="?attr/colorOnSurfaceVariant"/>
<!-- 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
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>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</ScrollView>
<!-- Submit Button Container -->
<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">
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSubmit"
</com.google.android.material.card.MaterialCardView>
<!-- Description -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/SUBMIT"
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/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"
app:cornerRadius="8dp"
tools:ignore="HardcodedText" />
</FrameLayout>
</RelativeLayout>
android:backgroundTint="@color/primaryColor_dark"
app:cornerRadius="12dp"
android:padding="16dp" />
</LinearLayout>
</ScrollView>

View File

@ -173,4 +173,4 @@
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
</RelativeLayout>

View File

@ -31,4 +31,4 @@
app:itemIconTint="?attr/colorOnBackground"
app:itemTextColor="?attr/colorOnBackground"
app:menu="@menu/menu_bottom_navigation" />
</RelativeLayout>
</RelativeLayout>

View File

@ -44,4 +44,4 @@
tools:listitem="@layout/list_view_users" />
</RelativeLayout>
</RelativeLayout>

View File

@ -242,4 +242,4 @@
android:text="@string/ADD_REPORT"
android:textColor="?attr/colorOnPrimary" />
</RelativeLayout>
</RelativeLayout>

View File

@ -216,4 +216,4 @@
tools:ignore="HardcodedText" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</RelativeLayout>
</RelativeLayout>

View File

@ -85,4 +85,4 @@
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -83,4 +83,4 @@
</LinearLayout>
</RelativeLayout>
</RelativeLayout>

View File

@ -12,6 +12,17 @@
android:orientation="vertical"
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 -->
<RelativeLayout
android:layout_width="match_parent"
@ -90,6 +101,29 @@
android:text="@string/Add_Report" />
</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 -->
<View
android:layout_width="match_parent"

View File

@ -24,4 +24,4 @@
android:textAlignment="center"
tools:ignore="HardcodedText" />
</FrameLayout>
</FrameLayout>

View File

@ -51,4 +51,4 @@
android:elevation="4dp"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>

View File

@ -42,4 +42,4 @@
app:iconTint="?attr/colorOnPrimary"/>
</FrameLayout>
</FrameLayout>

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:padding="12dp">
<!-- Report Description -->
<TextView
android:id="@+id/tvDescription"
android:layout_width="match_parent"
@ -21,30 +22,70 @@
android:ellipsize="end"
android:maxLines="3"
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
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="vertical">
<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/primaryColor_dark" />
<TextView
android:id="@+id/tvRating"
android:layout_width="wrap_content"
<!-- Rating Row -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textStyle="bold"
tools:text="GOOD" />
android:gravity="center_vertical"
android:orientation="horizontal">
<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>
</androidx.cardview.widget.CardView>

View File

@ -8,4 +8,4 @@
android:textColor="?attr/colorOnPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.DayNight"
app:titleTextColor="?attr/colorOnPrimary" />
app:titleTextColor="?attr/colorOnPrimary" />

View File

@ -15,4 +15,4 @@
android:icon="@drawable/ic_favorite"
android:title="@string/Favorite" />
</menu>
</menu>

View File

@ -32,4 +32,4 @@
android:title="@string/Logout"
app:iconTint="?attr/colorError" />
</menu>
</menu>

View File

@ -2,4 +2,4 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
</adaptive-icon>

View File

@ -2,4 +2,4 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
</adaptive-icon>

View File

@ -174,6 +174,46 @@
<string name="please">Por favor</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="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>
</resources>
<!-- 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>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="bottom_sheet_peek_height" type="dimen">50%</item>
</resources>
</resources>

View File

@ -22,4 +22,4 @@
</style>
<item name="bottom_sheet_peek_height" type="dimen">50%</item>
</resources>
</resources>

View File

@ -4,11 +4,11 @@
<color name="white">#FFFFFFFF</color>
<!-- 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>
<!-- 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>
<!-- Accessibility Status Colors -->
@ -17,12 +17,12 @@
<color name="notAccessibleColor">#C62828</color>
<!-- Background Colors -->
<color name="backgroundColor_light">#FAFAFA</color> <!-- Light background for bright theme -->
<color name="backgroundColor_dark">#121212</color> <!-- Dark background for dark mode -->
<color name="backgroundColor_light">#FAFAFA</color>
<color name="backgroundColor_dark">#121212</color>
<!-- Surface Colors -->
<color name="surfaceColor_light">#FFFFFF</color> <!-- Surface for light theme -->
<color name="surfaceColor_dark">#040404</color> <!-- Surface for dark theme --> <!--changed -->
<color name="surfaceColor_light">#FFFFFF</color>
<color name="surfaceColor_dark">#040404</color>
<!-- Text & Icon Colors -->
<color name="onPrimaryColor_light">#FFFFFF</color>
@ -31,20 +31,19 @@
<color name="onSecondaryColor_light">#000000</color>
<color name="onSecondaryColor_dark">#FFFFFF</color>
<color name="onBackgroundColor_light">#212121
</color> <!-- Light Gray: soft background (cards/app bg) -->
<color name="onBackgroundColor_light">#212121</color>
<color name="onBackgroundColor_dark">#E0E0E0</color>
<color name="onSurfaceColor_light">#212121</color> <!-- Dark text on surface -->
<color name="onSurfaceColor_dark">#F5F5F5</color> <!-- Light Gray for dark surfaces -->
<color name="onSurfaceColor_light">#212121</color>
<color name="onSurfaceColor_dark">#F5F5F5</color>
<!-- Error Colors -->
<color name="errorColor_light">#C62828</color> <!-- Error red in light mode -->
<color name="errorColor_dark">#F44336</color> <!-- Error red in dark mode -->
<color name="errorColor_light">#C62828</color>
<color name="errorColor_dark">#F44336</color>
<!-- Accent / Highlight -->
<color name="accentColor_light">#FF4081</color> <!-- Bright pink: attention-grabbing -->
<color name="accentColor_dark">#C51162</color> <!-- Darker pink for dark mode -->
<color name="accentColor_light">#FF4081</color>
<color name="accentColor_dark">#C51162</color>
<color name="colorTertiary_light">#e8edf6</color>
<color name="colorTertiary_dark">#232324</color>
@ -56,4 +55,25 @@
<color name="red">#F44336</color>
<color name="light_blue">#e8edf6</color>
</resources>
<!-- 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>

View File

@ -48,4 +48,4 @@
<dimen name="fab_margin">16dp</dimen>
<dimen name="appbar_padding_top">8dp</dimen>
</resources>
</resources>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>
</resources>

View File

@ -1,182 +1,224 @@
<resources>
<string name="app_name">AcLoc - Accessible Locations Application</string>
<string name="app_name">AcLoc - Accessible Locations Application</string>
<!-- BUTTON TITLE -->
<string name="LOGIN">LOGIN</string>
<string name="REGISTER">REGISTER</string>
<string name="SAVE_PLACE">SAVE PLACE</string>
<string name="UPDATE">UPDATE</string>
<string name="CANCEL">CANCEL</string>
<string name="SUBMIT">SUBMIT</string>
<string name="ADD_REPORT">ADD REPORT</string>
<!-- BUTTON TITLE -->
<string name="LOGIN">LOGIN</string>
<string name="REGISTER">REGISTER</string>
<string name="SAVE_PLACE">SAVE PLACE</string>
<string name="UPDATE">UPDATE</string>
<string name="CANCEL">CANCEL</string>
<string name="SUBMIT">SUBMIT</string>
<string name="ADD_REPORT">ADD REPORT</string>
<!-- toolbar -->
<string name="Add_Report">Add Report</string>
<string name="Place_Details">Place Details</string>
<string name="Add_Place">Add Place</string>
<!-- toolbar -->
<string name="Add_Report">Add Report</string>
<string name="Place_Details">Place Details</string>
<string name="Add_Place">Add Place</string>
<!-- edittext -->
<string name="Enter_Username">Enter Username</string>
<string name="Enter_Password">Enter Password</string>
<string name="Enter_Email">Enter Email</string>
<string name="Enter_Name">Enter Name</string>
<string name="Enter_Location">Enter Location</string>
<string name="Enter_Contact">Enter Contact</string>
<string name="Already_have_an_Account">"Already have an Account? </string>
<string name="Please_login">Please login</string>
<string name="Please_register">Please register</string>
<string name="Dont_have_an_Account">Don\'t have an Account? </string>
<string name="Favorite">Favorite</string>
<string name="My_Report">My Report</string>
<string name="Map">Map</string>
<string name="Profile">Profile</string>
<string name="Change_Password">Change Password</string>
<string name="Manage_Roles">Manage Roles</string>
<string name="Change_Language">Change Language</string>
<string name="Logout">Logout</string>
<string name="Enter_Place_Name">Enter Place Name</string>
<string name="Enter_Latitude">Enter Latitude</string>
<string name="Enter_Longitude">Enter Longitude</string>
<string name="Enter_Address">Enter Address</string>
<string name="Enter_Place_Description">Enter Place Description</string>
<string name="Search_Place">Search Place</string>
<string name="Enter_Old_Password">Enter Old Password</string>
<string name="Enter_New_Password">Enter New Password</string>
<string name="Place_Name">Place Name</string>
<string name="Address">Address</string>
<string name="Place_Description">Place Description</string>
<string name="Enter_Description">Enter Description</string>
<string name="Report_Description">Report Description</string>
<string name="Report">Reports</string>
<string name="Search_User">Search User</string>
<string name="User">User</string>
<string name="Role">Role</string>
<string name="Change_Role">Change Role</string>
<!-- edittext -->
<string name="Enter_Username">Enter Username</string>
<string name="Enter_Password">Enter Password</string>
<string name="Enter_Email">Enter Email</string>
<string name="Enter_Name">Enter Name</string>
<string name="Enter_Location">Enter Location</string>
<string name="Enter_Contact">Enter Contact</string>
<string name="Already_have_an_Account">"Already have an Account? </string>
<string name="Please_login">Please login</string>
<string name="Please_register">Please register</string>
<string name="Dont_have_an_Account">Don\'t have an Account? </string>
<string name="Favorite">Favorite</string>
<string name="My_Report">My Report</string>
<string name="Map">Map</string>
<string name="Profile">Profile</string>
<string name="Change_Password">Change Password</string>
<string name="Manage_Roles">Manage Roles</string>
<string name="Change_Language">Change Language</string>
<string name="Logout">Logout</string>
<string name="Enter_Place_Name">Enter Place Name</string>
<string name="Enter_Latitude">Enter Latitude</string>
<string name="Enter_Longitude">Enter Longitude</string>
<string name="Enter_Address">Enter Address</string>
<string name="Enter_Place_Description">Enter Place Description</string>
<string name="Search_Place">Search Place</string>
<string name="Enter_Old_Password">Enter Old Password</string>
<string name="Enter_New_Password">Enter New Password</string>
<string name="Place_Name">Place Name</string>
<string name="Address">Address</string>
<string name="Place_Description">Place Description</string>
<string name="Enter_Description">Enter Description</string>
<string name="Report_Description">Report Description</string>
<string name="Report">Reports</string>
<string name="Search_User">Search User</string>
<string name="User">User</string>
<string name="Role">Role</string>
<string name="Change_Role">Change Role</string>
<!--TextView-->
<string name="GOOD">GOOD</string>
<string name="AVERAGE">AVERAGE</string>
<string name="BAD">BAD</string>
<!--TextView-->
<string name="GOOD">GOOD</string>
<string name="AVERAGE">AVERAGE</string>
<string name="BAD">BAD</string>
<!-- Alert dialog -->
<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="confirmation_message">Are you sure you want to %1$s?\nWARNING: This action cannot be undone</string>
<string name="yes">Yes</string>
<string name="no">No</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="Go_to_Settings">Go to Settings</string>
<string name="Exit_App">Exit App</string>
<!-- Alert dialog -->
<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="confirmation_message">Are you sure you want to %1$s?\nWARNING: This action cannot be undone</string>
<string name="yes">Yes</string>
<string name="no">No</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="Go_to_Settings">Go to Settings</string>
<string name="Exit_App">Exit App</string>
<!-- Snackbar text -->
<string name="Something_went_wrong">Something went wrong!!!</string>
<string name="Login_failed">Login failed</string>
<string name="Invalid_Credentials_Please_try_again">Invalid Credentials. Please try again.</string>
<string name="Login_Successful">Login Successful</string>
<string name="Please_wait">Please wait…</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="Registration_Successful">Registration Successful</string>
<string name="Try_again_later">Try again later</string>
<string name="Update_Failed">Update Failed </string>
<string name="Something_went_wrong_Try_again">Something went wrong. Try again.</string>
<string name="Updating">Updating…</string>
<string name="Invalid_old_password">Invalid old password</string>
<string name="Network_error_Try_again">Network error. Try again.</string>
<string name="Changing_password">Changing password…</string>
<string name="Password_updated_successfully">Password updated successfully!</string>
<string name="Password_update_failed">Password update failed.</string>
<string name="Verifying_old_password">Verifying old password…</string>
<string name="Change_Role_to">change Role to </string>
<string name="Updating_Role">Updating Roles…</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="Rating_BAD">Rating: BAD</string>
<string name="Rating_AVERAGE">Rating: AVERAGE</string>
<string name="Rating_GOOD">Rating: GOOD</string>
<string name="Delete_report">Delete report</string>
<string name="Removing_Report">Removing Report…</string>
<string name="Report_removed">Report removed!</string>
<string name="Failed_to_remove_report">Failed to remove report</string>
<string name="Removing_from_favorites">Removing from favorites…</string>
<string name="Favorite_removed">Favorite removed</string>
<string name="Failed_to_remove_Favorite">Failed to remove Favorite</string>
<string name="Loading_Favorites">Loading favorites…</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="Location_permission_is_required">Location permission is required</string>
<string name="Failed_to_load_places">Failed to load places</string>
<string name="Loading_reports">Loading reports…</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="Place_updated_successfully">Place updated successfully!</string>
<string name="Updating_place">Updating place…</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="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_submitted_successfully">Report submitted successfully!</string>
<string name="Please_select_rating">Please select rating!</string>
<string name="Updating_report">Updating report…</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="No_users_found">No users found</string>
<string name="Loading_users">Loading users…</string>
<string name="Adding_to_favorites">Adding 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="Restoring_favorite">Restoring favorite…</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="Removed_from_favorites">Removed 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="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>-->
<!-- <string name="Logout">Logout</string>-->
<!-- Snackbar text -->
<string name="Something_went_wrong">Something went wrong!!!</string>
<string name="Login_failed">Login failed</string>
<string name="Invalid_Credentials_Please_try_again">Invalid Credentials. Please try again.</string>
<string name="Login_Successful">Login Successful</string>
<string name="Please_wait">Please wait…</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="Registration_Successful">Registration Successful</string>
<string name="Try_again_later">Try again later</string>
<string name="Update_Failed">Update Failed </string>
<string name="Something_went_wrong_Try_again">Something went wrong. Try again.</string>
<string name="Updating">Updating…</string>
<string name="Invalid_old_password">Invalid old password</string>
<string name="Network_error_Try_again">Network error. Try again.</string>
<string name="Changing_password">Changing password…</string>
<string name="Password_updated_successfully">Password updated successfully!</string>
<string name="Password_update_failed">Password update failed.</string>
<string name="Verifying_old_password">Verifying old password…</string>
<string name="Change_Role_to">change Role to </string>
<string name="Updating_Role">Updating Roles…</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="Rating_BAD">Rating: BAD</string>
<string name="Rating_AVERAGE">Rating: AVERAGE</string>
<string name="Rating_GOOD">Rating: GOOD</string>
<string name="Delete_report">Delete report</string>
<string name="Removing_Report">Removing Report…</string>
<string name="Report_removed">Report removed!</string>
<string name="Failed_to_remove_report">Failed to remove report</string>
<string name="Removing_from_favorites">Removing from favorites…</string>
<string name="Favorite_removed">Favorite removed</string>
<string name="Failed_to_remove_Favorite">Failed to remove Favorite</string>
<string name="Loading_Favorites">Loading favorites…</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="Location_permission_is_required">Location permission is required</string>
<string name="Failed_to_load_places">Failed to load places</string>
<string name="Loading_reports">Loading reports…</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="Place_updated_successfully">Place updated successfully!</string>
<string name="Updating_place">Updating place…</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="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_submitted_successfully">Report submitted successfully!</string>
<string name="Updating_report">Updating report…</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="No_users_found">No users found</string>
<string name="Loading_users">Loading users…</string>
<string name="Adding_to_favorites">Adding 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="Restoring_favorite">Restoring favorite…</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="Removed_from_favorites">Removed 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="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="tap_to_add_photo">Tap to add photo</string>
<string name="location_details">Location Details</string>
<string name="additional_information">Additional Information</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="welcome_back">Welcome Back</string>
<string name="sign_in_to_continue">Sign in to continue</string>
<string name="expand">Expand</string>
<string name="address">Address</string>
<string name="description">Description</string>
<string name="edit">Edit</string>
<string name="recent_reports">Recent Reports</string>
<string name="no_reports_yet">No reports about this place yet</string>
<string name="details">Details</string>
<string name="add_to_favorites">Add to favorites</string>
<string name="image_uploaded_successfully">Image uploaded successfully</string>
<string name="upload_failed">Upload failed</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="location_not_found">Location not found</string>
<string name="invalid_email_address">Invalid email address</string>
<string name="please">Please</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="add_new_location">Add New Location</string>
<string name="tap_to_add_photo">Tap to add photo</string>
<string name="location_details">Location Details</string>
<string name="additional_information">Additional Information</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="welcome_back">Welcome Back</string>
<string name="sign_in_to_continue">Sign in to continue</string>
<string name="expand">Expand</string>
<string name="address">Address</string>
<string name="description">Description</string>
<string name="edit">Edit</string>
<string name="recent_reports">Recent Reports</string>
<string name="no_reports_yet">No reports about this place yet</string>
<string name="details">Details</string>
<string name="add_to_favorites">Add to favorites</string>
<string name="image_uploaded_successfully">Image uploaded successfully</string>
<string name="upload_failed">Upload failed</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="location_not_found">Location not found</string>
<string name="invalid_email_address">Invalid email address</string>
<string name="please">Please</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>
</resources>
<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>

View File

@ -33,4 +33,4 @@
</style>
<item name="bottom_sheet_peek_height" type="dimen">50%</item>
</resources>
</resources>

View File

@ -10,4 +10,4 @@
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>
</full-backup-content>

View File

@ -16,4 +16,4 @@
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>
</data-extraction-rules>