Updated UI regarding place visualization in map
This commit is contained in:
parent
3e167da742
commit
598978ee15
|
|
@ -86,16 +86,12 @@ public class MyReportsAdapter extends RecyclerView.Adapter<MyReportsAdapter.View
|
||||||
AlertDialog dialog = DialogUtils.confirmationDialog(
|
AlertDialog dialog = DialogUtils.confirmationDialog(
|
||||||
context,
|
context,
|
||||||
confirmationText,
|
confirmationText,
|
||||||
(dialogInterface, i) -> {
|
(dialogInterface, i) -> removeReport(report.getUuid())
|
||||||
removeReport(report.getUuid());
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
holder.ivEdit.setOnClickListener(v -> {
|
holder.ivEdit.setOnClickListener(v -> Helper.goTo(context, AddReportActivity.class, Constants.REPORT, report));
|
||||||
Helper.goTo(context, AddReportActivity.class, Constants.REPORT, report);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Error in MyReports Adapter", e);
|
Log.e(TAG, "Error in MyReports Adapter", e);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapte
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.reportList = reportList;
|
this.reportList = reportList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearReports() {
|
public void clearReports() {
|
||||||
reportList.clear();
|
reportList.clear();
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
|
|
@ -60,14 +61,14 @@ public class PlaceReportsAdapter extends RecyclerView.Adapter<PlaceReportsAdapte
|
||||||
holder.tvDescription.setText(report.getDescription());
|
holder.tvDescription.setText(report.getDescription());
|
||||||
if (report.getReportRating() == 1) {
|
if (report.getReportRating() == 1) {
|
||||||
holder.tvRating.setText(context.getString(R.string.Rating_BAD));
|
holder.tvRating.setText(context.getString(R.string.Rating_BAD));
|
||||||
holder.ivRating.setImageResource(R.drawable.ic_thumbs_down);} else if (report.getReportRating() == 2) {
|
holder.ivRating.setImageResource(R.drawable.ic_thumbs_down);
|
||||||
|
} else if (report.getReportRating() == 2) {
|
||||||
holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE));
|
holder.tvRating.setText(context.getString(R.string.Rating_AVERAGE));
|
||||||
holder.ivRating.setImageResource(R.drawable.ic_thumb_up_average);
|
holder.ivRating.setImageResource(R.drawable.ic_thumb_up_average);
|
||||||
} else if (report.getReportRating() == 3) {
|
} else if (report.getReportRating() == 3) {
|
||||||
holder.tvRating.setText(context.getString(R.string.Rating_GOOD));
|
holder.tvRating.setText(context.getString(R.string.Rating_GOOD));
|
||||||
holder.ivRating.setImageResource(R.drawable.ic_thumbs_up);
|
holder.ivRating.setImageResource(R.drawable.ic_thumbs_up);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Error in PlaceReportsAdapter", e);
|
Log.e(TAG, "Error in PlaceReportsAdapter", e);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,374 @@
|
||||||
|
package com.example.acloc.dialog;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.widget.AppCompatButton;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
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.api.LocationApiClient;
|
||||||
|
import com.example.acloc.model.Place;
|
||||||
|
import com.example.acloc.model.Report;
|
||||||
|
import com.example.acloc.service.FavoriteService;
|
||||||
|
import com.example.acloc.service.ReportService;
|
||||||
|
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.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.ieslamar.acloc.R;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class PlaceBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
|
private static final String TAG = "PlaceBottomSheetDialog";
|
||||||
|
|
||||||
|
private final Place place;
|
||||||
|
private Context context;
|
||||||
|
private boolean isFavorite = false;
|
||||||
|
|
||||||
|
private TextView tvPlaceName, tvAddress, tvDescription, tvNoReports;
|
||||||
|
private ImageView ivFavorite, ivEdit, ivExpand;
|
||||||
|
private AppCompatButton btnAddReport;
|
||||||
|
private RecyclerView rvReports;
|
||||||
|
private PlaceReportsAdapter adapter;
|
||||||
|
private final List<Report> reportList = new ArrayList<>();
|
||||||
|
private BottomSheetBehavior<View> behavior;
|
||||||
|
|
||||||
|
public PlaceBottomSheetDialog(Place place) {
|
||||||
|
this.place = place;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
|
BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
|
||||||
|
|
||||||
|
dialog.setOnShowListener(dialogInterface -> {
|
||||||
|
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialogInterface;
|
||||||
|
View bottomSheet = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
|
||||||
|
if (bottomSheet != null) {
|
||||||
|
behavior = BottomSheetBehavior.from(bottomSheet);
|
||||||
|
behavior.setPeekHeight(getResources().getDisplayMetrics().heightPixels / 2);
|
||||||
|
behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.bottom_sheet_place_detail, container, false);
|
||||||
|
context = getContext();
|
||||||
|
|
||||||
|
initUI(view);
|
||||||
|
setPlaceData();
|
||||||
|
initListeners();
|
||||||
|
checkIfPlaceIsFavorite(SharedPref.getUserUid(context), place.getUuid());
|
||||||
|
loadReports();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initUI(View view) {
|
||||||
|
tvPlaceName = view.findViewById(R.id.tvPlaceName);
|
||||||
|
tvAddress = view.findViewById(R.id.tvAddress);
|
||||||
|
tvDescription = view.findViewById(R.id.tvDescription);
|
||||||
|
tvNoReports = view.findViewById(R.id.tvNoData);
|
||||||
|
ivFavorite = view.findViewById(R.id.ivFavorite);
|
||||||
|
ivEdit = view.findViewById(R.id.ivEdit);
|
||||||
|
ivExpand = view.findViewById(R.id.ivExpand);
|
||||||
|
btnAddReport = view.findViewById(R.id.btnAddReport);
|
||||||
|
rvReports = view.findViewById(R.id.rvReports);
|
||||||
|
|
||||||
|
// Set up RecyclerView
|
||||||
|
rvReports.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPlaceData() {
|
||||||
|
tvPlaceName.setText(place.getName());
|
||||||
|
tvAddress.setText(place.getAddress());
|
||||||
|
tvDescription.setText(place.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initListeners() {
|
||||||
|
ivFavorite.setOnClickListener(v -> {
|
||||||
|
if (isFavorite) {
|
||||||
|
removePlaceFromFavorites(SharedPref.getUserUid(context), place.getUuid());
|
||||||
|
} else {
|
||||||
|
addPlaceToFavorites(SharedPref.getUserUid(context), place.getUuid());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ivEdit.setOnClickListener(v -> {
|
||||||
|
Helper.goTo(context, AddNewPlaceActivity.class, Constants.PLACE, place);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
ivExpand.setOnClickListener(v -> {
|
||||||
|
if (behavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
behavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
|
||||||
|
ivExpand.setImageResource(R.drawable.ic_expand_less);
|
||||||
|
} else {
|
||||||
|
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||||
|
ivExpand.setImageResource(R.drawable.ic_expand_more);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
btnAddReport.setOnClickListener(v -> {
|
||||||
|
Helper.goTo(context, AddReportActivity.class, Constants.PLACE, place);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open full screen details on click
|
||||||
|
View.OnClickListener fullScreenListener = v -> {
|
||||||
|
Helper.goTo(context, PlaceDetailActivity.class, Constants.PLACE, place);
|
||||||
|
dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
tvPlaceName.setOnClickListener(fullScreenListener);
|
||||||
|
tvAddress.setOnClickListener(fullScreenListener);
|
||||||
|
tvDescription.setOnClickListener(fullScreenListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadReports() {
|
||||||
|
String token = "Bearer " + SharedPref.getAccessToken(context);
|
||||||
|
ReportService reportService = LocationApiClient.getInstance().getReportService();
|
||||||
|
|
||||||
|
Call<JsonObject> call = reportService.getPlaceReports(token, place.getUuid());
|
||||||
|
call.enqueue(new Callback<JsonObject>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
JsonObject responseBody = response.body();
|
||||||
|
JsonObject data = responseBody.getAsJsonObject("_data");
|
||||||
|
|
||||||
|
if (data != null && data.has("reports")) {
|
||||||
|
reportList.clear();
|
||||||
|
|
||||||
|
for (JsonElement element : data.getAsJsonArray("reports")) {
|
||||||
|
JsonObject reportObject = element.getAsJsonObject();
|
||||||
|
Report report = new Report();
|
||||||
|
|
||||||
|
report.setUuid(reportObject.get("uuid").getAsString());
|
||||||
|
report.setReportRating(reportObject.get("rating").getAsInt());
|
||||||
|
report.setDescription(reportObject.get("description").getAsString());
|
||||||
|
report.setPlaceName(reportObject.get("place_name").getAsString());
|
||||||
|
report.setPlaceUuid(reportObject.get("place_uuid").getAsString());
|
||||||
|
|
||||||
|
reportList.add(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show latest reports first
|
||||||
|
Collections.reverse(reportList);
|
||||||
|
List<Report> latestReports = reportList.size() > 3 ?
|
||||||
|
reportList.subList(0, 3) : reportList;
|
||||||
|
|
||||||
|
updateReportsUI(latestReports);
|
||||||
|
} else {
|
||||||
|
showNoReports();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showNoReports();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
|
showNoReports();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateReportsUI(List<Report> reports) {
|
||||||
|
if (reports != null && !reports.isEmpty()) {
|
||||||
|
adapter = new PlaceReportsAdapter(context, reports);
|
||||||
|
rvReports.setAdapter(adapter);
|
||||||
|
rvReports.setVisibility(View.VISIBLE);
|
||||||
|
tvNoReports.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
showNoReports();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showNoReports() {
|
||||||
|
rvReports.setVisibility(View.GONE);
|
||||||
|
tvNoReports.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIfPlaceIsFavorite(String userUuid, String placeUuid) {
|
||||||
|
String token = "Bearer " + SharedPref.getAccessToken(context);
|
||||||
|
FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService();
|
||||||
|
|
||||||
|
Call<JsonObject> call = favoriteService.getFavoritePlaces(token, userUuid);
|
||||||
|
call.enqueue(new Callback<JsonObject>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
JsonObject body = response.body();
|
||||||
|
JsonArray favoritesArray = body.getAsJsonObject("_data").getAsJsonArray("favorites");
|
||||||
|
|
||||||
|
isFavorite = false;
|
||||||
|
for (JsonElement item : favoritesArray) {
|
||||||
|
JsonObject favoriteObj = item.getAsJsonObject();
|
||||||
|
String favPlaceUuid = favoriteObj.get("place_uuid").getAsString();
|
||||||
|
if (favPlaceUuid.equals(placeUuid)) {
|
||||||
|
isFavorite = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFavoriteIcon();
|
||||||
|
} else {
|
||||||
|
isFavorite = false;
|
||||||
|
updateFavoriteIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
|
isFavorite = false;
|
||||||
|
updateFavoriteIcon();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFavoriteIcon() {
|
||||||
|
if (isFavorite) {
|
||||||
|
ivFavorite.setImageResource(R.drawable.ic_favorite);
|
||||||
|
} else {
|
||||||
|
ivFavorite.setImageResource(R.drawable.ic_favorite_border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPlaceToFavorites(String userUuid, String placeUuid) {
|
||||||
|
DialogUtils.showLoadingDialog(context, getString(R.string.Adding_to_favorites));
|
||||||
|
|
||||||
|
JsonObject body = new JsonObject();
|
||||||
|
body.addProperty("place_uuid", placeUuid);
|
||||||
|
|
||||||
|
String token = "Bearer " + SharedPref.getAccessToken(context);
|
||||||
|
FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService();
|
||||||
|
|
||||||
|
Call<JsonObject> call = favoriteService.restorePlaceToFavorites(token, userUuid, body);
|
||||||
|
call.enqueue(new Callback<JsonObject>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
|
DialogUtils.dismissDialog();
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
isFavorite = true;
|
||||||
|
updateFavoriteIcon();
|
||||||
|
Helper.showToast(context, getString(R.string.Place_added_to_favorites));
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (response.errorBody() != null) {
|
||||||
|
String errorBody = response.errorBody().string();
|
||||||
|
|
||||||
|
// Try restoring if it's a duplicate (409 Conflict)
|
||||||
|
if (response.code() == 409 && errorBody.contains("ER_DUP_ENTRY")) {
|
||||||
|
restorePlaceToFavorites(userUuid, placeUuid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "ERROR: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Helper.showToast(context, getString(R.string.Failed_to_add_favorite_Server_error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
|
DialogUtils.dismissDialog();
|
||||||
|
Helper.showToast(context, getString(R.string.Network_error_Try_again));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restorePlaceToFavorites(String userUuid, String placeUuid) {
|
||||||
|
DialogUtils.showLoadingDialog(context, getString(R.string.Restoring_favorite));
|
||||||
|
|
||||||
|
JsonObject body = new JsonObject();
|
||||||
|
body.addProperty("place_uuid", placeUuid);
|
||||||
|
|
||||||
|
String token = "Bearer " + SharedPref.getAccessToken(context);
|
||||||
|
FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService();
|
||||||
|
|
||||||
|
Call<JsonObject> call = favoriteService.restorePlaceToFavorites(token, userUuid, body);
|
||||||
|
call.enqueue(new Callback<JsonObject>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
|
||||||
|
DialogUtils.dismissDialog();
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
isFavorite = true;
|
||||||
|
updateFavoriteIcon();
|
||||||
|
Helper.showToast(context, getString(R.string.Place_restored_to_favorites));
|
||||||
|
} else {
|
||||||
|
Helper.showToast(context, getString(R.string.Failed_to_restore_favorite));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<JsonObject> call, Throwable t) {
|
||||||
|
DialogUtils.dismissDialog();
|
||||||
|
Helper.showToast(context, getString(R.string.Network_error_Try_again));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removePlaceFromFavorites(String userUuid, String placeUuid) {
|
||||||
|
DialogUtils.showLoadingDialog(context, getString(R.string.Removing_from_favorites));
|
||||||
|
|
||||||
|
String token = "Bearer " + SharedPref.getAccessToken(context);
|
||||||
|
FavoriteService favoriteService = LocationApiClient.getInstance().getFavoriteService();
|
||||||
|
|
||||||
|
Call<Void> call = favoriteService.removePlaceFromFavorites(token, userUuid, placeUuid);
|
||||||
|
call.enqueue(new Callback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<Void> call, Response<Void> response) {
|
||||||
|
DialogUtils.dismissDialog();
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
isFavorite = false;
|
||||||
|
updateFavoriteIcon();
|
||||||
|
Helper.showToast(context, getString(R.string.Removed_from_favorites));
|
||||||
|
} else {
|
||||||
|
Helper.showToast(context, getString(R.string.Failed_to_remove_from_favorites));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<Void> call, Throwable t) {
|
||||||
|
DialogUtils.dismissDialog();
|
||||||
|
Helper.showToast(context, getString(R.string.Network_error_Try_again));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,23 +12,29 @@ import android.location.Geocoder;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import androidx.annotation.NonNull;
|
import android.os.Looper;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
|
|
||||||
import com.ieslamar.acloc.R;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.example.acloc.activity.AddNewPlaceActivity;
|
import com.example.acloc.activity.AddNewPlaceActivity;
|
||||||
import com.example.acloc.activity.PlaceDetailActivity;
|
import com.example.acloc.activity.PlaceDetailActivity;
|
||||||
import com.example.acloc.api.LocationApiClient;
|
import com.example.acloc.api.LocationApiClient;
|
||||||
|
import com.example.acloc.dialog.PlaceBottomSheetDialog;
|
||||||
import com.example.acloc.model.Place;
|
import com.example.acloc.model.Place;
|
||||||
import com.example.acloc.service.PlaceService;
|
import com.example.acloc.service.PlaceService;
|
||||||
import com.example.acloc.utility.Constants;
|
import com.example.acloc.utility.Constants;
|
||||||
|
|
@ -40,8 +46,10 @@ import com.google.android.gms.maps.CameraUpdateFactory;
|
||||||
import com.google.android.gms.maps.GoogleMap;
|
import com.google.android.gms.maps.GoogleMap;
|
||||||
import com.google.android.gms.maps.SupportMapFragment;
|
import com.google.android.gms.maps.SupportMapFragment;
|
||||||
import com.google.android.gms.maps.model.LatLng;
|
import com.google.android.gms.maps.model.LatLng;
|
||||||
|
import com.google.android.gms.maps.model.Marker;
|
||||||
import com.google.android.gms.maps.model.MarkerOptions;
|
import com.google.android.gms.maps.model.MarkerOptions;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
|
import com.ieslamar.acloc.R;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
@ -59,19 +67,26 @@ import retrofit2.Response;
|
||||||
public class MapFragment extends Fragment {
|
public class MapFragment extends Fragment {
|
||||||
public static final String TAG = MapFragment.class.getSimpleName();
|
public static final String TAG = MapFragment.class.getSimpleName();
|
||||||
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
|
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
|
||||||
|
private static final float DEFAULT_ZOOM = 14f;
|
||||||
|
private static final float SEARCH_ZOOM = 16f;
|
||||||
|
|
||||||
private RelativeLayout rlMap;
|
private RelativeLayout rlMap;
|
||||||
private View view;
|
private View view;
|
||||||
private TextInputEditText etSearchLocation;
|
private TextInputEditText etSearchLocation;
|
||||||
|
private ListView lvSuggestions;
|
||||||
private GoogleMap googleMap;
|
private GoogleMap googleMap;
|
||||||
private FusedLocationProviderClient fusedLocationClient;
|
private FusedLocationProviderClient fusedLocationClient;
|
||||||
private Geocoder geocoder;
|
private Geocoder geocoder;
|
||||||
private Dialog dialog;
|
private Dialog dialog;
|
||||||
private Context context;
|
private Context context;
|
||||||
|
private Handler searchHandler = new Handler(Looper.getMainLooper());
|
||||||
|
private Runnable searchRunnable;
|
||||||
|
private List<String> suggestionsList = new ArrayList<>();
|
||||||
|
private ArrayAdapter<String> suggestionsAdapter;
|
||||||
|
private List<Address> addressResults = new ArrayList<>();
|
||||||
|
|
||||||
private List<Place> placeList = new ArrayList<>();
|
private List<Place> placeList = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public MapFragment() {
|
public MapFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,10 +109,32 @@ public class MapFragment extends Fragment {
|
||||||
private void initUI() {
|
private void initUI() {
|
||||||
rlMap = view.findViewById(R.id.rlMap);
|
rlMap = view.findViewById(R.id.rlMap);
|
||||||
etSearchLocation = view.findViewById(R.id.etSearchLocation);
|
etSearchLocation = view.findViewById(R.id.etSearchLocation);
|
||||||
|
|
||||||
|
// Initialize suggestions ListView
|
||||||
|
lvSuggestions = view.findViewById(R.id.lvSuggestions);
|
||||||
|
if (lvSuggestions == null) {
|
||||||
|
// If the ListView doesn't exist in the layout, create it programmatically
|
||||||
|
lvSuggestions = new ListView(getContext());
|
||||||
|
lvSuggestions.setId(View.generateViewId());
|
||||||
|
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
params.addRule(RelativeLayout.BELOW, etSearchLocation.getId());
|
||||||
|
lvSuggestions.setLayoutParams(params);
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
|
lvSuggestions.setBackgroundColor(getResources().getColor(android.R.color.white));
|
||||||
|
rlMap.addView(lvSuggestions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initObj() {
|
private void initObj() {
|
||||||
context = getContext();
|
context = getContext();
|
||||||
|
|
||||||
|
// Initialize suggestions adapter
|
||||||
|
suggestionsAdapter = new ArrayAdapter<>(context,
|
||||||
|
android.R.layout.simple_list_item_1, suggestionsList);
|
||||||
|
lvSuggestions.setAdapter(suggestionsAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
|
@ -126,6 +163,7 @@ public class MapFragment extends Fragment {
|
||||||
String address = Helper.getStringFromInput(etSearchLocation);
|
String address = Helper.getStringFromInput(etSearchLocation);
|
||||||
if (!address.isEmpty()) {
|
if (!address.isEmpty()) {
|
||||||
searchLocationByAddress(address);
|
searchLocationByAddress(address);
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -134,16 +172,106 @@ public class MapFragment extends Fragment {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add TextWatcher for search suggestions
|
||||||
|
etSearchLocation.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
// Cancel any pending searches
|
||||||
|
if (searchRunnable != null) {
|
||||||
|
searchHandler.removeCallbacks(searchRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If text is empty, hide suggestions
|
||||||
|
if (s.length() == 0) {
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay search to avoid too many API calls while typing
|
||||||
|
searchRunnable = () -> getSuggestions(s.toString());
|
||||||
|
searchHandler.postDelayed(searchRunnable, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle suggestion click
|
||||||
|
lvSuggestions.setOnItemClickListener((parent, view, position, id) -> {
|
||||||
|
String selectedAddress = suggestionsList.get(position);
|
||||||
|
etSearchLocation.setText(selectedAddress);
|
||||||
|
|
||||||
|
// Get the corresponding Address object
|
||||||
|
if (position < addressResults.size()) {
|
||||||
|
Address address = addressResults.get(position);
|
||||||
|
LatLng latLng = new LatLng(address.getLatitude(), address.getLongitude());
|
||||||
|
|
||||||
|
// Zoom to the selected location
|
||||||
|
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, SEARCH_ZOOM));
|
||||||
|
|
||||||
|
// Find the closest place
|
||||||
|
Place closestPlace = findClosestPlace(latLng);
|
||||||
|
if (closestPlace != null) {
|
||||||
|
// Show the place details in a bottom sheet
|
||||||
|
showPlaceBottomSheet(closestPlace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
|
||||||
// trigger on Enter/Done key
|
// trigger on Enter/Done key
|
||||||
etSearchLocation.setOnEditorActionListener((v, actionId, event) -> {
|
etSearchLocation.setOnEditorActionListener((v, actionId, event) -> {
|
||||||
String address = Helper.getStringFromInput(etSearchLocation);
|
String address = Helper.getStringFromInput(etSearchLocation);
|
||||||
if (!address.isEmpty()) {
|
if (!address.isEmpty()) {
|
||||||
searchLocationByAddress(address);
|
searchLocationByAddress(address);
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void getSuggestions(String query) {
|
||||||
|
if (query.length() < 3) {
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Clear previous results
|
||||||
|
suggestionsList.clear();
|
||||||
|
addressResults.clear();
|
||||||
|
|
||||||
|
// Get suggestions from Geocoder
|
||||||
|
List<Address> addresses = geocoder.getFromLocationName(query, 5);
|
||||||
|
if (addresses != null && !addresses.isEmpty()) {
|
||||||
|
for (Address address : addresses) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) {
|
||||||
|
if (i > 0) sb.append(", ");
|
||||||
|
sb.append(address.getAddressLine(i));
|
||||||
|
}
|
||||||
|
String addressText = sb.toString();
|
||||||
|
suggestionsList.add(addressText);
|
||||||
|
addressResults.add(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionsAdapter.notifyDataSetChanged();
|
||||||
|
lvSuggestions.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Error getting suggestions", e);
|
||||||
|
lvSuggestions.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initMap() {
|
private void initMap() {
|
||||||
fetchAndShowAllPlaces();
|
fetchAndShowAllPlaces();
|
||||||
|
|
||||||
|
|
@ -158,7 +286,7 @@ public class MapFragment extends Fragment {
|
||||||
fusedLocationClient.getLastLocation().addOnSuccessListener(location -> {
|
fusedLocationClient.getLastLocation().addOnSuccessListener(location -> {
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
|
LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||||
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f));
|
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, DEFAULT_ZOOM));
|
||||||
showNearbyPlaces(currentLatLng);
|
showNearbyPlaces(currentLatLng);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -166,7 +294,7 @@ public class MapFragment extends Fragment {
|
||||||
googleMap.setOnMapClickListener(latLng -> {
|
googleMap.setOnMapClickListener(latLng -> {
|
||||||
Place existingPlace = getPlaceIfExists(latLng);
|
Place existingPlace = getPlaceIfExists(latLng);
|
||||||
if (existingPlace != null) {
|
if (existingPlace != null) {
|
||||||
Helper.goTo(getContext(), PlaceDetailActivity.class, Constants.PLACE, existingPlace); //Navigate to PlaceDetailActivity if the place already exists
|
showPlaceBottomSheet(existingPlace);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|
@ -193,7 +321,6 @@ public class MapFragment extends Fragment {
|
||||||
placeEntity.setDescription(""); // Empty description
|
placeEntity.setDescription(""); // Empty description
|
||||||
placeEntity.setUuid(null); // No UUID for a new place
|
placeEntity.setUuid(null); // No UUID for a new place
|
||||||
Helper.goTo(getContext(), AddNewPlaceActivity.class, Constants.PLACE, placeEntity);
|
Helper.goTo(getContext(), AddNewPlaceActivity.class, Constants.PLACE, placeEntity);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
@ -208,14 +335,12 @@ public class MapFragment extends Fragment {
|
||||||
Place existingPlace = getPlaceIfExists(latLng);
|
Place existingPlace = getPlaceIfExists(latLng);
|
||||||
|
|
||||||
if (existingPlace != null) {
|
if (existingPlace != null) {
|
||||||
Helper.goTo(getContext(), PlaceDetailActivity.class, Constants.PLACE, existingPlace);
|
showPlaceBottomSheet(existingPlace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
|
requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);
|
||||||
}
|
}
|
||||||
|
|
@ -239,6 +364,39 @@ public class MapFragment extends Fragment {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Place findClosestPlace(LatLng searchLatLng) {
|
||||||
|
if (placeList.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Place closestPlace = null;
|
||||||
|
float minDistance = Float.MAX_VALUE;
|
||||||
|
float[] result = new float[1];
|
||||||
|
|
||||||
|
for (Place place : placeList) {
|
||||||
|
double lat = Double.parseDouble(place.getLatitude());
|
||||||
|
double lng = Double.parseDouble(place.getLongitude());
|
||||||
|
|
||||||
|
Location.distanceBetween(
|
||||||
|
searchLatLng.latitude, searchLatLng.longitude,
|
||||||
|
lat, lng,
|
||||||
|
result);
|
||||||
|
|
||||||
|
if (result[0] < minDistance) {
|
||||||
|
minDistance = result[0];
|
||||||
|
closestPlace = place;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only return if within reasonable distance (1000 meters)
|
||||||
|
return minDistance < 1000 ? closestPlace : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPlaceBottomSheet(Place place) {
|
||||||
|
PlaceBottomSheetDialog bottomSheet = new PlaceBottomSheetDialog(place);
|
||||||
|
bottomSheet.show(getChildFragmentManager(), "PlaceBottomSheet");
|
||||||
|
}
|
||||||
|
|
||||||
private void showNearbyPlaces(LatLng latLng) {
|
private void showNearbyPlaces(LatLng latLng) {
|
||||||
googleMap.clear();
|
googleMap.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -249,8 +407,17 @@ public class MapFragment extends Fragment {
|
||||||
if (addresses != null && !addresses.isEmpty()) {
|
if (addresses != null && !addresses.isEmpty()) {
|
||||||
Address location = addresses.get(0);
|
Address location = addresses.get(0);
|
||||||
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
|
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||||
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 14f));
|
googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, SEARCH_ZOOM));
|
||||||
showNearbyPlaces(latLng);
|
|
||||||
|
// Find the closest place to the search result
|
||||||
|
Place closestPlace = findClosestPlace(latLng);
|
||||||
|
if (closestPlace != null) {
|
||||||
|
// Show the place details in a bottom sheet
|
||||||
|
showPlaceBottomSheet(closestPlace);
|
||||||
|
} else {
|
||||||
|
// No close places found
|
||||||
|
Helper.makeSnackBar(rlMap, "No places found near this location");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Helper.makeSnackBar(rlMap, "Location not found");
|
Helper.makeSnackBar(rlMap, "Location not found");
|
||||||
}
|
}
|
||||||
|
|
@ -294,6 +461,7 @@ public class MapFragment extends Fragment {
|
||||||
private void fetchAndShowAllPlaces() {
|
private void fetchAndShowAllPlaces() {
|
||||||
String token = "Bearer " + SharedPref.getAccessToken(context); // get saved token
|
String token = "Bearer " + SharedPref.getAccessToken(context); // get saved token
|
||||||
|
|
||||||
|
// Using the new PlaceService through LocationApiClient
|
||||||
PlaceService placeService = LocationApiClient.getInstance().getPlaceService();
|
PlaceService placeService = LocationApiClient.getInstance().getPlaceService();
|
||||||
Call<ResponseBody> call = placeService.getAllPlaces(token);
|
Call<ResponseBody> call = placeService.getAllPlaces(token);
|
||||||
|
|
||||||
|
|
@ -305,6 +473,9 @@ public class MapFragment extends Fragment {
|
||||||
JSONObject jsonObject = new JSONObject(response.body().string());
|
JSONObject jsonObject = new JSONObject(response.body().string());
|
||||||
JSONArray placesArray = jsonObject.getJSONObject("_data").getJSONArray("places");
|
JSONArray placesArray = jsonObject.getJSONObject("_data").getJSONArray("places");
|
||||||
|
|
||||||
|
// Clear existing places
|
||||||
|
placeList.clear();
|
||||||
|
|
||||||
for (int i = 0; i < placesArray.length(); i++) {
|
for (int i = 0; i < placesArray.length(); i++) {
|
||||||
JSONObject placeObj = placesArray.getJSONObject(i);
|
JSONObject placeObj = placesArray.getJSONObject(i);
|
||||||
String name = placeObj.getString("name");
|
String name = placeObj.getString("name");
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ package com.example.acloc.model;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class Report implements Serializable {
|
public class Report implements Serializable {
|
||||||
String uuid, fkUser, fkPlace, fkReportType, description, createdBy;
|
private String uuid, fkUser, fkPlace, fkReportType, description, created, createdBy;
|
||||||
String placeName, placeUuid;
|
private String placeName, placeUuid;
|
||||||
int reportRating;
|
private int reportRating;
|
||||||
|
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
|
|
@ -46,7 +46,9 @@ public class Report implements Serializable {
|
||||||
public void setDescription(String description) {
|
public void setDescription(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
public String getCreationDate(){
|
||||||
|
return created;
|
||||||
|
}
|
||||||
public String getCreatedBy() {
|
public String getCreatedBy() {
|
||||||
return createdBy;
|
return createdBy;
|
||||||
}
|
}
|
||||||
|
|
@ -78,4 +80,7 @@ public class Report implements Serializable {
|
||||||
public void setPlaceUuid(String placeUuid) {
|
public void setPlaceUuid(String placeUuid) {
|
||||||
this.placeUuid = placeUuid;
|
this.placeUuid = placeUuid;
|
||||||
}
|
}
|
||||||
|
public String getCreatedDate(){
|
||||||
|
return created;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.core.widget.NestedScrollView 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:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/white">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- Header section -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPlaceName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_toStartOf="@+id/ivExpand"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="Place Name" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivExpand"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@drawable/ic_expand_less"
|
||||||
|
android:contentDescription="@string/expand" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<!-- Address and description -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvAddress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="123 Main St, City, Country" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvDescription"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
tools:text="Description of the place" />
|
||||||
|
|
||||||
|
<!-- Action buttons -->
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivFavorite"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:src="@drawable/ic_favorite_border"
|
||||||
|
android:contentDescription="@string/Favorite" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivEdit"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_toEndOf="@id/ivFavorite"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:src="@drawable/ic_edit"
|
||||||
|
android:contentDescription="@string/edit" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
|
android:id="@+id/btnAddReport"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:background="@color/primaryColor_dark"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:text="@string/Add_Report" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<!-- Reports 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/recent_reports" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvNoData"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/no_reports_yet"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rvReports"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
android:id="@+id/rlFavorite"
|
android:id="@+id/rlFavorite"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginTop="?attr/actionBarSize"
|
android:layout_marginTop="?attr/actionBarSize">
|
||||||
tools:context=".fragment.FavoriteFragment">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/rvFavorite"
|
android:id="@+id/rvFavorite"
|
||||||
|
|
|
||||||
|
|
@ -2,37 +2,53 @@
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/rlMap"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/rlMap"
|
tools:context="com.example.acloc.fragments.MapFragment">
|
||||||
android:layout_marginTop="?attr/actionBarSize"
|
|
||||||
tools:context=".fragment.MapFragment">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:id="@+id/tilSearch"
|
|
||||||
android:padding="@dimen/content_padding"
|
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:startIconDrawable="@drawable/ic_location">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
|
||||||
android:id="@+id/etSearchLocation"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawableEnd="@drawable/ic_search"
|
|
||||||
android:hint="@string/Search_Place"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:imeOptions="actionSearch"
|
|
||||||
android:inputType="textPersonName"
|
|
||||||
android:drawableTint="?attr/colorOnBackground"/>
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/mapFrame"
|
android:id="@+id/mapFrame"
|
||||||
android:name="com.google.android.gms.maps.SupportMapFragment"
|
android:name="com.google.android.gms.maps.SupportMapFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:layout_below="@+id/tilSearch" />
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/tilSearchLocation"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:elevation="4dp"
|
||||||
|
app:endIconMode="custom"
|
||||||
|
app:endIconDrawable="@android:drawable/ic_menu_search"
|
||||||
|
app:boxCornerRadiusBottomEnd="8dp"
|
||||||
|
app:boxCornerRadiusBottomStart="8dp"
|
||||||
|
app:boxCornerRadiusTopEnd="8dp"
|
||||||
|
app:boxCornerRadiusTopStart="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etSearchLocation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/Search_Place"
|
||||||
|
android:imeOptions="actionSearch"
|
||||||
|
android:background="@color/primaryVariant_dark"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- ListView for search suggestions -->
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/lvSuggestions"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/tilSearchLocation"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:background="@color/primaryVariant_dark"
|
||||||
|
android:elevation="4dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
@ -1,91 +1,50 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="2dp">
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:cardCornerRadius="12dp"
|
android:orientation="vertical"
|
||||||
app:cardElevation="4dp"
|
android:padding="12dp">
|
||||||
app:cardUseCompatPadding="true"
|
|
||||||
app:strokeColor="?attr/colorPrimary"
|
|
||||||
app:strokeWidth="2dp"
|
|
||||||
tools:ignore="MissingConstraints">
|
|
||||||
|
|
||||||
<!--Report rating-->
|
<TextView
|
||||||
<LinearLayout
|
android:id="@+id/tvDescription"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:baselineAligned="false"
|
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." />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal">
|
||||||
android:padding="@dimen/content_padding"
|
|
||||||
android:weightSum="2">
|
|
||||||
|
|
||||||
<LinearLayout
|
<ImageView
|
||||||
android:layout_width="0dp"
|
android:id="@+id/ivRating"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="16dp"
|
||||||
android:layout_weight="0.6"
|
android:layout_height="16dp"
|
||||||
android:gravity="center_horizontal"
|
android:layout_marginEnd="4dp"
|
||||||
android:orientation="vertical">
|
android:src="@drawable/ic_thumbs_up"
|
||||||
|
app:tint="@color/primaryColor_dark" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:id="@+id/ivRating"
|
android:id="@+id/tvRating"
|
||||||
android:layout_width="@dimen/small_image_icon_height"
|
|
||||||
android:layout_height="@dimen/small_image_icon_height"
|
|
||||||
android:contentDescription="rating"
|
|
||||||
android:src="@drawable/ic_thumbs_up" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvRating"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/Rating_GOOD"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:textColor="?attr/colorOnBackground"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!--Report description-->
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/small_padding"
|
android:textSize="12sp"
|
||||||
android:layout_weight="1.5"
|
android:textStyle="bold"
|
||||||
android:orientation="vertical">
|
tools:text="GOOD" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="@dimen/small_padding"
|
|
||||||
android:text="@string/Report_Description"
|
|
||||||
android:textColor="?attr/colorPrimary"
|
|
||||||
android:textSize="@dimen/textSizeInEditText"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:startIconDrawable="@drawable/ic_location" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/tvDescription"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="false"
|
|
||||||
android:focusable="false"
|
|
||||||
android:hint="@string/Report_Description"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="textMultiLine"
|
|
||||||
android:text="@string/Report_Description"
|
|
||||||
android:textColor="@color/neutralGrey"
|
|
||||||
android:textSize="@dimen/textSizeSmall"
|
|
||||||
tools:ignore="HardcodedText" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</androidx.cardview.widget.CardView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue