mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-30 14:23:55 +01:00
Migrated all remaining files in util module
This commit is contained in:
parent
a42067ef34
commit
d543625353
18 changed files with 540 additions and 568 deletions
|
|
@ -87,7 +87,7 @@ public class ContributionController {
|
|||
},
|
||||
R.string.storage_permission_title,
|
||||
R.string.write_storage_permission_rationale,
|
||||
PermissionUtils.PERMISSIONS_STORAGE);
|
||||
PermissionUtils.getPERMISSIONS_STORAGE());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -224,7 +224,7 @@ public class ContributionController {
|
|||
() -> FilePicker.openCustomSelector(activity, resultLauncher, 0),
|
||||
R.string.storage_permission_title,
|
||||
R.string.write_storage_permission_rationale,
|
||||
PermissionUtils.PERMISSIONS_STORAGE);
|
||||
PermissionUtils.getPERMISSIONS_STORAGE());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -16,10 +13,8 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import fr.free.nrw.commons.databinding.MainBinding;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
|
|
@ -41,7 +36,6 @@ import fr.free.nrw.commons.notification.NotificationController;
|
|||
import fr.free.nrw.commons.quiz.QuizChecker;
|
||||
import fr.free.nrw.commons.settings.SettingsFragment;
|
||||
import fr.free.nrw.commons.theme.BaseActivity;
|
||||
import fr.free.nrw.commons.upload.UploadActivity;
|
||||
import fr.free.nrw.commons.upload.UploadProgressActivity;
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
|
||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@ import static fr.free.nrw.commons.location.LocationServiceManager.LocationChange
|
|||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL;
|
||||
|
||||
import android.Manifest;
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
|
|
@ -21,22 +19,17 @@ import android.location.Location;
|
|||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import fr.free.nrw.commons.BaseMarker;
|
||||
import fr.free.nrw.commons.MapController;
|
||||
|
|
@ -48,7 +41,6 @@ import fr.free.nrw.commons.databinding.FragmentExploreMapBinding;
|
|||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.explore.ExploreMapRootFragment;
|
||||
import fr.free.nrw.commons.explore.paging.LiveDataConverter;
|
||||
import fr.free.nrw.commons.filepicker.Constants;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.location.LocationPermissionsHelper;
|
||||
|
|
@ -60,7 +52,6 @@ import fr.free.nrw.commons.nearby.Place;
|
|||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.utils.MapUtils;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.Observable;
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
}
|
||||
|
||||
public void launchZoomActivity(final View view) {
|
||||
final boolean hasPermission = PermissionUtils.hasPermission(getActivity(), PermissionUtils.PERMISSIONS_STORAGE);
|
||||
final boolean hasPermission = PermissionUtils.hasPermission(getActivity(), PermissionUtils.getPERMISSIONS_STORAGE());
|
||||
if (hasPermission) {
|
||||
launchZoomActivityAfterPermissionCheck(view);
|
||||
} else {
|
||||
|
|
@ -328,7 +328,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements
|
|||
},
|
||||
R.string.storage_permission_title,
|
||||
R.string.read_storage_permission_rationale,
|
||||
PermissionUtils.PERMISSIONS_STORAGE
|
||||
PermissionUtils.getPERMISSIONS_STORAGE()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import android.net.Uri;
|
|||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
|
|
@ -543,7 +542,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
* First checks for external storage permissions and then sends logs via email
|
||||
*/
|
||||
private void checkPermissionsAndSendLogs() {
|
||||
if (PermissionUtils.hasPermission(getActivity(), PermissionUtils.PERMISSIONS_STORAGE)) {
|
||||
if (PermissionUtils.hasPermission(getActivity(), PermissionUtils.getPERMISSIONS_STORAGE())) {
|
||||
commonsLogSender.send(getActivity(), null);
|
||||
} else {
|
||||
requestExternalStoragePermissions();
|
||||
|
|
@ -556,7 +555,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||
*/
|
||||
private void requestExternalStoragePermissions() {
|
||||
Dexter.withActivity(getActivity())
|
||||
.withPermissions(PermissionUtils.PERMISSIONS_STORAGE)
|
||||
.withPermissions(PermissionUtils.getPERMISSIONS_STORAGE())
|
||||
.withListener(new MultiplePermissionsListener() {
|
||||
@Override
|
||||
public void onPermissionsChecked(MultiplePermissionsReport report) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package fr.free.nrw.commons.upload;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.ContributionController.ACTION_INTERNAL_UPLOADS;
|
||||
import static fr.free.nrw.commons.utils.PermissionUtils.PERMISSIONS_STORAGE;
|
||||
import static fr.free.nrw.commons.utils.PermissionUtils.checkPermissionsAndPerformAction;
|
||||
import static fr.free.nrw.commons.utils.PermissionUtils.getPERMISSIONS_STORAGE;
|
||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
|
||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.SELECTED_NEARBY_PLACE;
|
||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.SELECTED_NEARBY_PLACE_CATEGORY;
|
||||
|
|
@ -32,7 +32,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.LoginActivity;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
|
|
@ -277,7 +276,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
|||
|
||||
public void checkStoragePermissions() {
|
||||
// Check if all required permissions are granted
|
||||
final boolean hasAllPermissions = PermissionUtils.hasPermission(this, PERMISSIONS_STORAGE);
|
||||
final boolean hasAllPermissions = PermissionUtils.hasPermission(this, getPERMISSIONS_STORAGE());
|
||||
final boolean hasPartialAccess = PermissionUtils.hasPartialAccess(this);
|
||||
if (hasAllPermissions || hasPartialAccess) {
|
||||
// All required permissions are granted, so enable UI elements and perform actions
|
||||
|
|
@ -297,7 +296,7 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
|
|||
},
|
||||
R.string.storage_permission_title,
|
||||
R.string.write_storage_permission_rationale_for_image_share,
|
||||
PERMISSIONS_STORAGE);
|
||||
getPERMISSIONS_STORAGE());
|
||||
}
|
||||
}
|
||||
/* If all permissions are not granted and a dialog is already showing on screen
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList
|
||||
|
||||
object MediaDataExtractorUtil {
|
||||
|
||||
public class MediaDataExtractorUtil {
|
||||
/**
|
||||
* Extracts a list of categories from | separated category string
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
public static List<String> extractCategoriesFromList(String source) {
|
||||
if (StringUtils.isBlank(source)) {
|
||||
return new ArrayList<>();
|
||||
@JvmStatic
|
||||
fun extractCategoriesFromList(source: String): List<String> {
|
||||
if (source.isBlank()) {
|
||||
return emptyList()
|
||||
}
|
||||
String[] cats = source.split("\\|");
|
||||
List<String> categories = new ArrayList<>();
|
||||
for (String category : cats) {
|
||||
if (!StringUtils.isBlank(category.trim())) {
|
||||
categories.add(category);
|
||||
val cats = source.split("|")
|
||||
val categories = mutableListOf<String>()
|
||||
for (category in cats) {
|
||||
if (category.trim().isNotBlank()) {
|
||||
categories.add(category)
|
||||
}
|
||||
}
|
||||
return categories;
|
||||
return categories
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,55 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
object NearbyFABUtils {
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
public class NearbyFABUtils {
|
||||
/*
|
||||
* Add anchors back before making them visible again.
|
||||
* */
|
||||
public static void addAnchorToBigFABs(FloatingActionButton floatingActionButton, int anchorID) {
|
||||
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams
|
||||
(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.setAnchorId(anchorID);
|
||||
params.anchorGravity = Gravity.TOP|Gravity.RIGHT|Gravity.END;
|
||||
floatingActionButton.setLayoutParams(params);
|
||||
*/
|
||||
@JvmStatic
|
||||
fun addAnchorToBigFABs(floatingActionButton: FloatingActionButton, anchorID: Int) {
|
||||
val params = CoordinatorLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
params.anchorId = anchorID
|
||||
params.anchorGravity = Gravity.TOP or Gravity.RIGHT or Gravity.END
|
||||
floatingActionButton.layoutParams = params
|
||||
}
|
||||
|
||||
/*
|
||||
* Add anchors back before making them visible again. Big and small fabs have different anchor
|
||||
* gravities, therefore the are two methods.
|
||||
* */
|
||||
public static void addAnchorToSmallFABs(FloatingActionButton floatingActionButton, int anchorID) {
|
||||
CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams
|
||||
(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.setAnchorId(anchorID);
|
||||
params.anchorGravity = Gravity.CENTER_HORIZONTAL;
|
||||
floatingActionButton.setLayoutParams(params);
|
||||
* gravities, therefore there are two methods.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun addAnchorToSmallFABs(floatingActionButton: FloatingActionButton, anchorID: Int) {
|
||||
val params = CoordinatorLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
params.anchorId = anchorID
|
||||
params.anchorGravity = Gravity.CENTER_HORIZONTAL
|
||||
floatingActionButton.layoutParams = params
|
||||
}
|
||||
|
||||
/*
|
||||
* We are not able to hide FABs without removing anchors, this method removes anchors
|
||||
* */
|
||||
public static void removeAnchorFromFAB(FloatingActionButton floatingActionButton) {
|
||||
//get rid of anchors
|
||||
//Somehow this was the only way https://stackoverflow.com/questions/32732932
|
||||
// /floatingactionbutton-visible-for-sometime-even-if-visibility-is-set-to-gone
|
||||
CoordinatorLayout.LayoutParams param = (CoordinatorLayout.LayoutParams) floatingActionButton
|
||||
.getLayoutParams();
|
||||
param.setAnchorId(View.NO_ID);
|
||||
* We are not able to hide FABs without removing anchors, this method removes anchors.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun removeAnchorFromFAB(floatingActionButton: FloatingActionButton) {
|
||||
// get rid of anchors
|
||||
// Somehow this was the only way https://stackoverflow.com/questions/32732932
|
||||
// floatingactionbutton-visible-for-sometime-even-if-visibility-is-set-to-gone
|
||||
val params = floatingActionButton.layoutParams as CoordinatorLayout.LayoutParams
|
||||
params.anchorId = View.NO_ID
|
||||
// If we don't set them to zero, then they become visible for a moment on upper left side
|
||||
param.width = 0;
|
||||
param.height = 0;
|
||||
floatingActionButton.setLayoutParams(param);
|
||||
params.width = 0
|
||||
params.height = 0
|
||||
floatingActionButton.layoutParams = params
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkInfo
|
||||
import android.telephony.TelephonyManager
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.telephony.TelephonyManager;
|
||||
import fr.free.nrw.commons.utils.model.NetworkConnectionType
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import fr.free.nrw.commons.utils.model.NetworkConnectionType;
|
||||
|
||||
public class NetworkUtils {
|
||||
object NetworkUtils {
|
||||
|
||||
/**
|
||||
* https://developer.android.com/training/monitoring-device-state/connectivity-monitoring#java
|
||||
|
|
@ -21,74 +18,68 @@ public class NetworkUtils {
|
|||
* @return Returns current internet connection status. Returns false if null context was passed.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
public static boolean isInternetConnectionEstablished(@Nullable Context context) {
|
||||
@JvmStatic
|
||||
fun isInternetConnectionEstablished(context: Context?): Boolean {
|
||||
if (context == null) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
NetworkInfo activeNetwork = getNetworkInfo(context);
|
||||
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
|
||||
val activeNetwork = getNetworkInfo(context)
|
||||
return activeNetwork != null && activeNetwork.isConnectedOrConnecting
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect network connection type
|
||||
*/
|
||||
static NetworkConnectionType getNetworkType(Context context) {
|
||||
TelephonyManager telephonyManager = (TelephonyManager) context.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (telephonyManager == null) {
|
||||
return NetworkConnectionType.UNKNOWN;
|
||||
}
|
||||
@JvmStatic
|
||||
fun getNetworkType(context: Context): NetworkConnectionType {
|
||||
val telephonyManager = context.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
|
||||
?: return NetworkConnectionType.UNKNOWN
|
||||
|
||||
NetworkInfo networkInfo = getNetworkInfo(context);
|
||||
if (networkInfo == null) {
|
||||
return NetworkConnectionType.UNKNOWN;
|
||||
}
|
||||
val networkInfo = getNetworkInfo(context)
|
||||
?: return NetworkConnectionType.UNKNOWN
|
||||
|
||||
int network = networkInfo.getType();
|
||||
val network = networkInfo.type
|
||||
if (network == ConnectivityManager.TYPE_WIFI) {
|
||||
return NetworkConnectionType.WIFI;
|
||||
return NetworkConnectionType.WIFI
|
||||
}
|
||||
|
||||
// TODO for Android 12+ request permission from user is mandatory
|
||||
/*
|
||||
int mobileNetwork = telephonyManager.getNetworkType();
|
||||
switch (mobileNetwork) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||
return NetworkConnectionType.TWO_G;
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||
return NetworkConnectionType.THREE_G;
|
||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||
return NetworkConnectionType.FOUR_G;
|
||||
default:
|
||||
return NetworkConnectionType.UNKNOWN;
|
||||
val mobileNetwork = telephonyManager.networkType
|
||||
return when (mobileNetwork) {
|
||||
TelephonyManager.NETWORK_TYPE_GPRS,
|
||||
TelephonyManager.NETWORK_TYPE_EDGE,
|
||||
TelephonyManager.NETWORK_TYPE_CDMA,
|
||||
TelephonyManager.NETWORK_TYPE_1xRTT -> NetworkConnectionType.TWO_G
|
||||
|
||||
TelephonyManager.NETWORK_TYPE_HSDPA,
|
||||
TelephonyManager.NETWORK_TYPE_UMTS,
|
||||
TelephonyManager.NETWORK_TYPE_HSUPA,
|
||||
TelephonyManager.NETWORK_TYPE_HSPA,
|
||||
TelephonyManager.NETWORK_TYPE_EHRPD,
|
||||
TelephonyManager.NETWORK_TYPE_EVDO_0,
|
||||
TelephonyManager.NETWORK_TYPE_EVDO_A,
|
||||
TelephonyManager.NETWORK_TYPE_EVDO_B -> NetworkConnectionType.THREE_G
|
||||
|
||||
TelephonyManager.NETWORK_TYPE_LTE,
|
||||
TelephonyManager.NETWORK_TYPE_HSPAP -> NetworkConnectionType.FOUR_G
|
||||
|
||||
else -> NetworkConnectionType.UNKNOWN
|
||||
}
|
||||
*/
|
||||
return NetworkConnectionType.UNKNOWN;
|
||||
return NetworkConnectionType.UNKNOWN
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracted private method to get nullable network info
|
||||
*/
|
||||
@Nullable
|
||||
private static NetworkInfo getNetworkInfo(Context context) {
|
||||
ConnectivityManager connectivityManager =
|
||||
(ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
@JvmStatic
|
||||
private fun getNetworkInfo(context: Context): NetworkInfo? {
|
||||
val connectivityManager =
|
||||
context.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
|
||||
?: return null
|
||||
|
||||
if (connectivityManager == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return connectivityManager.getActiveNetworkInfo();
|
||||
return connectivityManager.activeNetworkInfo
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,54 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.Manifest;
|
||||
import android.Manifest.permission;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.karumi.dexter.Dexter;
|
||||
import com.karumi.dexter.MultiplePermissionsReport;
|
||||
import com.karumi.dexter.PermissionToken;
|
||||
import com.karumi.dexter.listener.PermissionRequest;
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.upload.UploadActivity;
|
||||
import java.util.List;
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.upload.UploadActivity
|
||||
|
||||
public class PermissionUtils {
|
||||
public static String[] PERMISSIONS_STORAGE = getPermissionsStorage();
|
||||
|
||||
static String[] getPermissionsStorage() {
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
return new String[]{ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
|
||||
object PermissionUtils {
|
||||
|
||||
@JvmStatic
|
||||
val PERMISSIONS_STORAGE: Array<String> = getPermissionsStorage()
|
||||
|
||||
@JvmStatic
|
||||
private fun getPermissionsStorage(): Array<String> {
|
||||
return when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> arrayOf(
|
||||
Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED,
|
||||
Manifest.permission.READ_MEDIA_IMAGES,
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION };
|
||||
}
|
||||
if(Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU) {
|
||||
return new String[]{ Manifest.permission.READ_MEDIA_IMAGES,
|
||||
Manifest. permission.ACCESS_MEDIA_LOCATION };
|
||||
}
|
||||
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
|
||||
return new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION };
|
||||
}
|
||||
if(Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
|
||||
return new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION
|
||||
)
|
||||
Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU -> arrayOf(
|
||||
Manifest.permission.READ_MEDIA_IMAGES,
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION
|
||||
)
|
||||
Build.VERSION.SDK_INT > Build.VERSION_CODES.Q -> arrayOf(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION
|
||||
)
|
||||
Build.VERSION.SDK_INT == Build.VERSION_CODES.Q -> arrayOf(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION };
|
||||
Manifest.permission.ACCESS_MEDIA_LOCATION
|
||||
)
|
||||
else -> arrayOf(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
return new String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -55,11 +58,12 @@ public class PermissionUtils {
|
|||
*
|
||||
* @param activity The Activity which requires a permission which has been blocked
|
||||
*/
|
||||
private static void askUserToManuallyEnablePermissionFromSettings(final Activity activity) {
|
||||
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
final Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
activity.startActivity(intent);
|
||||
@JvmStatic
|
||||
private fun askUserToManuallyEnablePermissionFromSettings(activity: Activity) {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", activity.packageName, null)
|
||||
}
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -69,25 +73,26 @@ public class PermissionUtils {
|
|||
* @param permissions An array of permission strings to check
|
||||
* @return `true if the app has all the specified permissions, `false` otherwise
|
||||
*/
|
||||
public static boolean hasPermission(final Activity activity, final String[] permissions) {
|
||||
boolean hasPermission = true;
|
||||
for(final String permission : permissions) {
|
||||
hasPermission = hasPermission &&
|
||||
ContextCompat.checkSelfPermission(activity, permission)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
@JvmStatic
|
||||
fun hasPermission(activity: Activity, permissions: Array<String>): Boolean {
|
||||
return permissions.all { permission ->
|
||||
ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
public static boolean hasPartialAccess(final Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
return ContextCompat.checkSelfPermission(activity,
|
||||
permission.READ_MEDIA_VISUAL_USER_SELECTED
|
||||
) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
|
||||
activity, permission.READ_MEDIA_IMAGES
|
||||
) == PackageManager.PERMISSION_DENIED;
|
||||
}
|
||||
return false;
|
||||
/**
|
||||
* Check if the app has partial access permissions.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun hasPartialAccess(activity: Activity): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
ContextCompat.checkSelfPermission(
|
||||
activity, Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
|
||||
) == PackageManager.PERMISSION_GRANTED &&
|
||||
ContextCompat.checkSelfPermission(
|
||||
activity, Manifest.permission.READ_MEDIA_IMAGES
|
||||
) == PackageManager.PERMISSION_DENIED
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -116,19 +121,21 @@ public class PermissionUtils {
|
|||
* @param rationaleMessage rationale message to be displayed when permission was denied. It
|
||||
* can be an invalid @StringRes
|
||||
*/
|
||||
public static void checkPermissionsAndPerformAction(
|
||||
final Activity activity,
|
||||
final Runnable onPermissionGranted,
|
||||
final @StringRes int rationaleTitle,
|
||||
final @StringRes int rationaleMessage,
|
||||
final String... permissions
|
||||
@JvmStatic
|
||||
fun checkPermissionsAndPerformAction(
|
||||
activity: Activity,
|
||||
onPermissionGranted: Runnable,
|
||||
rationaleTitle: Int,
|
||||
rationaleMessage: Int,
|
||||
vararg permissions: String
|
||||
) {
|
||||
if (hasPartialAccess(activity)) {
|
||||
onPermissionGranted.run();
|
||||
return;
|
||||
Thread(onPermissionGranted).start()
|
||||
return
|
||||
}
|
||||
checkPermissionsAndPerformAction(activity, onPermissionGranted, null,
|
||||
rationaleTitle, rationaleMessage, permissions);
|
||||
checkPermissionsAndPerformAction(
|
||||
activity, onPermissionGranted, null, rationaleTitle, rationaleMessage, *permissions
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -150,75 +157,75 @@ public class PermissionUtils {
|
|||
* @param rationaleTitle rationale title to be displayed when permission was denied
|
||||
* @param rationaleMessage rationale message to be displayed when permission was denied
|
||||
*/
|
||||
public static void checkPermissionsAndPerformAction(
|
||||
final Activity activity,
|
||||
final Runnable onPermissionGranted,
|
||||
final Runnable onPermissionDenied,
|
||||
final @StringRes int rationaleTitle,
|
||||
final @StringRes int rationaleMessage,
|
||||
final String... permissions
|
||||
@JvmStatic
|
||||
fun checkPermissionsAndPerformAction(
|
||||
activity: Activity,
|
||||
onPermissionGranted: Runnable,
|
||||
onPermissionDenied: Runnable? = null,
|
||||
rationaleTitle: Int,
|
||||
rationaleMessage: Int,
|
||||
vararg permissions: String
|
||||
) {
|
||||
Dexter.withActivity(activity)
|
||||
.withPermissions(permissions)
|
||||
.withListener(new MultiplePermissionsListener() {
|
||||
@Override
|
||||
public void onPermissionsChecked(final MultiplePermissionsReport report) {
|
||||
if (report.areAllPermissionsGranted() || hasPartialAccess(activity)) {
|
||||
onPermissionGranted.run();
|
||||
return;
|
||||
}
|
||||
if (report.isAnyPermissionPermanentlyDenied()) {
|
||||
// permission is denied permanently, we will show user a dialog message.
|
||||
DialogUtil.showAlertDialog(
|
||||
activity, activity.getString(rationaleTitle),
|
||||
activity.getString(rationaleMessage),
|
||||
activity.getString(R.string.navigation_item_settings),
|
||||
null, () -> {
|
||||
askUserToManuallyEnablePermissionFromSettings(activity);
|
||||
if (activity instanceof UploadActivity) {
|
||||
((UploadActivity) activity).setShowPermissionsDialog(true);
|
||||
}
|
||||
}, null, null,
|
||||
!(activity instanceof UploadActivity));
|
||||
} else {
|
||||
if (null != onPermissionDenied) {
|
||||
onPermissionDenied.run();
|
||||
.withPermissions(*permissions)
|
||||
.withListener(object : MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport) {
|
||||
when {
|
||||
report.areAllPermissionsGranted() || hasPartialAccess(activity) ->
|
||||
Thread(onPermissionGranted).start()
|
||||
report.isAnyPermissionPermanentlyDenied -> {
|
||||
DialogUtil.showAlertDialog(
|
||||
activity,
|
||||
activity.getString(rationaleTitle),
|
||||
activity.getString(rationaleMessage),
|
||||
activity.getString(R.string.navigation_item_settings),
|
||||
null,
|
||||
{
|
||||
askUserToManuallyEnablePermissionFromSettings(activity)
|
||||
if (activity is UploadActivity) {
|
||||
activity.isShowPermissionsDialog = true
|
||||
}
|
||||
},
|
||||
null, null, activity !is UploadActivity
|
||||
)
|
||||
}
|
||||
else -> Thread(onPermissionDenied).start()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionRationaleShouldBeShown(
|
||||
final List<PermissionRequest> permissions,
|
||||
final PermissionToken token
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: List<PermissionRequest>, token: PermissionToken
|
||||
) {
|
||||
if (rationaleTitle == -1 && rationaleMessage == -1) {
|
||||
token.continuePermissionRequest();
|
||||
return;
|
||||
token.continuePermissionRequest()
|
||||
return
|
||||
}
|
||||
DialogUtil.showAlertDialog(
|
||||
activity, activity.getString(rationaleTitle),
|
||||
activity,
|
||||
activity.getString(rationaleTitle),
|
||||
activity.getString(rationaleMessage),
|
||||
activity.getString(android.R.string.ok),
|
||||
activity.getString(android.R.string.cancel),
|
||||
() -> {
|
||||
if (activity instanceof UploadActivity) {
|
||||
((UploadActivity) activity).setShowPermissionsDialog(true);
|
||||
{
|
||||
if (activity is UploadActivity) {
|
||||
activity.setShowPermissionsDialog(true)
|
||||
}
|
||||
token.continuePermissionRequest();
|
||||
token.continuePermissionRequest()
|
||||
},
|
||||
() -> {
|
||||
Toast.makeText(activity.getApplicationContext(),
|
||||
{
|
||||
Toast.makeText(
|
||||
activity.applicationContext,
|
||||
R.string.permissions_are_required_for_functionality,
|
||||
Toast.LENGTH_LONG
|
||||
).show();
|
||||
token.cancelPermissionRequest();
|
||||
if (activity instanceof UploadActivity) {
|
||||
activity.finish();
|
||||
).show()
|
||||
token.cancelPermissionRequest()
|
||||
if (activity is UploadActivity) {
|
||||
activity.finish()
|
||||
}
|
||||
}, null, false
|
||||
);
|
||||
},
|
||||
null, false
|
||||
)
|
||||
}
|
||||
}).onSameThread().check();
|
||||
}).onSameThread().check()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,22 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.Sitelinks;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.Sitelinks
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
object PlaceUtils {
|
||||
|
||||
public class PlaceUtils {
|
||||
|
||||
public static LatLng latLngFromPointString(String pointString) {
|
||||
double latitude;
|
||||
double longitude;
|
||||
Matcher matcher = Pattern.compile("Point\\(([^ ]+) ([^ ]+)\\)").matcher(pointString);
|
||||
if (!matcher.find()) {
|
||||
return null;
|
||||
@JvmStatic
|
||||
fun latLngFromPointString(pointString: String): LatLng? {
|
||||
val matcher = Regex("Point\\(([^ ]+) ([^ ]+)\\)").find(pointString) ?: return null
|
||||
return try {
|
||||
val longitude = matcher.groupValues[1].toDouble()
|
||||
val latitude = matcher.groupValues[2].toDouble()
|
||||
LatLng(latitude, longitude, 0.0F)
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
}
|
||||
try {
|
||||
longitude = Double.parseDouble(matcher.group(1));
|
||||
latitude = Double.parseDouble(matcher.group(2));
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LatLng(latitude, longitude, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,22 +24,27 @@ public class PlaceUtils {
|
|||
* @param mediaList
|
||||
* @return
|
||||
*/
|
||||
public static List<Place> mediaToExplorePlace( List<Media> mediaList) {
|
||||
List<Place> explorePlaceList = new ArrayList<>();
|
||||
for (Media media :mediaList) {
|
||||
explorePlaceList.add(new Place(media.getFilename(),
|
||||
media.getFallbackDescription(),
|
||||
media.getCoordinates(),
|
||||
media.getCategories().toString(),
|
||||
new Sitelinks.Builder()
|
||||
.setCommonsLink(media.getPageTitle().getCanonicalUri())
|
||||
.setWikipediaLink("") // we don't necessarily have them, can be fetched later
|
||||
.setWikidataLink("") // we don't necessarily have them, can be fetched later
|
||||
.build(),
|
||||
media.getImageUrl(),
|
||||
media.getThumbUrl(),
|
||||
""));
|
||||
@JvmStatic
|
||||
fun mediaToExplorePlace(mediaList: List<Media>): List<Place> {
|
||||
val explorePlaceList = mutableListOf<Place>()
|
||||
for (media in mediaList) {
|
||||
explorePlaceList.add(
|
||||
Place(
|
||||
media.filename,
|
||||
media.fallbackDescription,
|
||||
media.coordinates,
|
||||
media.categories.toString(),
|
||||
Sitelinks.Builder()
|
||||
.setCommonsLink(media.pageTitle.canonicalUri)
|
||||
.setWikipediaLink("") // we don't necessarily have them, can be fetched later
|
||||
.setWikidataLink("") // we don't necessarily have them, can be fetched later
|
||||
.build(),
|
||||
media.imageUrl,
|
||||
media.thumbUrl,
|
||||
""
|
||||
)
|
||||
)
|
||||
}
|
||||
return explorePlaceList;
|
||||
return explorePlaceList
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import fr.free.nrw.commons.category.CategoryItem;
|
||||
import java.util.Comparator;
|
||||
import fr.free.nrw.commons.category.CategoryItem
|
||||
import java.lang.Math.signum
|
||||
import java.util.Comparator
|
||||
|
||||
public class StringSortingUtils {
|
||||
|
||||
private StringSortingUtils() {
|
||||
//no-op
|
||||
}
|
||||
object StringSortingUtils {
|
||||
|
||||
/**
|
||||
* Returns Comparator for sorting strings by their similarity to the filter.
|
||||
|
|
@ -17,74 +15,72 @@ public class StringSortingUtils {
|
|||
* @param filter String to compare similarity with
|
||||
* @return Comparator with string similarity
|
||||
*/
|
||||
public static Comparator<CategoryItem> sortBySimilarity(final String filter) {
|
||||
return (firstItem, secondItem) -> {
|
||||
double firstItemSimilarity = calculateSimilarity(firstItem.getName(), filter);
|
||||
double secondItemSimilarity = calculateSimilarity(secondItem.getName(), filter);
|
||||
return (int) Math.signum(secondItemSimilarity - firstItemSimilarity);
|
||||
};
|
||||
@JvmStatic
|
||||
fun sortBySimilarity(filter: String): Comparator<CategoryItem> {
|
||||
return Comparator { firstItem, secondItem ->
|
||||
val firstItemSimilarity = calculateSimilarity(firstItem.name, filter)
|
||||
val secondItemSimilarity = calculateSimilarity(secondItem.name, filter)
|
||||
signum(secondItemSimilarity - firstItemSimilarity).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines String similarity between str1 and str2 on scale from 0.0 to 1.0
|
||||
* @param str1 String 1
|
||||
* @param str2 String 2
|
||||
* @return Double between 0.0 and 1.0 that reflects string similarity
|
||||
*/
|
||||
private static double calculateSimilarity(String str1, String str2) {
|
||||
int longerLength = Math.max(str1.length(), str2.length());
|
||||
private fun calculateSimilarity(str1: String, str2: String): Double {
|
||||
val longerLength = maxOf(str1.length, str2.length)
|
||||
|
||||
if (longerLength == 0) return 1.0;
|
||||
if (longerLength == 0) return 1.0
|
||||
|
||||
int distanceBetweenStrings = levenshteinDistance(str1, str2);
|
||||
return (longerLength - distanceBetweenStrings) / (double) longerLength;
|
||||
val distanceBetweenStrings = levenshteinDistance(str1, str2)
|
||||
return (longerLength - distanceBetweenStrings) / longerLength.toDouble()
|
||||
}
|
||||
|
||||
/**
|
||||
* Levershtein distance algorithm
|
||||
* Levenshtein distance algorithm
|
||||
* https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Java
|
||||
*
|
||||
* @param str1 String 1
|
||||
* @param str2 String 2
|
||||
* @return Number of characters the strings differ by
|
||||
*/
|
||||
private static int levenshteinDistance(String str1, String str2) {
|
||||
if (str1.equals(str2)) return 0;
|
||||
if (str1.length() == 0) return str2.length();
|
||||
if (str2.length() == 0) return str1.length();
|
||||
private fun levenshteinDistance(str1: String, str2: String): Int {
|
||||
if (str1 == str2) return 0
|
||||
if (str1.isEmpty()) return str2.length
|
||||
if (str2.isEmpty()) return str1.length
|
||||
|
||||
int[] cost = new int[str1.length() + 1];
|
||||
int[] newcost = new int[str1.length() + 1];
|
||||
|
||||
// initial cost of skipping prefix in str1
|
||||
for (int i = 0; i < cost.length; i++) cost[i] = i;
|
||||
var cost = IntArray(str1.length + 1) { it }
|
||||
var newCost = IntArray(str1.length + 1)
|
||||
|
||||
// transformation cost for each letter in str2
|
||||
for (int j = 1; j <= str2.length(); j++) {
|
||||
for (j in 1..str2.length) {
|
||||
// initial cost of skipping prefix in String str2
|
||||
newcost[0] = j;
|
||||
newCost[0] = j
|
||||
|
||||
// transformation cost for each letter in str1
|
||||
for(int i = 1; i < cost.length; i++) {
|
||||
for (i in 1..str1.length) {
|
||||
// matching current letters in both strings
|
||||
int match = (str1.charAt(i - 1) == str2.charAt(j - 1)) ? 0 : 1;
|
||||
val match = if (str1[i - 1] == str2[j - 1]) 0 else 1
|
||||
|
||||
// computing cost for each transformation
|
||||
int cost_replace = cost[i - 1] + match;
|
||||
int cost_insert = cost[i] + 1;
|
||||
int cost_delete = newcost[i - 1] + 1;
|
||||
val costReplace = cost[i - 1] + match
|
||||
val costInsert = cost[i] + 1
|
||||
val costDelete = newCost[i - 1] + 1
|
||||
|
||||
// keep minimum cost
|
||||
newcost[i] = Math.min(Math.min(cost_insert, cost_delete), cost_replace);
|
||||
newCost[i] = minOf(costInsert, costDelete, costReplace)
|
||||
}
|
||||
|
||||
int[] tmp = cost;
|
||||
cost = newcost;
|
||||
newcost = tmp;
|
||||
// swap cost arrays
|
||||
val tmp = cost
|
||||
cost = newCost
|
||||
newCost = tmp
|
||||
}
|
||||
|
||||
// the distance is the cost for transforming all letters in both strings
|
||||
return cost[str1.length()];
|
||||
return cost[str1.length]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,37 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.os.Build;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.text.SpannedString;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.os.Build
|
||||
import android.text.Html
|
||||
import android.text.Spanned
|
||||
import android.text.SpannedString
|
||||
|
||||
public final class StringUtil {
|
||||
object StringUtil {
|
||||
|
||||
/**
|
||||
* @param source String that may contain HTML tags.
|
||||
* @return returned Spanned string that may contain spans parsed from the HTML source.
|
||||
*/
|
||||
@NonNull public static Spanned fromHtml(@Nullable String source) {
|
||||
@JvmStatic
|
||||
fun fromHtml(source: String?): Spanned {
|
||||
if (source == null) {
|
||||
return new SpannedString("");
|
||||
return SpannedString("")
|
||||
}
|
||||
if (!source.contains("<") && !source.contains("&")) {
|
||||
// If the string doesn't contain any hints of HTML entities, then skip the expensive
|
||||
// processing that fromHtml() performs.
|
||||
return new SpannedString(source);
|
||||
return SpannedString(source)
|
||||
}
|
||||
source = source.replaceAll("‎", "\u200E")
|
||||
.replaceAll("‏", "\u200F")
|
||||
.replaceAll("&", "&");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY);
|
||||
val processedSource = source
|
||||
.replace("‎", "\u200E")
|
||||
.replace("‏", "\u200F")
|
||||
.replace("&", "&")
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(processedSource, Html.FROM_HTML_MODE_LEGACY)
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
return Html.fromHtml(source);
|
||||
@Suppress("DEPRECATION")
|
||||
Html.fromHtml(processedSource)
|
||||
}
|
||||
}
|
||||
|
||||
private StringUtil() {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,74 +1,64 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.cardview.widget.CardView
|
||||
|
||||
import timber.log.Timber;
|
||||
import timber.log.Timber
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* A card view which informs onSwipe events to its child
|
||||
*/
|
||||
public abstract class SwipableCardView extends CardView {
|
||||
float x1, x2;
|
||||
private static final float MINIMUM_THRESHOLD_FOR_SWIPE = 100;
|
||||
abstract class SwipableCardView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : CardView(context, attrs, defStyleAttr) {
|
||||
|
||||
public SwipableCardView(@NonNull Context context) {
|
||||
super(context);
|
||||
interceptOnTouchListener();
|
||||
private var x1 = 0f
|
||||
private var x2 = 0f
|
||||
private val MINIMUM_THRESHOLD_FOR_SWIPE = 100f
|
||||
|
||||
init {
|
||||
interceptOnTouchListener()
|
||||
}
|
||||
|
||||
public SwipableCardView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
interceptOnTouchListener();
|
||||
}
|
||||
|
||||
public SwipableCardView(@NonNull Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
interceptOnTouchListener();
|
||||
}
|
||||
|
||||
private void interceptOnTouchListener() {
|
||||
this.setOnTouchListener((v, event) -> {
|
||||
boolean isSwipe = false;
|
||||
float deltaX = 0.0f;
|
||||
Timber.e(event.getAction() + "");
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
x1 = event.getX();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
x2 = event.getX();
|
||||
deltaX = x2 - x1;
|
||||
if (deltaX < 0) {
|
||||
//Right to left swipe
|
||||
isSwipe = true;
|
||||
} else if (deltaX > 0) {
|
||||
//Left to right swipe
|
||||
isSwipe = true;
|
||||
}
|
||||
break;
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private fun interceptOnTouchListener() {
|
||||
this.setOnTouchListener { v, event ->
|
||||
var isSwipe = false
|
||||
var deltaX = 0f
|
||||
Timber.e(event.action.toString())
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
x1 = event.x
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
x2 = event.x
|
||||
deltaX = x2 - x1
|
||||
isSwipe = deltaX != 0f
|
||||
}
|
||||
}
|
||||
if (isSwipe && (pixelToDp(Math.abs(deltaX)) > MINIMUM_THRESHOLD_FOR_SWIPE)) {
|
||||
return onSwipe(v);
|
||||
if (isSwipe && pixelToDp(abs(deltaX)) > MINIMUM_THRESHOLD_FOR_SWIPE) {
|
||||
onSwipe(v)
|
||||
return@setOnTouchListener true
|
||||
}
|
||||
return false;
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* abstract function which informs swipe events to those who have inherited from it
|
||||
*/
|
||||
public abstract boolean onSwipe(View view);
|
||||
abstract fun onSwipe(view: View): Boolean
|
||||
|
||||
private float pixelToDp(float pixels) {
|
||||
return (pixels / Resources.getSystem().getDisplayMetrics().density);
|
||||
private fun pixelToDp(pixels: Float): Float {
|
||||
return pixels / Resources.getSystem().displayMetrics.density
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,49 +1,52 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.settings.Prefs
|
||||
|
||||
public class SystemThemeUtils {
|
||||
|
||||
private Context context;
|
||||
private JsonKvStore applicationKvStore;
|
||||
class SystemThemeUtils @Inject constructor(
|
||||
private val context: Context,
|
||||
@Named("default_preferences") private val applicationKvStore: JsonKvStore
|
||||
) {
|
||||
|
||||
public static final String THEME_MODE_DEFAULT = "0";
|
||||
public static final String THEME_MODE_DARK = "1";
|
||||
public static final String THEME_MODE_LIGHT = "2";
|
||||
|
||||
@Inject
|
||||
public SystemThemeUtils(Context context, @Named("default_preferences") JsonKvStore applicationKvStore) {
|
||||
this.context = context;
|
||||
this.applicationKvStore = applicationKvStore;
|
||||
companion object {
|
||||
const val THEME_MODE_DEFAULT = "0"
|
||||
const val THEME_MODE_DARK = "1"
|
||||
const val THEME_MODE_LIGHT = "2"
|
||||
}
|
||||
|
||||
// Return true is system wide dark theme is enabled else false
|
||||
public boolean getSystemDefaultThemeBool(String theme) {
|
||||
if (theme.equals(THEME_MODE_DARK)) {
|
||||
return true;
|
||||
} else if (theme.equals(THEME_MODE_DEFAULT)) {
|
||||
return getSystemDefaultThemeBool(getSystemDefaultTheme());
|
||||
// Return true if system wide dark theme is enabled else false
|
||||
private fun getSystemDefaultThemeBool(theme: String): Boolean {
|
||||
return when (theme) {
|
||||
THEME_MODE_DARK -> true
|
||||
THEME_MODE_DEFAULT -> getSystemDefaultThemeBool(getSystemDefaultTheme())
|
||||
else -> false
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns the default system wide theme
|
||||
public String getSystemDefaultTheme() {
|
||||
return (context.getResources().getConfiguration().uiMode &
|
||||
Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES ? THEME_MODE_DARK : THEME_MODE_LIGHT;
|
||||
private fun getSystemDefaultTheme(): String {
|
||||
return if (
|
||||
(
|
||||
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK)
|
||||
== Configuration.UI_MODE_NIGHT_YES
|
||||
) {
|
||||
THEME_MODE_DARK
|
||||
} else {
|
||||
THEME_MODE_LIGHT
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the device is in night mode or false otherwise
|
||||
public boolean isDeviceInNightMode() {
|
||||
fun isDeviceInNightMode(): Boolean {
|
||||
return getSystemDefaultThemeBool(
|
||||
applicationKvStore.getString(Prefs.KEY_THEME_VALUE, getSystemDefaultTheme()));
|
||||
applicationKvStore.getString(Prefs.KEY_THEME_VALUE, getSystemDefaultTheme())
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,30 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UiUtils {
|
||||
object UiUtils {
|
||||
|
||||
/**
|
||||
* Draws a vectorial image onto a bitmap.
|
||||
* @param vectorDrawable vectorial image
|
||||
* @return bitmap representation of the vectorial image
|
||||
*/
|
||||
public static Bitmap getBitmap(VectorDrawableCompat vectorDrawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
|
||||
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
vectorDrawable.draw(canvas);
|
||||
return bitmap;
|
||||
@JvmStatic
|
||||
fun getBitmap(vectorDrawable: VectorDrawableCompat): Bitmap {
|
||||
val bitmap = Bitmap.createBitmap(
|
||||
vectorDrawable.intrinsicWidth,
|
||||
vectorDrawable.intrinsicHeight,
|
||||
Bitmap.Config.ARGB_8888
|
||||
)
|
||||
val canvas = Canvas(bitmap)
|
||||
vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||
vectorDrawable.draw(canvas)
|
||||
return bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -32,8 +33,9 @@ public class UiUtils {
|
|||
* @param context Context to access display metrics
|
||||
* @return px equivalent to dp value
|
||||
*/
|
||||
public static float convertDpToPixel(float dp, Context context) {
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
|
||||
@JvmStatic
|
||||
fun convertDpToPixel(dp: Float, context: Context): Float {
|
||||
val metrics = context.resources.displayMetrics
|
||||
return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,121 +1,126 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.view.Display
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
import fr.free.nrw.commons.R;
|
||||
import timber.log.Timber;
|
||||
import fr.free.nrw.commons.R
|
||||
import timber.log.Timber
|
||||
|
||||
|
||||
object ViewUtil {
|
||||
|
||||
public class ViewUtil {
|
||||
/**
|
||||
* Utility function to show short snack bar
|
||||
* @param view
|
||||
* @param messageResourceId
|
||||
*/
|
||||
public static void showShortSnackbar(View view, int messageResourceId) {
|
||||
if (view.getContext() == null) {
|
||||
return;
|
||||
@JvmStatic
|
||||
fun showShortSnackbar(view: View, messageResourceId: Int) {
|
||||
if (view.context == null) {
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute(() -> {
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
try {
|
||||
Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show();
|
||||
}catch (IllegalStateException e){
|
||||
Timber.e(e.getMessage());
|
||||
Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show()
|
||||
} catch (e: IllegalStateException) {
|
||||
Timber.e(e.message)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public static void showLongSnackbar(View view, String text) {
|
||||
if(view.getContext() == null) {
|
||||
return;
|
||||
|
||||
@JvmStatic
|
||||
fun showLongSnackbar(view: View, text: String) {
|
||||
if (view.context == null) {
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute(()-> {
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
try {
|
||||
Snackbar snackbar = Snackbar.make(view, text, Snackbar.LENGTH_SHORT);
|
||||
val snackbar = Snackbar.make(view, text, Snackbar.LENGTH_SHORT)
|
||||
val snackView = snackbar.view
|
||||
val snackText: TextView = snackView.findViewById(R.id.snackbar_text)
|
||||
|
||||
View snack_view = snackbar.getView();
|
||||
TextView snack_text = snack_view.findViewById(R.id.snackbar_text);
|
||||
snackView.setBackgroundColor(Color.LTGRAY)
|
||||
snackText.setTextColor(ContextCompat.getColor(view.context, R.color.primaryColor))
|
||||
snackbar.setActionTextColor(Color.RED)
|
||||
|
||||
snack_view.setBackgroundColor(Color.LTGRAY);
|
||||
snack_text.setTextColor(ContextCompat.getColor(view.getContext(), R.color.primaryColor));
|
||||
snackbar.setActionTextColor(Color.RED);
|
||||
snackbar.setAction("Dismiss") { snackbar.dismiss() }
|
||||
snackbar.show()
|
||||
|
||||
snackbar.setAction("Dismiss", new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Handle the action click
|
||||
snackbar.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
snackbar.show();
|
||||
|
||||
}catch (IllegalStateException e) {
|
||||
Timber.e(e.getMessage());
|
||||
} catch (e: IllegalStateException) {
|
||||
Timber.e(e.message)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void showLongToast(Context context, String text) {
|
||||
@JvmStatic
|
||||
fun showLongToast(context: Context, text: String) {
|
||||
if (context == null) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute(() -> Toast.makeText(context, text, Toast.LENGTH_LONG).show());
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
Toast.makeText(context, text, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
public static void showLongToast(Context context, @StringRes int stringResourceId) {
|
||||
@JvmStatic
|
||||
fun showLongToast(context: Context, @StringRes stringResourceId: Int) {
|
||||
if (context == null) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute(() -> Toast.makeText(context, context.getString(stringResourceId), Toast.LENGTH_LONG).show());
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
Toast.makeText(context, context.getString(stringResourceId), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
public static void showShortToast(Context context, String text) {
|
||||
@JvmStatic
|
||||
fun showShortToast(context: Context, text: String) {
|
||||
if (context == null) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute(() -> Toast.makeText(context, text, Toast.LENGTH_SHORT).show());
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
public static void showShortToast(Context context, @StringRes int stringResourceId) {
|
||||
@JvmStatic
|
||||
fun showShortToast(context: Context?, @StringRes stringResourceId: Int) {
|
||||
if (context == null) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute(() -> Toast.makeText(context, context.getString(stringResourceId), Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
|
||||
public static boolean isPortrait(Context context) {
|
||||
Display orientation = ((Activity)context).getWindowManager().getDefaultDisplay();
|
||||
if (orientation.getWidth() < orientation.getHeight()){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
Toast.makeText(context, context.getString(stringResourceId), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
public static void hideKeyboard(View view){
|
||||
if (view != null) {
|
||||
InputMethodManager manager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
view.clearFocus();
|
||||
if (manager != null) {
|
||||
manager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
@JvmStatic
|
||||
fun isPortrait(context: Context): Boolean {
|
||||
val orientation = (context as Activity).windowManager.defaultDisplay
|
||||
return orientation.width < orientation.height
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun hideKeyboard(view: View?) {
|
||||
view?.let {
|
||||
val manager = it.context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
it.clearFocus()
|
||||
manager?.hideSoftInputFromWindow(it.windowToken, 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,21 +128,24 @@ public class ViewUtil {
|
|||
* A snack bar which has an action button which on click dismisses the snackbar and invokes the
|
||||
* listener passed
|
||||
*/
|
||||
public static void showDismissibleSnackBar(View view,
|
||||
int messageResourceId,
|
||||
int actionButtonResourceId,
|
||||
View.OnClickListener onClickListener) {
|
||||
if (view.getContext() == null) {
|
||||
return;
|
||||
@JvmStatic
|
||||
fun showDismissibleSnackBar(
|
||||
view: View,
|
||||
messageResourceId: Int,
|
||||
actionButtonResourceId: Int,
|
||||
onClickListener: View.OnClickListener
|
||||
) {
|
||||
if (view.context == null) {
|
||||
return
|
||||
}
|
||||
|
||||
ExecutorUtils.uiExecutor().execute {
|
||||
val snackbar = Snackbar.make(view, view.context.getString(messageResourceId), Snackbar.LENGTH_INDEFINITE)
|
||||
snackbar.setAction(view.context.getString(actionButtonResourceId)) {
|
||||
snackbar.dismiss()
|
||||
onClickListener.onClick(it)
|
||||
}
|
||||
snackbar.show()
|
||||
}
|
||||
ExecutorUtils.uiExecutor().execute(() -> {
|
||||
Snackbar snackbar = Snackbar.make(view, view.getContext().getString(messageResourceId),
|
||||
Snackbar.LENGTH_INDEFINITE);
|
||||
snackbar.setAction(view.getContext().getString(actionButtonResourceId), v -> {
|
||||
snackbar.dismiss();
|
||||
onClickListener.onClick(v);
|
||||
});
|
||||
snackbar.show();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,17 @@
|
|||
package fr.free.nrw.commons.utils;
|
||||
package fr.free.nrw.commons.utils
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import android.content.Context
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
public class ViewUtilWrapper {
|
||||
|
||||
@Inject
|
||||
public ViewUtilWrapper() {
|
||||
class ViewUtilWrapper @Inject constructor() {
|
||||
|
||||
fun showShortToast(context: Context, text: String) {
|
||||
ViewUtil.showShortToast(context, text)
|
||||
}
|
||||
|
||||
public void showShortToast(Context context, String text) {
|
||||
ViewUtil.showShortToast(context, text);
|
||||
}
|
||||
|
||||
public void showLongToast(Context context, String text) {
|
||||
ViewUtil.showLongToast(context, text);
|
||||
fun showLongToast(context: Context, text: String) {
|
||||
ViewUtil.showLongToast(context, text)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue