mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
* Resolves issue #2239 by adding an arrow for direction * Removed unnecessary change in styles.xml * spacing * javadoc --------- Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
This commit is contained in:
parent
e99ff1c044
commit
e5c789e874
6 changed files with 105 additions and 5 deletions
|
|
@ -1,15 +1,21 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import static android.content.Context.SENSOR_SERVICE;
|
||||
import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED;
|
||||
import static fr.free.nrw.commons.contributions.Contribution.STATE_PAUSED;
|
||||
import static fr.free.nrw.commons.nearby.fragments.NearbyParentFragment.WLM_URL;
|
||||
import static fr.free.nrw.commons.profile.ProfileActivity.KEY_USERNAME;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.computeBearing;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
|
||||
import android.Manifest;
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
|
@ -83,6 +89,7 @@ public class ContributionsFragment
|
|||
OnBackStackChangedListener,
|
||||
LocationUpdateListener,
|
||||
MediaDetailProvider,
|
||||
SensorEventListener,
|
||||
ICampaignsView, ContributionsContract.View, Callback{
|
||||
@Inject @Named("default_preferences") JsonKvStore store;
|
||||
@Inject NearbyController nearbyController;
|
||||
|
|
@ -122,6 +129,10 @@ public class ContributionsFragment
|
|||
|
||||
String userName;
|
||||
private boolean isUserProfile;
|
||||
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mLight;
|
||||
private float direction;
|
||||
private ActivityResultLauncher<String[]> nearbyLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
||||
@Override
|
||||
public void onActivityResult(Map<String, Boolean> result) {
|
||||
|
|
@ -162,6 +173,8 @@ public class ContributionsFragment
|
|||
userName = getArguments().getString(KEY_USERNAME);
|
||||
isUserProfile = true;
|
||||
}
|
||||
mSensorManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);
|
||||
mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -428,6 +441,7 @@ public class ContributionsFragment
|
|||
super.onPause();
|
||||
locationManager.removeLocationListener(this);
|
||||
locationManager.unregisterLocationManager();
|
||||
mSensorManager.unregisterListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -464,6 +478,7 @@ public class ContributionsFragment
|
|||
fetchCampaigns();
|
||||
}
|
||||
}
|
||||
mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
|
||||
private void checkPermissionsAndShowNearbyCardView() {
|
||||
|
|
@ -521,7 +536,8 @@ public class ContributionsFragment
|
|||
Place closestNearbyPlace = nearbyPlacesInfo.placeList.get(0);
|
||||
String distance = formatDistanceBetween(curLatLng, closestNearbyPlace.location);
|
||||
closestNearbyPlace.setDistance(distance);
|
||||
nearbyNotificationCardView.updateContent(closestNearbyPlace);
|
||||
direction = (float) computeBearing(curLatLng, closestNearbyPlace.location);
|
||||
nearbyNotificationCardView.updateContent(closestNearbyPlace, direction);
|
||||
} else {
|
||||
// Means that no close nearby place is found
|
||||
nearbyNotificationCardView.setVisibility(View.GONE);
|
||||
|
|
@ -793,6 +809,17 @@ public class ContributionsFragment
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When the device rotates, rotate the Nearby banner's compass arrow in tandem.
|
||||
*/
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
float rotateDegree = Math.round(event.values[0]);
|
||||
nearbyNotificationCardView.rotateCompass(rotateDegree, direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
private TextView notificationTitle;
|
||||
private TextView notificationDistance;
|
||||
private ImageView notificationIcon;
|
||||
private ImageView notificationCompass;
|
||||
private ProgressBar progressBar;
|
||||
|
||||
public CardViewVisibilityState cardViewVisibilityState;
|
||||
|
|
@ -64,6 +65,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
notificationDistance = rootView.findViewById(R.id.nearby_distance);
|
||||
|
||||
notificationIcon = rootView.findViewById(R.id.nearby_icon);
|
||||
notificationCompass = rootView.findViewById(R.id.nearby_compass);
|
||||
|
||||
progressBar = rootView.findViewById(R.id.progressBar);
|
||||
|
||||
|
|
@ -111,10 +113,11 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
}
|
||||
|
||||
/**
|
||||
* Pass place information to views.
|
||||
* Pass place information to views and set compass arrow direction
|
||||
* @param place Closes place where we will get information from
|
||||
* @param direction Direction in which compass arrow needs to be set
|
||||
*/
|
||||
public void updateContent(Place place) {
|
||||
public void updateContent(Place place, float direction) {
|
||||
Timber.d("Update nearby card notification content");
|
||||
this.setVisibility(VISIBLE);
|
||||
cardViewVisibilityState = CardViewVisibilityState.READY;
|
||||
|
|
@ -129,7 +132,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
notificationIcon.setVisibility(VISIBLE);
|
||||
notificationTitle.setText(place.name);
|
||||
notificationDistance.setText(place.distance);
|
||||
|
||||
notificationCompass.setRotation(direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -151,6 +154,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
notificationTitle.setVisibility(VISIBLE);
|
||||
notificationDistance.setVisibility(VISIBLE);
|
||||
notificationIcon.setVisibility(VISIBLE);
|
||||
notificationCompass.setVisibility(VISIBLE);
|
||||
break;
|
||||
case LOADING:
|
||||
permissionRequestButton.setVisibility(GONE);
|
||||
|
|
@ -160,6 +164,7 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
notificationTitle.setVisibility(GONE);
|
||||
notificationDistance.setVisibility(GONE);
|
||||
notificationIcon.setVisibility(GONE);
|
||||
notificationCompass.setVisibility(GONE);
|
||||
permissionRequestButton.setVisibility(GONE);
|
||||
break;
|
||||
case ASK_PERMISSION:
|
||||
|
|
@ -192,4 +197,14 @@ public class NearbyNotificationCardView extends SwipableCardView {
|
|||
ENABLE_LOCATION_PERMISSION, // For only after Marshmallow
|
||||
NO_PERMISSION_NEEDED
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the compass arrow in tandem with the rotation of device
|
||||
*
|
||||
* @param rotateDegree Degree by which device was rotated
|
||||
* @param direction Direction in which arrow has to point
|
||||
*/
|
||||
public void rotateCompass(float rotateDegree, float direction){
|
||||
notificationCompass.setRotation(-(rotateDegree-direction));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,4 +123,23 @@ public class LengthUtils {
|
|||
double sinHalf = Math.sin(x * 0.5D);
|
||||
return sinHalf * sinHalf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes bearing between the two given points
|
||||
*
|
||||
* @see <a href="https://www.movable-type.co.uk/scripts/latlong.html">Bearing</a>
|
||||
* @param point1 Coordinates of first point
|
||||
* @param point2 Coordinates of second point
|
||||
* @return Bearing between the two end points in degrees
|
||||
* @throws NullPointerException if one or both the points are null
|
||||
*/
|
||||
public static double computeBearing(@NonNull LatLng point1, @NonNull LatLng point2) {
|
||||
double diffLongitute = Math.toRadians(point2.getLongitude() - point1.getLongitude());
|
||||
double lat1 = Math.toRadians(point1.getLatitude());
|
||||
double lat2 = Math.toRadians(point2.getLatitude());
|
||||
double y = Math.sin(diffLongitute) * Math.cos(lat2);
|
||||
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(diffLongitute);
|
||||
double bearing = Math.atan2(y, x);
|
||||
return (Math.toDegrees(bearing) + 360) % 360;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
app/src/main/res/drawable/baseline_arrow_upward_24.xml
Normal file
5
app/src/main/res/drawable/baseline_arrow_upward_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="?attr/tabTextColor"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="?attr/tabTextColor" android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
|
||||
</vector>
|
||||
|
|
@ -93,6 +93,13 @@
|
|||
|
||||
</TextView>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/nearby_compass"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:srcCompat="@drawable/baseline_arrow_upward_24"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -106,6 +106,29 @@ class LengthUtilsTest {
|
|||
assertDistanceBetween(20015115.07, pointA, pointB)
|
||||
}
|
||||
|
||||
// Test LengthUtils.formatDistanceBetween()
|
||||
|
||||
@Test
|
||||
fun testBearingPoleToPole() {
|
||||
val pointA = LatLng(90.0, 0.0, 0f)
|
||||
val pointB = LatLng(-90.0, 0.0, 0f)
|
||||
assertBearing(180.00, pointA, pointB)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBearingRandomPoints() {
|
||||
val pointA = LatLng(27.17, 78.04, 0f)
|
||||
val pointB = LatLng(-40.69, 04.13, 0f)
|
||||
assertBearing(227.46, pointA, pointB)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBearingSamePlace() {
|
||||
val pointA = LatLng(90.0, 0.0, 0f)
|
||||
val pointB = LatLng(90.0, 0.0, 0f)
|
||||
assertBearing(0.0, pointA, pointB)
|
||||
}
|
||||
|
||||
// Test assertion helper functions
|
||||
|
||||
private fun assertFormattedDistanceBetween(expected: String, pointA: LatLng, pointB: LatLng) =
|
||||
|
|
@ -117,4 +140,8 @@ class LengthUtilsTest {
|
|||
private fun assertDistanceBetween(expected: Double, pointA: LatLng, pointB: LatLng) =
|
||||
// Acceptable error: 1cm
|
||||
assertEquals(expected, LengthUtils.computeDistanceBetween(pointA, pointB), 0.01)
|
||||
|
||||
private fun assertBearing(expected: Double, pointA: LatLng, pointB: LatLng) =
|
||||
// Acceptable error: 1 degree
|
||||
assertEquals(expected, LengthUtils.computeBearing(pointA,pointB), 1.0)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue