getInstance(@NonNull Context context) {
if (!ENGINE.isPresent()) {
var installTask = CronetProviderInstaller.installProvider(context);
- return TaskAdapter.fromTask(installTask)
+ return RXJavaAdapters.fromTask(installTask)
.map(_void -> new CronetEngine.Builder(context))
.onErrorResumeNext(throwable -> {
Log.e("CronetEngineProvider", "Failed to install Cronet provider " + throwable);
diff --git a/app/src/main/java/rs/chir/invtracker/api/package-info.java b/app/src/main/java/rs/chir/invtracker/api/package-info.java
index 29aebc8..6b4ba1f 100644
--- a/app/src/main/java/rs/chir/invtracker/api/package-info.java
+++ b/app/src/main/java/rs/chir/invtracker/api/package-info.java
@@ -1,6 +1,6 @@
/**
* API client tools.
- *
+ *
* You can retrieve an API client using {@link rs.chir.invtracker.client.Application#getClient()}.
*/
package rs.chir.invtracker.api;
\ No newline at end of file
diff --git a/app/src/main/java/rs/chir/invtracker/client/Application.java b/app/src/main/java/rs/chir/invtracker/client/Application.java
index 2f65475..3a0f4bd 100644
--- a/app/src/main/java/rs/chir/invtracker/client/Application.java
+++ b/app/src/main/java/rs/chir/invtracker/client/Application.java
@@ -25,7 +25,7 @@ import rs.chir.invtracker.api.ClientImpl;
* @see android.app.Application
*/
public class Application extends android.app.Application {
- /**
+ /**
* The instance of the API client.
*/
private Optional client = Optional.empty();
@@ -36,6 +36,7 @@ public class Application extends android.app.Application {
/**
* Returns the Application instance for a context
+ *
* @param context the context to get the Application instance for
* @return the Application instance for the context
*/
@@ -64,6 +65,7 @@ public class Application extends android.app.Application {
/**
* Returns the preferences datastore.
+ *
* @return the preferences datastore
*/
@NonNull
@@ -73,6 +75,7 @@ public class Application extends android.app.Application {
/**
* Returns the API client.
+ *
* @return A single that completes with the API client.
*/
@NonNull
diff --git a/app/src/main/java/rs/chir/invtracker/client/EditItemFragment.java b/app/src/main/java/rs/chir/invtracker/client/EditItemFragment.java
index 1d3be3f..2622a7b 100644
--- a/app/src/main/java/rs/chir/invtracker/client/EditItemFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/EditItemFragment.java
@@ -1,10 +1,8 @@
package rs.chir.invtracker.client;
-import static android.app.Activity.RESULT_OK;
import static android.provider.MediaStore.ACTION_PICK_IMAGES;
import android.Manifest;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -20,7 +18,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;
-import androidx.fragment.app.Fragment;
import java.io.File;
import java.io.IOException;
@@ -112,7 +109,7 @@ public class EditItemFragment extends FragmentBase {
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
- * @param itemId the item ID to edit.
+ * @param itemId the item ID to edit.
* @param editMode true
if you want to edit, create otherwise.
* @return A new instance of fragment EditItemFragment.
*/
@@ -145,7 +142,7 @@ public class EditItemFragment extends FragmentBase {
this.subscribe(this.getClient().flatMap(client -> client.getObject(mId)), this::prefillItem);
}
this.getBinding().buttonTakePicture.setOnClickListener(v -> {
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.requestPermission(Manifest.permission.CAMERA);
return;
}
@@ -178,7 +175,7 @@ public class EditItemFragment extends FragmentBase {
var description = this.getBinding().editTextDescription.getText().toString();
var item = new TrackedItem(mId, name, description, this.image, Optional.empty());
// Update or create the item
- if(mEditMode) {
+ if (mEditMode) {
this.subscribe(this.getClient().flatMap(client -> client.updateObject(item)), this::onActionSuccess);
} else {
this.subscribe(this.getClient().flatMap(client -> client.createObject(item)), this::onActionSuccess);
@@ -187,10 +184,11 @@ public class EditItemFragment extends FragmentBase {
/**
* Handler for when the saving of the item is successful.
+ *
* @param item the item that was saved.
*/
private void onActionSuccess(TrackedItem trackedItem) {
- if(mEditMode) {
+ if (mEditMode) {
// return if we were editing
this.getNavController().navigateUp();
} else {
@@ -201,6 +199,7 @@ public class EditItemFragment extends FragmentBase {
/**
* Pick an @{link ActivityResultLauncher} to use for picking an image.
+ *
* @return the @{link ActivityResultLauncher} to use for picking an image.
*/
private ActivityResultLauncher getImagePickerLauncher() {
@@ -220,6 +219,7 @@ public class EditItemFragment extends FragmentBase {
/**
* Callback for when an image was taken.
+ *
* @param success true
if the image was taken successfully.
*/
private void onPictureTaken(@NonNull Boolean success) {
@@ -234,6 +234,7 @@ public class EditItemFragment extends FragmentBase {
/**
* Upload an image to the server.
+ *
* @param uri the source image URI.
*/
private void uploadImage(Uri uri) {
@@ -255,6 +256,7 @@ public class EditItemFragment extends FragmentBase {
/**
* Attempts to take a picture with the camera.
+ *
* @throws IOException if the camera cannot be accessed.
*/
private void takePicture() throws IOException {
@@ -277,6 +279,7 @@ public class EditItemFragment extends FragmentBase {
/**
* Prefill the fragment with the given item.
+ *
* @param item the item to prefill with.
*/
private void prefillItem(@NonNull TrackedItem trackedItem) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/FragmentBase.java b/app/src/main/java/rs/chir/invtracker/client/FragmentBase.java
index d2cd179..61776a6 100644
--- a/app/src/main/java/rs/chir/invtracker/client/FragmentBase.java
+++ b/app/src/main/java/rs/chir/invtracker/client/FragmentBase.java
@@ -5,7 +5,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import androidx.activity.result.ActivityResultCaller;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.IdRes;
@@ -22,8 +21,8 @@ import androidx.viewbinding.ViewBinding;
import com.google.android.material.snackbar.Snackbar;
-import java.util.ConcurrentModificationException;
import java.lang.reflect.InvocationTargetException;
+import java.util.ConcurrentModificationException;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
@@ -38,6 +37,7 @@ import rs.chir.utils.TypeParameterGetter;
/**
* Base class for all fragments.
+ *
* @param the type of the view binding.
*/
public class FragmentBase extends Fragment implements TypeParameterGetter {
@@ -56,9 +56,23 @@ public class FragmentBase extends Fragment
*/
@Nullable
private MenuProvider menuProvider;
+ private String requestedPermission;
+ /**
+ * Permissions request launcher
+ */
+ private final ActivityResultLauncher permissionLauncher = this.registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
+ var permission = this.requestedPermission;
+ this.requestedPermission = null;
+ if (isGranted) {
+ this.onPermissionGranted(permission);
+ } else {
+ this.onPermissionDenied(permission);
+ }
+ });
/**
* Retrieves the fragment binding
+ *
* @return the fragment binding
*/
@NonNull
@@ -71,6 +85,7 @@ public class FragmentBase extends Fragment
/**
* Sets the fragment binding
+ *
* @param binding the fragment binding
*/
protected void setBinding(@NonNull FragmentBinding binding) {
@@ -79,8 +94,9 @@ public class FragmentBase extends Fragment
/**
* Called when the view is created.
- * @param inflater the layout inflater
- * @param container the container view
+ *
+ * @param inflater the layout inflater
+ * @param container the container view
* @param savedInstanceState the saved instance state
* @return the inflated view
*/
@@ -92,10 +108,11 @@ public class FragmentBase extends Fragment
/**
* Called when the view is created.
- * @param inflater the layout inflater
- * @param container the container view
+ *
+ * @param inflater the layout inflater
+ * @param container the container view
* @param savedInstanceState the saved instance state
- * @param clazz the class of the fragment binding
+ * @param clazz the class of the fragment binding
* @return the inflated view
*/
protected View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@@ -115,6 +132,7 @@ public class FragmentBase extends Fragment
/**
* Adds a disposable to the {@link CompositeDisposable}
+ *
* @param disposable the disposable to add
*/
protected void setAction(@NonNull Disposable action) {
@@ -127,7 +145,8 @@ public class FragmentBase extends Fragment
/**
* Subscribe to the given observable and add it to the {@link CompositeDisposable}
- * @param value the observable to subscribe to
+ *
+ * @param value the observable to subscribe to
* @param consumer the consumer to call when the observable emits an item
*/
protected void subscribe(@NonNull Observable value, @NonNull Consumer super T> consumer) {
@@ -136,7 +155,8 @@ public class FragmentBase extends Fragment
/**
* Subscribe to the given single and add it to the {@link CompositeDisposable}
- * @param value the single to subscribe to
+ *
+ * @param value the single to subscribe to
* @param consumer the consumer to call when the single emits an item
*/
protected void subscribe(@NonNull Single value, @NonNull Consumer consumer) {
@@ -145,9 +165,10 @@ public class FragmentBase extends Fragment
/**
* Subscribe to the given single and add it to the {@link CompositeDisposable}
- * @param value the single to subscribe to
+ *
+ * @param value the single to subscribe to
* @param consumer the consumer to call when the observable emits an item
- * @param error the consumer to call when an error occurs
+ * @param error the consumer to call when an error occurs
*/
protected void subscribe(@NonNull Single extends T> value, @NonNull Consumer super T> consumer, @NonNull Consumer super Throwable> error) {
this.subscribe(value.toObservable(), consumer, error);
@@ -155,9 +176,10 @@ public class FragmentBase extends Fragment
/**
* Subscribe to the given observable and add it to the {@link CompositeDisposable}
- * @param value the observable to subscribe to
+ *
+ * @param value the observable to subscribe to
* @param consumer the consumer to call when the observable emits an item
- * @param error the consumer to call when an error occurs
+ * @param error the consumer to call when an error occurs
*/
protected void subscribe(@NonNull Observable value, @NonNull Consumer super T> consumer, @NonNull Consumer super Throwable> error) {
this.setAction(value.subscribeOn(Schedulers.io())
@@ -167,7 +189,8 @@ public class FragmentBase extends Fragment
/**
* Called when the fragment is attached to the view.
- * @param view the view
+ *
+ * @param view the view
* @param savedInstanceState the saved instance state
*/
@Override
@@ -181,6 +204,7 @@ public class FragmentBase extends Fragment
/**
* Creates this fragment’s menu provider.
+ *
* @return the menu provider, or null if no menu provider is needed
*/
@Nullable
@@ -213,6 +237,7 @@ public class FragmentBase extends Fragment
/**
* Returns the menu host
+ *
* @return the menu host
*/
@NonNull
@@ -223,6 +248,7 @@ public class FragmentBase extends Fragment
/**
* Returns the application
+ *
* @return the application
*/
@NonNull
@@ -232,6 +258,7 @@ public class FragmentBase extends Fragment
/**
* Returns the API client
+ *
* @return the API client
*/
@NonNull
@@ -241,6 +268,7 @@ public class FragmentBase extends Fragment
/**
* Returns the navigation controller
+ *
* @return the navigation controller
*/
@NonNull
@@ -250,15 +278,16 @@ public class FragmentBase extends Fragment
/**
* Navigate to the given fragment
+ *
* @param id the action id
*/
void navigate(@IdRes int id) {
this.getNavController().navigate(id);
}
-
/**
* Checks if the app has the given permission
+ *
* @param permission the permission to check
* @return true if the app has the permission, false otherwise
*/
@@ -268,6 +297,7 @@ public class FragmentBase extends Fragment
/**
* Called on action error
+ *
* @param throwable the throwable
*/
protected void onActionError(@NonNull Throwable throwable) {
@@ -279,51 +309,41 @@ public class FragmentBase extends Fragment
/**
* Navigates to the given fragment
+ *
* @param fragmentDirection the fragment direction
*/
void navigate(NavDirections fragmentDirection) {
this.getNavController().navigate(fragmentDirection);
}
- private String requestedPermission;
-
- /**
- * Permissions request launcher
- */
- private final ActivityResultLauncher permissionLauncher = this.registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
- var permission = this.requestedPermission;
- this.requestedPermission = null;
- if (isGranted) {
- this.onPermissionGranted(permission);
- } else {
- this.onPermissionDenied(permission);
- }
- });
-
/**
* Called when the requested permission is granted
+ *
* @param permission the permission
*/
protected void onPermissionGranted(@NonNull String permission) {
}
+
/**
* Called when the requested permission is denied
+ *
* @param permission the permission
*/
protected void onPermissionDenied(@NonNull String permission) {
- this.onActionError(new RuntimeException("Permission denied: " + permission));
+ this.onActionError(new RuntimeException("Permission denied: " + permission));
}
/**
* Requests the given permission
+ *
* @param permission the permission to request
*/
protected void requestPermission(@NonNull String permission) {
- if(this.hasPermission(permission)) {
+ if (this.hasPermission(permission)) {
this.onPermissionGranted(permission);
return;
}
- if(this.requestedPermission != null) {
+ if (this.requestedPermission != null) {
throw new ConcurrentModificationException("Only one permission can be requested at a time");
}
this.requestedPermission = permission;
diff --git a/app/src/main/java/rs/chir/invtracker/client/ItemDetailFragment.java b/app/src/main/java/rs/chir/invtracker/client/ItemDetailFragment.java
index 9162402..caa981b 100644
--- a/app/src/main/java/rs/chir/invtracker/client/ItemDetailFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/ItemDetailFragment.java
@@ -11,7 +11,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.view.MenuProvider;
-import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.io.File;
@@ -60,6 +59,7 @@ public class ItemDetailFragment extends FragmentBase
/**
* Called when the fragment is created.
+ *
* @param savedInstanceState The saved instance state.
*/
@Override
@@ -72,7 +72,8 @@ public class ItemDetailFragment extends FragmentBase
/**
* Called when the fragment is attached to the activity.
- * @param view The view.
+ *
+ * @param view The view.
* @param savedInstanceState The saved instance state.
*/
@Override
@@ -99,7 +100,7 @@ public class ItemDetailFragment extends FragmentBase
// Reload the item
this.subscribe(this.getClient().flatMap(client -> client.getObject(this.mId)), this::itemLoaded);
}
-
+
@Override
protected void onActionError(@NonNull Throwable throwable) {
Log.e("ItemDetailFragment", "Error loading item", throwable);
@@ -134,6 +135,7 @@ public class ItemDetailFragment extends FragmentBase
/**
* Fetches the image from the server
+ *
* @param image The image URI
*/
private void fetchImage(@NonNull URI image) {
@@ -143,7 +145,8 @@ public class ItemDetailFragment extends FragmentBase
/**
* Called when the URL is loaded
- * @param image The image URI
+ *
+ * @param image The image URI
* @param inputStream the response body
*/
private void imageLoaded(@NonNull URI image, @NonNull InputStream inputStream) {
@@ -171,6 +174,7 @@ public class ItemDetailFragment extends FragmentBase
/**
* Loads and returns the image if present
+ *
* @param image The image URI
* @return The image if present
*/
@@ -195,6 +199,7 @@ public class ItemDetailFragment extends FragmentBase
/**
* Returns the item id
+ *
* @return The item id
*/
long getmId() {
@@ -208,7 +213,8 @@ public class ItemDetailFragment extends FragmentBase
var builder = new AlertDialog.Builder(this.requireContext());
builder.setMessage(R.string.delete_warning)
.setPositiveButton(R.string.yes, (__1, __2) -> this.reallyDelete())
- .setNegativeButton(R.string.no, (__1, __2) -> {});
+ .setNegativeButton(R.string.no, (__1, __2) -> {
+ });
builder.create().show();
}
diff --git a/app/src/main/java/rs/chir/invtracker/client/ItemDetailMenuProvider.java b/app/src/main/java/rs/chir/invtracker/client/ItemDetailMenuProvider.java
index 9386779..dde7175 100644
--- a/app/src/main/java/rs/chir/invtracker/client/ItemDetailMenuProvider.java
+++ b/app/src/main/java/rs/chir/invtracker/client/ItemDetailMenuProvider.java
@@ -18,6 +18,7 @@ class ItemDetailMenuProvider implements MenuProvider {
/**
* Creates a new instance of {@link ItemDetailMenuProvider}
+ *
* @param itemDetailFragment the fragment
*/
ItemDetailMenuProvider(ItemDetailFragment itemDetailFragment) {
@@ -26,7 +27,8 @@ class ItemDetailMenuProvider implements MenuProvider {
/**
* Called when the menu is created
- * @param menu the menu
+ *
+ * @param menu the menu
* @param inflater the menu inflater
*/
@Override
@@ -36,6 +38,7 @@ class ItemDetailMenuProvider implements MenuProvider {
/**
* Called when an item is selected
+ *
* @param item the item
* @return true if the item was handled, false otherwise
*/
diff --git a/app/src/main/java/rs/chir/invtracker/client/LoadFragment.java b/app/src/main/java/rs/chir/invtracker/client/LoadFragment.java
index 237fe26..f855dd9 100644
--- a/app/src/main/java/rs/chir/invtracker/client/LoadFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/LoadFragment.java
@@ -19,6 +19,7 @@ public class LoadFragment extends FragmentBase {
/**
* Called when the API key is set.
+ *
* @param hasToken {@code true} if the API key is set, {@code false} otherwise.
*/
private void tokenResponse(boolean hasToken) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/LoginFragment.java b/app/src/main/java/rs/chir/invtracker/client/LoginFragment.java
index 0e5bcdc..d326565 100644
--- a/app/src/main/java/rs/chir/invtracker/client/LoginFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/LoginFragment.java
@@ -40,6 +40,7 @@ public class LoginFragment extends FragmentBase {
/**
* Called when the login button is clicked.
+ *
* @param view The view.
*/
private void login(View view) {
@@ -54,6 +55,7 @@ public class LoginFragment extends FragmentBase {
/**
* Called when the login response is received.
+ *
* @param token The token.
*/
private void loginResponse(@NonNull PasetoToken pasetoToken) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/MainActivity.java b/app/src/main/java/rs/chir/invtracker/client/MainActivity.java
index 85079b0..8fcca7b 100644
--- a/app/src/main/java/rs/chir/invtracker/client/MainActivity.java
+++ b/app/src/main/java/rs/chir/invtracker/client/MainActivity.java
@@ -45,6 +45,7 @@ public class MainActivity extends AppCompatActivity {
/**
* Returns the activity binding.
+ *
* @return The activity binding.
*/
@NonNull
diff --git a/app/src/main/java/rs/chir/invtracker/client/MapFragment.java b/app/src/main/java/rs/chir/invtracker/client/MapFragment.java
index c80dd93..1c12b3c 100644
--- a/app/src/main/java/rs/chir/invtracker/client/MapFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/MapFragment.java
@@ -1,7 +1,6 @@
package rs.chir.invtracker.client;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@@ -18,9 +17,6 @@ import org.osmdroid.config.Configuration;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.overlay.Marker;
-import java.util.ArrayList;
-import java.util.List;
-
import rs.chir.invtracker.client.databinding.FragmentMapBinding;
import rs.chir.invtracker.model.TrackedItem;
import rs.chir.invtracker.utils.SingleLocation;
@@ -70,6 +66,7 @@ public class MapFragment extends FragmentBase {
/**
* Creates and adds a marker for a tracked item
+ *
* @param item the tracked item to add a marker for
*/
private void addMarker(@NonNull TrackedItem item) {
@@ -103,8 +100,8 @@ public class MapFragment extends FragmentBase {
var map = this.getBinding().map;
map.getOverlays().clear();
this.subscribe(this.getClient().toObservable()
- .flatMap(client -> client.streamObjects().toObservable())
- .filter(item -> item.lastKnownLocation().isPresent()),
+ .flatMap(client -> client.streamObjects().toObservable())
+ .filter(item -> item.lastKnownLocation().isPresent()),
this::addMarker);
}
diff --git a/app/src/main/java/rs/chir/invtracker/client/MapMenuProvider.java b/app/src/main/java/rs/chir/invtracker/client/MapMenuProvider.java
index d803306..78b11d4 100644
--- a/app/src/main/java/rs/chir/invtracker/client/MapMenuProvider.java
+++ b/app/src/main/java/rs/chir/invtracker/client/MapMenuProvider.java
@@ -18,6 +18,7 @@ public class MapMenuProvider implements MenuProvider {
/**
* Creates a new instance of {@link MapMenuProvider}
+ *
* @param mapFragment the fragment
*/
public MapMenuProvider(MapFragment mapFragment) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/NearbyFragment.java b/app/src/main/java/rs/chir/invtracker/client/NearbyFragment.java
index e09585a..f703603 100644
--- a/app/src/main/java/rs/chir/invtracker/client/NearbyFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/NearbyFragment.java
@@ -58,6 +58,7 @@ public class NearbyFragment extends FragmentBase {
/**
* Change the filter mode.
+ *
* @param filterMode The new filter mode.
*/
void switchFilter(ListFilterMode filterMode) {
@@ -87,6 +88,7 @@ public class NearbyFragment extends FragmentBase {
/**
* Called when the location response is received.
+ *
* @param location The location.
*/
private void onLocationResponse(@NonNull GeoLocation location) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/NearbyMenuProvider.java b/app/src/main/java/rs/chir/invtracker/client/NearbyMenuProvider.java
index 456f64b..f420b40 100644
--- a/app/src/main/java/rs/chir/invtracker/client/NearbyMenuProvider.java
+++ b/app/src/main/java/rs/chir/invtracker/client/NearbyMenuProvider.java
@@ -6,7 +6,6 @@ import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.core.view.MenuProvider;
-import androidx.navigation.fragment.NavHostFragment;
/**
* The menu provider for {@link NearbyFragment}
@@ -19,6 +18,7 @@ class NearbyMenuProvider implements MenuProvider {
/**
* Creates a new instance of {@link NearbyMenuProvider}
+ *
* @param nearbyFragment the fragment
*/
public NearbyMenuProvider(NearbyFragment nearbyFragment) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/NearbyOnTouchListener.java b/app/src/main/java/rs/chir/invtracker/client/NearbyOnTouchListener.java
index 27d2411..5e4e32a 100644
--- a/app/src/main/java/rs/chir/invtracker/client/NearbyOnTouchListener.java
+++ b/app/src/main/java/rs/chir/invtracker/client/NearbyOnTouchListener.java
@@ -18,6 +18,7 @@ class NearbyOnTouchListener implements RecyclerView.OnItemTouchListener {
/**
* Creates a new instance of {@link NearbyOnTouchListener}
+ *
* @param nearbyFragment the fragment
*/
public NearbyOnTouchListener(NearbyFragment nearbyFragment) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/QRCodeFragment.java b/app/src/main/java/rs/chir/invtracker/client/QRCodeFragment.java
index e1b6098..e196286 100644
--- a/app/src/main/java/rs/chir/invtracker/client/QRCodeFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/QRCodeFragment.java
@@ -8,7 +8,6 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
import androidx.print.PrintHelper;
import com.google.zxing.BarcodeFormat;
@@ -130,6 +129,6 @@ public class QRCodeFragment extends FragmentBase {
@Override
protected void onPermissionGranted(@NonNull String permission) {
- this.storeBitmap();
+ this.storeBitmap();
}
}
diff --git a/app/src/main/java/rs/chir/invtracker/client/QRScanFragment.java b/app/src/main/java/rs/chir/invtracker/client/QRScanFragment.java
index 53be539..c316402 100644
--- a/app/src/main/java/rs/chir/invtracker/client/QRScanFragment.java
+++ b/app/src/main/java/rs/chir/invtracker/client/QRScanFragment.java
@@ -29,7 +29,7 @@ import java.util.regex.Pattern;
import rs.chir.cv.QRAnalyzer;
import rs.chir.invtracker.client.databinding.FragmentQrScanBinding;
import rs.chir.invtracker.model.GeoLocation;
-import rs.chir.invtracker.utils.ListenableFutureAdapter;
+import rs.chir.invtracker.utils.RXJavaAdapters;
import rs.chir.invtracker.utils.SingleLocation;
import rs.chir.utils.math.Vec2;
@@ -84,20 +84,20 @@ public class QRScanFragment extends FragmentBase implemen
@Override
protected void onPermissionGranted(String permission) {
- if(permission.equals(Manifest.permission.CAMERA)) {
- this.startCamera();
- } else if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
- var fusedLocationClient = LocationServices.getFusedLocationProviderClient(this.requireActivity());
- this.subscribe(SingleLocation.getNextLocation(fusedLocationClient, this.requireContext()), location -> this.updateLocation(id, location), err -> {
- err.printStackTrace();
- this.showDetailView(id);
- });
- }
+ if (permission.equals(Manifest.permission.CAMERA)) {
+ this.startCamera();
+ } else if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
+ var fusedLocationClient = LocationServices.getFusedLocationProviderClient(this.requireActivity());
+ this.subscribe(SingleLocation.getNextLocation(fusedLocationClient, this.requireContext()), location -> this.updateLocation(id, location), err -> {
+ err.printStackTrace();
+ this.showDetailView(id);
+ });
+ }
}
@Override
protected void onPermissionDenied(String permission) {
- if(permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
+ if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
this.showDetailView(id);
} else {
super.onPermissionDenied(permission);
@@ -121,6 +121,7 @@ public class QRScanFragment extends FragmentBase implemen
/**
* Returns the size of the application window in pixels
+ *
* @return the size of the application window in pixels
*/
@NonNull
@@ -139,7 +140,7 @@ public class QRScanFragment extends FragmentBase implemen
private void startCamera() {
// request the camera provider
- this.subscribe(new ListenableFutureAdapter<>(ProcessCameraProvider.getInstance(this.requireContext()), ContextCompat.getMainExecutor(this.requireContext())), this::openedCamera);
+ this.subscribe(RXJavaAdapters.fromListenableFuture(ProcessCameraProvider.getInstance(this.requireContext()), ContextCompat.getMainExecutor(this.requireContext())), this::openedCamera);
}
@Override
@@ -164,6 +165,7 @@ public class QRScanFragment extends FragmentBase implemen
/**
* Show or hide the viewfinder
+ *
* @param hide true to hide the viewfinder, false to show it
*/
private void hideUI(boolean b) {
@@ -175,7 +177,8 @@ public class QRScanFragment extends FragmentBase implemen
/**
* Update the location of the object
- * @param id the object id
+ *
+ * @param id the object id
* @param location the location of the object
*/
private void updateLocation(long id, GeoLocation location) {
@@ -193,6 +196,7 @@ public class QRScanFragment extends FragmentBase implemen
/**
* Show the detail view of the object
+ *
* @param id the object id
*/
private void showDetailView(long id) {
@@ -201,6 +205,7 @@ public class QRScanFragment extends FragmentBase implemen
/**
* Initializes the camera
+ *
* @param cameraProvider the camera provider
*/
private void openedCamera(@NonNull ProcessCameraProvider cameraProvider) {
diff --git a/app/src/main/java/rs/chir/invtracker/client/model/APIKey.java b/app/src/main/java/rs/chir/invtracker/client/model/APIKey.java
index 18cd697..b5d3e33 100644
--- a/app/src/main/java/rs/chir/invtracker/client/model/APIKey.java
+++ b/app/src/main/java/rs/chir/invtracker/client/model/APIKey.java
@@ -7,7 +7,6 @@ import androidx.datastore.preferences.core.Preferences;
import androidx.datastore.preferences.core.PreferencesKeys;
import io.reactivex.rxjava3.core.Single;
-import rs.chir.compat.java.util.Objects;
import rs.chir.compat.java.util.Optional;
import rs.chir.invtracker.client.Application;
@@ -25,7 +24,7 @@ public enum APIKey {
* Sets the API key in the preferences datastore.
*
* @param context the context to use for accessing the preferences datastore.
- * @param key the API key to set.
+ * @param key the API key to set.
* @return a {@link Single} that completes when the API key is set.
*/
@NonNull
diff --git a/app/src/main/java/rs/chir/invtracker/client/model/ItemListAdapter.java b/app/src/main/java/rs/chir/invtracker/client/model/ItemListAdapter.java
index 2ecfd76..de498b7 100644
--- a/app/src/main/java/rs/chir/invtracker/client/model/ItemListAdapter.java
+++ b/app/src/main/java/rs/chir/invtracker/client/model/ItemListAdapter.java
@@ -14,13 +14,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
-import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
import rs.chir.compat.java.util.Optional;
-import rs.chir.invtracker.api.Client;
import rs.chir.invtracker.client.Application;
import rs.chir.invtracker.client.R;
import rs.chir.invtracker.model.GeoRect;
@@ -56,7 +53,7 @@ public class ItemListAdapter extends RecyclerView.Adapter bounds) {
Application.getInstance(context)
@@ -88,7 +85,7 @@ public class ItemListAdapter extends RecyclerView.Adapter client.streamLocations(itemId).toObservable())
+ .getClient().toObservable().flatMap(client -> client.streamLocations(itemId).toObservable())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(item -> {
@@ -83,7 +80,8 @@ public class LocationListAdapter extends RecyclerView.Adapter[trunc(val), trunc(val) + 1).
+ *
* @param val the value to randomize.
* @return the randomized value.
*/
@@ -86,6 +91,7 @@ public class LocationRounder {
/**
* Performs the rounding operation.
+ *
* @param val the value to round.
* @return the rounded value.
*/
@@ -100,6 +106,7 @@ public class LocationRounder {
/**
* Rounds a {@link GeoLocation}.
+ *
* @param location the location to round.
* @return the rounded location.
*/
diff --git a/app/src/main/java/rs/chir/invtracker/client/model/ServerPublicKey.java b/app/src/main/java/rs/chir/invtracker/client/model/ServerPublicKey.java
index aa846b1..2f50ab7 100644
--- a/app/src/main/java/rs/chir/invtracker/client/model/ServerPublicKey.java
+++ b/app/src/main/java/rs/chir/invtracker/client/model/ServerPublicKey.java
@@ -27,6 +27,7 @@ public enum ServerPublicKey {
/**
* Returns a flowable for the serialized public key.
+ *
* @param context the context to use for accessing the preferences datastore.
* @return a flowable for the serialized public key.
*/
diff --git a/app/src/main/java/rs/chir/invtracker/utils/BitmapStorage.java b/app/src/main/java/rs/chir/invtracker/utils/BitmapStorage.java
index 4f868f8..2f836e4 100644
--- a/app/src/main/java/rs/chir/invtracker/utils/BitmapStorage.java
+++ b/app/src/main/java/rs/chir/invtracker/utils/BitmapStorage.java
@@ -14,6 +14,7 @@ import java.io.IOException;
public interface BitmapStorage {
/**
* Creates an instance of {@link BitmapStorage} optimized for the current android version.
+ *
* @param context The application context.
*/
@NonNull
@@ -27,7 +28,8 @@ public interface BitmapStorage {
/**
* Saves the bitmap to the storage.
- * @param bitmap The bitmap to save.
+ *
+ * @param bitmap The bitmap to save.
* @param fileName The name of the file to save the bitmap to.
* @throws IOException If the bitmap cannot be saved.
*/
diff --git a/app/src/main/java/rs/chir/invtracker/utils/BitmapStorageQ.java b/app/src/main/java/rs/chir/invtracker/utils/BitmapStorageQ.java
index 24db1bc..2c4de3c 100644
--- a/app/src/main/java/rs/chir/invtracker/utils/BitmapStorageQ.java
+++ b/app/src/main/java/rs/chir/invtracker/utils/BitmapStorageQ.java
@@ -26,6 +26,7 @@ public class BitmapStorageQ implements BitmapStorage {
/**
* Creates a new instance of {@link BitmapStorageQ}.
+ *
* @param context the context to use.
*/
public BitmapStorageQ(@NonNull Context context) {
diff --git a/app/src/main/java/rs/chir/invtracker/utils/BitmapUtils.java b/app/src/main/java/rs/chir/invtracker/utils/BitmapUtils.java
index e989f6e..a14537f 100644
--- a/app/src/main/java/rs/chir/invtracker/utils/BitmapUtils.java
+++ b/app/src/main/java/rs/chir/invtracker/utils/BitmapUtils.java
@@ -17,9 +17,10 @@ public enum BitmapUtils {
/**
* Saves the bitmap to file
+ *
* @param bitmap The bitmap to save
- * @param file The file to save to
- * @throws IOException If the file cannot be saved
+ * @param file The file to save to
+ * @throws IOException If the file cannot be saved
* @throws FileNotFoundException If the file cannot be found
*/
public static void saveBitmap(@NonNull Bitmap bitmap, @NonNull String fileName) throws FileNotFoundException, IOException {
@@ -28,8 +29,9 @@ public enum BitmapUtils {
/**
* Saves the bitmap to an output stream
+ *
* @param bitmap The bitmap to save
- * @param os The output stream to save to
+ * @param os The output stream to save to
* @throws IOException If the file cannot be saved
*/
public static void saveBitmap(@NonNull Bitmap bitmap, @NonNull OutputStream os) throws IOException {
diff --git a/app/src/main/java/rs/chir/invtracker/utils/CallAdapter.java b/app/src/main/java/rs/chir/invtracker/utils/CallAdapter.java
deleted file mode 100644
index 9d6f8af..0000000
--- a/app/src/main/java/rs/chir/invtracker/utils/CallAdapter.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package rs.chir.invtracker.utils;
-
-import java.io.IOException;
-import java.util.List;
-
-import io.reactivex.rxjava3.annotations.NonNull;
-import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.core.SingleObserver;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.Response;
-
-/**
- * Adapts a {@link Call} to a {@link Single}.
- */
-public class CallAdapter extends Single implements Callback {
- /**
- * Subscribers to the call.
- */
- private final List> subscribers = new java.util.ArrayList<>(1);
-
- /**
- * Creates a new adapter.
- */
- public CallAdapter(@androidx.annotation.NonNull Call call) {
- call.enqueue(this);
- }
-
- @Override
- protected void subscribeActual(@NonNull SingleObserver super Response> observer) {
- subscribers.add(observer);
- }
-
- @Override
- public void onFailure(@androidx.annotation.NonNull Call call, @androidx.annotation.NonNull IOException e) {
- for (var subscriber : subscribers) {
- subscriber.onError(e);
- }
- }
-
- @Override
- public void onResponse(@androidx.annotation.NonNull Call call, @androidx.annotation.NonNull Response response) throws IOException {
- for (var subscriber : subscribers) {
- subscriber.onSuccess(response);
- }
- }
-}
diff --git a/app/src/main/java/rs/chir/invtracker/utils/ConnectionScorer.java b/app/src/main/java/rs/chir/invtracker/utils/ConnectionScorer.java
index 94a903c..487f494 100644
--- a/app/src/main/java/rs/chir/invtracker/utils/ConnectionScorer.java
+++ b/app/src/main/java/rs/chir/invtracker/utils/ConnectionScorer.java
@@ -15,6 +15,7 @@ public enum ConnectionScorer {
/**
* Check if the data saver is enabled
+ *
* @param cm the connectivity manager
* @return true if the data saver is enabled
*/
@@ -27,6 +28,7 @@ public enum ConnectionScorer {
/**
* Scores the connection quality.
+ *
* @param context
* @return the connection quality score
*/
diff --git a/app/src/main/java/rs/chir/invtracker/utils/CursorStreamable.java b/app/src/main/java/rs/chir/invtracker/utils/CursorStreamable.java
deleted file mode 100644
index d90c64e..0000000
--- a/app/src/main/java/rs/chir/invtracker/utils/CursorStreamable.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package rs.chir.invtracker.utils;
-
-import org.reactivestreams.Subscriber;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import io.reactivex.rxjava3.annotations.NonNull;
-import io.reactivex.rxjava3.core.Flowable;
-import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.schedulers.Schedulers;
-import rs.chir.compat.java.util.Optional;
-import rs.chir.compat.java.util.function.Function;
-import rs.chir.invtracker.model.Cursor;
-import rs.chir.utils.xml.XMLSerializable;
-
-/**
- * Adapts a {@link Cursor} to a {@link Flowable}.
- */
-public class CursorStreamable extends Flowable {
- /**
- * Subscribers
- */
- private final List> subscribers = new ArrayList<>(1);
- /**
- * The cursor supplier
- */
- private final Function, Single>> cursorSupplier;
- /**
- * Whether the loading has started. We don’t start streaming data until the first subscriber is
- * added.
- */
- private final AtomicBoolean isLoading = new AtomicBoolean(false);
-
- /**
- * Creates a new streamable.
- * @param cursorSupplier the cursor supplier
- */
- public CursorStreamable(@NonNull Function, Single>> cursorSupplier) {
- this.cursorSupplier = cursorSupplier;
- }
-
- @Override
- protected void subscribeActual(@NonNull Subscriber super T> subscriber) {
- subscribers.add(subscriber);
- if (this.isLoading.compareAndSet(false, true)) {
- this.loadNextChunk(Optional.empty());
- }
- }
-
- /**
- * Loads the next chunk of data.
- * @param lastId the ID of the last item in the previous chunk
- */
- private void loadNextChunk(Optional lastId) {
- this.cursorSupplier.apply(lastId)
- .subscribeOn(Schedulers.io())
- .subscribe(cursor -> {
- for (var item : cursor.items()) {
- // send all items to all subscribers
- for (var subscriber : subscribers) {
- subscriber.onNext(item);
- }
- }
- // While the nextId should be empty if there are no more items,
- // some places may still return it, so we check for how many items are in the cursor.
- if (cursor.nextId().isEmpty() || cursor.items().isEmpty()) {
- // no more items to load, tell that to all subscribers
- for (var subscriber : subscribers) {
- subscriber.onComplete();
- }
- } else {
- // otherwise, load the next chunk
- this.loadNextChunk(cursor.nextId());
- }
- }, t -> {
- // notify all subscribers of the error
- for (var subscriber : subscribers) {
- subscriber.onError(t);
- }
- });
- }
-}
diff --git a/app/src/main/java/rs/chir/invtracker/utils/ListenableFutureAdapter.java b/app/src/main/java/rs/chir/invtracker/utils/ListenableFutureAdapter.java
deleted file mode 100644
index fab00c4..0000000
--- a/app/src/main/java/rs/chir/invtracker/utils/ListenableFutureAdapter.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package rs.chir.invtracker.utils;
-
-import androidx.annotation.NonNull;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-
-import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.core.SingleObserver;
-
-/**
- * Adapts a {@link ListenableFuture} to a {@link Single}.
- */
-public class ListenableFutureAdapter extends Single {
- /**
- * The subscribers that are waiting for the future to complete.
- */
- private final List> subscribers = new java.util.ArrayList<>(1);
-
- public ListenableFutureAdapter(@NonNull ListenableFuture future, @NonNull Executor executor) {
- future.addListener(() -> {
- try {
- var result = future.get();
- for (var subscriber : subscribers) {
- subscriber.onSuccess(result);
- }
- } catch (InterruptedException | ExecutionException e) {
- for (var subscriber : subscribers) {
- subscriber.onError(e);
- }
- }
- }, executor);
- }
-
- @Override
- protected void subscribeActual(@NonNull SingleObserver super T> observer) {
- subscribers.add(observer);
- }
-}
diff --git a/app/src/main/java/rs/chir/invtracker/utils/RXJavaAdapters.java b/app/src/main/java/rs/chir/invtracker/utils/RXJavaAdapters.java
new file mode 100644
index 0000000..6a8038d
--- /dev/null
+++ b/app/src/main/java/rs/chir/invtracker/utils/RXJavaAdapters.java
@@ -0,0 +1,105 @@
+package rs.chir.invtracker.utils;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.gms.tasks.Task;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+import io.reactivex.rxjava3.core.BackpressureStrategy;
+import io.reactivex.rxjava3.core.Flowable;
+import io.reactivex.rxjava3.core.FlowableEmitter;
+import io.reactivex.rxjava3.core.Single;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.Response;
+import rs.chir.compat.java.util.Optional;
+import rs.chir.compat.java.util.function.Function;
+import rs.chir.invtracker.model.Cursor;
+import rs.chir.utils.xml.XMLSerializable;
+
+/**
+ * Various adapters to convert to {@link Single}s or {@link Flowable}s.
+ */
+public enum RXJavaAdapters {
+ ;
+
+ /**
+ * Adapts a {@link Call} to a {@link Single}.
+ *
+ * @param call the call to adapt
+ * @return the single
+ */
+ @NonNull
+ public static Single fromCall(@NonNull Call call) {
+ return Single.create(subscriber -> call.enqueue(new Callback() {
+ @Override
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
+ subscriber.onError(e);
+ }
+
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
+ subscriber.onSuccess(response);
+ }
+ }));
+ }
+
+ private static void loadNextChunk(@NonNull Function, Single>> cursorSupplier, @NonNull FlowableEmitter subscriber, Optional lastId) {
+ var d = cursorSupplier.apply(lastId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(Schedulers.io())
+ .subscribe(cursor -> {
+ for (var item : cursor.items()) {
+ subscriber.onNext(item);
+ }
+ if (cursor.nextId().isEmpty() || cursor.items().isEmpty()) {
+ subscriber.onComplete();
+ } else {
+ RXJavaAdapters.loadNextChunk(cursorSupplier, subscriber, cursor.nextId());
+ }
+ }, subscriber::onError);
+ subscriber.setDisposable(d);
+ }
+
+ @NonNull
+ public static Flowable fromCursor(@NonNull Function, Single>> cursorSupplier) {
+ return Flowable.create(subscriber -> {
+ RXJavaAdapters.loadNextChunk(cursorSupplier, subscriber, Optional.empty());
+ }, BackpressureStrategy.BUFFER);
+ }
+
+ @NonNull
+ public static Single fromListenableFuture(@NonNull ListenableFuture future, @NonNull Executor executor) {
+ return Single.create(subscriber -> {
+ future.addListener(() -> {
+ try {
+ var result = future.get();
+ subscriber.onSuccess(result);
+ } catch (InterruptedException | ExecutionException e) {
+ subscriber.onError(e);
+ }
+ }, executor);
+ });
+ }
+
+ @NonNull
+ public static Single> fromTask(@NonNull Task task) {
+ if (task.isComplete()) {
+ if (task.isSuccessful()) {
+ return Single.just(Optional.of(task.getResult()));
+ } else {
+ return Single.error(task.getException());
+ }
+ } else {
+ return Single.create(subscriber -> {
+ task.addOnSuccessListener(v -> subscriber.onSuccess(Optional.ofNullable(v)));
+ task.addOnFailureListener(subscriber::onError);
+ });
+ }
+ }
+}
diff --git a/app/src/main/java/rs/chir/invtracker/utils/SingleBackoff.java b/app/src/main/java/rs/chir/invtracker/utils/SingleBackoff.java
index 9d94603..d363361 100644
--- a/app/src/main/java/rs/chir/invtracker/utils/SingleBackoff.java
+++ b/app/src/main/java/rs/chir/invtracker/utils/SingleBackoff.java
@@ -55,7 +55,7 @@ public class SingleBackoff extends Single {
/**
* Creates a new single backoff.
*
- * @param singleSupplier the supplier of the single to retry
+ * @param singleSupplier the supplier of the single to retry
* @param exceptionFilter the exception filter for the single. If it returns true, the single is retried.
*/
public SingleBackoff(@androidx.annotation.NonNull Supplier> singleSupplier, @NonNull Predicate super Throwable> exceptionFilter) {
@@ -87,6 +87,7 @@ public class SingleBackoff extends Single {
/**
* Reports the success of the single
+ *
* @param result the result of the single
*/
private void onSuccess(T result) {
@@ -98,6 +99,7 @@ public class SingleBackoff extends Single {
/**
* Reports the error of the single
+ *
* @param error the error of the single
*/
private void onError(Throwable error) {
diff --git a/app/src/main/java/rs/chir/invtracker/utils/SingleLocation.java b/app/src/main/java/rs/chir/invtracker/utils/SingleLocation.java
index 63c75e0..e8982f2 100644
--- a/app/src/main/java/rs/chir/invtracker/utils/SingleLocation.java
+++ b/app/src/main/java/rs/chir/invtracker/utils/SingleLocation.java
@@ -17,11 +17,8 @@ import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.Priority;
import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.List;
import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.core.SingleObserver;
import rs.chir.compat.java.util.OptionalDouble;
import rs.chir.invtracker.client.model.LocationRounder;
import rs.chir.invtracker.model.GeoLocation;
@@ -29,44 +26,14 @@ import rs.chir.invtracker.model.GeoLocation;
/**
* {@link Single} implementation that returns a location
*/
-public class SingleLocation extends Single {
- /**
- * List of subscribers to this single.
- */
- final List> observers = new ArrayList<>(1);
-
- /**
- * Creates a new Location Single
- *
- * @param client the location client to use for getting the location
- * @param locationRequest the location request to use for getting the location
- * @param context the context to use for rounding the location
- */
- @SuppressLint("MissingPermission")
- private SingleLocation(@NonNull FusedLocationProviderClient client, LocationRequest request, Context context) {
- // Request a location update
- client.requestLocationUpdates(request, new LocationCallback() {
- @Override
- public void onLocationResult(LocationResult locationResult) {
- var location = locationResult.getLastLocation();
- if (location != null) {
- for (var observer : observers) {
- observer.onSuccess(SingleLocation.fromAndroidLocation(location, context));
- }
- } else {
- for (var observer : observers) {
- observer.onError(new AndroidException("No location available"));
- }
- }
- }
- }, Looper.getMainLooper());
- }
+public enum SingleLocation {
+ ;
/**
* Converts an Android location to a GeoLocation
*
* @param location the location to convert
- * @param context the context to use for rounding the location
+ * @param context the context to use for rounding the location
* @return the converted location
*/
@NonNull
@@ -85,7 +52,8 @@ public class SingleLocation extends Single {
/**
* Retrieve the most recent location, requesting a location update if necessary.
- * @param client the location client to use for getting the location
+ *
+ * @param client the location client to use for getting the location
* @param context the context to use for rounding the location
* @return the most recent location
*/
@@ -93,23 +61,25 @@ public class SingleLocation extends Single {
@SuppressLint("MissingPermission")
public static Single getSingleLocation(@NonNull FusedLocationProviderClient client, @NonNull Context context) {
// Try accessing the last location
- return TaskAdapter.fromTask(client.getLastLocation())
+ return RXJavaAdapters.fromTask(client.getLastLocation())
.flatMap(location -> {
if (location.isPresent()) {
return Single.just(SingleLocation.fromAndroidLocation(location.get(), context));
} else {
// if there is no last location, request a location update
- return SingleLocation.getNextLocation(client, context);
+ return SingleLocation.getNextLocation(client, context);
}
});
}
/**
* Retrieves a location update, requesting a location update if necessary.
- * @param client the location client to use for getting the location
+ *
+ * @param client the location client to use for getting the location
* @param context the context to use for rounding the location
* @return the next location
*/
+ @SuppressLint("MissingPermission")
@NonNull
public static Single getNextLocation(@NonNull FusedLocationProviderClient client, @NonNull Context context) {
var request = LocationRequest.create();
@@ -122,12 +92,19 @@ public class SingleLocation extends Single {
.addLocationRequest(request);
// TODO: you could probably cache the settings client?
var settingsClient = LocationServices.getSettingsClient(context);
- return TaskAdapter.fromTask(settingsClient.checkLocationSettings(builder.build()))
- .flatMap(resp -> new SingleLocation(client, request, context));
- }
-
- @Override
- protected void subscribeActual(@io.reactivex.rxjava3.annotations.NonNull SingleObserver super GeoLocation> observer) {
- observers.add(observer);
+ return RXJavaAdapters.fromTask(settingsClient.checkLocationSettings(builder.build()))
+ .flatMap(resp -> Single.create(subscriber -> {
+ client.requestLocationUpdates(request, new LocationCallback() {
+ @Override
+ public void onLocationResult(@NonNull LocationResult locationResult) {
+ var location = locationResult.getLastLocation();
+ if (location != null) {
+ subscriber.onSuccess(SingleLocation.fromAndroidLocation(location, context));
+ } else {
+ subscriber.onError(new AndroidException("No location available"));
+ }
+ }
+ }, Looper.getMainLooper());
+ }));
}
}
diff --git a/app/src/main/java/rs/chir/invtracker/utils/TaskAdapter.java b/app/src/main/java/rs/chir/invtracker/utils/TaskAdapter.java
deleted file mode 100644
index 597b6f1..0000000
--- a/app/src/main/java/rs/chir/invtracker/utils/TaskAdapter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package rs.chir.invtracker.utils;
-
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.google.android.gms.tasks.Task;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.core.SingleObserver;
-import rs.chir.compat.java.util.Optional;
-
-/**
- * Single adapter for a GMS {@link Task};
- * @param the type of the result of the task.
- */
-public class TaskAdapter extends Single> {
- /**
- * The subscribers to the task.
- */
- private final List>> observers = new ArrayList<>(1);
-
- /**
- * Creates a new adapter.
- * @param task the task to wrap.
- */
- private TaskAdapter(@NonNull Task task) {
- task.addOnCompleteListener(result -> {
- Log.i("TaskAdapter", "Task completed: " + result);
- if (result.isSuccessful()) {
- // rxjava does not like nulls, so we use Optional.empty() instead.
- var out = Optional.ofNullable(result.getResult());
- for (var observer : observers) {
- observer.onSuccess(out);
- }
- } else {
- for (var observer : observers) {
- observer.onError(result.getException());
- }
- }
- });
- }
-
- /**
- * Creates a new adapter from a task
- *
- * @param task the task to wrap.
- * @param the type of the result of the task.
- * @return the adapter.
- */
- @NonNull
- public static Single> fromTask(@NonNull Task task) {
- if (task.isComplete()) {
- // if the task is successful, we don’t need to wrap it in an adapter.
- if (task.isSuccessful()) {
- return Single.just(Optional.ofNullable(task.getResult()));
- } else {
- return Single.error(Objects.requireNonNull(task.getException()));
- }
- } else {
- return new TaskAdapter<>(task);
- }
- }
-
- @Override
- protected void subscribeActual(@io.reactivex.rxjava3.annotations.NonNull SingleObserver super Optional> observer) {
- observers.add(observer);
- }
-}
diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml
index 54634a5..f6264a4 100644
--- a/app/src/main/res/xml/provider_paths.xml
+++ b/app/src/main/res/xml/provider_paths.xml
@@ -1,4 +1,6 @@
-
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 57c9193..3b5e2d0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Wed Aug 10 11:16:39 GMT 2022
+#Mon Aug 15 10:52:08 GMT 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
distributionPath=wrapper/dists