Fixes #2001 New main UI - progress bar in Nearby card view sometimes runs forever. (#2021)

* Localisation updates from https://translatewiki.net.

* Remove unused mediawiki api dependency (#1991)

* Categories with pipe suffix (#1873)

* Bug fix issue #1826
Changes made :
-Certain category names used to show suffixed with strings prefixed with pipe '|'. Removed everything after the pipe. As per the discussion on the thread, its safe to remove everything after the pipe, including the pipe

* review suggested changes
*Code formatting
*Extracted out the index of pipe in a variable
*Added issue link in comments

* Remove libraries section from README (#1988)

* Remove libraries section from README

* Add wiki link to "libraries used" to README

* Localisation updates from https://translatewiki.net.

* Localisation updates from https://translatewiki.net.

* Display nearby notification only if it is loaded

* Cover don't ask again checkbox is selected posibility

* Clean commented out codes

* Add strings to string.xml

* Add unable to display text to strings xml

* Fix nearby card permission explanation string

* Add never ask again checkbox to dialogbox

* Add action to never display checkbox

* Implement a setting on settings page, to be able to enable this setting later

* Revert unnecessary changes
This commit is contained in:
neslihanturan 2018-11-25 19:47:41 +02:00 committed by Josephine Lim
parent f7ce8934cb
commit d62a7586e0
7 changed files with 209 additions and 18 deletions

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.contributions; package fr.free.nrw.commons.contributions;
import android.Manifest;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -20,12 +21,14 @@ import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.CursorAdapter;
import android.util.Log; import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Adapter; import android.widget.Adapter;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -50,6 +53,8 @@ import fr.free.nrw.commons.notification.NotificationController;
import fr.free.nrw.commons.notification.UnreadNotificationsCheckAsync; import fr.free.nrw.commons.notification.UnreadNotificationsCheckAsync;
import fr.free.nrw.commons.settings.Prefs; import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.upload.UploadService; import fr.free.nrw.commons.upload.UploadService;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
@ -102,10 +107,11 @@ public class ContributionsFragment
private LatLng curLatLng; private LatLng curLatLng;
private boolean firstLocationUpdate = true; private boolean firstLocationUpdate = true;
private LocationServiceManager locationManager; public LocationServiceManager locationManager;
private boolean isFragmentAttachedBefore = false; private boolean isFragmentAttachedBefore = false;
private View checkBoxView;
private CheckBox checkBox;
/** /**
* Since we will need to use parent activity on onAuthCookieAcquired, we have to wait * Since we will need to use parent activity on onAuthCookieAcquired, we have to wait
@ -137,6 +143,18 @@ public class ContributionsFragment
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_contributions, container, false); View view = inflater.inflate(R.layout.fragment_contributions, container, false);
nearbyNoificationCardView = view.findViewById(R.id.card_view_nearby); nearbyNoificationCardView = view.findViewById(R.id.card_view_nearby);
checkBoxView = View.inflate(getActivity(), R.layout.nearby_permission_dialog, null);
checkBox = (CheckBox) checkBoxView.findViewById(R.id.never_ask_again);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// Do not ask for permission on activity start again
prefs.edit().putBoolean("displayLocationPermissionForCardView",false).apply();
}
}
});
if (savedInstanceState != null) { if (savedInstanceState != null) {
mediaDetailPagerFragment = (MediaDetailPagerFragment)getChildFragmentManager().findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG); mediaDetailPagerFragment = (MediaDetailPagerFragment)getChildFragmentManager().findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
@ -186,7 +204,9 @@ public class ContributionsFragment
// show nearby card view on contributions list is visible // show nearby card view on contributions list is visible
if (nearbyNoificationCardView != null) { if (nearbyNoificationCardView != null) {
if (prefs.getBoolean("displayNearbyCardView", true)) { if (prefs.getBoolean("displayNearbyCardView", true)) {
nearbyNoificationCardView.setVisibility(View.VISIBLE); if (nearbyNoificationCardView.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) {
nearbyNoificationCardView.setVisibility(View.VISIBLE);
}
} else { } else {
nearbyNoificationCardView.setVisibility(View.GONE); nearbyNoificationCardView.setVisibility(View.GONE);
} }
@ -312,16 +332,24 @@ public class ContributionsFragment
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Timber.d("onRequestPermissionsResult");
switch (requestCode) { switch (requestCode) {
case LOCATION_REQUEST: { case LOCATION_REQUEST: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Location permission granted, refreshing view"); Timber.d("Location permission granted, refreshing view");
// No need to display permission request button anymore // No need to display permission request button anymore
nearbyNoificationCardView.displayPermissionRequestButton(false);
locationManager.registerLocationManager(); locationManager.registerLocationManager();
} else { } else {
// Still ask for permission if (prefs.getBoolean("displayLocationPermissionForCardView", true)) {
nearbyNoificationCardView.displayPermissionRequestButton(true); // Still ask for permission
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.nearby_card_permission_title),
getString(R.string.nearby_card_permission_explanation),
() -> displayYouWontSeeNearbyMessage(),
() -> enableLocationPermission(),
checkBoxView,
false);
}
} }
} }
break; break;
@ -499,9 +527,10 @@ public class ContributionsFragment
if (prefs.getBoolean("displayNearbyCardView", true)) { if (prefs.getBoolean("displayNearbyCardView", true)) {
nearbyNoificationCardView.cardViewVisibilityState = NearbyNoificationCardView.CardViewVisibilityState.LOADING;
nearbyNoificationCardView.setVisibility(View.VISIBLE);
checkGPS(); checkGPS();
if (nearbyNoificationCardView.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) {
nearbyNoificationCardView.setVisibility(View.VISIBLE);
}
} else { } else {
// Hide nearby notification card view if related shared preferences is false // Hide nearby notification card view if related shared preferences is false
@ -511,7 +540,6 @@ public class ContributionsFragment
} }
/** /**
* Check GPS to decide displaying request permission button or not. * Check GPS to decide displaying request permission button or not.
*/ */
@ -519,7 +547,15 @@ public class ContributionsFragment
if (!locationManager.isProviderEnabled()) { if (!locationManager.isProviderEnabled()) {
Timber.d("GPS is not enabled"); Timber.d("GPS is not enabled");
nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.ENABLE_GPS; nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.ENABLE_GPS;
nearbyNoificationCardView.displayPermissionRequestButton(true); if (prefs.getBoolean("displayLocationPermissionForCardView", true)) {
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.nearby_card_permission_title),
getString(R.string.nearby_card_permission_explanation),
() -> displayYouWontSeeNearbyMessage(),
() -> enableGPS(),
checkBoxView,
false);
}
} else { } else {
Timber.d("GPS is enabled"); Timber.d("GPS is enabled");
checkLocationPermission(); checkLocationPermission();
@ -530,20 +566,57 @@ public class ContributionsFragment
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (locationManager.isLocationPermissionGranted()) { if (locationManager.isLocationPermissionGranted()) {
nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.NO_PERMISSION_NEEDED; nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.NO_PERMISSION_NEEDED;
nearbyNoificationCardView.displayPermissionRequestButton(false);
locationManager.registerLocationManager(); locationManager.registerLocationManager();
} else { } else {
nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.ENABLE_LOCATION_PERMISSON; nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.ENABLE_LOCATION_PERMISSON;
nearbyNoificationCardView.displayPermissionRequestButton(true); // If user didn't selected Don't ask again
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
&& prefs.getBoolean("displayLocationPermissionForCardView", true)) {
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.nearby_card_permission_title),
getString(R.string.nearby_card_permission_explanation),
() -> displayYouWontSeeNearbyMessage(),
() -> enableLocationPermission(),
checkBoxView,
false);
}
} }
} else { } else {
// If device is under Marshmallow, we already checked for GPS // If device is under Marshmallow, we already checked for GPS
nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.NO_PERMISSION_NEEDED; nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.NO_PERMISSION_NEEDED;
nearbyNoificationCardView.displayPermissionRequestButton(false);
locationManager.registerLocationManager(); locationManager.registerLocationManager();
} }
} }
private void enableLocationPermission() {
if (!getActivity().isFinishing()) {
((MainActivity) getActivity()).locationManager.requestPermissions(getActivity());
}
}
private void enableGPS() {
new AlertDialog.Builder(getActivity())
.setMessage(R.string.gps_disabled)
.setCancelable(false)
.setPositiveButton(R.string.enable_gps,
(dialog, id) -> {
Intent callGPSSettingIntent = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
Timber.d("Loaded settings page");
((MainActivity) getActivity()).startActivityForResult(callGPSSettingIntent, 1);
})
.setNegativeButton(R.string.menu_cancel_upload, (dialog, id) -> {
dialog.cancel();
displayYouWontSeeNearbyMessage();
})
.create()
.show();
}
private void displayYouWontSeeNearbyMessage() {
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.unable_to_display_nearest_place));
}
private void updateClosestNearbyCardViewInfo() { private void updateClosestNearbyCardViewInfo() {
curLatLng = locationManager.getLastLocation(); curLatLng = locationManager.getLastLocation();

View file

@ -31,6 +31,7 @@ import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.nearby.NearbyFragment; import fr.free.nrw.commons.nearby.NearbyFragment;
import fr.free.nrw.commons.nearby.NearbyMapFragment; import fr.free.nrw.commons.nearby.NearbyMapFragment;
import fr.free.nrw.commons.nearby.NearbyNoificationCardView;
import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.upload.UploadService; import fr.free.nrw.commons.upload.UploadService;
@ -253,7 +254,9 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
showTabs(); showTabs();
// Nearby Notification Card View was invisible when Media Details Fragment is active, make it visible again on Contrib List Fragment active, according to preferences // Nearby Notification Card View was invisible when Media Details Fragment is active, make it visible again on Contrib List Fragment active, according to preferences
if (prefs.getBoolean("displayNearbyCardView", true)) { if (prefs.getBoolean("displayNearbyCardView", true)) {
contributionsFragment.nearbyNoificationCardView.setVisibility(View.VISIBLE); if (contributionsFragment.nearbyNoificationCardView.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) {
contributionsFragment.nearbyNoificationCardView.setVisibility(View.VISIBLE);
}
} else { } else {
contributionsFragment.nearbyNoificationCardView.setVisibility(View.GONE); contributionsFragment.nearbyNoificationCardView.setVisibility(View.GONE);
} }
@ -468,6 +471,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
if (grantResults.length > 0 if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) { && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Location permission given"); Timber.d("Location permission given");
((ContributionsFragment)contributionsActivityPagerAdapter
.getItem(0)).locationManager.registerLocationManager();
} else { } else {
// If nearby fragment is visible and location permission is not given, send user back to contrib fragment // If nearby fragment is visible and location permission is not given, send user back to contrib fragment
if (!isContributionsFragmentVisible) { if (!isContributionsFragmentVisible) {

View file

@ -3,6 +3,7 @@ package fr.free.nrw.commons.nearby;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.CoordinatorLayout;
@ -10,6 +11,7 @@ import android.support.design.widget.SwipeDismissBehavior;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
@ -19,6 +21,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
@ -86,7 +89,7 @@ public class NearbyNoificationCardView extends CardView{
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
// If you don't setVisibility after getting layout params, then you will se an empty space in place of nerabyNotificationCardView // If you don't setVisibility after getting layout params, then you will se an empty space in place of nerabyNotificationCardView
if (((MainActivity)context).prefs.getBoolean("displayNearbyCardView", true)) { if (((MainActivity)context).prefs.getBoolean("displayNearbyCardView", true) && this.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) {
this.setVisibility(VISIBLE); this.setVisibility(VISIBLE);
} else { } else {
this.setVisibility(GONE); this.setVisibility(GONE);
@ -183,7 +186,7 @@ public class NearbyNoificationCardView extends CardView{
} else { } else {
cardViewVisibilityState = CardViewVisibilityState.LOADING; cardViewVisibilityState = CardViewVisibilityState.LOADING;
permissionRequestButton.setVisibility(GONE); /*permissionRequestButton.setVisibility(GONE);
contentLayout.setVisibility(VISIBLE); contentLayout.setVisibility(VISIBLE);
// Set visibility of elements in content layout once it become visible // Set visibility of elements in content layout once it become visible
progressBar.setVisibility(VISIBLE); progressBar.setVisibility(VISIBLE);
@ -191,10 +194,35 @@ public class NearbyNoificationCardView extends CardView{
notificationDistance.setVisibility(GONE); notificationDistance.setVisibility(GONE);
notificationIcon.setVisibility(GONE); notificationIcon.setVisibility(GONE);
permissionRequestButton.setVisibility(GONE); permissionRequestButton.setVisibility(GONE);*/
this.setVisibility(GONE);
Handler nearbyNotificationHandler = new Handler();
Runnable nearbyNotificationRunnable = new Runnable() {
@Override
public void run() {
if (cardViewVisibilityState != NearbyNoificationCardView.CardViewVisibilityState.READY
&& cardViewVisibilityState != NearbyNoificationCardView.CardViewVisibilityState.ASK_PERMISSION
&& cardViewVisibilityState != NearbyNoificationCardView.CardViewVisibilityState.INVISIBLE) {
// If after 30 seconds, card view is not ready
errorOcured();
} else {
suceeded();
}
}
};
nearbyNotificationHandler.postDelayed(nearbyNotificationRunnable, 30000);
} }
} }
private void errorOcured() {
this.setVisibility(GONE);
}
private void suceeded() {
this.setVisibility(VISIBLE);
}
/** /**
* Pass place information to views. * Pass place information to views.
* @param isClosestNearbyPlaceFound false if there are no close place * @param isClosestNearbyPlaceFound false if there are no close place
@ -202,6 +230,7 @@ public class NearbyNoificationCardView extends CardView{
*/ */
public void updateContent(boolean isClosestNearbyPlaceFound, Place place) { public void updateContent(boolean isClosestNearbyPlaceFound, Place place) {
Timber.d("Update nearby card notification content"); Timber.d("Update nearby card notification content");
this.setVisibility(VISIBLE);
cardViewVisibilityState = CardViewVisibilityState.READY; cardViewVisibilityState = CardViewVisibilityState.READY;
permissionRequestButton.setVisibility(GONE); permissionRequestButton.setVisibility(GONE);
contentLayout.setVisibility(VISIBLE); contentLayout.setVisibility(VISIBLE);
@ -269,6 +298,7 @@ public class NearbyNoificationCardView extends CardView{
READY, READY,
INVISIBLE, INVISIBLE,
ASK_PERMISSION, ASK_PERMISSION,
ERROR_OCURED
} }
/** /**

View file

@ -10,6 +10,7 @@ import android.os.Build;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.view.View;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import timber.log.Timber; import timber.log.Timber;
@ -160,6 +161,63 @@ public class DialogUtil {
showSafely(activity, dialog); showSafely(activity, dialog);
} }
/*
Shows alert dialog with custom view
*/
public static void showAlertDialog(Activity activity,
String title,
String message,
final Runnable onPositiveBtnClick,
final Runnable onNegativeBtnClick,
View customView,
boolean cancelable) {
showAlertDialog(activity,
title,
message,
activity.getString(R.string.no),
activity.getString(R.string.yes),
onPositiveBtnClick,
onNegativeBtnClick,
customView,
false);
}
/*
Shows alert dialog with custom view
*/
private static void showAlertDialog(Activity activity,
String title,
String message,
String positiveButtonText,
String negativeButtonText,
final Runnable onPositiveBtnClick,
final Runnable onNegativeBtnClick,
View customView,
boolean cancelable) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(title);
builder.setMessage(message);
builder.setView(customView);
builder.setCancelable(cancelable);
builder.setPositiveButton(positiveButtonText, (dialogInterface, i) -> {
dialogInterface.dismiss();
if (onPositiveBtnClick != null) {
onPositiveBtnClick.run();
}
});
builder.setNegativeButton(negativeButtonText, (DialogInterface dialogInterface, int i) -> {
dialogInterface.dismiss();
if (onNegativeBtnClick != null) {
onNegativeBtnClick.run();
}
});
AlertDialog dialog = builder.create();
showSafely(activity, dialog);
}
public interface Callback { public interface Callback {
void onPositiveButtonClicked(); void onPositiveButtonClicked();

View file

@ -0,0 +1,13 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<CheckBox
android:id="@+id/never_ask_again"
style="?android:attr/textAppearanceMedium"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/never_ask_again"
android:layout_margin="5dp" />
</FrameLayout>

View file

@ -414,5 +414,11 @@ Upload your first media by touching the camera or gallery icon above.</string>
<string name="no_go_back">No, Go Back</string> <string name="no_go_back">No, Go Back</string>
<string name="upload_flow_all_images_in_set">(For all images in set)</string> <string name="upload_flow_all_images_in_set">(For all images in set)</string>
<string name="nearby_card_permission_title">Permission Request</string>
<string name="nearby_card_permission_explanation">Would you like us to use your current location to display the nearest place that needs pictures?</string>
<string name="unable_to_display_nearest_place">Unable to display nearest place that needs pictures without location permissions</string>
<string name="never_ask_again">Never ask this again</string>
<string name="display_location_permission_title">Display location permission</string>
<string name="display_location_permission_explanation">Ask for location permission when needed for nearby notification card view feature.</string>
</resources> </resources>

View file

@ -42,6 +42,12 @@
android:defaultValue="true" android:defaultValue="true"
android:summary="@string/display_nearby_notification_summary" /> android:summary="@string/display_nearby_notification_summary" />
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleSwitchPreference
android:key="displayLocationPermissionForCardView"
android:title="@string/display_location_permission_title"
android:defaultValue="true"
android:summary="@string/display_location_permission_explanation" />
</fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory> </fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory>
<!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599. <!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599.