mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
Merge remote-tracking branch 'upstream/master' into refactorNearbyClassesMVP
This commit is contained in:
commit
52e9ef9245
45 changed files with 1128 additions and 679 deletions
|
|
@ -135,31 +135,4 @@ public class BookmarksActivity extends NavigationBaseActivity
|
|||
}
|
||||
return adapter.getMediaAdapter().getCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void notifyDatasetChanged() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,32 +173,6 @@ public class CategoryDetailsActivity extends NavigationBaseActivity
|
|||
return categoryImagesListFragment.getAdapter().getCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void notifyDatasetChanged() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inflates the menu in the toolbar
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -180,33 +180,6 @@ public class CategoryImagesActivity
|
|||
return categoryImagesListFragment.getAdapter().getCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void notifyDatasetChanged() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inflates the menu in the toolbar
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,35 +1,34 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.collection.LruCache;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.ViewHolder;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class ContributionViewHolder implements ViewHolder<DisplayableContribution> {
|
||||
public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final Callback callback;
|
||||
@BindView(R.id.contributionImage)
|
||||
SimpleDraweeView imageView;
|
||||
@BindView(R.id.contributionTitle) TextView titleView;
|
||||
|
|
@ -47,15 +46,18 @@ public class ContributionViewHolder implements ViewHolder<DisplayableContributio
|
|||
|
||||
private DisplayableContribution contribution;
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private int position;
|
||||
|
||||
ContributionViewHolder(View parent) {
|
||||
ContributionViewHolder(View parent, Callback callback) {
|
||||
super(parent);
|
||||
ButterKnife.bind(this, parent);
|
||||
this.callback=callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindModel(Context context, DisplayableContribution contribution) {
|
||||
ApplicationlessInjection.getInstance(context)
|
||||
public void init(int position, DisplayableContribution contribution) {
|
||||
ApplicationlessInjection.getInstance(itemView.getContext())
|
||||
.getCommonsApplicationComponent().inject(this);
|
||||
this.position=position;
|
||||
this.contribution = contribution;
|
||||
fetchAndDisplayThumbnail(contribution);
|
||||
titleView.setText(contribution.getDisplayTitle());
|
||||
|
|
@ -104,19 +106,39 @@ public class ContributionViewHolder implements ViewHolder<DisplayableContributio
|
|||
* @param contribution
|
||||
*/
|
||||
private void fetchAndDisplayThumbnail(DisplayableContribution contribution) {
|
||||
if (!StringUtils.isBlank(thumbnailCache.get(contribution.getFilename()))) {
|
||||
imageView.setImageURI(thumbnailCache.get(contribution.getFilename()));
|
||||
String keyForLRUCache = getKeyForLRUCache(contribution.getContentUri());
|
||||
String cacheUrl = thumbnailCache.get(keyForLRUCache);
|
||||
if (!StringUtils.isBlank(cacheUrl)) {
|
||||
imageView.setImageURI(cacheUrl);
|
||||
return;
|
||||
}
|
||||
Timber.d("Fetching thumbnail for %s", contribution.getFilename());
|
||||
Disposable disposable = mediaDataExtractor.getMediaFromFileName(contribution.getFilename())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(media -> {
|
||||
thumbnailCache.put(contribution.getFilename(), media.getThumbUrl());
|
||||
imageView.setImageURI(media.getThumbUrl());
|
||||
});
|
||||
compositeDisposable.add(disposable);
|
||||
|
||||
imageView.setBackground(null);
|
||||
if ((contribution.getState() != Contribution.STATE_COMPLETED) && FileUtils.fileExists(
|
||||
contribution.getLocalUri())) {
|
||||
imageView.setImageURI(contribution.getLocalUri());
|
||||
} else {
|
||||
Timber.d("Fetching thumbnail for %s", contribution.getFilename());
|
||||
Disposable disposable = mediaDataExtractor
|
||||
.getMediaFromFileName(contribution.getFilename())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(media -> {
|
||||
thumbnailCache.put(keyForLRUCache, media.getThumbUrl());
|
||||
imageView.setImageURI(media.getThumbUrl());
|
||||
});
|
||||
compositeDisposable.add(disposable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns image key for the LRU cache, basically the id of the image, (the content uri is the ""+/id)
|
||||
* @param contentUri
|
||||
* @return
|
||||
*/
|
||||
private String getKeyForLRUCache(Uri contentUri) {
|
||||
return contentUri.getLastPathSegment();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
|
@ -128,10 +150,7 @@ public class ContributionViewHolder implements ViewHolder<DisplayableContributio
|
|||
*/
|
||||
@OnClick(R.id.retryButton)
|
||||
public void retryUpload() {
|
||||
DisplayableContribution.ContributionActions actions = contribution.getContributionActions();
|
||||
if (actions != null) {
|
||||
actions.retryUpload();
|
||||
}
|
||||
callback.retryUpload(contribution);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -139,17 +158,11 @@ public class ContributionViewHolder implements ViewHolder<DisplayableContributio
|
|||
*/
|
||||
@OnClick(R.id.cancelButton)
|
||||
public void deleteUpload() {
|
||||
DisplayableContribution.ContributionActions actions = contribution.getContributionActions();
|
||||
if (actions != null) {
|
||||
actions.deleteUpload();
|
||||
}
|
||||
callback.deleteUpload(contribution);
|
||||
}
|
||||
|
||||
@OnClick(R.id.contributionImage)
|
||||
public void imageClicked(){
|
||||
DisplayableContribution.ContributionActions actions = contribution.getContributionActions();
|
||||
if (actions != null) {
|
||||
actions.onClick();
|
||||
}
|
||||
callback.openMediaDetail(position);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import android.database.Cursor;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import fr.free.nrw.commons.BasePresenter;
|
||||
import fr.free.nrw.commons.Media;
|
||||
|
||||
/**
|
||||
* The contract for Contributions View & Presenter
|
||||
*/
|
||||
public class ContributionsContract {
|
||||
|
||||
public interface View {
|
||||
|
||||
void showWelcomeTip(boolean numberOfUploads);
|
||||
|
||||
void showProgress(boolean shouldShow);
|
||||
|
||||
void showNoContributionsUI(boolean shouldShow);
|
||||
|
||||
void setUploadCount(int count);
|
||||
|
||||
void onDataSetChanged();
|
||||
}
|
||||
|
||||
public interface UserActionListener extends BasePresenter<ContributionsContract.View>,
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
Contribution getContributionsFromCursor(Cursor cursor);
|
||||
|
||||
void deleteUpload(Contribution contribution);
|
||||
|
||||
Media getItemAtPosition(int i);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +1,28 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED;
|
||||
import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.database.Cursor;
|
||||
import android.database.DataSetObserver;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Adapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.cursoradapter.widget.CursorAdapter;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.CursorLoader;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import fr.free.nrw.commons.HandlerService;
|
||||
|
|
@ -40,12 +32,15 @@ import fr.free.nrw.commons.campaigns.Campaign;
|
|||
import fr.free.nrw.commons.campaigns.CampaignView;
|
||||
import fr.free.nrw.commons.campaigns.CampaignsPresenter;
|
||||
import fr.free.nrw.commons.campaigns.ICampaignsView;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListFragment.SourceRefresher;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.location.LocationUpdateListener;
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider;
|
||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import fr.free.nrw.commons.nearby.NearbyController;
|
||||
|
|
@ -55,29 +50,26 @@ import fr.free.nrw.commons.settings.Prefs;
|
|||
import fr.free.nrw.commons.upload.UploadService;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.ContributionDao.Table.ALL_FIELDS;
|
||||
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI;
|
||||
import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION;
|
||||
import static fr.free.nrw.commons.settings.Prefs.UPLOADS_SHOWING;
|
||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||
|
||||
public class ContributionsFragment
|
||||
extends CommonsDaggerSupportFragment
|
||||
implements LoaderManager.LoaderCallbacks<Cursor>,
|
||||
MediaDetailPagerFragment.MediaDetailProvider,
|
||||
FragmentManager.OnBackStackChangedListener,
|
||||
ContributionsListFragment.SourceRefresher,
|
||||
LocationUpdateListener,
|
||||
ICampaignsView,
|
||||
ContributionsListAdapter.EventListener{
|
||||
implements
|
||||
MediaDetailProvider,
|
||||
OnBackStackChangedListener,
|
||||
SourceRefresher,
|
||||
LocationUpdateListener,
|
||||
ICampaignsView, ContributionsContract.View {
|
||||
@Inject @Named("default_preferences") JsonKvStore store;
|
||||
@Inject ContributionDao contributionDao;
|
||||
@Inject MediaWikiApi mediaWikiApi;
|
||||
|
|
@ -99,6 +91,8 @@ public class ContributionsFragment
|
|||
@BindView(R.id.card_view_nearby) public NearbyNotificationCardView nearbyNotificationCardView;
|
||||
@BindView(R.id.campaigns_view) CampaignView campaignView;
|
||||
|
||||
@Inject ContributionsPresenter contributionsPresenter;
|
||||
|
||||
private LatLng curLatLng;
|
||||
|
||||
private boolean firstLocationUpdate = true;
|
||||
|
|
@ -116,9 +110,6 @@ public class ContributionsFragment
|
|||
uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder)
|
||||
.getService();
|
||||
isUploadServiceConnected = true;
|
||||
if (contributionsListFragment.getAdapter() != null) {
|
||||
((ContributionsListAdapter)contributionsListFragment.getAdapter()).setUploadService(uploadService);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -127,6 +118,8 @@ public class ContributionsFragment
|
|||
Timber.e(new RuntimeException("UploadService died but the rest of the process did not!"));
|
||||
}
|
||||
};
|
||||
private boolean shouldShowMediaDetailsFragment;
|
||||
private int numberOfContributions;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
|
|
@ -140,6 +133,7 @@ public class ContributionsFragment
|
|||
View view = inflater.inflate(R.layout.fragment_contributions, container, false);
|
||||
ButterKnife.bind(this, view);
|
||||
presenter.onAttachView(this);
|
||||
contributionsPresenter.onAttachView(this);
|
||||
campaignView.setVisibility(View.GONE);
|
||||
checkBoxView = View.inflate(getActivity(), R.layout.nearby_permission_dialog, null);
|
||||
checkBox = (CheckBox) checkBoxView.findViewById(R.id.never_ask_again);
|
||||
|
|
@ -151,16 +145,19 @@ public class ContributionsFragment
|
|||
});
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mediaDetailPagerFragment = (MediaDetailPagerFragment)getChildFragmentManager().findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
||||
contributionsListFragment = (ContributionsListFragment) getChildFragmentManager().findFragmentByTag(CONTRIBUTION_LIST_FRAGMENT_TAG);
|
||||
mediaDetailPagerFragment = (MediaDetailPagerFragment) getChildFragmentManager()
|
||||
.findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
||||
contributionsListFragment = (ContributionsListFragment) getChildFragmentManager()
|
||||
.findFragmentByTag(CONTRIBUTION_LIST_FRAGMENT_TAG);
|
||||
shouldShowMediaDetailsFragment = savedInstanceState.getBoolean("mediaDetailsVisible");
|
||||
}
|
||||
|
||||
if (savedInstanceState.getBoolean("mediaDetailsVisible")) {
|
||||
setMediaDetailPagerFragment();
|
||||
} else {
|
||||
setContributionsListFragment();
|
||||
}
|
||||
} else {
|
||||
setContributionsListFragment();
|
||||
initFragments();
|
||||
|
||||
if(shouldShowMediaDetailsFragment){
|
||||
showMediaDetailPagerFragment();
|
||||
}else{
|
||||
showContributionsListFragment();
|
||||
}
|
||||
|
||||
if (!ConfigUtils.isBetaFlavour()) {
|
||||
|
|
@ -191,6 +188,65 @@ public class ContributionsFragment
|
|||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialose the ContributionsListFragment and MediaDetailPagerFragment fragment
|
||||
*/
|
||||
private void initFragments() {
|
||||
if (null == contributionsListFragment) {
|
||||
contributionsListFragment = new ContributionsListFragment();
|
||||
}
|
||||
|
||||
contributionsListFragment.setCallback(new Callback() {
|
||||
@Override
|
||||
public void retryUpload(Contribution contribution) {
|
||||
ContributionsFragment.this.retryUpload(contribution);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUpload(Contribution contribution) {
|
||||
contributionsPresenter.deleteUpload(contribution);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openMediaDetail(int position) {
|
||||
showDetail(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfContributions() {
|
||||
return numberOfContributions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contribution getContributionForPosition(int position) {
|
||||
return (Contribution) contributionsPresenter.getItemAtPosition(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findItemPositionWithId(String id) {
|
||||
return contributionsPresenter.getChildPositionWithId(id);
|
||||
}
|
||||
});
|
||||
|
||||
if(null==mediaDetailPagerFragment){
|
||||
mediaDetailPagerFragment=new MediaDetailPagerFragment();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the root frame layout with the given fragment
|
||||
* @param fragment
|
||||
* @param tag
|
||||
*/
|
||||
private void showFragment(Fragment fragment, String tag) {
|
||||
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
|
||||
transaction.replace(R.id.root_frame, fragment, tag);
|
||||
transaction.addToBackStack(CONTRIBUTION_LIST_FRAGMENT_TAG);
|
||||
transaction.commit();
|
||||
getChildFragmentManager().executePendingTransactions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
|
@ -209,132 +265,45 @@ public class ContributionsFragment
|
|||
}
|
||||
|
||||
/**
|
||||
* Replace FrameLayout with ContributionsListFragment, user will see contributions list.
|
||||
* Creates new one if null.
|
||||
* Replace FrameLayout with ContributionsListFragment, user will see contributions list. Creates
|
||||
* new one if null.
|
||||
*/
|
||||
public void setContributionsListFragment() {
|
||||
public void showContributionsListFragment() {
|
||||
// show tabs on contribution list is visible
|
||||
((MainActivity)getActivity()).showTabs();
|
||||
((MainActivity) getActivity()).showTabs();
|
||||
// show nearby card view on contributions list is visible
|
||||
if (nearbyNotificationCardView != null) {
|
||||
if (store.getBoolean("displayNearbyCardView", true)) {
|
||||
if (nearbyNotificationCardView.cardViewVisibilityState == NearbyNotificationCardView.CardViewVisibilityState.READY) {
|
||||
if (nearbyNotificationCardView.cardViewVisibilityState
|
||||
== NearbyNotificationCardView.CardViewVisibilityState.READY) {
|
||||
nearbyNotificationCardView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
nearbyNotificationCardView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
// Create if null
|
||||
if (getContributionsListFragment() == null) {
|
||||
contributionsListFragment = new ContributionsListFragment();
|
||||
}
|
||||
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
|
||||
// When this container fragment is created, we fill it with our ContributionsListFragment
|
||||
transaction.replace(R.id.root_frame, contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG);
|
||||
transaction.addToBackStack(CONTRIBUTION_LIST_FRAGMENT_TAG);
|
||||
transaction.commit();
|
||||
getChildFragmentManager().executePendingTransactions();
|
||||
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace FrameLayout with MediaDetailPagerFragment, user will see details of selected media.
|
||||
* Creates new one if null.
|
||||
*/
|
||||
public void setMediaDetailPagerFragment() {
|
||||
public void showMediaDetailPagerFragment() {
|
||||
// hide tabs on media detail view is visible
|
||||
((MainActivity)getActivity()).hideTabs();
|
||||
// hide nearby card view on media detail is visible
|
||||
nearbyNotificationCardView.setVisibility(View.GONE);
|
||||
|
||||
// Create if null
|
||||
if (getMediaDetailPagerFragment() == null) {
|
||||
mediaDetailPagerFragment = new MediaDetailPagerFragment();
|
||||
}
|
||||
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
|
||||
// When this container fragment is created, we fill it with our MediaDetailPagerFragment
|
||||
//transaction.addToBackStack(null);
|
||||
transaction.add(R.id.root_frame, mediaDetailPagerFragment, MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
||||
transaction.addToBackStack(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
||||
transaction.commit();
|
||||
getChildFragmentManager().executePendingTransactions();
|
||||
showFragment(mediaDetailPagerFragment,MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Just getter method of ContributionsListFragment child of ContributionsFragment
|
||||
* @return contributionsListFragment, if any created
|
||||
*/
|
||||
public ContributionsListFragment getContributionsListFragment() {
|
||||
return contributionsListFragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just getter method of MediaDetailPagerFragment child of ContributionsFragment
|
||||
* @return mediaDetailsFragment, if any created
|
||||
*/
|
||||
public MediaDetailPagerFragment getMediaDetailPagerFragment() {
|
||||
return mediaDetailPagerFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
((MainActivity)getActivity()).initBackButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
|
||||
int uploads = store.getInt(UPLOADS_SHOWING, 100);
|
||||
return new CursorLoader(getActivity(), BASE_URI, //TODO find out the reason we pass activity here
|
||||
ALL_FIELDS, "", null,
|
||||
ContributionDao.CONTRIBUTION_SORT + "LIMIT " + uploads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
|
||||
if (contributionsListFragment != null) {
|
||||
contributionsListFragment.changeProgressBarVisibility(false);
|
||||
|
||||
if (contributionsListFragment.getAdapter() == null) {
|
||||
contributionsListFragment.setAdapter(new ContributionsListAdapter(getActivity().getApplicationContext(),
|
||||
cursor, 0, contributionDao, this));
|
||||
} else {
|
||||
((CursorAdapter) contributionsListFragment.getAdapter()).swapCursor(cursor);
|
||||
}
|
||||
|
||||
contributionsListFragment.showWelcomeTip(cursor.getCount() == 0);
|
||||
notifyAndMigrateDataSetObservers();
|
||||
((ContributionsListAdapter)contributionsListFragment.getAdapter()).setUploadService(uploadService);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> cursorLoader) {
|
||||
((CursorAdapter) contributionsListFragment.getAdapter()).swapCursor(null);
|
||||
}
|
||||
|
||||
private void notifyAndMigrateDataSetObservers() {
|
||||
Adapter adapter = contributionsListFragment.getAdapter();
|
||||
|
||||
// First, move the observers over to the adapter now that we have it.
|
||||
for (DataSetObserver observer : observersWaitingForLoad) {
|
||||
adapter.registerDataSetObserver(observer);
|
||||
}
|
||||
observersWaitingForLoad.clear();
|
||||
|
||||
// Now fire off a first notification...
|
||||
for (DataSetObserver observer : observersWaitingForLoad) {
|
||||
observer.onChanged();
|
||||
}
|
||||
|
||||
if (ConfigUtils.isBetaFlavour()) {
|
||||
betaSetUploadCount(getTotalMediaCount());
|
||||
} else {
|
||||
setUploadCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when onAuthCookieAcquired is called on authenticated parent activity
|
||||
* @param uploadServiceIntent
|
||||
|
|
@ -345,7 +314,7 @@ public class ContributionsFragment
|
|||
if (getActivity() != null) { // If fragment is attached to parent activity
|
||||
getActivity().bindService(uploadServiceIntent, uploadServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
isUploadServiceConnected = true;
|
||||
getActivity().getSupportLoaderManager().initLoader(0, null, ContributionsFragment.this);
|
||||
getActivity().getSupportLoaderManager().initLoader(0, null, contributionsPresenter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -358,57 +327,24 @@ public class ContributionsFragment
|
|||
public void showDetail(int i) {
|
||||
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
|
||||
mediaDetailPagerFragment = new MediaDetailPagerFragment();
|
||||
setMediaDetailPagerFragment();
|
||||
showMediaDetailPagerFragment();
|
||||
}
|
||||
mediaDetailPagerFragment.showImage(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshSource() {
|
||||
getActivity().getSupportLoaderManager().restartLoader(0, null, this);
|
||||
getActivity().getSupportLoaderManager().restartLoader(0, null, contributionsPresenter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Media getMediaAtPosition(int i) {
|
||||
if (contributionsListFragment.getAdapter() == null) {
|
||||
// not yet ready to return data
|
||||
return null;
|
||||
} else {
|
||||
return contributionDao.fromCursor((Cursor) contributionsListFragment.getAdapter().getItem(i));
|
||||
}
|
||||
return contributionsPresenter.getItemAtPosition(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalMediaCount() {
|
||||
if (contributionsListFragment.getAdapter() == null) {
|
||||
return 0;
|
||||
}
|
||||
return contributionsListFragment.getAdapter().getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDatasetChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
Adapter adapter = contributionsListFragment.getAdapter();
|
||||
if (adapter == null) {
|
||||
observersWaitingForLoad.add(observer);
|
||||
} else {
|
||||
adapter.registerDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
Adapter adapter = contributionsListFragment.getAdapter();
|
||||
if (adapter == null) {
|
||||
observersWaitingForLoad.remove(observer);
|
||||
} else {
|
||||
adapter.unregisterDataSetObserver(observer);
|
||||
}
|
||||
return numberOfContributions;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
|
|
@ -454,7 +390,7 @@ public class ContributionsFragment
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
contributionsPresenter.onAttachView(this);
|
||||
firstLocationUpdate = true;
|
||||
locationManager.addLocationListener(this);
|
||||
|
||||
|
|
@ -624,11 +560,48 @@ public class ContributionsFragment
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(String filename) {
|
||||
for (int i=0;i<getTotalMediaCount();i++){
|
||||
if (getMediaAtPosition(i).getFilename().equals(filename))
|
||||
showDetail(i);
|
||||
public void showWelcomeTip(boolean shouldShow) {
|
||||
contributionsListFragment.showWelcomeTip(shouldShow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showProgress(boolean shouldShow) {
|
||||
contributionsListFragment.showProgress(shouldShow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showNoContributionsUI(boolean shouldShow) {
|
||||
contributionsListFragment.showNoContributionsUI(shouldShow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUploadCount(int count) {
|
||||
this.numberOfContributions=count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataSetChanged() {
|
||||
contributionsListFragment.onDataSetChanged();
|
||||
mediaDetailPagerFragment.onDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry upload when it is failed
|
||||
*
|
||||
* @param contribution contribution to be retried
|
||||
*/
|
||||
private void retryUpload(Contribution contribution) {
|
||||
if (NetworkUtils.isInternetConnectionEstablished(getContext())) {
|
||||
if (contribution.getState() == STATE_FAILED && null != uploadService) {
|
||||
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, contribution);
|
||||
Timber.d("Restarting for %s", contribution.toString());
|
||||
} else {
|
||||
Timber.d("Skipping re-upload for non-failed %s", contribution.toString());
|
||||
}
|
||||
} else {
|
||||
ViewUtil.showLongToast(getContext(), R.string.this_function_needs_network_connection);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,121 +1,55 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cursoradapter.widget.CursorAdapter;
|
||||
import android.database.DataSetObserver;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.model.DisplayableContribution;
|
||||
import fr.free.nrw.commons.upload.UploadService;
|
||||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED;
|
||||
public class ContributionsListAdapter extends RecyclerView.Adapter<ContributionViewHolder> {
|
||||
|
||||
class ContributionsListAdapter extends CursorAdapter {
|
||||
private Callback callback;
|
||||
|
||||
private final ContributionDao contributionDao;
|
||||
private UploadService uploadService;
|
||||
|
||||
public ContributionsListAdapter(Context context,
|
||||
Cursor c,
|
||||
int flags,
|
||||
ContributionDao contributionDao, EventListener listener) {
|
||||
super(context, c, flags);
|
||||
this.contributionDao = contributionDao;
|
||||
this.listener=listener;
|
||||
public ContributionsListAdapter(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setUploadService(UploadService uploadService) {
|
||||
this.uploadService = uploadService;
|
||||
@NonNull
|
||||
@Override
|
||||
public ContributionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
ContributionViewHolder viewHolder = new ContributionViewHolder(
|
||||
LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.layout_contribution, parent, false), callback);
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
|
||||
View parent = LayoutInflater.from(context)
|
||||
.inflate(R.layout.layout_contribution, viewGroup, false);
|
||||
parent.setTag(new ContributionViewHolder(parent));
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
final ContributionViewHolder views = (ContributionViewHolder)view.getTag();
|
||||
final Contribution contribution = contributionDao.fromCursor(cursor);
|
||||
|
||||
Timber.d("Cursor position is %d", cursor.getPosition());
|
||||
public void onBindViewHolder(@NonNull ContributionViewHolder holder, int position) {
|
||||
final Contribution contribution = callback.getContributionForPosition(position);
|
||||
DisplayableContribution displayableContribution = new DisplayableContribution(contribution,
|
||||
cursor.getPosition(),
|
||||
new DisplayableContribution.ContributionActions() {
|
||||
@Override
|
||||
public void retryUpload() {
|
||||
ContributionsListAdapter.this.retryUpload(view.getContext(), contribution);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUpload() {
|
||||
ContributionsListAdapter.this.deleteUpload(view.getContext(), contribution);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
ContributionsListAdapter.this.openMediaDetail(contribution);
|
||||
}
|
||||
});
|
||||
views.bindModel(context, displayableContribution);
|
||||
position);
|
||||
holder.init(position, displayableContribution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry upload when it is failed
|
||||
* @param contribution contribution to be retried
|
||||
*/
|
||||
private void retryUpload(@NonNull Context context, Contribution contribution) {
|
||||
if (NetworkUtils.isInternetConnectionEstablished(context)) {
|
||||
if (contribution.getState() == STATE_FAILED
|
||||
&& uploadService!= null) {
|
||||
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, contribution);
|
||||
Timber.d("Restarting for %s", contribution.toString());
|
||||
} else {
|
||||
Timber.d("Skipping re-upload for non-failed %s", contribution.toString());
|
||||
}
|
||||
} else {
|
||||
ViewUtil.showLongToast(context, R.string.this_function_needs_network_connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return callback.getNumberOfContributions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a failed upload attempt
|
||||
* @param contribution contribution to be deleted
|
||||
*/
|
||||
private void deleteUpload(@NonNull Context context, Contribution contribution) {
|
||||
if (NetworkUtils.isInternetConnectionEstablished(context)) {
|
||||
if (contribution.getState() == STATE_FAILED) {
|
||||
Timber.d("Deleting failed contrib %s", contribution.toString());
|
||||
contributionDao.delete(contribution);
|
||||
} else {
|
||||
Timber.d("Skipping deletion for non-failed contrib %s", contribution.toString());
|
||||
}
|
||||
} else {
|
||||
ViewUtil.showLongToast(context, R.string.this_function_needs_network_connection);
|
||||
}
|
||||
public interface Callback {
|
||||
|
||||
}
|
||||
void retryUpload(Contribution contribution);
|
||||
|
||||
private void openMediaDetail(Contribution contribution){
|
||||
listener.onEvent(contribution.getFilename());
|
||||
void deleteUpload(Contribution contribution);
|
||||
|
||||
}
|
||||
EventListener listener;
|
||||
void openMediaDetail(int contribution);
|
||||
|
||||
public interface EventListener {
|
||||
void onEvent(String filename);
|
||||
int getNumberOfContributions();
|
||||
|
||||
Contribution getContributionForPosition(int position);
|
||||
|
||||
int findItemPositionWithId(String lastVisibleItemID);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,33 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.content.res.Configuration;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.LayoutManager;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* Created by root on 01.06.2018.
|
||||
|
|
@ -36,8 +35,9 @@ import static android.view.View.VISIBLE;
|
|||
|
||||
public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
||||
|
||||
private static final String VISIBLE_ITEM_ID = "visible_item_id";
|
||||
@BindView(R.id.contributionsList)
|
||||
GridView contributionsList;
|
||||
RecyclerView rvContributionsList;
|
||||
@BindView(R.id.loadingContributionsProgressBar)
|
||||
ProgressBar progressBar;
|
||||
@BindView(R.id.fab_plus)
|
||||
|
|
@ -62,29 +62,56 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
|||
|
||||
private boolean isFabOpen = false;
|
||||
|
||||
private ContributionsListAdapter adapter;
|
||||
|
||||
private Callback callback;
|
||||
private String lastVisibleItemID;
|
||||
|
||||
private int SPAN_COUNT=3;
|
||||
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_contributions_list, container, false);
|
||||
ButterKnife.bind(this, view);
|
||||
|
||||
changeProgressBarVisibility(true);
|
||||
initAdapter();
|
||||
return view;
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
adapter = new ContributionsListAdapter(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
initRecyclerView();
|
||||
initializeAnimations();
|
||||
setListeners();
|
||||
}
|
||||
|
||||
private void initRecyclerView() {
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
rvContributionsList.setLayoutManager(new GridLayoutManager(getContext(),SPAN_COUNT));
|
||||
} else {
|
||||
rvContributionsList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
}
|
||||
|
||||
rvContributionsList.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
// check orientation
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
fab_layout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
rvContributionsList.setLayoutManager(new GridLayoutManager(getContext(),SPAN_COUNT));
|
||||
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
fab_layout.setOrientation(LinearLayout.VERTICAL);
|
||||
rvContributionsList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,39 +154,78 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible to set progress bar invisible and visible
|
||||
* @param isVisible True when contributions list should be hidden.
|
||||
*/
|
||||
public void changeProgressBarVisibility(boolean isVisible) {
|
||||
this.progressBar.setVisibility(isVisible ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows welcome message if user has no contributions yet i.e. new user.
|
||||
*/
|
||||
protected void showWelcomeTip(boolean noContributions) {
|
||||
noContributionsYet.setVisibility(noContributions ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public ListAdapter getAdapter() {
|
||||
return contributionsList.getAdapter();
|
||||
public void showWelcomeTip(boolean shouldShow) {
|
||||
noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets adapter to contributions list. If beta mode, sets upload count for beta explicitly.
|
||||
* @param adapter List adapter for uploads of contributor
|
||||
* Responsible to set progress bar invisible and visible
|
||||
* @param shouldShow True when contributions list should be hidden.
|
||||
*/
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
this.contributionsList.setAdapter(adapter);
|
||||
public void showProgress(boolean shouldShow) {
|
||||
progressBar.setVisibility(shouldShow ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
if (ConfigUtils.isBetaFlavour()) {
|
||||
//TODO: add betaSetUploadCount method
|
||||
((ContributionsFragment) getParentFragment()).betaSetUploadCount(adapter.getCount());
|
||||
public void showNoContributionsUI(boolean shouldShow) {
|
||||
noContributionsYet.setVisibility(shouldShow?VISIBLE:GONE);
|
||||
}
|
||||
|
||||
public void onDataSetChanged() {
|
||||
if (null != adapter) {
|
||||
adapter.notifyDataSetChanged();
|
||||
//Restoring last visible item position in cases of orientation change
|
||||
if (null != lastVisibleItemID) {
|
||||
int itemPositionWithId = callback.findItemPositionWithId(lastVisibleItemID);
|
||||
rvContributionsList.scrollToPosition(itemPositionWithId);
|
||||
lastVisibleItemID = null;//Reset the lastVisibleItemID once we have used it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface SourceRefresher {
|
||||
void refreshSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
LayoutManager layoutManager = rvContributionsList.getLayoutManager();
|
||||
int lastVisibleItemPosition=0;
|
||||
if(layoutManager instanceof LinearLayoutManager){
|
||||
lastVisibleItemPosition= ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
|
||||
}else if(layoutManager instanceof GridLayoutManager){
|
||||
lastVisibleItemPosition=((GridLayoutManager)layoutManager).findLastCompletelyVisibleItemPosition();
|
||||
}
|
||||
String idOfItemWithPosition = findIdOfItemWithPosition(lastVisibleItemPosition);
|
||||
if (null != idOfItemWithPosition) {
|
||||
outState.putString(VISIBLE_ITEM_ID, idOfItemWithPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
if(null!=savedInstanceState){
|
||||
lastVisibleItemID =savedInstanceState.getString(VISIBLE_ITEM_ID, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the id of the contribution from the db
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private String findIdOfItemWithPosition(int position) {
|
||||
Contribution contributionForPosition = callback.getContributionForPosition(position);
|
||||
if (null != contributionForPosition) {
|
||||
return contributionForPosition.getContentUri().getLastPathSegment();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import android.database.Cursor;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* The LocalDataSource class for Contributions
|
||||
*/
|
||||
class ContributionsLocalDataSource {
|
||||
|
||||
private final ContributionDao contributionsDao;
|
||||
private final JsonKvStore defaultKVStore;
|
||||
|
||||
@Inject
|
||||
public ContributionsLocalDataSource(
|
||||
@Named("default_preferences") JsonKvStore defaultKVStore,
|
||||
ContributionDao contributionDao) {
|
||||
this.defaultKVStore = defaultKVStore;
|
||||
this.contributionsDao = contributionDao;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch default number of contributions to be show, based on user preferences
|
||||
*/
|
||||
public int get(String key) {
|
||||
return defaultKVStore.getInt(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contribution object from cursor
|
||||
* @param cursor
|
||||
* @return
|
||||
*/
|
||||
public Contribution getContributionFromCursor(Cursor cursor) {
|
||||
return contributionsDao.fromCursor(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a contribution from the contributions table
|
||||
* @param contribution
|
||||
*/
|
||||
public void deleteContribution(Contribution contribution) {
|
||||
contributionsDao.delete(contribution);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
|
||||
/**
|
||||
* The Dagger Module for contributions related presenters and (some other objects maybe in future)
|
||||
*/
|
||||
@Module
|
||||
public abstract class ContributionsModule {
|
||||
|
||||
@Binds
|
||||
public abstract ContributionsContract.UserActionListener bindsContibutionsPresenter(
|
||||
ContributionsPresenter presenter);
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import static fr.free.nrw.commons.contributions.ContributionDao.Table.ALL_FIELDS;
|
||||
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI;
|
||||
import static fr.free.nrw.commons.settings.Prefs.UPLOADS_SHOWING;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.DataSetObserver;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.content.CursorLoader;
|
||||
import androidx.loader.content.Loader;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.contributions.ContributionsContract.UserActionListener;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* The presenter class for Contributions
|
||||
*/
|
||||
public class ContributionsPresenter extends DataSetObserver implements UserActionListener {
|
||||
|
||||
private final ContributionsRepository repository;
|
||||
private ContributionsContract.View view;
|
||||
private Cursor cursor;
|
||||
|
||||
@Inject
|
||||
Context context;
|
||||
|
||||
@Inject
|
||||
ContributionsPresenter(ContributionsRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachView(ContributionsContract.View view) {
|
||||
this.view = view;
|
||||
if (null != cursor) {
|
||||
try {
|
||||
cursor.registerDataSetObserver(this);
|
||||
} catch (IllegalStateException e) {//Cursor might be already registered
|
||||
Timber.d(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachView() {
|
||||
this.view = null;
|
||||
if (null != cursor) {
|
||||
try {
|
||||
cursor.unregisterDataSetObserver(this);
|
||||
} catch (Exception e) {//Cursor might not be already registered
|
||||
Timber.d(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
|
||||
int preferredNumberOfUploads = repository.get(UPLOADS_SHOWING);
|
||||
return new CursorLoader(context, BASE_URI,
|
||||
ALL_FIELDS, "", null,
|
||||
ContributionDao.CONTRIBUTION_SORT + "LIMIT "
|
||||
+ (preferredNumberOfUploads>0?preferredNumberOfUploads:100));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
|
||||
view.showProgress(false);
|
||||
if (null != cursor && cursor.getCount() > 0) {
|
||||
view.showWelcomeTip(false);
|
||||
view.showNoContributionsUI(false);
|
||||
view.setUploadCount(cursor.getCount());
|
||||
} else {
|
||||
view.showWelcomeTip(true);
|
||||
view.showNoContributionsUI(true);
|
||||
}
|
||||
swapCursor(cursor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
|
||||
this.cursor = null;
|
||||
//On LoadFinished is not guaranteed to be called
|
||||
view.showProgress(false);
|
||||
view.showWelcomeTip(true);
|
||||
view.showNoContributionsUI(true);
|
||||
swapCursor(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contribution from the repository
|
||||
*/
|
||||
@Override
|
||||
public Contribution getContributionsFromCursor(Cursor cursor) {
|
||||
return repository.getContributionFromCursor(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a failed contribution from the local db
|
||||
* @param contribution
|
||||
*/
|
||||
@Override
|
||||
public void deleteUpload(Contribution contribution) {
|
||||
repository.deleteContributionFromDB(contribution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a contribution at the specified cursor position
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public Media getItemAtPosition(int i) {
|
||||
if (null != cursor && cursor.moveToPosition(i)) {
|
||||
return getContributionsFromCursor(cursor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contribution position with id
|
||||
*/
|
||||
public int getChildPositionWithId(String id) {
|
||||
int position = 0;
|
||||
cursor.moveToFirst();
|
||||
while (null != cursor && cursor.moveToNext()) {
|
||||
if (getContributionsFromCursor(cursor).getContentUri().getLastPathSegment()
|
||||
.equals(id)) {
|
||||
position = cursor.getPosition();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
view.onDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
super.onInvalidated();
|
||||
//Not letting the view know of this as of now, TODO discuss how to handle this and maybe show a proper ui for this
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap in a new Cursor, returning the old Cursor. The returned old Cursor is <em>not</em>
|
||||
* closed.
|
||||
*
|
||||
* @param newCursor The new cursor to be used.
|
||||
* @return Returns the previously set Cursor, or null if there was not one. If the given new
|
||||
* Cursor is the same instance is the previously set Cursor, null is also returned.
|
||||
*/
|
||||
private void swapCursor(Cursor newCursor) {
|
||||
try {
|
||||
if (newCursor == cursor) {
|
||||
return;
|
||||
}
|
||||
Cursor oldCursor = cursor;
|
||||
if (oldCursor != null) {
|
||||
oldCursor.unregisterDataSetObserver(this);
|
||||
}
|
||||
cursor = newCursor;
|
||||
if (newCursor != null) {
|
||||
newCursor.registerDataSetObserver(this);
|
||||
}
|
||||
view.onDataSetChanged();
|
||||
} catch (IllegalStateException e) {//Cursor might [not] be already registered/unregistered
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import android.database.Cursor;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* The repository class for contributions
|
||||
*/
|
||||
public class ContributionsRepository {
|
||||
|
||||
private ContributionsLocalDataSource localDataSource;
|
||||
|
||||
@Inject
|
||||
public ContributionsRepository(ContributionsLocalDataSource localDataSource) {
|
||||
this.localDataSource = localDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch default number of contributions to be show, based on user preferences
|
||||
*/
|
||||
public int get(String uploadsShowing) {
|
||||
return localDataSource.get(uploadsShowing);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get contribution object from cursor from LocalDataSource
|
||||
* @param cursor
|
||||
* @return
|
||||
*/
|
||||
public Contribution getContributionFromCursor(Cursor cursor) {
|
||||
return localDataSource.getContributionFromCursor(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a failed upload from DB
|
||||
* @param contribution
|
||||
*/
|
||||
public void deleteContributionFromDB(Contribution contribution) {
|
||||
localDataSource.deleteContribution(contribution);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package fr.free.nrw.commons.contributions;
|
|||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -386,13 +385,6 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
|
|||
case 0:
|
||||
ContributionsFragment retainedContributionsFragment = getContributionsFragment(0);
|
||||
if (retainedContributionsFragment != null) {
|
||||
// ContributionsFragment is parent of ContributionsListFragment and
|
||||
// MediaDetailsFragment. If below decides which child will be visible.
|
||||
if (isContributionsListFragment) {
|
||||
retainedContributionsFragment.setContributionsListFragment();
|
||||
} else {
|
||||
retainedContributionsFragment.setMediaDetailPagerFragment();
|
||||
}
|
||||
return retainedContributionsFragment;
|
||||
} else {
|
||||
// If we reach here, retainedContributionsFragment is null
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ import fr.free.nrw.commons.contributions.Contribution;
|
|||
|
||||
public class DisplayableContribution extends Contribution {
|
||||
private int position;
|
||||
private ContributionActions contributionActions;
|
||||
|
||||
private DisplayableContribution(Contribution contribution,
|
||||
public DisplayableContribution(Contribution contribution,
|
||||
int position) {
|
||||
super(contribution.getContentUri(),
|
||||
contribution.getFilename(),
|
||||
|
|
@ -27,13 +25,6 @@ public class DisplayableContribution extends Contribution {
|
|||
this.position = position;
|
||||
}
|
||||
|
||||
public DisplayableContribution(Contribution contribution,
|
||||
int position,
|
||||
ContributionActions contributionActions) {
|
||||
this(contribution, position);
|
||||
this.contributionActions = contributionActions;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
|
@ -41,16 +32,4 @@ public class DisplayableContribution extends Contribution {
|
|||
public void setPosition(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ContributionActions getContributionActions() {
|
||||
return contributionActions;
|
||||
}
|
||||
|
||||
public interface ContributionActions {
|
||||
void retryUpload();
|
||||
|
||||
void deleteUpload();
|
||||
|
||||
void onClick();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class DeleteHelper {
|
|||
* @return
|
||||
*/
|
||||
public Single<Boolean> makeDeletion(Context context, Media media, String reason) {
|
||||
viewUtil.showShortToast(context, "Trying to nominate " + media.getDisplayTitle() + " for deletion");
|
||||
viewUtil.showShortToast(context, context.getString((R.string.delete_helper_make_deletion_toast), media.getDisplayTitle()));
|
||||
return Single.fromCallable(() -> delete(media, reason))
|
||||
.flatMap(result -> Single.fromCallable(() ->
|
||||
showDeletionNotification(context, media, result)));
|
||||
|
|
@ -123,14 +123,14 @@ public class DeleteHelper {
|
|||
|
||||
private boolean showDeletionNotification(Context context, Media media, boolean result) {
|
||||
String message;
|
||||
String title = "Nominating for Deletion";
|
||||
String title = context.getString(R.string.delete_helper_show_deletion_title);
|
||||
|
||||
if (result) {
|
||||
title += ": Success";
|
||||
message = "Successfully nominated " + media.getDisplayTitle() + " deletion.";
|
||||
title += ": " + context.getString(R.string.delete_helper_show_deletion_title_success);
|
||||
message = context.getString((R.string.delete_helper_show_deletion_message_if),media.getDisplayTitle());
|
||||
} else {
|
||||
title += ": Failed";
|
||||
message = "Could not request deletion.";
|
||||
title += ": " + context.getString(R.string.delete_helper_show_deletion_title_failed);
|
||||
message = context.getString(R.string.delete_helper_show_deletion_message_else) ;
|
||||
}
|
||||
|
||||
String urlForDelete = BuildConfig.COMMONS_URL + "/wiki/Commons:Deletion_requests/" + media.getFilename();
|
||||
|
|
@ -162,15 +162,15 @@ public class DeleteHelper {
|
|||
|
||||
|
||||
if (problem == ReviewController.DeleteReason.SPAM) {
|
||||
reasonList[0] = context.getResources().getString(R.string.delete_reason_spam_selfie);
|
||||
reasonList[1] = context.getResources().getString(R.string.delete_reason_spam_blurry);
|
||||
reasonList[2] = context.getResources().getString(R.string.delete_reason_spam_nonsense);
|
||||
reasonList[3] = context.getResources().getString(R.string.delete_reason_spam_other);
|
||||
reasonList[0] = context.getString(R.string.delete_helper_ask_spam_selfie);
|
||||
reasonList[1] = context.getString(R.string.delete_helper_ask_spam_blurry);
|
||||
reasonList[2] = context.getString(R.string.delete_helper_ask_spam_nonsense);
|
||||
reasonList[3] = context.getString(R.string.delete_helper_ask_spam_other);
|
||||
} else if (problem == ReviewController.DeleteReason.COPYRIGHT_VIOLATION) {
|
||||
reasonList[0] = context.getResources().getString(R.string.delete_reason_copyright_pressphoto);
|
||||
reasonList[1] = context.getResources().getString(R.string.delete_reason_copyright_internetphoto);
|
||||
reasonList[2] = context.getResources().getString(R.string.delete_reason_copyright_logo);
|
||||
reasonList[3] = context.getResources().getString(R.string.delete_reason_copyright_other);
|
||||
reasonList[0] = context.getString(R.string.delete_helper_ask_reason_copyright_press_photo);
|
||||
reasonList[1] = context.getString(R.string.delete_helper_ask_reason_copyright_internet_photo);
|
||||
reasonList[2] = context.getString(R.string.delete_helper_ask_reason_copyright_logo);
|
||||
reasonList[3] = context.getString(R.string.delete_helper_ask_reason_copyright_other);
|
||||
}
|
||||
|
||||
alert.setMultiChoiceItems(reasonList, checkedItems, (dialogInterface, position, isChecked) -> {
|
||||
|
|
@ -181,9 +181,9 @@ public class DeleteHelper {
|
|||
}
|
||||
});
|
||||
|
||||
alert.setPositiveButton("OK", (dialogInterface, i) -> {
|
||||
alert.setPositiveButton(context.getString(R.string.ok), (dialogInterface, i) -> {
|
||||
|
||||
String reason = "Because it is ";
|
||||
String reason = context.getString(R.string.delete_helper_ask_alert_set_positive_button_reason) + " ";
|
||||
for (int j = 0; j < mUserReason.size(); j++) {
|
||||
reason = reason + reasonList[mUserReason.get(j)];
|
||||
if (j != mUserReason.size() - 1) {
|
||||
|
|
@ -203,7 +203,7 @@ public class DeleteHelper {
|
|||
});
|
||||
|
||||
});
|
||||
alert.setNegativeButton("Cancel", (dialog, which) -> reviewCallback.onFailure());
|
||||
alert.setNegativeButton(context.getString(R.string.cancel), (dialog, which) -> reviewCallback.onFailure());
|
||||
AlertDialog d = alert.create();
|
||||
d.show();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.di;
|
||||
|
||||
import fr.free.nrw.commons.contributions.ContributionsModule;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
|
|
@ -28,7 +29,7 @@ import fr.free.nrw.commons.widget.PicOfDayAppWidget;
|
|||
ActivityBuilderModule.class,
|
||||
FragmentBuilderModule.class,
|
||||
ServiceBuilderModule.class,
|
||||
ContentProviderBuilderModule.class, UploadModule.class
|
||||
ContentProviderBuilderModule.class, UploadModule.class, ContributionsModule.class
|
||||
})
|
||||
public interface CommonsApplicationComponent extends AndroidInjector<ApplicationlessInjection> {
|
||||
void inject(CommonsApplication application);
|
||||
|
|
|
|||
|
|
@ -143,14 +143,6 @@ public class SearchActivity extends NavigationBaseActivity implements MediaDetai
|
|||
return searchImageFragment.getTotalImagesCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void notifyDatasetChanged() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called on success of API call for image Search.
|
||||
* The viewpager will notified that number of items have changed.
|
||||
|
|
@ -161,24 +153,6 @@ public class SearchActivity extends NavigationBaseActivity implements MediaDetai
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Open media detail pager fragment on click of image in search results
|
||||
* @param index item index that should be opened
|
||||
|
|
|
|||
|
|
@ -141,14 +141,6 @@ public class ExploreActivity
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void notifyDatasetChanged() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called on success of API call for featured images or mobile uploads.
|
||||
* The viewpager will notified that number of items have changed.
|
||||
|
|
@ -159,23 +151,6 @@ public class ExploreActivity
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is never called but it was in MediaDetailProvider Interface
|
||||
* so it needs to be overrided.
|
||||
*/
|
||||
@Override
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called on backPressed of anyFragment in the activity.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package fr.free.nrw.commons.media;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
|
|
@ -21,25 +24,13 @@ import android.widget.ScrollView;
|
|||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.util.DateUtil;
|
||||
import org.wikipedia.util.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.R;
|
||||
|
|
@ -57,11 +48,15 @@ import io.reactivex.Single;
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import javax.inject.Inject;
|
||||
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;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
||||
|
||||
private boolean editable;
|
||||
|
|
@ -134,7 +129,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
private boolean categoriesPresent = false;
|
||||
private ViewTreeObserver.OnGlobalLayoutListener layoutListener; // for layout stuff, only used once!
|
||||
private ViewTreeObserver.OnScrollChangedListener scrollListener;
|
||||
private DataSetObserver dataObserver;
|
||||
|
||||
//Had to make this class variable, to implement various onClicks, which access the media, also I fell why make separate variables when one can serve the purpose
|
||||
private Media media;
|
||||
|
|
@ -232,34 +226,15 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if(getParentFragment()!=null && getParentFragment().getParentFragment()!=null) {
|
||||
if (getParentFragment() != null && getParentFragment().getParentFragment() != null) {
|
||||
//Added a check because, not necessarily, the parent fragment will have a parent fragment, say
|
||||
// in the case when MediaDetailPagerFragment is directly started by the CategoryImagesActivity
|
||||
((ContributionsFragment) (getParentFragment().getParentFragment())).nearbyNotificationCardView
|
||||
.setVisibility(View.GONE);
|
||||
((ContributionsFragment) (getParentFragment()
|
||||
.getParentFragment())).nearbyNotificationCardView
|
||||
.setVisibility(View.GONE);
|
||||
}
|
||||
media = detailProvider.getMediaAtPosition(index);
|
||||
if (media == null) {
|
||||
// Ask the detail provider to ping us when we're ready
|
||||
Timber.d("MediaDetailFragment not yet ready to display details; registering observer");
|
||||
dataObserver = new DataSetObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
if (!isAdded()) {
|
||||
return;
|
||||
}
|
||||
Timber.d("MediaDetailFragment ready to display delayed details!");
|
||||
detailProvider.unregisterDataSetObserver(dataObserver);
|
||||
dataObserver = null;
|
||||
media=detailProvider.getMediaAtPosition(index);
|
||||
displayMediaDetails();
|
||||
}
|
||||
};
|
||||
detailProvider.registerDataSetObserver(dataObserver);
|
||||
} else {
|
||||
Timber.d("MediaDetailFragment ready to display details");
|
||||
displayMediaDetails();
|
||||
}
|
||||
displayMediaDetails();
|
||||
}
|
||||
|
||||
private void displayMediaDetails() {
|
||||
|
|
@ -300,10 +275,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment {
|
|||
getView().getViewTreeObserver().removeOnScrollChangedListener(scrollListener);
|
||||
scrollListener = null;
|
||||
}
|
||||
if (dataObserver != null) {
|
||||
detailProvider.unregisterDataSetObserver(dataObserver);
|
||||
dataObserver = null;
|
||||
}
|
||||
|
||||
compositeDisposable.clear();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
package fr.free.nrw.commons.media;
|
||||
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
import static fr.free.nrw.commons.Utils.handleWebUrl;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.Intent;
|
||||
import android.database.DataSetObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
|
|
@ -15,11 +18,6 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
|
|
@ -44,12 +42,10 @@ import fr.free.nrw.commons.utils.ImageUtils;
|
|||
import fr.free.nrw.commons.utils.NetworkUtils;
|
||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
import static fr.free.nrw.commons.Utils.handleWebUrl;
|
||||
|
||||
public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment implements ViewPager.OnPageChangeListener {
|
||||
|
||||
@Inject MediaWikiApi mwApi;
|
||||
|
|
@ -351,16 +347,16 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
|
|||
public void onPageScrollStateChanged(int i) {
|
||||
}
|
||||
|
||||
public void onDataSetChanged() {
|
||||
if (null != adapter) {
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public interface MediaDetailProvider {
|
||||
Media getMediaAtPosition(int i);
|
||||
|
||||
int getTotalMediaCount();
|
||||
|
||||
void notifyDatasetChanged();
|
||||
|
||||
void registerDataSetObserver(DataSetObserver observer);
|
||||
|
||||
void unregisterDataSetObserver(DataSetObserver observer);
|
||||
}
|
||||
|
||||
//FragmentStatePagerAdapter allows user to swipe across collection of images (no. of images undetermined)
|
||||
|
|
|
|||
|
|
@ -1,28 +1,10 @@
|
|||
package fr.free.nrw.commons.mwapi;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.achievements.FeaturedImages;
|
||||
import fr.free.nrw.commons.achievements.FeedbackResponse;
|
||||
|
|
@ -38,10 +20,23 @@ import fr.free.nrw.commons.utils.ConfigUtils;
|
|||
import fr.free.nrw.commons.wikidata.model.GetWikidataEditCountResponse;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
|
|
@ -98,8 +93,16 @@ public class OkHttpJsonApiClient {
|
|||
return Single.fromCallable(() -> {
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
if (response != null && response.isSuccessful()) {
|
||||
if(!TextUtils.isEmpty(response.body().string().trim())){
|
||||
return Integer.parseInt(response.body().string().trim());
|
||||
ResponseBody responseBody = response.body();
|
||||
if (null != responseBody) {
|
||||
String responseBodyString = responseBody.string().trim();
|
||||
if (!TextUtils.isEmpty(responseBodyString)) {
|
||||
try {
|
||||
return Integer.parseInt(responseBodyString);
|
||||
} catch (NumberFormatException e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.content.ContentResolver;
|
|||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
|
@ -15,8 +15,6 @@ import java.io.InputStreamReader;
|
|||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class FileUtils {
|
||||
|
|
@ -164,4 +162,17 @@ public class FileUtils {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if file exists in local dirs
|
||||
*/
|
||||
public static boolean fileExists(Uri localUri) {
|
||||
try {
|
||||
File file = new File(localUri.getPath());
|
||||
return file.exists();
|
||||
} catch (Exception e) {
|
||||
Timber.d(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,21 +20,16 @@
|
|||
/>
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:id="@+id/loadingContributionsProgressBar"
|
||||
/>
|
||||
<GridView
|
||||
android:id="@+id/loadingContributionsProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/contributionsList"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:stretchMode="columnWidth"
|
||||
android:columnWidth="240dp"
|
||||
android:numColumns="auto_fit"
|
||||
android:listSelector="@null"
|
||||
android:fadingEdge="none"
|
||||
android:fastScrollEnabled="true"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
|
|
|
|||
|
|
@ -537,4 +537,19 @@
|
|||
<string name="dialog_box_text_nomination">لماذا يجب حذف %1$s؟</string>
|
||||
<string name="review_is_uploaded_by">%1$s رُفِع بواسطة: %2$s</string>
|
||||
<string name="default_description_language">لغة الوصف الافتراضية</string>
|
||||
<string name="delete_helper_make_deletion_toast">تجري محاولة ترشيح %1$s للحذف</string>
|
||||
<string name="delete_helper_show_deletion_title">ترشيح للحذف</string>
|
||||
<string name="delete_helper_show_deletion_title_success">نجاح</string>
|
||||
<string name="delete_helper_show_deletion_message_if">تم بنجاح ترشيح %1$s للحذف.</string>
|
||||
<string name="delete_helper_show_deletion_title_failed">فشل</string>
|
||||
<string name="delete_helper_show_deletion_message_else">لا يمكن طلب الحذف.</string>
|
||||
<string name="delete_helper_ask_spam_selfie">سيلفي</string>
|
||||
<string name="delete_helper_ask_spam_blurry">ضبابية</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">كلام فارغ</string>
|
||||
<string name="delete_helper_ask_spam_other">أخرى</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">اضغط على الصورة</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">صورة عشوائية من الإنترنت</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">شعار</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">أخرى</string>
|
||||
<string name="delete_helper_ask_alert_set_positive_button_reason">لأنها</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -370,9 +370,16 @@
|
|||
<string name="menu_option_unread">Vis ulæste</string>
|
||||
<string name="error_occurred_in_picking_images">Der opstod en fejl under udvælgelse af billeder</string>
|
||||
<string name="please_wait">Vent venligst…</string>
|
||||
<string name="skip_image" fuzzy="true">Spring over dette billede</string>
|
||||
<string name="skip_image">Spring over dette billede</string>
|
||||
<string name="exif_tag_name_copyright">Ophavsret</string>
|
||||
<string name="exif_tag_name_cameraModel">Kameramodel</string>
|
||||
<string name="exif_tag_name_serialNumbers">Serienumre</string>
|
||||
<string name="share_via">Del app via...</string>
|
||||
<string name="no_categories_found">Ingen kategorier blev fundet</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Et selvportræt</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Sløret</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Vrøvl</string>
|
||||
<string name="delete_helper_ask_spam_other">Andet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Vilkårligt billede fra internettet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Andet</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
* ManosHacker
|
||||
* Nikosgranturismogt
|
||||
* Nikosguard
|
||||
* Panos78
|
||||
* Protnet
|
||||
* Tgkarounos
|
||||
-->
|
||||
|
|
@ -268,17 +269,17 @@
|
|||
<string name="nearby_location_has_not_changed">Ο εντοπισμός δεν έχει αλλάξει.</string>
|
||||
<string name="nearby_location_not_available">Ο τόπος δεν είναι διαθέσιμος.</string>
|
||||
<string name="location_permission_rationale_nearby">Απαιτείται άδεια για την εμφάνιση λίστας κοντινών σημείων</string>
|
||||
<string name="get_directions" fuzzy="true">Λάβετε κατευθύνσεις</string>
|
||||
<string name="read_article" fuzzy="true">Ανάγνωση άρθρου</string>
|
||||
<string name="get_directions">Λήψη κατευθύνσεων</string>
|
||||
<string name="read_article">Ανάγνωση άρθρου</string>
|
||||
<string name="notifications_welcome">Καλωσήρθατε στο Wikimedia Commons, %1$s! Είμαστε χαρούμενοι που είστε εδώ.</string>
|
||||
<string name="notifications_talk_page_message">Ο %1$s άφησε ένα μήνυμα στην σελίδα συζήτησής σας</string>
|
||||
<string name="notifications_thank_you_edit">Ευχαριστούμε που κάνατε μια επεξεργασία</string>
|
||||
<string name="notifications_mention">Ο %1$s σας ανέφερε στο %2$s.</string>
|
||||
<string name="toggle_view_button">Μεταβολή προβολής</string>
|
||||
<string name="nearby_directions" fuzzy="true">Κατευθύνσεις</string>
|
||||
<string name="nearby_wikidata" fuzzy="true">Βικιδεδομένα</string>
|
||||
<string name="nearby_wikipedia" fuzzy="true">Βικιπαίδεια</string>
|
||||
<string name="nearby_commons" fuzzy="true">Κοινά</string>
|
||||
<string name="nearby_directions">Κατευθύνσεις</string>
|
||||
<string name="nearby_wikidata">Δεδομένα wiki</string>
|
||||
<string name="nearby_wikipedia">Βικιπαίδεια</string>
|
||||
<string name="nearby_commons">Κοινά</string>
|
||||
<string name="about_rate_us"><u>Βαθμολογήστε μας</u></string>
|
||||
<string name="about_faq"><u>Συχνές ερωτήσεις</u></string>
|
||||
<string name="welcome_skip_button">Παράβλεψη εισαγωγής</string>
|
||||
|
|
@ -310,8 +311,8 @@
|
|||
<string name="provider_searches">Πρόσφατα αναζητημένα ερωτήματα</string>
|
||||
<string name="error_loading_categories">Συνέβη σφάλμα κατά τη φόρτωση κατηγοριών.</string>
|
||||
<string name="error_loading_subcategories">Συνέβη σφάλμα κατά τη φόρτωση υποκατηγοριών.</string>
|
||||
<string name="search_tab_title_media" fuzzy="true">Μέσα ενημέρωσης</string>
|
||||
<string name="search_tab_title_categories" fuzzy="true">Κατηγορίες</string>
|
||||
<string name="search_tab_title_media">Μέσα</string>
|
||||
<string name="search_tab_title_categories">Κατηγορίες</string>
|
||||
<string name="successful_wikidata_edit">Η εικόνα προστέθηκε επιτυχώς στο %1$s στο Wikidata!</string>
|
||||
<string name="wikidata_edit_failure">Αποτυχία ενημέρωσης της αντιστοιχούσας οντότητας του Wikidata!</string>
|
||||
<string name="menu_set_wallpaper">Ρύθμιση ως ταπετσαρία</string>
|
||||
|
|
@ -344,10 +345,10 @@
|
|||
<string name="search_history_deleted">Το ιστορικό αναζήτησης διεγράφη</string>
|
||||
<string name="nominate_delete">Ορίστε για Αφαίρεση</string>
|
||||
<string name="Achievements">Κατορθώματα</string>
|
||||
<string name="statistics" fuzzy="true">Στατιστικά</string>
|
||||
<string name="statistics">Στατιστικά</string>
|
||||
<string name="statistics_thanks">Ευχαριστίες που έχουν ληφθεί</string>
|
||||
<string name="statistics_featured">Προβεβλημμένες εικόνες</string>
|
||||
<string name="level" fuzzy="true">Επίπεδο</string>
|
||||
<string name="level">Επίπεδο</string>
|
||||
<string name="images_uploaded">Εικόνες που ανέβηκαν</string>
|
||||
<string name="image_reverts">Εικόνες που δεν ανεστράφησαν</string>
|
||||
<string name="images_used_by_wiki">Εικόνες που χρησιμοποιήθηκαν</string>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Authors:
|
||||
* Abijeet Patro
|
||||
* Metraduk
|
||||
* Mirin
|
||||
* Robin van der Vliet
|
||||
|
|
@ -529,4 +530,12 @@
|
|||
<string name="dialog_box_text_nomination">Kial %1$s foriĝu?</string>
|
||||
<string name="review_is_uploaded_by">%1$s estas alŝutita de: %2$s</string>
|
||||
<string name="default_description_language">Implicita priskriba lingvo</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Memfoto</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Malklara</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Sensencaĵo</string>
|
||||
<string name="delete_helper_ask_spam_other">Alia</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Gazetara foo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Hazarda foto el Interreto</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Emblemo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Alia</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
* Mirzali
|
||||
* Tiberius1701
|
||||
* Vivaelcelta
|
||||
* Wizardeck
|
||||
-->
|
||||
<resources>
|
||||
<string name="title_activity_explore">Explorar</string>
|
||||
|
|
@ -188,6 +189,7 @@
|
|||
<string name="storage_permission_title">Pidiendo permiso de almacenamiento</string>
|
||||
<string name="read_storage_permission_rationale">Permiso necesario: lectura de almacenamiento externo. La aplicación no puede acceder a la galería sin él.</string>
|
||||
<string name="write_storage_permission_rationale">Permiso necesario: escritura en almacenamiento externo. La aplicación no puede acceder a la cámara o la galería sin este.</string>
|
||||
<string name="location_permission_title">Pidiendo Permiso de Ubicación</string>
|
||||
<string name="location_permission_rationale">Permiso opcional: obtener la ubicación actual para sugerir categorías</string>
|
||||
<string name="ok">Aceptar</string>
|
||||
<string name="title_activity_nearby">Lugares cercanos</string>
|
||||
|
|
@ -528,6 +530,7 @@
|
|||
<string name="skip_image">Omitir esta imagen</string>
|
||||
<string name="download_failed_we_cannot_download_the_file_without_storage_permission">La descarga falló!. No podemos descargar el archivo sin el permiso de almacenamiento externo.</string>
|
||||
<string name="manage_exif_tags">Gestionar etiquetas EXIF</string>
|
||||
<string name="manage_exif_tags_summary">Seleccionar qué etiquetas EXIF se mantendrán en la subida</string>
|
||||
<string name="exif_tag_name_author">Autor</string>
|
||||
<string name="exif_tag_name_copyright">Derechos de autor</string>
|
||||
<string name="exif_tag_name_location">Ubicación</string>
|
||||
|
|
@ -535,9 +538,21 @@
|
|||
<string name="exif_tag_name_lensModel">Modelo de lente</string>
|
||||
<string name="exif_tag_name_serialNumbers">Números de serie</string>
|
||||
<string name="exif_tag_name_software">Programa</string>
|
||||
<string name="share_text">Sube fotos a Wikimedia Commons desde tu celular, descarga la aplicación de Commons: %1$s</string>
|
||||
<string name="share_via">Compartir la aplicación vía...</string>
|
||||
<string name="image_info">Información de la imagen</string>
|
||||
<string name="no_categories_found">No se encontró ninguna categoría</string>
|
||||
<string name="upload_cancelled">Se canceló la carga</string>
|
||||
<string name="previous_image_title_description_not_found">No hay datos sobre el título o la descripción anteriores de la imagen</string>
|
||||
<string name="dialog_box_text_nomination">¿Por qué debe borrarse %1$s?</string>
|
||||
<string name="review_is_uploaded_by">%1$s fue subida por: %2$s</string>
|
||||
<string name="default_description_language">Idioma por defecto de la descripción</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Un autorretrato</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Borrosa</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Sinsentido</string>
|
||||
<string name="delete_helper_ask_spam_other">Otra</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Fotografía para prensa</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Foto cualquiera tomada de internet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Otra</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
<!-- Authors:
|
||||
* Abijeet Patro
|
||||
* Cyclicus
|
||||
* Derugon
|
||||
* Fitoschido
|
||||
* Friday83260
|
||||
* Gomoko
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
* Tpt
|
||||
* Urhixidur
|
||||
* VIGNERON
|
||||
* Verdy p
|
||||
* Wladek92
|
||||
* Y-M D
|
||||
-->
|
||||
|
|
@ -545,6 +547,16 @@
|
|||
<string name="upload_cancelled">Téléversement annulé</string>
|
||||
<string name="previous_image_title_description_not_found">Il n’y a pas de données pour le titre ou la description de l’image précédente</string>
|
||||
<string name="dialog_box_text_nomination">Pourquoi %1$s devrait-il être supprimé ?</string>
|
||||
<string name="review_is_uploaded_by">%1$s est téléversé par : %2$s</string>
|
||||
<string name="review_is_uploaded_by">%1$s est téléversé par&nbsp;: %2$s</string>
|
||||
<string name="default_description_language">Langue de description par défaut</string>
|
||||
<string name="delete_helper_make_deletion_toast">Tentative de signalement de %1$s pour la suppression</string>
|
||||
<string name="delete_helper_show_deletion_title_failed">Échec</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Un selfie</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Flou</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Non-sens</string>
|
||||
<string name="delete_helper_ask_spam_other">Autre</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Photo de presse</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Photo aléatoire sur internet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Autre</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -481,4 +481,7 @@
|
|||
<string name="dialog_box_text_nomination">Perché %1$s dovrebbe essere cancellato?</string>
|
||||
<string name="review_is_uploaded_by">%1$s è stato caricato da: %2$s</string>
|
||||
<string name="default_description_language">Lingua predefinita descrizione</string>
|
||||
<string name="delete_helper_ask_spam_other">Altro</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Altro</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Authors:
|
||||
* Abijeet Patro
|
||||
* CYAN
|
||||
* Dlsrks1021
|
||||
* Doyoon1995
|
||||
|
|
@ -468,4 +469,9 @@
|
|||
<string name="no_categories_found">분류가 없습니다</string>
|
||||
<string name="upload_cancelled">업로드 취소됨</string>
|
||||
<string name="default_description_language">기본 설명 언어</string>
|
||||
<string name="delete_helper_ask_spam_selfie">셀카</string>
|
||||
<string name="delete_helper_ask_spam_other">기타</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">인터넷의 임의 사진</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">로고</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">기타</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -241,9 +241,9 @@
|
|||
<string name="notifications_thank_you_edit">Merci datt Dir eng Ännerung gemaach hutt</string>
|
||||
<string name="notifications_mention">%1$s huet Iech op %2$s ernimmt.</string>
|
||||
<string name="nearby_directions" fuzzy="true">RICHTUNGEN</string>
|
||||
<string name="nearby_wikidata" fuzzy="true">WIKIDATA</string>
|
||||
<string name="nearby_wikipedia" fuzzy="true">WIKIPEDIA</string>
|
||||
<string name="nearby_commons" fuzzy="true">COMMONS</string>
|
||||
<string name="nearby_wikidata">Wikidata</string>
|
||||
<string name="nearby_wikipedia">Wikipedia</string>
|
||||
<string name="nearby_commons">Commons</string>
|
||||
<string name="about_rate_us"><u>Bewäert eis</u></string>
|
||||
<string name="about_faq"><u>FAQ</u></string>
|
||||
<string name="no_internet">Internet net disponibel</string>
|
||||
|
|
@ -267,7 +267,7 @@
|
|||
<string name="search_commons">Op Commons sichen</string>
|
||||
<string name="title_activity_search">Sichen</string>
|
||||
<string name="search_tab_title_media" fuzzy="true">MEDIEN</string>
|
||||
<string name="search_tab_title_categories" fuzzy="true">KATEGORIEN</string>
|
||||
<string name="search_tab_title_categories">Kategorien</string>
|
||||
<string name="explore_tab_title_mobile" fuzzy="true">MOBIL EROPGELUEDEN</string>
|
||||
<string name="wikidata_edit_failure">Déi entspriechend Wikidata-Entitéit konnt net aktualiséiert ginn!</string>
|
||||
<string name="menu_set_wallpaper">Als Hannergrondbild festleeën</string>
|
||||
|
|
@ -280,9 +280,9 @@
|
|||
<string name="wrong">Falsch Äntwert</string>
|
||||
<string name="add_description">+ Beschreiwung derbäisetzen</string>
|
||||
<string name="nominate_delete">Nominéiere fir ze Läschen</string>
|
||||
<string name="delete" fuzzy="true">LÄSCHEN</string>
|
||||
<string name="delete">Läschen</string>
|
||||
<string name="Achievements">Realisatiounen</string>
|
||||
<string name="statistics" fuzzy="true">STATISTIKEN</string>
|
||||
<string name="statistics">Statistiken</string>
|
||||
<string name="statistics_thanks">Merci\'e kritt</string>
|
||||
<string name="statistics_featured">Bemierkenswäert Biller</string>
|
||||
<string name="level" fuzzy="true">NIVEAU</string>
|
||||
|
|
@ -345,4 +345,5 @@
|
|||
<string name="exif_tag_name_software">Software</string>
|
||||
<string name="no_categories_found">Keng Kategorie fonnt.</string>
|
||||
<string name="upload_cancelled">Eroplueden ofgebrach</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logo</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Authors:
|
||||
* Abijeet Patro
|
||||
* Admresdeserv.
|
||||
* Papuass
|
||||
* Silraks
|
||||
|
|
@ -48,7 +49,7 @@
|
|||
<string name="title_activity_settings">Iestatījumi</string>
|
||||
<string name="title_activity_signup">Reģistrēties</string>
|
||||
<string name="menu_about">Par</string>
|
||||
<string name="about_improve" fuzzy="true"><a href=\"https://github.com/commons-app/apps-android-commons\">Izejas kods</a> un <a href=\"https://commons-app.github.io/\">tīmekļa vietne</a> GitHub. Izveido jaunu <a href=\"https://github.com/commons-app/apps-android-commons/issues\">GitHub pieteikumu</a> kļūdas ziņojumam vai ieteikumam.</string>
|
||||
<string name="about_improve"><a href=\"https://github.com/commons-app/apps-android-commons\">Izejas kods</a> un <a href=\"https://commons-app.github.io/\">tīmekļa vietne</a> GitHub. Izveido jaunu <a href=\"%1$s\">GitHub pieteikumu</a> kļūdas ziņojumam vai ieteikumam.</string>
|
||||
<string name="about_privacy_policy" fuzzy="true"><a href=\"https://github.com/commons-app/apps-android-commons/wiki/Privacy-policy\">Privātuma politika</a></string>
|
||||
<string name="title_activity_about">Par</string>
|
||||
<string name="menu_feedback">Nosūtīt atsauksmes (pa e-pastu)</string>
|
||||
|
|
@ -105,15 +106,20 @@
|
|||
<string name="give_permission">Atļaut</string>
|
||||
<string name="use_external_storage">Izmantot ārējo krātuvi</string>
|
||||
<string name="skip_login">Izlaist</string>
|
||||
<string name="read_article">LASĪT RAKSTU</string>
|
||||
<string name="get_directions">Saņemt norādes</string>
|
||||
<string name="read_article">Lasīt rakstu</string>
|
||||
<string name="notifications_thank_you_edit">Paldies par labojumu</string>
|
||||
<string name="toggle_view_button">Pārslēgt skatu</string>
|
||||
<string name="nearby_directions">Norādes</string>
|
||||
<string name="about_translate_title">Valodas</string>
|
||||
<string name="about_translate_proceed">Turpināt</string>
|
||||
<string name="about_translate_cancel">Atcelt</string>
|
||||
<string name="showcase_view_got_it_button">Sapratu!</string>
|
||||
<string name="search_tab_title_categories">Kategorijas</string>
|
||||
<string name="question">Jautājums</string>
|
||||
<string name="add_description">+ Pievienot aprakstu</string>
|
||||
<string name="delete">Dzēst</string>
|
||||
<string name="statistics">Statistika</string>
|
||||
<string name="submit">Iesniegt</string>
|
||||
<string name="navigation_item_bookmarks">Grāmatzīmes</string>
|
||||
<string name="title_activity_bookmarks">Grāmatzīmes</string>
|
||||
|
|
@ -125,6 +131,23 @@
|
|||
<string name="yes_submit">Jā, iesniegt</string>
|
||||
<string name="nearby_card_permission_title">Atļaujas pieprasījums</string>
|
||||
<string name="never_ask_again">Nekad vairs šo nejautāt</string>
|
||||
<string name="nominate_for_deletion_done">Pabeigts</string>
|
||||
<string name="send_thank_send">Sūta pateicību</string>
|
||||
<string name="send_thank_notification_title">Sūta pateicību</string>
|
||||
<string name="menu_option_archived">Skatīt arhivētos</string>
|
||||
<string name="menu_option_unread">Skatīt nelasītos</string>
|
||||
<string name="skip_image">Izlaist šo attēlu</string>
|
||||
<string name="exif_tag_name_author">Autors</string>
|
||||
<string name="exif_tag_name_copyright">Autortiesības</string>
|
||||
<string name="exif_tag_name_location">Atrašanās vieta</string>
|
||||
<string name="exif_tag_name_cameraModel">Fotoaparāta modelis</string>
|
||||
<string name="exif_tag_name_lensModel">Objektīva modelis</string>
|
||||
<string name="exif_tag_name_serialNumbers">Sērijas numuri</string>
|
||||
<string name="exif_tag_name_software">Programmatūra</string>
|
||||
<string name="delete_helper_show_deletion_title_failed">Neizdevās</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Pašbilde</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Miglains</string>
|
||||
<string name="delete_helper_ask_spam_other">Cits</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Nejaušs foto no interneta</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logotips</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -527,4 +527,19 @@
|
|||
<string name="dialog_box_text_nomination">Зошто сметате дека %1$s треба да се избрише?</string>
|
||||
<string name="review_is_uploaded_by">%1$s е подигната од: %2$s</string>
|
||||
<string name="default_description_language">Стандарден јазик на описот</string>
|
||||
<string name="delete_helper_make_deletion_toast">Се обидувам да ја предложам %1$s за бришење</string>
|
||||
<string name="delete_helper_show_deletion_title">Предлагам за бришење</string>
|
||||
<string name="delete_helper_show_deletion_title_success">Успеа</string>
|
||||
<string name="delete_helper_show_deletion_message_if">Успешно предложена %1$s за бришење.</string>
|
||||
<string name="delete_helper_show_deletion_title_failed">Не успеа</string>
|
||||
<string name="delete_helper_show_deletion_message_else">Не можев да побарам бришење.</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Самослик</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Матно</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Бесмислено</string>
|
||||
<string name="delete_helper_ask_spam_other">Друго</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Новинарска слика</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Произволна слика од семрежјето</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Лого</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Друго</string>
|
||||
<string name="delete_helper_ask_alert_set_positive_button_reason">Бидејќи е</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -540,4 +540,12 @@
|
|||
<string name="dialog_box_text_nomination">Por que %1$s deve ser excluído?</string>
|
||||
<string name="review_is_uploaded_by">%1$s é carregado por: %2$s</string>
|
||||
<string name="default_description_language">Idioma de descrição padrão</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Uma selfie</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Embaçado</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Absurdo</string>
|
||||
<string name="delete_helper_ask_spam_other">Outro</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Divulgação</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Foto aleatória da internet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logótipo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Outro</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -287,14 +287,14 @@
|
|||
<string name="nearby_location_has_not_changed">A localização não foi alterada.</string>
|
||||
<string name="nearby_location_not_available">A localização não está disponível.</string>
|
||||
<string name="location_permission_rationale_nearby">É necessária a permissão para mostrar uma lista dos sítios aqui perto</string>
|
||||
<string name="get_directions" fuzzy="true">OBTER INDICAÇÕES</string>
|
||||
<string name="get_directions">Obter indicações</string>
|
||||
<string name="read_article">Ler artigo</string>
|
||||
<string name="notifications_welcome">Bem-vindo à wiki Wikimedia Commons, %1$s! É um prazer tê-lo aqui.</string>
|
||||
<string name="notifications_talk_page_message">%1$s deixou uma mensagem na sua página de discussão</string>
|
||||
<string name="notifications_thank_you_edit">Obrigado por ter realizado uma edição</string>
|
||||
<string name="notifications_mention">%1$s fez menção a si em %2$s.</string>
|
||||
<string name="toggle_view_button">Alternar modo de visionamento</string>
|
||||
<string name="nearby_directions" fuzzy="true">INDICAÇÕES</string>
|
||||
<string name="nearby_directions">Indicações</string>
|
||||
<string name="nearby_wikidata">Wikidata</string>
|
||||
<string name="nearby_wikipedia">Wikipédia</string>
|
||||
<string name="nearby_commons">Commons</string>
|
||||
|
|
@ -334,7 +334,7 @@
|
|||
<string name="search_tab_title_media">Multimédia</string>
|
||||
<string name="search_tab_title_categories">Categorias</string>
|
||||
<string name="explore_tab_title_featured">Destacadas</string>
|
||||
<string name="explore_tab_title_mobile" fuzzy="true">CARREGADA VIA TELEMÓVEL</string>
|
||||
<string name="explore_tab_title_mobile">Carregada via telemóvel</string>
|
||||
<string name="successful_wikidata_edit">Imagem adicionada a %1$s na wiki Wikidata!</string>
|
||||
<string name="wikidata_edit_failure">Falha ao atualizar a entidade Wikidata correspondente!</string>
|
||||
<string name="menu_set_wallpaper">Definir como imagem de fundo</string>
|
||||
|
|
@ -520,7 +520,7 @@
|
|||
<string name="previous_button_tooltip_message">Clique para reutilizar o título e a descrição que inseriu na sua fotografia anterior e adequá-los à atual</string>
|
||||
<string name="welcome_do_upload_content_description">Exemplos de imagens que podem ser carregadas na wiki Commons</string>
|
||||
<string name="welcome_dont_upload_content_description">Exemplos de imagens que não devem ser carregadas</string>
|
||||
<string name="skip_image" fuzzy="true">SALTAR ESTA IMAGEM</string>
|
||||
<string name="skip_image">Saltar esta imagem</string>
|
||||
<string name="download_failed_we_cannot_download_the_file_without_storage_permission">O descarregamento falhou! Não podemos descarregar o ficheiro sem permissão de armazenagem externa.</string>
|
||||
<string name="manage_exif_tags">Gerir etiquetas EXIF</string>
|
||||
<string name="manage_exif_tags_summary">Selecionar as etiquetas EXIF a manter nos carregamentos</string>
|
||||
|
|
@ -538,5 +538,14 @@
|
|||
<string name="upload_cancelled">Carregamento cancelado</string>
|
||||
<string name="previous_image_title_description_not_found">Não há dados para o título ou descrição da imagem anterior</string>
|
||||
<string name="dialog_box_text_nomination">Porque deve %1$s ser eliminado?</string>
|
||||
<string name="review_is_uploaded_by">%1$s é carregada por: %2$s</string>
|
||||
<string name="default_description_language">Língua de descrição padrão</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Um autorretrato</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Desfocada</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Sem sentido</string>
|
||||
<string name="delete_helper_ask_spam_other">Outro</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Fotografia de imprensa</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Fotografia aleatória da Internet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logótipo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Outro</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -547,4 +547,12 @@
|
|||
<string name="dialog_box_text_nomination">Почему %1$s должно быть удалено?</string>
|
||||
<string name="review_is_uploaded_by">%1$s загружено с помощью: %2$s</string>
|
||||
<string name="default_description_language">Язык описаний по умолчанию</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Селфи</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Размыто</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Бессмыслица</string>
|
||||
<string name="delete_helper_ask_spam_other">Другое</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Новостное фото</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Случайное фото из интернет</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Логотип</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Другое</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -532,4 +532,12 @@
|
|||
<string name="dialog_box_text_nomination">Varför bör %1$s raderas?</string>
|
||||
<string name="review_is_uploaded_by">%1$s laddas upp av: %2$s</string>
|
||||
<string name="default_description_language">Standardspråk för beskrivning</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Ett självporträtt</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Suddig</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Strunt</string>
|
||||
<string name="delete_helper_ask_spam_other">Annat</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Pressfoto</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Slumpbild från Internet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logotyp</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Annat</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
* Sayginer
|
||||
* Sucsuzz
|
||||
* TmY e12
|
||||
* ToprakM
|
||||
* Trockya
|
||||
* VikipediBilgini
|
||||
-->
|
||||
|
|
|
|||
|
|
@ -291,17 +291,17 @@
|
|||
<string name="nearby_location_has_not_changed">Розташування не змінено</string>
|
||||
<string name="nearby_location_not_available">Місцезнаходження недоступне</string>
|
||||
<string name="location_permission_rationale_nearby">Потрібний дозвіл для показу списку місць поблизу</string>
|
||||
<string name="get_directions" fuzzy="true">Показати на мапі у зовнішній програмі</string>
|
||||
<string name="read_article" fuzzy="true">ЧИТАТИ СТАТТЮ</string>
|
||||
<string name="get_directions">Показати на мапі у зовнішній програмі</string>
|
||||
<string name="read_article">Читати статтю</string>
|
||||
<string name="notifications_welcome">Вітаємо у Вікісховищі, %1$s! Раді вас бачити.</string>
|
||||
<string name="notifications_talk_page_message">%1$s залишив повідомлення на вашій сторінці обговорення</string>
|
||||
<string name="notifications_thank_you_edit">Дякуємо за редагування</string>
|
||||
<string name="notifications_mention">%1$s згадав вас на %2$s.</string>
|
||||
<string name="toggle_view_button">Перемкнути режим перегляду</string>
|
||||
<string name="nearby_directions" fuzzy="true">НАПРЯМКИ</string>
|
||||
<string name="nearby_wikidata" fuzzy="true">ВІКІДАНІ</string>
|
||||
<string name="nearby_wikipedia" fuzzy="true">ВІКІПЕДІЯ</string>
|
||||
<string name="nearby_commons" fuzzy="true">ВІКІСХОВИЩЕ</string>
|
||||
<string name="nearby_directions">Напрямки</string>
|
||||
<string name="nearby_wikidata">Вікідані</string>
|
||||
<string name="nearby_wikipedia">Вікіпедія</string>
|
||||
<string name="nearby_commons">Вікісховище</string>
|
||||
<string name="about_rate_us"><u>Оцініть нас</u></string>
|
||||
<string name="about_faq">Часті запитання</string>
|
||||
<string name="welcome_skip_button">Пропустити інструкцію</string>
|
||||
|
|
@ -335,10 +335,10 @@
|
|||
<string name="provider_searches">Недавні запити пошуку</string>
|
||||
<string name="error_loading_categories">Сталася помилка під час завантаження категорій.</string>
|
||||
<string name="error_loading_subcategories">Сталася помилка під час завантаження підкатегорій.</string>
|
||||
<string name="search_tab_title_media" fuzzy="true">МЕДІАФАЙЛИ</string>
|
||||
<string name="search_tab_title_categories" fuzzy="true">КАТЕГОРІЇ</string>
|
||||
<string name="explore_tab_title_featured" fuzzy="true">ОБРАНЕ</string>
|
||||
<string name="explore_tab_title_mobile" fuzzy="true">ЗАВАНТАЖЕННЯ З МОБІЛЬНОГО</string>
|
||||
<string name="search_tab_title_media">Медіафайли</string>
|
||||
<string name="search_tab_title_categories">Категорії</string>
|
||||
<string name="explore_tab_title_featured">Обране</string>
|
||||
<string name="explore_tab_title_mobile">Завантаження з мобільного</string>
|
||||
<string name="successful_wikidata_edit">Зображення успішно додано до сторінки %1$s у Вікіданих!</string>
|
||||
<string name="wikidata_edit_failure">Не вдалось оновити відповідну сторінку Вікіданих!</string>
|
||||
<string name="menu_set_wallpaper">Поставити шпалерами екрану</string>
|
||||
|
|
@ -372,13 +372,13 @@
|
|||
<string name="delete_search_dialog">Вилучити цей пошук?</string>
|
||||
<string name="search_history_deleted">Історія пошуку очищена</string>
|
||||
<string name="nominate_delete">Номінувати на вилучення</string>
|
||||
<string name="delete" fuzzy="true">ВИЛУЧИТИ</string>
|
||||
<string name="delete">Вилучити</string>
|
||||
<string name="Achievements">Досягнення</string>
|
||||
<string name="statistics" fuzzy="true">СТАТИСТИКА</string>
|
||||
<string name="statistics">Статистика</string>
|
||||
<string name="statistics_thanks">Отримані подяки</string>
|
||||
<string name="statistics_featured">Вибрані зображення</string>
|
||||
<string name="statistics_wikidata_edits">Зображення місць поблизу</string>
|
||||
<string name="level" fuzzy="true">РІВЕНЬ</string>
|
||||
<string name="level">Рівень</string>
|
||||
<string name="images_uploaded">Завантажені зображення</string>
|
||||
<string name="image_reverts">Не відхилені зображення</string>
|
||||
<string name="images_used_by_wiki">Використані зображення</string>
|
||||
|
|
@ -526,7 +526,7 @@
|
|||
<string name="previous_button_tooltip_message">Натисніть, щоб використати назву та опис, які ви вводили для свого попереднього зображення, і змінити їх під поточне</string>
|
||||
<string name="welcome_do_upload_content_description">Приклади добрих зображень для завантаження у Вікісховище</string>
|
||||
<string name="welcome_dont_upload_content_description">Приклади зображень, які не слід завантажувати</string>
|
||||
<string name="skip_image" fuzzy="true">ПРОПУСТИТИ ЦЕ ЗОБРАЖЕННЯ</string>
|
||||
<string name="skip_image">Пропустити це зображення</string>
|
||||
<string name="download_failed_we_cannot_download_the_file_without_storage_permission">Завантаження не вдалося. Ми не змогли завантажити файл без доступу до зовнішнього носія.</string>
|
||||
<string name="manage_exif_tags">Робота з EXIF-тегами</string>
|
||||
<string name="manage_exif_tags_summary">Вкажіть, які EXIF-теги мають бути збережені при завантаженні файлів</string>
|
||||
|
|
@ -544,5 +544,14 @@
|
|||
<string name="upload_cancelled">Завантаження скасовано</string>
|
||||
<string name="previous_image_title_description_not_found">Відсутній заголовок або опис попереднього зображення</string>
|
||||
<string name="dialog_box_text_nomination">Чому %1$s має бути видалено?</string>
|
||||
<string name="review_is_uploaded_by">%1$s завантажено з допомогою: %2$s</string>
|
||||
<string name="default_description_language">Усталена мова описів</string>
|
||||
<string name="delete_helper_ask_spam_selfie">Селфі</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Розмито</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Безглуздя</string>
|
||||
<string name="delete_helper_ask_spam_other">Інше</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Фото з новин</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Випадкове фото з інтернет</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Логотип</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Інше</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -536,4 +536,12 @@
|
|||
<string name="dialog_box_text_nomination">為何應刪除%1$s?</string>
|
||||
<string name="review_is_uploaded_by">%1$s 是由 %2$s 所上傳</string>
|
||||
<string name="default_description_language">預設描述語言</string>
|
||||
<string name="delete_helper_ask_spam_selfie">自拍</string>
|
||||
<string name="delete_helper_ask_spam_blurry">糢糊</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">無意義</string>
|
||||
<string name="delete_helper_ask_spam_other">其它</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">攝影作品</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">來自網路的隨意照片</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">標誌</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">其它</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
<string name="preference_category_appearance">外观</string>
|
||||
<string name="preference_category_general">一般</string>
|
||||
<string name="preference_category_feedback">反馈</string>
|
||||
<string name="preference_category_privacy">隐私政策</string>
|
||||
<string name="preference_category_privacy">隐私</string>
|
||||
<string name="preference_category_location">位置</string>
|
||||
<string name="app_name">共享资源</string>
|
||||
<string name="bullet">•</string>
|
||||
|
|
@ -277,6 +277,7 @@
|
|||
<string name="nominate_deletion">提交删除</string>
|
||||
<string name="nominated_for_deletion">此图片已被提交删除。</string>
|
||||
<string name="nominated_see_more"><u>查看网页获取详情</u></string>
|
||||
<string name="nominating_file_for_deletion">提名%1$s删除。</string>
|
||||
<string name="nominating_for_deletion_status">提名删除:%1$s</string>
|
||||
<string name="view_browser">在浏览器中预览</string>
|
||||
<string name="skip_login">忽略</string>
|
||||
|
|
@ -425,8 +426,8 @@
|
|||
<string name="deletion_reason_bad_for_my_privacy">我意识到这对我的隐私不利</string>
|
||||
<string name="deletion_reason_no_longer_want_public">我改变了主意,我不想再让公众看到它了</string>
|
||||
<string name="deletion_reason_not_interesting">对不起,这幅图对百科全书没什么意思</string>
|
||||
<string name="uploaded_by_myself" fuzzy="true">我自己上传的在</string>
|
||||
<string name="no_uploads" fuzzy="true">欢迎使用共享资源!\n\n通过触摸相机或画廊图标以上来上传您的首个媒体。</string>
|
||||
<string name="uploaded_by_myself">由我自己上传在%1$s,使用于%2$d个条目。</string>
|
||||
<string name="no_uploads">欢迎使用共享资源!\n\n通过点击添加按钮以上传您的首个媒体。</string>
|
||||
<string name="desc_language_Worldwide">世界各地</string>
|
||||
<string name="desc_language_America">美洲</string>
|
||||
<string name="desc_language_Europe">欧洲</string>
|
||||
|
|
@ -471,8 +472,11 @@
|
|||
<string name="review_spam_report_question">该文件不在收录范围内,原因是</string>
|
||||
<string name="review_c_violation_report_question">该文件侵犯版权,原因是</string>
|
||||
<string name="review_category_yes_button_text">否,分类错误</string>
|
||||
<string name="review_category_no_button_text">看起来没问题</string>
|
||||
<string name="review_spam_yes_button_text">否,不在收录范围内</string>
|
||||
<string name="review_spam_no_button_text">看起来没问题</string>
|
||||
<string name="review_copyright_yes_button_text">否,侵犯版权</string>
|
||||
<string name="review_copyright_no_button_text">看起来没问题</string>
|
||||
<string name="review_thanks_yes_button_text">是,为什么不呢</string>
|
||||
<string name="review_thanks_no_button_text">下一张图片</string>
|
||||
<plurals name="receiving_shared_content">
|
||||
|
|
@ -503,4 +507,10 @@
|
|||
<string name="no_categories_found">找不到分类</string>
|
||||
<string name="upload_cancelled">取消上传</string>
|
||||
<string name="dialog_box_text_nomination">%1$s为何应被删除?</string>
|
||||
<string name="delete_helper_ask_spam_selfie">自拍</string>
|
||||
<string name="delete_helper_ask_spam_blurry">模糊</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">无意义</string>
|
||||
<string name="delete_helper_ask_spam_other">其他</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">标志</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">其他</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -560,12 +560,19 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="dialog_box_text_nomination">Why should %1$s be deleted?</string>
|
||||
<string name="review_is_uploaded_by">%1$s is uploaded by: %2$s</string>
|
||||
<string name="default_description_language">Default description language</string>
|
||||
<string name="delete_reason_spam_selfie">A selfie</string>
|
||||
<string name="delete_reason_spam_blurry">Blurry</string>
|
||||
<string name="delete_reason_spam_nonsense">Nonsense</string>
|
||||
<string name="delete_reason_spam_other">Other</string>
|
||||
<string name="delete_reason_copyright_pressphoto">Press photo</string>
|
||||
<string name="delete_reason_copyright_internetphoto">Random photo from internet</string>
|
||||
<string name="delete_reason_copyright_logo">Logo</string>
|
||||
<string name="delete_reason_copyright_other">Other</string>
|
||||
<string name="delete_helper_make_deletion_toast">Trying to nominate %1$s for deletion</string>
|
||||
<string name="delete_helper_show_deletion_title">Nominating for deletion</string>
|
||||
<string name="delete_helper_show_deletion_title_success">Success</string>
|
||||
<string name="delete_helper_show_deletion_message_if">Successfully nominated %1$s for deletion.</string>
|
||||
<string name="delete_helper_show_deletion_title_failed">Failed</string>
|
||||
<string name="delete_helper_show_deletion_message_else">Could not request deletion.</string>
|
||||
<string name="delete_helper_ask_spam_selfie">A selfie</string>
|
||||
<string name="delete_helper_ask_spam_blurry">Blurry</string>
|
||||
<string name="delete_helper_ask_spam_nonsense">Nonsense</string>
|
||||
<string name="delete_helper_ask_spam_other">Other</string>
|
||||
<string name="delete_helper_ask_reason_copyright_press_photo">Press photo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_internet_photo">Random photo from internet</string>
|
||||
<string name="delete_helper_ask_reason_copyright_logo">Logo</string>
|
||||
<string name="delete_helper_ask_reason_copyright_other">Other</string>
|
||||
<string name="delete_helper_ask_alert_set_positive_button_reason">Because it is</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import android.database.Cursor
|
||||
import androidx.loader.content.CursorLoader
|
||||
import androidx.loader.content.Loader
|
||||
import com.nhaarman.mockito_kotlin.verify
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
/**
|
||||
* The unit test class for ContributionsPresenter
|
||||
*/
|
||||
class ContributionsPresenterTest {
|
||||
@Mock
|
||||
internal var repository: ContributionsRepository? = null
|
||||
@Mock
|
||||
internal var view: ContributionsContract.View? = null
|
||||
|
||||
private var contributionsPresenter: ContributionsPresenter? = null
|
||||
|
||||
private lateinit var cursor: Cursor
|
||||
|
||||
lateinit var contribution: Contribution
|
||||
|
||||
lateinit var loader: Loader<Cursor>
|
||||
|
||||
/**
|
||||
* initial setup
|
||||
*/
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
cursor = Mockito.mock(Cursor::class.java)
|
||||
contribution = Mockito.mock(Contribution::class.java)
|
||||
contributionsPresenter = ContributionsPresenter(repository)
|
||||
loader = Mockito.mock(CursorLoader::class.java)
|
||||
contributionsPresenter?.onAttachView(view)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test presenter actions onGetContributionFromCursor
|
||||
*/
|
||||
@Test
|
||||
fun testGetContributionFromCursor() {
|
||||
contributionsPresenter?.getContributionsFromCursor(cursor)
|
||||
verify(repository)?.getContributionFromCursor(cursor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test presenter actions onDeleteContribution
|
||||
*/
|
||||
@Test
|
||||
fun testDeleteContribution() {
|
||||
contributionsPresenter?.deleteUpload(contribution)
|
||||
verify(repository)?.deleteContributionFromDB(contribution)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test presenter actions on loaderFinished and has non zero media objects
|
||||
*/
|
||||
@Test
|
||||
fun testOnLoaderFinishedNonZeroContributions() {
|
||||
Mockito.`when`(cursor.count).thenReturn(1)
|
||||
contributionsPresenter?.onLoadFinished(loader, cursor)
|
||||
verify(view)?.showProgress(false)
|
||||
verify(view)?.showWelcomeTip(false)
|
||||
verify(view)?.showNoContributionsUI(false)
|
||||
verify(view)?.setUploadCount(cursor.count)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test presenter actions on loaderFinished and has Zero media objects
|
||||
*/
|
||||
@Test
|
||||
fun testOnLoaderFinishedZeroContributions() {
|
||||
Mockito.`when`(cursor.count).thenReturn(0)
|
||||
contributionsPresenter?.onLoadFinished(loader, cursor)
|
||||
verify(view)?.showProgress(false)
|
||||
verify(view)?.showWelcomeTip(true)
|
||||
verify(view)?.showNoContributionsUI(true)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test presenter actions on loader reset
|
||||
*/
|
||||
@Test
|
||||
fun testOnLoaderReset() {
|
||||
contributionsPresenter?.onLoaderReset(loader)
|
||||
verify(view)?.showProgress(false)
|
||||
verify(view)?.showWelcomeTip(true)
|
||||
verify(view)?.showNoContributionsUI(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test presenter actions on loader change
|
||||
*/
|
||||
@Test
|
||||
fun testOnChanged() {
|
||||
contributionsPresenter?.onChanged()
|
||||
verify(view)?.onDataSetChanged()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package fr.free.nrw.commons.mwapi
|
||||
|
||||
import com.google.gson.Gson
|
||||
import fr.free.nrw.commons.BuildConfig
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
|
|
@ -344,6 +343,15 @@ class OkHttpJsonApiClientTest {
|
|||
return it
|
||||
}
|
||||
|
||||
/**
|
||||
* Check request params with encoded path
|
||||
*/
|
||||
private fun assertBasicRequestParameters(server: MockWebServer, method: String,encodedPath: String): RecordedRequest = server.takeRequest().let {
|
||||
Assert.assertEquals(encodedPath, it.requestUrl.encodedPath())
|
||||
Assert.assertEquals(method, it.method)
|
||||
return it
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse query params
|
||||
|
|
@ -354,4 +362,37 @@ class OkHttpJsonApiClientTest {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test getUploadCount posititive and negative cases
|
||||
*/
|
||||
@Test
|
||||
fun testGetUploadCount(){
|
||||
//Positive
|
||||
assertEquals(testBaseCasesAndGetUploadCount(true), 20)
|
||||
//Negative
|
||||
assertEquals(testBaseCasesAndGetUploadCount(false), 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getUploadCount base cases
|
||||
*/
|
||||
private fun testBaseCasesAndGetUploadCount(shouldAddResponse: Boolean): Int? {
|
||||
val mockResponse = MockResponse()
|
||||
mockResponse.setResponseCode(200)
|
||||
if(shouldAddResponse) {
|
||||
val responseBody = "20"
|
||||
mockResponse.setBody(responseBody)
|
||||
}
|
||||
toolsForgeServer.enqueue(mockResponse)
|
||||
|
||||
val uploadCount=testObject.getUploadCount("ashishkumar294").blockingGet()
|
||||
assertBasicRequestParameters(toolsForgeServer, "GET","/uploadsbyuser.py").let { request ->
|
||||
parseQueryParams(request).let { body ->
|
||||
Assert.assertEquals("ashishkumar294", body["user"])
|
||||
}
|
||||
}
|
||||
return uploadCount
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue