diff --git a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesContentProvider.java b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesContentProvider.java deleted file mode 100644 index de94c4b090..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesContentProvider.java +++ /dev/null @@ -1,122 +0,0 @@ -package fr.free.nrw.commons.recentlanguages; - -import static fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.COLUMN_NAME; -import static fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.TABLE_NAME; - -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.text.TextUtils; -import androidx.annotation.NonNull; -import fr.free.nrw.commons.BuildConfig; -import fr.free.nrw.commons.data.DBOpenHelper; -import fr.free.nrw.commons.di.CommonsDaggerContentProvider; -import javax.inject.Inject; -import timber.log.Timber; - -/** - * Content provider of recently used languages - */ -public class RecentLanguagesContentProvider extends CommonsDaggerContentProvider { - - private static final String BASE_PATH = "recent_languages"; - public static final Uri BASE_URI = - Uri.parse("content://" + BuildConfig.RECENT_LANGUAGE_AUTHORITY + "/" + BASE_PATH); - - - /** - * Append language code to the base uri - * @param languageCode Code of a language - */ - public static Uri uriForCode(final String languageCode) { - return Uri.parse(BASE_URI + "/" + languageCode); - } - - @Inject - DBOpenHelper dbOpenHelper; - - @Override - public String getType(@NonNull final Uri uri) { - return null; - } - - /** - * Queries the SQLite database for the recently used languages - * @param uri : contains the uri for recently used languages - * @param projection : contains the all fields of the table - * @param selection : handles Where - * @param selectionArgs : the condition of Where clause - * @param sortOrder : ascending or descending - */ - @Override - public Cursor query(@NonNull final Uri uri, final String[] projection, final String selection, - final String[] selectionArgs, final String sortOrder) { - final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); - queryBuilder.setTables(TABLE_NAME); - final SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); - final Cursor cursor = queryBuilder.query(db, projection, selection, - selectionArgs, null, null, sortOrder); - cursor.setNotificationUri(getContext().getContentResolver(), uri); - return cursor; - } - - /** - * Handles the update query of local SQLite Database - * @param uri : contains the uri for recently used languages - * @param contentValues : new values to be entered to db - * @param selection : handles Where - * @param selectionArgs : the condition of Where clause - */ - @Override - public int update(@NonNull final Uri uri, final ContentValues contentValues, - final String selection, final String[] selectionArgs) { - final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); - final int rowsUpdated; - if (TextUtils.isEmpty(selection)) { - final int id = Integer.parseInt(uri.getLastPathSegment()); - rowsUpdated = sqlDB.update(TABLE_NAME, - contentValues, - COLUMN_NAME + " = ?", - new String[]{String.valueOf(id)}); - } else { - throw new IllegalArgumentException( - "Parameter `selection` should be empty when updating an ID"); - } - - getContext().getContentResolver().notifyChange(uri, null); - return rowsUpdated; - } - - /** - * Handles the insertion of new recently used languages record to local SQLite Database - * @param uri : contains the uri for recently used languages - * @param contentValues : new values to be entered to db - */ - @Override - public Uri insert(@NonNull final Uri uri, final ContentValues contentValues) { - final SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); - final long id = sqlDB.insert(TABLE_NAME, null, contentValues); - getContext().getContentResolver().notifyChange(uri, null); - return Uri.parse(BASE_URI + "/" + id); - } - - /** - * Handles the deletion of new recently used languages record to local SQLite Database - * @param uri : contains the uri for recently used languages - */ - @Override - public int delete(@NonNull final Uri uri, final String s, final String[] strings) { - final int rows; - final SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); - Timber.d("Deleting recently used language %s", uri.getLastPathSegment()); - rows = db.delete( - TABLE_NAME, - "language_code = ?", - new String[]{uri.getLastPathSegment()} - ); - getContext().getContentResolver().notifyChange(uri, null); - return rows; - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesContentProvider.kt b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesContentProvider.kt new file mode 100644 index 0000000000..facc4384f8 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesContentProvider.kt @@ -0,0 +1,142 @@ +package fr.free.nrw.commons.recentlanguages + + +import android.content.ContentValues +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteQueryBuilder +import android.net.Uri +import android.text.TextUtils +import fr.free.nrw.commons.BuildConfig +import fr.free.nrw.commons.data.DBOpenHelper +import fr.free.nrw.commons.di.CommonsDaggerContentProvider +import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.COLUMN_NAME +import fr.free.nrw.commons.recentlanguages.RecentLanguagesDao.Table.TABLE_NAME +import javax.inject.Inject +import timber.log.Timber + + +/** + * Content provider of recently used languages + */ +class RecentLanguagesContentProvider : CommonsDaggerContentProvider() { + + companion object { + private const val BASE_PATH = "recent_languages" + val BASE_URI: Uri = + Uri.parse( + "content://${BuildConfig.RECENT_LANGUAGE_AUTHORITY}/$BASE_PATH" + ) + + /** + * Append language code to the base URI + * @param languageCode Code of a language + */ + @JvmStatic + fun uriForCode(languageCode: String): Uri { + return Uri.parse("$BASE_URI/$languageCode") + } + } + + @Inject + lateinit var dbOpenHelper: DBOpenHelper + + override fun getType(uri: Uri): String? { + return null + } + + /** + * Queries the SQLite database for the recently used languages + * @param uri : contains the URI for recently used languages + * @param projection : contains all fields of the table + * @param selection : handles WHERE + * @param selectionArgs : the condition of WHERE clause + * @param sortOrder : ascending or descending + */ + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? { + val queryBuilder = SQLiteQueryBuilder() + queryBuilder.tables = TABLE_NAME + val db = dbOpenHelper.readableDatabase + val cursor = queryBuilder.query( + db, + projection, + selection, + selectionArgs, + null, + null, + sortOrder + ) + cursor.setNotificationUri(context?.contentResolver, uri) + return cursor + } + + /** + * Handles the update query of local SQLite Database + * @param uri : contains the URI for recently used languages + * @param contentValues : new values to be entered to the database + * @param selection : handles WHERE + * @param selectionArgs : the condition of WHERE clause + */ + override fun update( + uri: Uri, + contentValues: ContentValues?, + selection: String?, + selectionArgs: Array? + ): Int { + val sqlDB = dbOpenHelper.writableDatabase + val rowsUpdated: Int + if (selection.isNullOrEmpty()) { + val id = uri.lastPathSegment?.toInt() + ?: throw IllegalArgumentException("Invalid URI: $uri") + rowsUpdated = sqlDB.update( + TABLE_NAME, + contentValues, + "$COLUMN_NAME = ?", + arrayOf(id.toString()) + ) + } else { + throw IllegalArgumentException("Parameter `selection` should be empty when updating an ID") + } + + context?.contentResolver?.notifyChange(uri, null) + return rowsUpdated + } + + /** + * Handles the insertion of new recently used languages record to local SQLite Database + * @param uri : contains the URI for recently used languages + * @param contentValues : new values to be entered to the database + */ + override fun insert(uri: Uri, contentValues: ContentValues?): Uri? { + val sqlDB = dbOpenHelper.writableDatabase + val id = sqlDB.insert( + TABLE_NAME, + null, + contentValues + ) + context?.contentResolver?.notifyChange(uri, null) + return Uri.parse("$BASE_URI/$id") + } + + /** + * Handles the deletion of a recently used languages record from local SQLite Database + * @param uri : contains the URI for recently used languages + */ + override fun delete(uri: Uri, s: String?, strings: Array?): Int { + val db = dbOpenHelper.readableDatabase + Timber.d("Deleting recently used language %s", uri.lastPathSegment) + val rows = db.delete( + TABLE_NAME, + "language_code = ?", + arrayOf(uri.lastPathSegment) + ) + context?.contentResolver?.notifyChange(uri, null) + return rows + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesDao.java b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesDao.java deleted file mode 100644 index cbb8c8a1cc..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesDao.java +++ /dev/null @@ -1,204 +0,0 @@ -package fr.free.nrw.commons.recentlanguages; - -import android.annotation.SuppressLint; -import android.content.ContentProviderClient; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.os.RemoteException; -import androidx.annotation.NonNull; -import java.util.ArrayList; -import java.util.List; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Provider; -import javax.inject.Singleton; - -/** - * Handles database operations for recently used languages - */ -@Singleton -public class RecentLanguagesDao { - - private final Provider clientProvider; - - @Inject - public RecentLanguagesDao - (@Named("recent_languages") final Provider clientProvider) { - this.clientProvider = clientProvider; - } - - /** - * Find all persisted recently used languages on database - * @return list of recently used languages - */ - public List getRecentLanguages() { - final List languages = new ArrayList<>(); - final ContentProviderClient db = clientProvider.get(); - try (final Cursor cursor = db.query( - RecentLanguagesContentProvider.BASE_URI, - RecentLanguagesDao.Table.ALL_FIELDS, - null, - new String[]{}, - null)) { - if(cursor != null && cursor.moveToLast()) { - do { - languages.add(fromCursor(cursor)); - } while (cursor.moveToPrevious()); - } - } catch (final RemoteException e) { - throw new RuntimeException(e); - } finally { - db.release(); - } - return languages; - } - - /** - * Add a Language to database - * @param language : Language to add - */ - public void addRecentLanguage(final Language language) { - final ContentProviderClient db = clientProvider.get(); - try { - db.insert(RecentLanguagesContentProvider.BASE_URI, toContentValues(language)); - } catch (final RemoteException e) { - throw new RuntimeException(e); - } finally { - db.release(); - } - } - - /** - * Delete a language from database - * @param languageCode : code of the Language to delete - */ - public void deleteRecentLanguage(final String languageCode) { - final ContentProviderClient db = clientProvider.get(); - try { - db.delete(RecentLanguagesContentProvider.uriForCode(languageCode), null, null); - } catch (final RemoteException e) { - throw new RuntimeException(e); - } finally { - db.release(); - } - } - - /** - * Find a language from database based on its name - * @param languageCode : code of the Language to find - * @return boolean : is language in database ? - */ - public boolean findRecentLanguage(final String languageCode) { - if (languageCode == null) { //Avoiding NPE's - return false; - } - final ContentProviderClient db = clientProvider.get(); - try (final Cursor cursor = db.query( - RecentLanguagesContentProvider.BASE_URI, - RecentLanguagesDao.Table.ALL_FIELDS, - Table.COLUMN_CODE + "=?", - new String[]{languageCode}, - null - )) { - if (cursor != null && cursor.moveToFirst()) { - return true; - } - } catch (final RemoteException e) { - throw new RuntimeException(e); - } finally { - db.release(); - } - return false; - } - - /** - * It creates an Recent Language object from data stored in the SQLite DB by using cursor - * @param cursor cursor - * @return Language object - */ - @NonNull - @SuppressLint("Range") - Language fromCursor(final Cursor cursor) { - // Hardcoding column positions! - final String languageName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME)); - final String languageCode = cursor.getString(cursor.getColumnIndex(Table.COLUMN_CODE)); - return new Language(languageName, languageCode); - } - - /** - * Takes data from Language and create a content value object - * @param recentLanguage recently used language - * @return ContentValues - */ - private ContentValues toContentValues(final Language recentLanguage) { - final ContentValues cv = new ContentValues(); - cv.put(Table.COLUMN_NAME, recentLanguage.getLanguageName()); - cv.put(Table.COLUMN_CODE, recentLanguage.getLanguageCode()); - return cv; - } - - /** - * This class contains the database table architecture for recently used languages, - * It also contains queries and logic necessary to the create, update, delete this table. - */ - public static final class Table { - public static final String TABLE_NAME = "recent_languages"; - static final String COLUMN_NAME = "language_name"; - static final String COLUMN_CODE = "language_code"; - - // NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES. - public static final String[] ALL_FIELDS = { - COLUMN_NAME, - COLUMN_CODE - }; - - static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME; - - static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " (" - + COLUMN_NAME + " STRING," - + COLUMN_CODE + " STRING PRIMARY KEY" - + ");"; - - /** - * This method creates a LanguagesTable in SQLiteDatabase - * @param db SQLiteDatabase - */ - public static void onCreate(final SQLiteDatabase db) { - db.execSQL(CREATE_TABLE_STATEMENT); - } - - /** - * This method deletes LanguagesTable from SQLiteDatabase - * @param db SQLiteDatabase - */ - public static void onDelete(final SQLiteDatabase db) { - db.execSQL(DROP_TABLE_STATEMENT); - onCreate(db); - } - - /** - * This method is called on migrating from a older version to a newer version - * @param db SQLiteDatabase - * @param from Version from which we are migrating - * @param to Version to which we are migrating - */ - public static void onUpdate(final SQLiteDatabase db, int from, final int to) { - if (from == to) { - return; - } - if (from < 19) { - // doesn't exist yet - from++; - onUpdate(db, from, to); - return; - } - if (from == 19) { - // table added in version 20 - onCreate(db); - from++; - onUpdate(db, from, to); - } - } - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesDao.kt b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesDao.kt new file mode 100644 index 0000000000..e97c4f8165 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/recentlanguages/RecentLanguagesDao.kt @@ -0,0 +1,216 @@ +package fr.free.nrw.commons.recentlanguages + +import android.annotation.SuppressLint +import android.content.ContentProviderClient +import android.content.ContentValues +import android.database.Cursor +import android.database.sqlite.SQLiteDatabase +import android.os.RemoteException +import java.util.ArrayList +import javax.inject.Inject +import javax.inject.Named +import javax.inject.Provider +import javax.inject.Singleton + + +/** + * Handles database operations for recently used languages + */ +@Singleton +class RecentLanguagesDao @Inject constructor( + @Named("recent_languages") + private val clientProvider: Provider +) { + + /** + * Find all persisted recently used languages on database + * @return list of recently used languages + */ + fun getRecentLanguages(): List { + val languages = mutableListOf() + val db = clientProvider.get() + try { + db.query( + RecentLanguagesContentProvider.BASE_URI, + Table.ALL_FIELDS, + null, + arrayOf(), + null + )?.use { cursor -> + if (cursor.moveToLast()) { + do { + languages.add(fromCursor(cursor)) + } while (cursor.moveToPrevious()) + } + } + } catch (e: RemoteException) { + throw RuntimeException(e) + } finally { + db.release() + } + return languages + } + + /** + * Add a Language to database + * @param language : Language to add + */ + fun addRecentLanguage(language: Language) { + val db = clientProvider.get() + try { + db.insert( + RecentLanguagesContentProvider.BASE_URI, + toContentValues(language) + ) + } catch (e: RemoteException) { + throw RuntimeException(e) + } finally { + db.release() + } + } + + /** + * Delete a language from database + * @param languageCode : code of the Language to delete + */ + fun deleteRecentLanguage(languageCode: String) { + val db = clientProvider.get() + try { + db.delete( + RecentLanguagesContentProvider.uriForCode(languageCode), + null, + null + ) + } catch (e: RemoteException) { + throw RuntimeException(e) + } finally { + db.release() + } + } + + /** + * Find a language from database based on its name + * @param languageCode : code of the Language to find + * @return boolean : is language in database ? + */ + fun findRecentLanguage(languageCode: String?): Boolean { + if (languageCode == null) { // Avoiding NPEs + return false + } + val db = clientProvider.get() + try { + db.query( + RecentLanguagesContentProvider.BASE_URI, + Table.ALL_FIELDS, + "${Table.COLUMN_CODE}=?", + arrayOf(languageCode), + null + )?.use { cursor -> + if (cursor.moveToFirst()) { + return true + } + } + } catch (e: RemoteException) { + throw RuntimeException(e) + } finally { + db.release() + } + return false + } + + /** + * It creates an Recent Language object from data stored in the SQLite DB by using cursor + * @param cursor cursor + * @return Language object + */ + @SuppressLint("Range") + fun fromCursor(cursor: Cursor): Language { + // Hardcoding column positions! + val languageName = cursor.getString( + cursor.getColumnIndex(Table.COLUMN_NAME) + ) + val languageCode = cursor.getString( + cursor.getColumnIndex(Table.COLUMN_CODE) + ) + return Language(languageName, languageCode) + } + + /** + * Takes data from Language and create a content value object + * @param recentLanguage recently used language + * @return ContentValues + */ + private fun toContentValues(recentLanguage: Language): ContentValues { + return ContentValues().apply { + put(Table.COLUMN_NAME, recentLanguage.languageName) + put(Table.COLUMN_CODE, recentLanguage.languageCode) + } + } + + /** + * This class contains the database table architecture for recently used languages, + * It also contains queries and logic necessary to the create, update, delete this table. + */ + object Table { + const val TABLE_NAME = "recent_languages" + const val COLUMN_NAME = "language_name" + const val COLUMN_CODE = "language_code" + + // NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES. + @JvmStatic + val ALL_FIELDS = arrayOf( + COLUMN_NAME, + COLUMN_CODE + ) + + private const val DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS $TABLE_NAME" + + private const val CREATE_TABLE_STATEMENT = "CREATE TABLE $TABLE_NAME (" + + "$COLUMN_NAME STRING," + + "$COLUMN_CODE STRING PRIMARY KEY" + + ");" + + /** + * This method creates a LanguagesTable in SQLiteDatabase + * @param db SQLiteDatabase + */ + @SuppressLint("SQLiteString") + @JvmStatic + fun onCreate(db: SQLiteDatabase) { + db.execSQL(CREATE_TABLE_STATEMENT) + } + + /** + * This method deletes LanguagesTable from SQLiteDatabase + * @param db SQLiteDatabase + */ + @JvmStatic + fun onDelete(db: SQLiteDatabase) { + db.execSQL(DROP_TABLE_STATEMENT) + onCreate(db) + } + + /** + * This method is called on migrating from a older version to a newer version + * @param db SQLiteDatabase + * @param from Version from which we are migrating + * @param to Version to which we are migrating + */ + @JvmStatic + fun onUpdate(db: SQLiteDatabase, from: Int, to: Int) { + if (from == to) { + return + } + if (from < 19) { + // doesn't exist yet + onUpdate(db, from + 1, to) + return + } + if (from == 19) { + // table added in version 20 + onCreate(db) + onUpdate(db, from + 1, to) + } + } + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java deleted file mode 100644 index de01549478..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java +++ /dev/null @@ -1,423 +0,0 @@ -package fr.free.nrw.commons.repository; - -import androidx.annotation.Nullable; -import fr.free.nrw.commons.Media; -import fr.free.nrw.commons.category.CategoriesModel; -import fr.free.nrw.commons.category.CategoryItem; -import fr.free.nrw.commons.contributions.Contribution; -import fr.free.nrw.commons.contributions.ContributionDao; -import fr.free.nrw.commons.filepicker.UploadableFile; -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.nearby.NearbyPlaces; -import fr.free.nrw.commons.nearby.Place; -import fr.free.nrw.commons.upload.ImageCoordinates; -import fr.free.nrw.commons.upload.SimilarImageInterface; -import fr.free.nrw.commons.upload.UploadController; -import fr.free.nrw.commons.upload.UploadItem; -import fr.free.nrw.commons.upload.UploadModel; -import fr.free.nrw.commons.upload.structure.depictions.DepictModel; -import fr.free.nrw.commons.upload.structure.depictions.DepictedItem; -import io.reactivex.Flowable; -import io.reactivex.Observable; -import io.reactivex.Single; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import javax.inject.Inject; -import javax.inject.Singleton; -import timber.log.Timber; - -/** - * The repository class for UploadActivity - */ -@Singleton -public class UploadRepository { - - private final UploadModel uploadModel; - private final UploadController uploadController; - private final CategoriesModel categoriesModel; - private final NearbyPlaces nearbyPlaces; - private final DepictModel depictModel; - - private static final double NEARBY_RADIUS_IN_KILO_METERS = 0.1; //100 meters - private final ContributionDao contributionDao; - - @Inject - public UploadRepository(UploadModel uploadModel, - UploadController uploadController, - CategoriesModel categoriesModel, - NearbyPlaces nearbyPlaces, - DepictModel depictModel, - ContributionDao contributionDao) { - this.uploadModel = uploadModel; - this.uploadController = uploadController; - this.categoriesModel = categoriesModel; - this.nearbyPlaces = nearbyPlaces; - this.depictModel = depictModel; - this.contributionDao=contributionDao; - } - - /** - * asks the RemoteDataSource to build contributions - * - * @return - */ - public Observable buildContributions() { - return uploadModel.buildContributions(); - } - - /** - * asks the RemoteDataSource to start upload for the contribution - * - * @param contribution - */ - - public void prepareMedia(Contribution contribution) { - uploadController.prepareMedia(contribution); - } - - - public void saveContribution(Contribution contribution) { - contributionDao.save(contribution).blockingAwait(); - } - - /** - * Fetches and returns all the Upload Items - * - * @return - */ - public List getUploads() { - return uploadModel.getUploads(); - } - - /** - *Prepare for a fresh upload - */ - public void cleanup() { - uploadModel.cleanUp(); - //This needs further refactoring, this should not be here, right now the structure wont suppoort rhis - categoriesModel.cleanUp(); - depictModel.cleanUp(); - } - - /** - * Fetches and returns the selected categories for the current upload - * - * @return - */ - public List getSelectedCategories() { - return categoriesModel.getSelectedCategories(); - } - - /** - * all categories from MWApi - * - * @param query - * @param imageTitleList - * @param selectedDepictions - * @return - */ - public Observable> searchAll(String query, List imageTitleList, - List selectedDepictions) { - return categoriesModel.searchAll(query, imageTitleList, selectedDepictions); - } - - /** - * sets the list of selected categories for the current upload - * - * @param categoryStringList - */ - public void setSelectedCategories(List categoryStringList) { - uploadModel.setSelectedCategories(categoryStringList); - } - - /** - * handles the category selection/deselection - * - * @param categoryItem - */ - public void onCategoryClicked(CategoryItem categoryItem, final Media media) { - categoriesModel.onCategoryItemClicked(categoryItem, media); - } - - /** - * prunes the category list for irrelevant categories see #750 - * - * @param name - * @return - */ - public boolean isSpammyCategory(String name) { - return categoriesModel.isSpammyCategory(name); - } - - /** - * retursn the string list of available license from the LocalDataSource - * - * @return - */ - public List getLicenses() { - return uploadModel.getLicenses(); - } - - /** - * returns the selected license for the current upload - * - * @return - */ - public String getSelectedLicense() { - return uploadModel.getSelectedLicense(); - } - - /** - * returns the number of Upload Items - * - * @return - */ - public int getCount() { - return uploadModel.getCount(); - } - - /** - * ask the RemoteDataSource to pre process the image - * - * @param uploadableFile - * @param place - * @param similarImageInterface - * @return - */ - public Observable preProcessImage(UploadableFile uploadableFile, Place place, - SimilarImageInterface similarImageInterface, LatLng inAppPictureLocation) { - return uploadModel.preProcessImage(uploadableFile, place, - similarImageInterface, inAppPictureLocation); - } - - /** - * query the RemoteDataSource for image quality - * - * @param uploadItem UploadItem whose caption is to be checked - * @return Quality of UploadItem - */ - public Single getImageQuality(UploadItem uploadItem, LatLng location) { - return uploadModel.getImageQuality(uploadItem, location); - } - - /** - * query the RemoteDataSource for image duplicity check - * - * @param filePath file to be checked - * @return IMAGE_DUPLICATE or IMAGE_OK - */ - public Single checkDuplicateImage(String filePath) { - return uploadModel.checkDuplicateImage(filePath); - } - - /** - * query the RemoteDataSource for caption quality - * - * @param uploadItem UploadItem whose caption is to be checked - * @return Quality of caption of the UploadItem - */ - public Single getCaptionQuality(UploadItem uploadItem) { - return uploadModel.getCaptionQuality(uploadItem); - } - - /** - * asks the LocalDataSource to delete the file with the given file path - * - * @param filePath - */ - public void deletePicture(String filePath) { - uploadModel.deletePicture(filePath); - } - - /** - * fetches and returns the upload item - * - * @param index - * @return - */ - public UploadItem getUploadItem(int index) { - if (index >= 0) { - return uploadModel.getItems().get(index); - } - return null; //There is no item to copy details - } - - /** - * set selected license for the current upload - * - * @param licenseName - */ - public void setSelectedLicense(String licenseName) { - uploadModel.setSelectedLicense(licenseName); - } - - public void onDepictItemClicked(DepictedItem depictedItem, final Media media) { - uploadModel.onDepictItemClicked(depictedItem, media); - } - - /** - * Fetches and returns the selected depictions for the current upload - * - * @return - */ - - public List getSelectedDepictions() { - return uploadModel.getSelectedDepictions(); - } - - /** - * Provides selected existing depicts - * - * @return selected existing depicts - */ - public List getSelectedExistingDepictions() { - return uploadModel.getSelectedExistingDepictions(); - } - - /** - * Initialize existing depicts - * - * @param selectedExistingDepictions existing depicts - */ - public void setSelectedExistingDepictions(final List selectedExistingDepictions) { - uploadModel.setSelectedExistingDepictions(selectedExistingDepictions); - } - /** - * Search all depictions from - * - * @param query - * @return - */ - - public Flowable> searchAllEntities(String query) { - return depictModel.searchAllEntities(query, this); - } - - /** - * Gets the depiction for each unique {@link Place} associated with an {@link UploadItem} - * from {@link #getUploads()} - * - * @return a single that provides the depictions - */ - public Single> getPlaceDepictions() { - final Set qids = new HashSet<>(); - for (final UploadItem item : getUploads()) { - final Place place = item.getPlace(); - if (place != null) { - qids.add(place.getWikiDataEntityId()); - } - } - return depictModel.getPlaceDepictions(new ArrayList<>(qids)); - } - - /** - * Gets the category for each unique {@link Place} associated with an {@link UploadItem} - * from {@link #getUploads()} - * - * @return a single that provides the categories - */ - public Single> getPlaceCategories() { - final Set qids = new HashSet<>(); - for (final UploadItem item : getUploads()) { - final Place place = item.getPlace(); - if (place != null) { - qids.add(place.getCategory()); - } - } - return Single.fromObservable(categoriesModel.getCategoriesByName(new ArrayList<>(qids))); - } - - /** - * Takes depict IDs as a parameter, converts into a slash separated String and Gets DepictItem - * from the server - * - * @param depictionsQIDs IDs of Depiction - * @return Flowable> - */ - public Flowable> getDepictions(final List depictionsQIDs){ - final String ids = joinQIDs(depictionsQIDs); - return depictModel.getDepictions(ids).toFlowable(); - } - - /** - * Builds a string by joining all IDs divided by "|" - * - * @param depictionsQIDs IDs of depiction ex. ["Q11023","Q1356"] - * @return string ex. "Q11023|Q1356" - */ - private String joinQIDs(final List depictionsQIDs) { - if (depictionsQIDs != null && !depictionsQIDs.isEmpty()) { - final StringBuilder buffer = new StringBuilder(depictionsQIDs.get(0)); - - if (depictionsQIDs.size() > 1) { - for (int i = 1; i < depictionsQIDs.size(); i++) { - buffer.append("|"); - buffer.append(depictionsQIDs.get(i)); - } - } - return buffer.toString(); - } - return null; - } - - /** - * Returns nearest place matching the passed latitude and longitude - * - * @param decLatitude - * @param decLongitude - * @return - */ - @Nullable - public Place checkNearbyPlaces(final double decLatitude, final double decLongitude) { - try { - final List fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng( - decLatitude, decLongitude, 0.0f), - Locale.getDefault().getLanguage(), - NEARBY_RADIUS_IN_KILO_METERS, null); - return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery - .get(0) : null; - } catch (final Exception e) { - Timber.e("Error fetching nearby places: %s", e.getMessage()); - return null; - } - } - - public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) { - uploadModel.useSimilarPictureCoordinates(imageCoordinates, uploadItemIndex); - } - - public boolean isWMLSupportedForThisPlace() { - return uploadModel.getItems().get(0).isWLMUpload(); - } - - /** - * Provides selected existing categories - * - * @return selected existing categories - */ - public List getSelectedExistingCategories() { - return categoriesModel.getSelectedExistingCategories(); - } - - /** - * Initialize existing categories - * - * @param selectedExistingCategories existing categories - */ - public void setSelectedExistingCategories(final List selectedExistingCategories) { - categoriesModel.setSelectedExistingCategories(selectedExistingCategories); - } - - /** - * Takes category names and Gets CategoryItem from the server - * - * @param categories names of Category - * @return Observable> - */ - public Observable> getCategories(final List categories){ - return categoriesModel.getCategoriesByName(categories); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt new file mode 100644 index 0000000000..0500f4946a --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.kt @@ -0,0 +1,410 @@ +package fr.free.nrw.commons.repository + +import fr.free.nrw.commons.Media +import fr.free.nrw.commons.category.CategoriesModel +import fr.free.nrw.commons.category.CategoryItem +import fr.free.nrw.commons.contributions.Contribution +import fr.free.nrw.commons.contributions.ContributionDao +import fr.free.nrw.commons.filepicker.UploadableFile +import fr.free.nrw.commons.location.LatLng +import fr.free.nrw.commons.nearby.NearbyPlaces +import fr.free.nrw.commons.nearby.Place +import fr.free.nrw.commons.upload.ImageCoordinates +import fr.free.nrw.commons.upload.SimilarImageInterface +import fr.free.nrw.commons.upload.UploadController +import fr.free.nrw.commons.upload.UploadItem +import fr.free.nrw.commons.upload.UploadModel +import fr.free.nrw.commons.upload.structure.depictions.DepictModel +import fr.free.nrw.commons.upload.structure.depictions.DepictedItem +import io.reactivex.Flowable +import io.reactivex.Observable +import io.reactivex.Single +import java.util.Locale +import javax.inject.Inject +import javax.inject.Singleton +import timber.log.Timber + +/** + * The repository class for UploadActivity + */ +@Singleton +class UploadRepository @Inject constructor( + private val uploadModel: UploadModel, + private val uploadController: UploadController, + private val categoriesModel: CategoriesModel, + private val nearbyPlaces: NearbyPlaces, + private val depictModel: DepictModel, + private val contributionDao: ContributionDao +) { + + companion object { + private const val NEARBY_RADIUS_IN_KILO_METERS = 0.1 // 100 meters + } + + /** + * Asks the RemoteDataSource to build contributions + * + * @return + */ + fun buildContributions(): Observable { + return uploadModel.buildContributions() + } + + /** + * Asks the RemoteDataSource to start upload for the contribution + * + * @param contribution + */ + fun prepareMedia(contribution: Contribution) { + uploadController.prepareMedia(contribution) + } + + fun saveContribution(contribution: Contribution) { + contributionDao.save(contribution).blockingAwait() + } + + /** + * Fetches and returns all the Upload Items + * + * @return + */ + fun getUploads(): List { + return uploadModel.getUploads() + } + + /** + * Prepare for a fresh upload + */ + fun cleanup() { + uploadModel.cleanUp() + // This needs further refactoring, this should not be here, right now the structure + // won't support this + categoriesModel.cleanUp() + depictModel.cleanUp() + } + + /** + * Fetches and returns the selected categories for the current upload + * + * @return + */ + fun getSelectedCategories(): List { + return categoriesModel.getSelectedCategories() + } + + /** + * All categories from MWApi + * + * @param query + * @param imageTitleList + * @param selectedDepictions + * @return + */ + fun searchAll( + query: String, + imageTitleList: List, + selectedDepictions: List + ): Observable> { + return categoriesModel.searchAll(query, imageTitleList, selectedDepictions) + } + + /** + * Sets the list of selected categories for the current upload + * + * @param categoryStringList + */ + fun setSelectedCategories(categoryStringList: List) { + uploadModel.setSelectedCategories(categoryStringList) + } + + /** + * Handles the category selection/deselection + * + * @param categoryItem + */ + fun onCategoryClicked(categoryItem: CategoryItem, media: Media?) { + categoriesModel.onCategoryItemClicked(categoryItem, media) + } + + /** + * Prunes the category list for irrelevant categories see #750 + * + * @param name + * @return + */ + fun isSpammyCategory(name: String): Boolean { + return categoriesModel.isSpammyCategory(name) + } + + /** + * Returns the string list of available licenses from the LocalDataSource + * + * @return + */ + fun getLicenses(): List { + return uploadModel.licenses + } + + /** + * Returns the selected license for the current upload + * + * @return + */ + fun getSelectedLicense(): String { + return uploadModel.selectedLicense + } + + /** + * Returns the number of Upload Items + * + * @return + */ + fun getCount(): Int { + return uploadModel.count + } + + /** + * Ask the RemoteDataSource to preprocess the image + * + * @param uploadableFile + * @param place + * @param similarImageInterface + * @param inAppPictureLocation + * @return + */ + fun preProcessImage( + uploadableFile: UploadableFile, + place: Place?, + similarImageInterface: SimilarImageInterface, + inAppPictureLocation: LatLng? + ): Observable { + return uploadModel.preProcessImage( + uploadableFile, + place, + similarImageInterface, + inAppPictureLocation + ) + } + + /** + * Query the RemoteDataSource for image quality + * + * @param uploadItem UploadItem whose caption is to be checked + * @param location Location of the image + * @return Quality of UploadItem + */ + fun getImageQuality(uploadItem: UploadItem, location: LatLng?): Single { + return uploadModel.getImageQuality(uploadItem, location) + } + + /** + * Query the RemoteDataSource for image duplicity check + * + * @param filePath file to be checked + * @return IMAGE_DUPLICATE or IMAGE_OK + */ + fun checkDuplicateImage(filePath: String): Single { + return uploadModel.checkDuplicateImage(filePath) + } + + /** + * query the RemoteDataSource for caption quality + * + * @param uploadItem UploadItem whose caption is to be checked + * @return Quality of caption of the UploadItem + */ + fun getCaptionQuality(uploadItem: UploadItem): Single { + return uploadModel.getCaptionQuality(uploadItem) + } + + /** + * asks the LocalDataSource to delete the file with the given file path + * + * @param filePath + */ + fun deletePicture(filePath: String) { + uploadModel.deletePicture(filePath) + } + + /** + * fetches and returns the upload item + * + * @param index + * @return + */ + fun getUploadItem(index: Int): UploadItem? { + return if (index >= 0) { + uploadModel.items.getOrNull(index) + } else null //There is no item to copy details + } + + /** + * set selected license for the current upload + * + * @param licenseName + */ + fun setSelectedLicense(licenseName: String) { + uploadModel.selectedLicense = licenseName + } + + fun onDepictItemClicked(depictedItem: DepictedItem, media: Media?) { + uploadModel.onDepictItemClicked(depictedItem, media) + } + + /** + * Fetches and returns the selected depictions for the current upload + * + * @return + */ + fun getSelectedDepictions(): List { + return uploadModel.selectedDepictions + } + + /** + * Provides selected existing depicts + * + * @return selected existing depicts + */ + fun getSelectedExistingDepictions(): List { + return uploadModel.selectedExistingDepictions + } + + /** + * Initialize existing depicts + * + * @param selectedExistingDepictions existing depicts + */ + fun setSelectedExistingDepictions(selectedExistingDepictions: List) { + uploadModel.selectedExistingDepictions = selectedExistingDepictions + } + + /** + * Search all depictions from + * + * @param query + * @return + */ + fun searchAllEntities(query: String): Flowable> { + return depictModel.searchAllEntities(query, this) + } + + /** + * Gets the depiction for each unique {@link Place} associated with an {@link UploadItem} + * from {@link #getUploads()} + * + * @return a single that provides the depictions + */ + fun getPlaceDepictions(): Single> { + val qids = mutableSetOf() + getUploads().forEach { item -> + item.place?.let { + it.wikiDataEntityId?.let { it1 -> + qids.add(it1) + } + } + } + return depictModel.getPlaceDepictions(qids.toList()) + } + + /** + * Gets the category for each unique {@link Place} associated with an {@link UploadItem} + * from {@link #getUploads()} + * + * @return a single that provides the categories + */ + fun getPlaceCategories(): Single> { + val qids = mutableSetOf() + getUploads().forEach { item -> + item.place?.category?.let { qids.add(it) } + } + return Single.fromObservable(categoriesModel.getCategoriesByName(qids.toList())) + } + + /** + * Takes depict IDs as a parameter, converts into a slash separated String and Gets DepictItem + * from the server + * + * @param depictionsQIDs IDs of Depiction + * @return Flowable> + */ + fun getDepictions(depictionsQIDs: List): Flowable> { + val ids = joinQIDs(depictionsQIDs) ?: "" + return depictModel.getDepictions(ids).toFlowable() + } + + /** + * Builds a string by joining all IDs divided by "|" + * + * @param depictionsQIDs IDs of depiction ex. ["Q11023","Q1356"] + * @return string ex. "Q11023|Q1356" + */ + private fun joinQIDs(depictionsQIDs: List?): String? { + return depictionsQIDs?.takeIf { + it.isNotEmpty() + }?.joinToString("|") + } + + /** + * Returns nearest place matching the passed latitude and longitude + * + * @param decLatitude + * @param decLongitude + * @return + */ + fun checkNearbyPlaces(decLatitude: Double, decLongitude: Double): Place? { + return try { + val fromWikidataQuery = nearbyPlaces.getFromWikidataQuery( + LatLng(decLatitude, decLongitude, 0.0f), + Locale.getDefault().language, + NEARBY_RADIUS_IN_KILO_METERS, + null + ) + fromWikidataQuery?.firstOrNull() + } catch (e: Exception) { + Timber.e("Error fetching nearby places: %s", e.message) + null + } + } + + fun useSimilarPictureCoordinates(imageCoordinates: ImageCoordinates, uploadItemIndex: Int) { + uploadModel.useSimilarPictureCoordinates( + imageCoordinates, + uploadItemIndex + ) + } + + fun isWMLSupportedForThisPlace(): Boolean { + return uploadModel.items.firstOrNull()?.isWLMUpload == true + } + + /** + * Provides selected existing categories + * + * @return selected existing categories + */ + fun getSelectedExistingCategories(): List { + return categoriesModel.getSelectedExistingCategories() + } + + /** + * Initialize existing categories + * + * @param selectedExistingCategories existing categories + */ + fun setSelectedExistingCategories(selectedExistingCategories: List) { + categoriesModel.setSelectedExistingCategories( + selectedExistingCategories.toMutableList() + ) + } + + /** + * Takes category names and Gets CategoryItem from the server + * + * @param categories names of Category + * @return Observable> + */ + fun getCategories(categories: List): Observable> { + return categoriesModel.getCategoriesByName(categories) + ?.map { it.toList() } ?: Observable.empty() + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt b/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt index 1822df8302..712f6fc3ed 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/categories/CategoriesPresenter.kt @@ -61,7 +61,7 @@ class CategoriesPresenter .doOnNext { view.showProgress(true) }.switchMap(::searchResults) - .map { repository.selectedCategories + it } + .map { repository.getSelectedCategories() + it } .map { it.distinctBy { categoryItem -> categoryItem.name } } .observeOn(mainThreadScheduler) .subscribe( @@ -89,7 +89,7 @@ class CategoriesPresenter private fun searchResults(term: String): Observable>? { if (media == null) { return repository - .searchAll(term, getImageTitleList(), repository.selectedDepictions) + .searchAll(term, getImageTitleList(), repository.getSelectedDepictions()) .subscribeOn(ioScheduler) .map { it.filter { categoryItem -> @@ -101,13 +101,13 @@ class CategoriesPresenter return Observable .zip( repository - .getCategories(repository.selectedExistingCategories) + .getCategories(repository.getSelectedExistingCategories()) .map { list -> list.map { CategoryItem(it.name, it.description, it.thumbnail, true) } }, - repository.searchAll(term, getImageTitleList(), repository.selectedDepictions), + repository.searchAll(term, getImageTitleList(), repository.getSelectedDepictions()), ) { it1, it2 -> it1 + it2 }.subscribeOn(ioScheduler) @@ -138,7 +138,7 @@ class CategoriesPresenter * @return */ private fun getImageTitleList(): List = - repository.uploads + repository.getUploads() .map { it.uploadMediaDetails[0].captionText } .filterNot { TextUtils.isEmpty(it) } @@ -146,7 +146,7 @@ class CategoriesPresenter * Verifies the number of categories selected, prompts the user if none selected */ override fun verifyCategories() { - val selectedCategories = repository.selectedCategories + val selectedCategories = repository.getSelectedCategories() if (selectedCategories.isNotEmpty()) { repository.setSelectedCategories(selectedCategories.map { it.name }) view.goToNextScreen() @@ -173,14 +173,14 @@ class CategoriesPresenter ) { this.view = view this.media = media - repository.selectedExistingCategories = view.existingCategories + repository.setSelectedExistingCategories(view.existingCategories) compositeDisposable.add( searchTerms .observeOn(mainThreadScheduler) .doOnNext { view.showProgress(true) }.switchMap(::searchResults) - .map { repository.selectedCategories + it } + .map { repository.getSelectedCategories() + it } .map { it.distinctBy { categoryItem -> categoryItem.name } } .observeOn(mainThreadScheduler) .subscribe( @@ -218,13 +218,21 @@ class CategoriesPresenter wikiText: String, ) { // check if view.existingCategories is null - if (repository.selectedCategories.isNotEmpty() || - (view.existingCategories != null && repository.selectedExistingCategories.size != view.existingCategories.size) + if ( + repository.getSelectedCategories().isNotEmpty() + || + ( + view.existingCategories != null + && + repository.getSelectedExistingCategories().size + != + view.existingCategories.size + ) ) { val selectedCategories: MutableList = ( - repository.selectedCategories.map { it.name }.toMutableList() + - repository.selectedExistingCategories + repository.getSelectedCategories().map { it.name }.toMutableList() + + repository.getSelectedExistingCategories() ).toMutableList() if (selectedCategories.isNotEmpty()) { @@ -305,7 +313,7 @@ class CategoriesPresenter override fun selectCategories() { compositeDisposable.add( - repository.placeCategories + repository.getPlaceCategories() .subscribeOn(ioScheduler) .observeOn(mainThreadScheduler) .subscribe(::selectNewCategories), diff --git a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsPresenter.kt b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsPresenter.kt index 3beedd9d5c..fa3eb354ee 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsPresenter.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/depicts/DepictsPresenter.kt @@ -93,14 +93,14 @@ class DepictsPresenter return repository .searchAllEntities(querystring) .subscribeOn(ioScheduler) - .map { repository.selectedDepictions + it + recentDepictedItemList + controller.loadFavoritesItems() } + .map { repository.getSelectedDepictions() + it + recentDepictedItemList + controller.loadFavoritesItems() } .map { it.filterNot { item -> WikidataDisambiguationItems.isDisambiguationItem(item.instanceOfs) } } .map { it.distinctBy(DepictedItem::id) } } else { return Flowable .zip( repository - .getDepictions(repository.selectedExistingDepictions) + .getDepictions(repository.getSelectedExistingDepictions()) .map { list -> list.map { DepictedItem( @@ -118,7 +118,7 @@ class DepictsPresenter ) { it1, it2 -> it1 + it2 }.subscribeOn(ioScheduler) - .map { repository.selectedDepictions + it + recentDepictedItemList + controller.loadFavoritesItems() } + .map { repository.getSelectedDepictions() + it + recentDepictedItemList + controller.loadFavoritesItems() } .map { it.filterNot { item -> WikidataDisambiguationItems.isDisambiguationItem(item.instanceOfs) } } .map { it.distinctBy(DepictedItem::id) } } @@ -135,7 +135,7 @@ class DepictsPresenter */ override fun selectPlaceDepictions() { compositeDisposable.add( - repository.placeDepictions + repository.getPlaceDepictions() .subscribeOn(ioScheduler) .observeOn(mainThreadScheduler) .subscribe(::selectNewDepictions), @@ -188,10 +188,10 @@ class DepictsPresenter * from the depiction list */ override fun verifyDepictions() { - if (repository.selectedDepictions.isNotEmpty()) { + if (repository.getSelectedDepictions().isNotEmpty()) { if (::depictsDao.isInitialized) { // save all the selected Depicted item in room Database - depictsDao.savingDepictsInRoomDataBase(repository.selectedDepictions) + depictsDao.savingDepictsInRoomDataBase(repository.getSelectedDepictions()) } view.goToNextScreen() } else { @@ -205,20 +205,20 @@ class DepictsPresenter */ @SuppressLint("CheckResult") override fun updateDepictions(media: Media) { - if (repository.selectedDepictions.isNotEmpty() || - repository.selectedExistingDepictions.size != view.existingDepictions.size + if (repository.getSelectedDepictions().isNotEmpty() || + repository.getSelectedExistingDepictions().size != view.existingDepictions.size ) { view.showProgressDialog() val selectedDepictions: MutableList = ( - repository.selectedDepictions.map { it.id }.toMutableList() + - repository.selectedExistingDepictions + repository.getSelectedDepictions().map { it.id }.toMutableList() + + repository.getSelectedExistingDepictions() ).toMutableList() if (selectedDepictions.isNotEmpty()) { if (::depictsDao.isInitialized) { // save all the selected Depicted item in room Database - depictsDao.savingDepictsInRoomDataBase(repository.selectedDepictions) + depictsDao.savingDepictsInRoomDataBase(repository.getSelectedDepictions()) } compositeDisposable.add( @@ -254,7 +254,7 @@ class DepictsPresenter ) { this.view = view this.media = media - repository.selectedExistingDepictions = view.existingDepictions + repository.setSelectedExistingDepictions(view.existingDepictions) compositeDisposable.add( searchTerm .observeOn(mainThreadScheduler) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictModel.kt b/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictModel.kt index 7242b8eed3..9337cb8b58 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictModel.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictModel.kt @@ -39,7 +39,7 @@ class DepictModel for (place in places) { place.wikiDataEntityId?.let { qids.add(it) } } - repository.uploads.forEach { item -> + repository.getUploads().forEach { item -> if (item.gpsCoords != null && item.gpsCoords.imageCoordsExists) { Coordinates2Country .countryQID( diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/CategoriesPresenterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/CategoriesPresenterTest.kt index 4b321071fe..bb8fd1fc5e 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/CategoriesPresenterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/CategoriesPresenterTest.kt @@ -56,9 +56,9 @@ class CategoriesPresenterTest { @Throws(Exception::class) fun `Test onAttachViewWithMedia when media is not null`() { categoriesPresenter.onAttachViewWithMedia(view, media()) - whenever(repository.getCategories(repository.selectedExistingCategories)) + whenever(repository.getCategories(repository.getSelectedExistingCategories())) .thenReturn(Observable.just(mutableListOf(categoryItem()))) - whenever(repository.searchAll("mock", emptyList(), repository.selectedDepictions)) + whenever(repository.searchAll("mock", emptyList(), repository.getSelectedDepictions())) .thenReturn(Observable.just(mutableListOf(categoryItem()))) val method: Method = CategoriesPresenter::class.java.getDeclaredMethod( @@ -88,7 +88,7 @@ class CategoriesPresenterTest { val emptyCaptionUploadItem = mock() whenever(emptyCaptionUploadItem.uploadMediaDetails) .thenReturn(listOf(UploadMediaDetail(captionText = ""))) - whenever(repository.uploads).thenReturn( + whenever(repository.getUploads()).thenReturn( listOf( nonEmptyCaptionUploadItem, emptyCaptionUploadItem, @@ -105,7 +105,7 @@ class CategoriesPresenterTest { ) whenever(repository.isSpammyCategory("selected")).thenReturn(false) whenever(repository.isSpammyCategory("doesContainYear")).thenReturn(true) - whenever(repository.selectedCategories).thenReturn( + whenever(repository.getSelectedCategories()).thenReturn( listOf( categoryItem("selected", "", "", true), ), @@ -130,7 +130,7 @@ class CategoriesPresenterTest { whenever(repository.searchAll(any(), any(), any())) .thenReturn(Observable.just(emptyCategories)) - whenever(repository.selectedCategories).thenReturn(listOf()) + whenever(repository.getSelectedCategories()).thenReturn(listOf()) categoriesPresenter.searchForCategories(query) testScheduler.triggerActions() val method: Method = @@ -154,7 +154,7 @@ class CategoriesPresenterTest { fun `verifyCategories with non empty selection goes to next screen`() { categoriesPresenter.onAttachView(view) val item = categoryItem() - whenever(repository.selectedCategories).thenReturn(listOf(item)) + whenever(repository.getSelectedCategories()).thenReturn(listOf(item)) categoriesPresenter.verifyCategories() verify(repository).setSelectedCategories(listOf(item.name)) verify(view).goToNextScreen() @@ -163,7 +163,7 @@ class CategoriesPresenterTest { @Test fun `verifyCategories with empty selection show no category selected`() { categoriesPresenter.onAttachView(view) - whenever(repository.selectedCategories).thenReturn(listOf()) + whenever(repository.getSelectedCategories()).thenReturn(listOf()) categoriesPresenter.verifyCategories() verify(view).showNoCategorySelected() } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/DepictsPresenterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/DepictsPresenterTest.kt index 748b95ea6d..1abff908e2 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/DepictsPresenterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/DepictsPresenterTest.kt @@ -74,7 +74,7 @@ class DepictsPresenterTest { ) whenever(repository.searchAllEntities("")).thenReturn(Flowable.just(searchResults)) val selectedItem = depictedItem(id = "selected") - whenever(repository.selectedDepictions).thenReturn(listOf(selectedItem)) + whenever(repository.getSelectedDepictions()).thenReturn(listOf(selectedItem)) depictsPresenter.searchForDepictions("") testScheduler.triggerActions() verify(view).showProgress(false) @@ -123,14 +123,14 @@ class DepictsPresenterTest { @Test fun `verifyDepictions with non empty selectedDepictions goes to next screen`() { - whenever(repository.selectedDepictions).thenReturn(listOf(depictedItem())) + whenever(repository.getSelectedDepictions()).thenReturn(listOf(depictedItem())) depictsPresenter.verifyDepictions() verify(view).goToNextScreen() } @Test fun `verifyDepictions with empty selectedDepictions goes to noDepictionSelected`() { - whenever(repository.selectedDepictions).thenReturn(emptyList()) + whenever(repository.getSelectedDepictions()).thenReturn(emptyList()) depictsPresenter.verifyDepictions() verify(view).noDepictionSelected() } @@ -162,7 +162,7 @@ class DepictsPresenterTest { @Test fun `Test searchResults when media is not null`() { Whitebox.setInternalState(depictsPresenter, "media", media) - whenever(repository.getDepictions(repository.selectedExistingDepictions)) + whenever(repository.getDepictions(repository.getSelectedExistingDepictions())) .thenReturn(Flowable.just(listOf(depictedItem()))) whenever(repository.searchAllEntities("querystring")) .thenReturn(Flowable.just(listOf(depictedItem()))) diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadPresenterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadPresenterTest.kt index bbaaaec1cf..29a35c1e55 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadPresenterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadPresenterTest.kt @@ -84,7 +84,7 @@ class UploadPresenterTest { fun handleSubmitImagesNoLocationWithConsecutiveNoLocationUploads() { `when`(imageCoords.imageCoordsExists).thenReturn(false) `when`(uploadItem.getGpsCoords()).thenReturn(imageCoords) - `when`(repository.uploads).thenReturn(uploadableItems) + `when`(repository.getUploads()).thenReturn(uploadableItems) uploadableItems.add(uploadItem) // test 1 - insufficient count @@ -112,7 +112,7 @@ class UploadPresenterTest { ).thenReturn(UploadPresenter.CONSECUTIVE_UPLOADS_WITHOUT_COORDINATES_REMINDER_THRESHOLD) `when`(imageCoords.imageCoordsExists).thenReturn(true) `when`(uploadItem.getGpsCoords()).thenReturn(imageCoords) - `when`(repository.uploads).thenReturn(uploadableItems) + `when`(repository.getUploads()).thenReturn(uploadableItems) uploadableItems.add(uploadItem) uploadPresenter.handleSubmit() // no alert dialog expected diff --git a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt index 54d35494a3..233b0de32c 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/upload/UploadRepositoryUnitTest.kt @@ -117,7 +117,7 @@ class UploadRepositoryUnitTest { @Test fun testGetUploads() { - assertEquals(repository.uploads, uploadModel.uploads) + assertEquals(repository.getUploads(), uploadModel.uploads) } @Test @@ -130,7 +130,7 @@ class UploadRepositoryUnitTest { @Test fun testGetSelectedCategories() { - assertEquals(repository.selectedCategories, categoriesModel.getSelectedCategories()) + assertEquals(repository.getSelectedCategories(), categoriesModel.getSelectedCategories()) } @Test @@ -163,17 +163,17 @@ class UploadRepositoryUnitTest { @Test fun testGetLicenses() { - assertEquals(repository.licenses, uploadModel.licenses) + assertEquals(repository.getLicenses(), uploadModel.licenses) } @Test fun testGetSelectedLicense() { - assertEquals(repository.selectedLicense, uploadModel.selectedLicense) + assertEquals(repository.getSelectedLicense(), uploadModel.selectedLicense) } @Test fun testGetCount() { - assertEquals(repository.count, uploadModel.count) + assertEquals(repository.getCount(), uploadModel.count) } @Test @@ -242,12 +242,12 @@ class UploadRepositoryUnitTest { @Test fun testGetSelectedDepictions() { - assertEquals(repository.selectedDepictions, uploadModel.selectedDepictions) + assertEquals(repository.getSelectedDepictions(), uploadModel.selectedDepictions) } @Test fun testGetSelectedExistingDepictions() { - assertEquals(repository.selectedExistingDepictions, uploadModel.selectedExistingDepictions) + assertEquals(repository.getSelectedExistingDepictions(), uploadModel.selectedExistingDepictions) } @Test @@ -264,7 +264,7 @@ class UploadRepositoryUnitTest { `when`(uploadItem.place).thenReturn(place) `when`(place.wikiDataEntityId).thenReturn("1") assertEquals( - repository.placeDepictions, + repository.getPlaceDepictions(), depictModel.getPlaceDepictions(listOf("1")), ) } @@ -326,7 +326,7 @@ class UploadRepositoryUnitTest { `when`(uploadModel.items).thenReturn(listOf(uploadItem)) `when`(uploadItem.isWLMUpload).thenReturn(true) assertEquals( - repository.isWMLSupportedForThisPlace, + repository.isWMLSupportedForThisPlace(), true, ) } @@ -369,7 +369,7 @@ class UploadRepositoryUnitTest { @Test fun testGetSelectedExistingCategories() { assertEquals( - repository.selectedExistingCategories, + repository.getSelectedExistingCategories(), categoriesModel.getSelectedExistingCategories(), ) }