Migrated all remaining files in util module

This commit is contained in:
Saifuddin 2024-11-18 14:18:31 +05:30
parent a42067ef34
commit d543625353
18 changed files with 540 additions and 568 deletions

View file

@ -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());
}

View file

@ -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;

View file

@ -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;

View file

@ -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()
);
}
}

View file

@ -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) {

View file

@ -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

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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()
}
}

View file

@ -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
}
}

View file

@ -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]
}
}

View file

@ -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("&#8206;", "\u200E")
.replaceAll("&#8207;", "\u200F")
.replaceAll("&amp;", "&");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY);
val processedSource = source
.replace("&#8206;", "\u200E")
.replace("&#8207;", "\u200F")
.replace("&amp;", "&")
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() {
}
}

View file

@ -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
}
}

View file

@ -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())
)
}
}

View file

@ -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())
}
}

View file

@ -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();
});
}
}

View file

@ -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)
}
}