diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index a5d456928..f39734eb4 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -1,16 +1,12 @@
-
-
-
-
@@ -25,13 +21,11 @@
-
-
@@ -47,6 +41,5 @@
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index b21d02b39..e89a391e8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -94,6 +94,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-reflect:$KOTLIN_VERSION"
//Mocking
+ testImplementation("io.mockk:mockk:1.13.4")
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
testImplementation 'org.mockito:mockito-inline:5.2.0'
testImplementation 'org.mockito:mockito-core:5.6.0'
@@ -227,7 +228,7 @@ android {
excludes += ['META-INF/androidx.*']
}
resources {
- excludes += ['META-INF/androidx.*', 'META-INF/proguard/androidx-annotations.pro']
+ excludes += ['META-INF/androidx.*', 'META-INF/proguard/androidx-annotations.pro', '/META-INF/LICENSE.md', '/META-INF/LICENSE-notice.md']
}
}
@@ -381,7 +382,7 @@ android {
compose true
}
composeOptions {
- kotlinCompilerExtensionVersion '1.3.2'
+ kotlinCompilerExtensionVersion '1.5.8'
}
namespace 'fr.free.nrw.commons'
lint {
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt
index b75a6e1d4..872388f40 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/NotForUploadStatusDao.kt
@@ -15,19 +15,19 @@ abstract class NotForUploadStatusDao {
* Insert into Not For Upload status.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract suspend fun insert(notForUploadStatus: NotForUploadStatus)
+ abstract fun insert(notForUploadStatus: NotForUploadStatus)
/**
* Delete Not For Upload status entry.
*/
@Delete
- abstract suspend fun delete(notForUploadStatus: NotForUploadStatus)
+ abstract fun delete(notForUploadStatus: NotForUploadStatus)
/**
* Query Not For Upload status with image sha1.
*/
@Query("SELECT * FROM images_not_for_upload_table WHERE imageSHA1 = (:imageSHA1) ")
- abstract suspend fun getFromImageSHA1(imageSHA1: String): NotForUploadStatus?
+ abstract fun getFromImageSHA1(imageSHA1: String): NotForUploadStatus?
/**
* Asynchronous image sha1 query.
@@ -38,7 +38,7 @@ abstract class NotForUploadStatusDao {
* Deletion Not For Upload status with image sha1.
*/
@Query("DELETE FROM images_not_for_upload_table WHERE imageSHA1 = (:imageSHA1) ")
- abstract suspend fun deleteWithImageSHA1(imageSHA1: String)
+ abstract fun deleteWithImageSHA1(imageSHA1: String)
/**
* Asynchronous image sha1 deletion.
@@ -49,5 +49,5 @@ abstract class NotForUploadStatusDao {
* Check whether the imageSHA1 is present in database
*/
@Query("SELECT COUNT() FROM images_not_for_upload_table WHERE imageSHA1 = (:imageSHA1) ")
- abstract suspend fun find(imageSHA1: String): Int
+ abstract fun find(imageSHA1: String): Int
}
diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt
index 378af5b8d..03cbb176f 100644
--- a/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/customselector/database/UploadedStatusDao.kt
@@ -17,31 +17,31 @@ abstract class UploadedStatusDao {
* Insert into uploaded status.
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract suspend fun insert(uploadedStatus: UploadedStatus)
+ abstract fun insert(uploadedStatus: UploadedStatus)
/**
* Update uploaded status entry.
*/
@Update
- abstract suspend fun update(uploadedStatus: UploadedStatus)
+ abstract fun update(uploadedStatus: UploadedStatus)
/**
* Delete uploaded status entry.
*/
@Delete
- abstract suspend fun delete(uploadedStatus: UploadedStatus)
+ abstract fun delete(uploadedStatus: UploadedStatus)
/**
* Query uploaded status with image sha1.
*/
@Query("SELECT * FROM uploaded_table WHERE imageSHA1 = (:imageSHA1) ")
- abstract suspend fun getFromImageSHA1(imageSHA1: String): UploadedStatus?
+ abstract fun getFromImageSHA1(imageSHA1: String): UploadedStatus?
/**
* Query uploaded status with modified image sha1.
*/
@Query("SELECT * FROM uploaded_table WHERE modifiedImageSHA1 = (:modifiedImageSHA1) ")
- abstract suspend fun getFromModifiedImageSHA1(modifiedImageSHA1: String): UploadedStatus?
+ abstract fun getFromModifiedImageSHA1(modifiedImageSHA1: String): UploadedStatus?
/**
* Asynchronous insert into uploaded status table.
@@ -55,7 +55,7 @@ abstract class UploadedStatusDao {
* Check whether the imageSHA1 is present in database
*/
@Query("SELECT COUNT() FROM uploaded_table WHERE imageSHA1 = (:imageSHA1) AND imageResult = (:imageResult) ")
- abstract suspend fun findByImageSHA1(
+ abstract fun findByImageSHA1(
imageSHA1: String,
imageResult: Boolean,
): Int
@@ -66,7 +66,7 @@ abstract class UploadedStatusDao {
@Query(
"SELECT COUNT() FROM uploaded_table WHERE modifiedImageSHA1 = (:modifiedImageSHA1) AND modifiedImageResult = (:modifiedImageResult) ",
)
- abstract suspend fun findByModifiedImageSHA1(
+ abstract fun findByModifiedImageSHA1(
modifiedImageSHA1: String,
modifiedImageResult: Boolean,
): Int
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java
index 8c0a0a393..7babee3b7 100644
--- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceDao.java
@@ -41,4 +41,23 @@ public abstract class PlaceDao {
saveSynchronous(place);
});
}
+
+ /**
+ * Deletes all Place objects from the database.
+ *
+ * @return A Completable that completes once the deletion operation is done.
+ */
+ @Query("DELETE FROM place")
+ public abstract void deleteAllSynchronous();
+
+ /**
+ * Deletes all Place objects from the database.
+ *
+ */
+ public Completable deleteAll() {
+ return Completable
+ .fromAction(() -> {
+ deleteAllSynchronous();
+ });
+ }
}
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java
index a7f1dadcd..86a57eadc 100644
--- a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesLocalDataSource.java
@@ -35,4 +35,8 @@ public class PlacesLocalDataSource {
public Completable savePlace(Place place) {
return placeDao.save(place);
}
+
+ public Completable clearCache() {
+ return placeDao.deleteAll();
+ }
}
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java
index 85e964ddb..846e54fac 100644
--- a/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlacesRepository.java
@@ -3,6 +3,7 @@ package fr.free.nrw.commons.nearby;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.location.LatLng;
import io.reactivex.Completable;
+import io.reactivex.schedulers.Schedulers;
import javax.inject.Inject;
/**
@@ -38,4 +39,13 @@ public class PlacesRepository {
return localDataSource.fetchPlace(entityID);
}
+ /**
+ * Clears the Nearby cache on an IO thread.
+ *
+ * @return A Completable that completes once the cache has been successfully cleared.
+ */
+ public Completable clearCache() {
+ return localDataSource.clearCache()
+ .subscribeOn(Schedulers.io()); // Ensure it runs on IO thread
+ }
}
diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java
index 7a7d5cdcb..6a2e5c3a9 100644
--- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java
+++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java
@@ -108,6 +108,7 @@ import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.SystemThemeUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.wikidata.WikidataEditListener;
+import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -342,9 +343,21 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
public void onCreateOptionsMenu(@NonNull final Menu menu,
@NonNull final MenuInflater inflater) {
inflater.inflate(R.menu.nearby_fragment_menu, menu);
+ MenuItem refreshButton = menu.findItem(R.id.item_refresh);
MenuItem listMenu = menu.findItem(R.id.list_sheet);
MenuItem saveAsGPXButton = menu.findItem(R.id.list_item_gpx);
MenuItem saveAsKMLButton = menu.findItem(R.id.list_item_kml);
+ refreshButton.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ try {
+ emptyCache();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return false;
+ }
+ });
listMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
@@ -1158,6 +1171,48 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
}
}
+ /**
+ * Reloads the Nearby map
+ * Clears all location markers, refreshes them, reinserts them into the map.
+ *
+ */
+ private void reloadMap() {
+ clearAllMarkers(); // Clear the list of markers
+ binding.map.getController().setZoom(ZOOM_LEVEL); // Reset the zoom level
+ binding.map.getController().setCenter(lastMapFocus); // Recenter the focus
+ if (locationPermissionsHelper.checkLocationPermission(getActivity())) {
+ locationPermissionGranted(); // Reload map with user's location
+ } else {
+ startMapWithoutPermission(); // Reload map without user's location
+ }
+ binding.map.invalidate(); // Invalidate the map
+ presenter.updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED); // Restart the map
+ Timber.d("Reloaded Map Successfully");
+ }
+
+
+ /**
+ * Clears the Nearby local cache and then calls for the map to be reloaded
+ *
+ */
+ private void emptyCache() {
+ // reload the map once the cache is cleared
+ compositeDisposable.add(
+ placesRepository.clearCache()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .andThen(Completable.fromAction(this::reloadMap))
+ .subscribe(
+ () -> {
+ Timber.d("Nearby Cache cleared successfully.");
+ },
+ throwable -> {
+ Timber.e(throwable, "Failed to clear the Nearby Cache");
+ }
+ )
+ );
+ }
+
private void savePlacesAsKML() {
final Observable savePlacesObservable = Observable
.fromCallable(() -> nearbyController
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/categories/BaseDelegateAdapter.kt b/app/src/main/java/fr/free/nrw/commons/upload/categories/BaseDelegateAdapter.kt
index f1e4917a0..ce12d3915 100644
--- a/app/src/main/java/fr/free/nrw/commons/upload/categories/BaseDelegateAdapter.kt
+++ b/app/src/main/java/fr/free/nrw/commons/upload/categories/BaseDelegateAdapter.kt
@@ -10,15 +10,13 @@ abstract class BaseDelegateAdapter(
areContentsTheSame: (T, T) -> Boolean = { old, new -> old == new },
) : AsyncListDifferDelegationAdapter(
object : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(
- oldItem: T,
- newItem: T,
- ) = areItemsTheSame(oldItem, newItem)
+ override fun areItemsTheSame(oldItem: T & Any, newItem: T & Any): Boolean {
+ return areItemsTheSame(oldItem, newItem)
+ }
- override fun areContentsTheSame(
- oldItem: T,
- newItem: T,
- ) = areContentsTheSame(oldItem, newItem)
+ override fun areContentsTheSame(oldItem: T & Any, newItem: T & Any): Boolean {
+ return areContentsTheSame(oldItem, newItem)
+ }
},
*delegates,
) {
diff --git a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsDao.kt b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsDao.kt
index 684400301..c20d65abf 100644
--- a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsDao.kt
+++ b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsDao.kt
@@ -22,16 +22,16 @@ abstract class DepictsDao {
private val maxItemsAllowed = 10
@Insert(onConflict = OnConflictStrategy.REPLACE)
- abstract suspend fun insert(depictedItem: Depicts)
+ abstract fun insert(depictedItem: Depicts)
@Query("Select * From depicts_table order by lastUsed DESC")
- abstract suspend fun getAllDepicts(): List
+ abstract fun getAllDepicts(): List
@Query("Select * From depicts_table order by lastUsed DESC LIMIT :n OFFSET 10")
- abstract suspend fun getDepictsForDeletion(n: Int): List
+ abstract fun getDepictsForDeletion(n: Int): List
@Delete
- abstract suspend fun delete(depicts: Depicts)
+ abstract fun delete(depicts: Depicts)
/**
* Gets all Depicts objects from the database, ordered by lastUsed in descending order.
diff --git a/app/src/main/res/drawable/ic_refresh_24dp_nearby.xml b/app/src/main/res/drawable/ic_refresh_24dp_nearby.xml
new file mode 100644
index 000000000..89f49ad9e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_refresh_24dp_nearby.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/nearby_fragment_menu.xml b/app/src/main/res/menu/nearby_fragment_menu.xml
index 30b5c9dd5..fe049cde4 100644
--- a/app/src/main/res/menu/nearby_fragment_menu.xml
+++ b/app/src/main/res/menu/nearby_fragment_menu.xml
@@ -1,17 +1,25 @@
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 0f765a1fb..6ee931542 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -307,4 +307,5 @@
Моля, изчакайте...
напълно размазано
Наблизо
+ Прочетете повече
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 2aa04017a..3b6822c47 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -789,4 +789,7 @@
Afventer
Mislykkedes
Kunne ikke indlæse steddata
+ Dette sted har endnu ikke noget billede, så gå hen og tag et!
+ Dette sted har allerede et billede.
+ Tjekker nu, om dette sted har et billede.
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index be69fa045..f40863870 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -760,4 +760,7 @@
- %d immagine selezionata
- %d immagini selezionate
+ Questo posto non ha ancora una foto, scattane una!
+ Questo posto ha già una foto.
+ Ora controlliamo se questo posto ha una foto.
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index 00a8ba098..916f4f420 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -475,6 +475,7 @@
Немате непрочитани известувања
Немате прочитани известувања
Споделувај дневници користејќи
+ Проверете си ја дојдовната е-пошта
Погл. прочитани
Погл. непрочитани
Се јави грешка при избирањето на сликите
@@ -784,4 +785,7 @@
Во исчекување
Неуспешно
Не можев да ги вчитам податоците за место
+ Местово сè уште нема слика. Направете ја!
+ Местово веќе има слика.
+ Проверувам дали местово има слика.
diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml
index 48713104d..8c64900a5 100644
--- a/app/src/main/res/values-pa/strings.xml
+++ b/app/src/main/res/values-pa/strings.xml
@@ -42,6 +42,7 @@
ਵਰਤੋਂਕਾਰ ਨਾਂ
ਲੰਘ-ਸ਼ਬਦ
ਦਾਖ਼ਲ ਹੋਵੋ
+ ਪਾਰਸ਼ਬਦ ਭੁੱਲ ਗਏ?
ਦਾਖ਼ਲਾ ਹੋ ਰਿਹਾ ਹੈ
ਉਡੀਕੋ ਜੀ…
ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕੋ...
@@ -67,7 +68,7 @@
ਨੇੜੇ-ਤੇੜੇ
ਮੇਰੇ ਅੱਪਲੋਡ
ਸਾਂਝਾ ਕਰੋ
- ਸਿਰਲੇਖ
+ ਸੁਰਖੀ (ਲੋੜੀਂਦੀ)
ਵੇਰਵਾ
ਦਾਖ਼ਲ ਹੋਣ ਵਿੱਚ ਅਸਮਰੱਥ - ਨੈੱਟਵਰਕ ਫੇਲ੍ਹ ਹੋਇਆ ਹੈ
ਬਹੁਤ ਸਾਰੀਆਂ ਅਸਫ਼ਲ ਕੋਸ਼ਿਸ਼ਾਂ। ਥੋੜ੍ਹੀ ਦੇਰ ਬਾਅਦ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index e54fb9d76..cd3cf80df 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -806,4 +806,7 @@
待處理
失敗
無法載入地點資料
+ 這個地點還沒有照片,來拍一張吧!
+ 這個地點已有照片。
+ 現在檢查這個地點是否有照片。
diff --git a/build.gradle b/build.gradle
index e11d4f4fa..8a0702d8a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,8 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.6.0'
+
+ classpath 'com.android.tools.build:gradle:8.7.0'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
classpath 'org.codehaus.groovy:groovy-all:2.4.15'
diff --git a/gradle.properties b/gradle.properties
index ecfe43a80..9ca154b75 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -17,7 +17,7 @@ org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
android.enableR8.fullMode=false
-KOTLIN_VERSION=1.7.20
+KOTLIN_VERSION=1.9.22
LEAK_CANARY_VERSION=2.10
DAGGER_VERSION=2.23
ROOM_VERSION=2.5.0
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index fb6a72053..fd53d45f9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Sun Apr 23 18:22:54 IST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
\ No newline at end of file