Skip to content

Commit

Permalink
Feature/refractor uploads [WIP] (#2887)
Browse files Browse the repository at this point in the history
* Fix duplicate param information (#2515)

* Bug fix issue #2476 (#2526)

* Added wikidataEntityID in all db versions, handled db.execSql via method runQuery

* Versioning and changelog for v2.10.2 (#2531)

* Update changelog.md

* Versioning for v2.10.2

* Update changelog.md

* Bugfix/issue 2580 (#2584)

* Corrected string placedholders in certain string files

* Corrected string placedholders in certain string files[Bug fix #2580]

* Bug Fix #2585 (#2647)

* Bug Fix #2585
* Added null checks on view in SearchImageFragment when updating views from external sources
* Disposed the disposables in SearchActivity and SearchImageFragment when no longer in active lifecycle

* use FragmentUtils to verify fragment active state

* Bug Fix issue #2648 (#2678)

* Bug Fix issue #2648
* Handled external storage permission before file download

* * Removed redudant check for permission in MediaDetailPagerFragment (Dexter already does that)
* Removed duplicate code in PermissionUtil$checkPermissionsAndPerformAction, used the existing function with conditional extra parameters

* string name typo correction

* BugFix issue #2652 (#2706)

* Addded null check on bookmark before operating on it

* BugFix issue #2711 (#2712)

* Added null checks in OkHttpJsonApiClient$searchImages MwQueryResponse

* BugFix #2718 (#2719)

* Handled null auth cookies

* Fix #2791: NPE when nominating for deletion and leaving screen (#2792)

* Bug Fix issue #2789 (#2790)

* Handled Illegal State Exception for non existent appropriate view parents in ViewUtils$showShortSnackbar

* BugFix #2720 (#2831)

BugFix deprecated licenes #2720

* ui fixes, wip, upload

* *Issue #2886, BugFix #2832[wip]
* updated UploadActivity code
* modified ui
* Updated UploadPresenterTest

* * updated interfaces names to follow names suffixed with Contract
* added test cases

* card view elevation

* view pager disabled swipe

* bug fix, duplicate image

* used existing non-swipable view pager

* Avoid image view resize with keyboard, added adjustPan and stateVisible as softinputMode for UploadActivity

* retain UploadBaseFragment instances on orientation changes

* * Added test cases for UploadMediaPresenter
* Injected io and main thread schedulers

* categories presenter test cased wip

* Added CategoriesPresenter test

* * Added the logic to show open map (with to be uploaded image's coordinates while uploading image)

* codacy suggested changes * added java docs

* Added travis_wait fot android-wait-for-emulator

* ranamed interface onResponseCallback to Callback

* * Added api to delete picture in UploadModel
* cleanUp in UploadModel. once upload has been initiated
* Removed unused methods from UploadModel and the corresponding test class

* * Added tests for UploadPresenter
* Travis suggested changes
* Addded copy previous title and description

* * Made the upload add descriptions visible when keyboard visible
* add description request focus only when user manually requests it

* Added JavaDocs, review suggested changes

* Fix dagger injection

* use DialogUtil to show info in descriptions

* use activity context for DialogUtil

* Minor changes
  • Loading branch information
ashishkumar468 committed May 28, 2019
1 parent 12883e3 commit a7712f0
Show file tree
Hide file tree
Showing 68 changed files with 3,556 additions and 1,984 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle
Expand Up @@ -63,6 +63,8 @@ dependencies {
testImplementation 'org.robolectric:robolectric:3.7.1'
testImplementation 'com.nhaarman:mockito-kotlin:1.5.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.10.0'
testImplementation "org.powermock:powermock-module-junit4:2.0.0-beta.5"
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"

// Android testing
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -50,10 +50,13 @@
</activity>
<activity android:name=".WelcomeActivity" />

<activity android:name=".upload.UploadActivity"
<activity
android:name=".upload.UploadActivity"
android:configChanges="orientation|screenSize|keyboard"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:configChanges="orientation|screenSize|keyboard">
android:windowSoftInputMode="adjustResize"
>
<intent-filter android:label="@string/intent_share_upload_label">
<action android:name="android.intent.action.SEND" />

Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/fr/free/nrw/commons/BasePresenter.java
Expand Up @@ -3,11 +3,11 @@
/**
* Base presenter, enforcing contracts to atach and detach view
*/
public interface BasePresenter {
public interface BasePresenter<T> {
/**
* Until a view is attached, it is open to listen events from the presenter
*/
void onAttachView(MvpView view);
void onAttachView(T view);

/**
* Detaching a view makes sure that the view no more receives events from the presenter
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/fr/free/nrw/commons/Utils.java
Expand Up @@ -11,16 +11,16 @@

import org.wikipedia.dataclient.WikiSite;
import org.wikipedia.page.PageTitle;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.utils.ViewUtil;

import java.util.Locale;
import java.util.regex.Pattern;

import androidx.annotation.NonNull;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber;

import static android.widget.Toast.LENGTH_SHORT;
Expand Down
Expand Up @@ -28,7 +28,7 @@
* success and error
*/
@Singleton
public class CampaignsPresenter implements BasePresenter {
public class CampaignsPresenter implements BasePresenter<ICampaignsView> {
private final OkHttpJsonApiClient okHttpJsonApiClient;

private ICampaignsView view;
Expand All @@ -40,8 +40,9 @@ public CampaignsPresenter(OkHttpJsonApiClient okHttpJsonApiClient) {
this.okHttpJsonApiClient = okHttpJsonApiClient;
}

@Override public void onAttachView(MvpView view) {
this.view = (ICampaignsView) view;
@Override
public void onAttachView(ICampaignsView view) {
this.view = view;
}

@Override public void onDetachView() {
Expand Down
Expand Up @@ -19,7 +19,7 @@
import io.reactivex.Observable;
import timber.log.Timber;

public class CategoriesModel implements CategoryClickedListener {
public class CategoriesModel{
private static final int SEARCH_CATS_LIMIT = 25;

private final MediaWikiApi mwApi;
Expand Down Expand Up @@ -186,8 +186,7 @@ private Observable<CategoryItem> recentCategories() {
//endregion

//region Category Selection
@Override
public void categoryClicked(CategoryItem item) {
public void onCategoryItemClicked(CategoryItem item) {
if (item.isSelected()) {
selectCategory(item);
updateCategoryCount(item);
Expand Down
Expand Up @@ -19,7 +19,7 @@ public CategoryItem[] newArray(int i) {
}
};

CategoryItem(String name, boolean selected) {
public CategoryItem(String name, boolean selected) {
this.name = name;
this.selected = selected;
}
Expand Down
Expand Up @@ -100,7 +100,7 @@ ContentValues toContentValues(Contribution contribution) {
cv.put(Table.COLUMN_UPLOADED, contribution.getDateUploaded().getTime());
}
cv.put(Table.COLUMN_LENGTH, contribution.getDataLength());
//This was always meant to store the date created..If somehow date created is not fetched while actually saving the contribution, lets save today's date
//This was always meant to store the date created..If somehow date created is not fetched while actually saving the contribution, lets saveValue today's date
cv.put(Table.COLUMN_TIMESTAMP, contribution.getDateCreated()==null?System.currentTimeMillis():contribution.getDateCreated().getTime());
cv.put(Table.COLUMN_STATE, contribution.getState());
cv.put(Table.COLUMN_TRANSFERRED, contribution.getTransferred());
Expand Down
Expand Up @@ -15,6 +15,7 @@
import fr.free.nrw.commons.review.ReviewController;
import fr.free.nrw.commons.settings.SettingsFragment;
import fr.free.nrw.commons.upload.FileProcessor;
import fr.free.nrw.commons.upload.UploadModule;
import fr.free.nrw.commons.widget.PicOfDayAppWidget;


Expand All @@ -27,7 +28,7 @@
ActivityBuilderModule.class,
FragmentBuilderModule.class,
ServiceBuilderModule.class,
ContentProviderBuilderModule.class
ContentProviderBuilderModule.class, UploadModule.class
})
public interface CommonsApplicationComponent extends AndroidInjector<ApplicationlessInjection> {
void inject(CommonsApplication application);
Expand Down
Expand Up @@ -8,6 +8,9 @@

import com.google.gson.Gson;

import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -36,6 +39,8 @@
@SuppressWarnings({"WeakerAccess", "unused"})
public class CommonsApplicationModule {
private Context applicationContext;
public static final String IO_THREAD="io_thread";
public static final String MAIN_THREAD="main_thread";

public CommonsApplicationModule(Context applicationContext) {
this.applicationContext = applicationContext;
Expand Down Expand Up @@ -171,4 +176,16 @@ public WikidataEditListener provideWikidataEditListener() {
public boolean provideIsBetaVariant() {
return ConfigUtils.isBetaFlavour();
}

@Named(IO_THREAD)
@Provides
public Scheduler providesIoThread(){
return Schedulers.io();
}

@Named(MAIN_THREAD)
@Provides
public Scheduler providesMainThread(){
return AndroidSchedulers.mainThread();
}
}
Expand Up @@ -18,6 +18,9 @@
import fr.free.nrw.commons.nearby.NearbyMapFragment;
import fr.free.nrw.commons.review.ReviewImageFragment;
import fr.free.nrw.commons.settings.SettingsFragment;
import fr.free.nrw.commons.upload.categories.UploadCategoriesFragment;
import fr.free.nrw.commons.upload.license.MediaLicenseFragment;
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment;

@Module
@SuppressWarnings({"WeakerAccess", "unused"})
Expand Down Expand Up @@ -71,4 +74,12 @@ public abstract class FragmentBuilderModule {
@ContributesAndroidInjector
abstract ReviewImageFragment bindReviewOutOfContextFragment();

@ContributesAndroidInjector
abstract UploadMediaDetailFragment bindUploadMediaDetailFragment();

@ContributesAndroidInjector
abstract UploadCategoriesFragment bindUploadCategoriesFragment();

@ContributesAndroidInjector
abstract MediaLicenseFragment bindMediaLicenseFragment();
}
11 changes: 0 additions & 11 deletions app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java
Expand Up @@ -16,10 +16,6 @@
import com.google.android.material.tabs.TabLayout;
import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxSearchView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.jakewharton.rxbinding2.view.RxView;
import com.jakewharton.rxbinding2.widget.RxSearchView;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.explore.categories.SearchCategoryFragment;
Expand All @@ -33,13 +29,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.reactivex.disposables.Disposable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
* Represents search screen of this app
Expand Down
Expand Up @@ -56,9 +56,6 @@
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.StringUtils;
import org.wikipedia.util.DateUtil;
import org.wikipedia.util.StringUtil;
import timber.log.Timber;

import static android.view.View.GONE;
Expand Down
@@ -0,0 +1,150 @@
package fr.free.nrw.commons.repository;

import androidx.annotation.Nullable;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.upload.UploadModel;
import fr.free.nrw.commons.upload.UploadModel.UploadItem;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

/**
* The Local Data Source for UploadRepository, fetches and returns data from local db/shared prefernces
*/

@Singleton
public class UploadLocalDataSource {

private final UploadModel uploadModel;
private JsonKvStore defaultKVStore;

@Inject
public UploadLocalDataSource(
@Named("default_preferences") JsonKvStore defaultKVStore,
UploadModel uploadModel) {
this.defaultKVStore = defaultKVStore;
this.uploadModel = uploadModel;
}


/**
* Fetches and returns the string list of valid licenses
*
* @return
*/
public List<String> getLicenses() {
return uploadModel.getLicenses();
}

/**
* Returns the number of Upload Items
*
* @return
*/
public int getCount() {
return uploadModel.getCount();
}

/**
* Fetches and return the selected license for the current upload
*
* @return
*/
public String getSelectedLicense() {
return uploadModel.getSelectedLicense();
}

/**
* Set selected license for the current upload
*
* @param licenseName
*/
public void setSelectedLicense(String licenseName) {
uploadModel.setSelectedLicense(licenseName);
}

/**
* Updates the current upload item
*
* @param index
* @param uploadItem
*/
public void updateUploadItem(int index, UploadItem uploadItem) {
uploadModel.updateUploadItem(index, uploadItem);
}

/**
* upload is halted, cleanup the acquired resources
*/
public void cleanUp() {
uploadModel.cleanUp();
}

/**
* Deletes the upload item at the current index
*
* @param filePath
*/
public void deletePicture(String filePath) {
uploadModel.deletePicture(filePath);
}

/**
* Fethces and returns the previous upload item, if any, returns null otherwise
*
* @param index
* @return
*/
@Nullable
public UploadItem getPreviousUploadItem(int index) {
if (index - 1 >= 0) {
return uploadModel.getItems().get(index - 1);
}
return null; //There is no previous item to copy details
}

/**
* saves boolean value in default store
*
* @param key
* @param value
*/
public void saveValue(String key, boolean value) {
defaultKVStore.putBoolean(key, value);
}

/**
* saves string value in default store
*
* @param key
* @param value
*/
public void saveValue(String key, String value) {
defaultKVStore.putString(key, value);
}

/**
* Fetches and returns string value from the default store
*
* @param key
* @param defaultValue
* @return
*/
public String getValue(String key, String defaultValue) {
return defaultKVStore.getString(key, defaultValue);
}

/**
* Fetches and returns boolean value from the default store
*
* @param key
* @param defaultValue
* @return
*/
public boolean getValue(String key, boolean defaultValue) {
return defaultKVStore.getBoolean(key, defaultValue);
}
}

0 comments on commit a7712f0

Please sign in to comment.