mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
converted/Migrated
This commit is contained in:
parent
2d1834aa38
commit
adf15f2fbd
17 changed files with 1098 additions and 1130 deletions
|
|
@ -1,110 +1,96 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.webkit.URLUtil;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AlertDialog.Builder;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||
import fr.free.nrw.commons.databinding.LayoutContributionBinding;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.File;
|
||||
import android.net.Uri
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.webkit.URLUtil
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.imagepipeline.request.ImageRequest
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.databinding.LayoutContributionBinding
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.io.File
|
||||
|
||||
public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
||||
class ContributionViewHolder internal constructor(
|
||||
private val parent: View, private val callback: ContributionsListAdapter.Callback,
|
||||
private val mediaClient: MediaClient
|
||||
) : RecyclerView.ViewHolder(parent) {
|
||||
var binding: LayoutContributionBinding = LayoutContributionBinding.bind(parent)
|
||||
|
||||
private final Callback callback;
|
||||
private var position = 0
|
||||
private var contribution: Contribution? = null
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
private var isWikipediaButtonDisplayed = false
|
||||
private val pausingPopUp: AlertDialog
|
||||
var imageRequest: ImageRequest? = null
|
||||
private set
|
||||
|
||||
LayoutContributionBinding binding;
|
||||
|
||||
private int position;
|
||||
private Contribution contribution;
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private final MediaClient mediaClient;
|
||||
private boolean isWikipediaButtonDisplayed;
|
||||
private AlertDialog pausingPopUp;
|
||||
private View parent;
|
||||
private ImageRequest imageRequest;
|
||||
|
||||
ContributionViewHolder(final View parent, final Callback callback,
|
||||
final MediaClient mediaClient) {
|
||||
super(parent);
|
||||
this.parent = parent;
|
||||
this.mediaClient = mediaClient;
|
||||
this.callback = callback;
|
||||
|
||||
binding = LayoutContributionBinding.bind(parent);
|
||||
|
||||
binding.contributionImage.setOnClickListener(v -> imageClicked());
|
||||
binding.wikipediaButton.setOnClickListener(v -> wikipediaButtonClicked());
|
||||
init {
|
||||
binding.contributionImage.setOnClickListener { v: View? -> imageClicked() }
|
||||
binding.wikipediaButton.setOnClickListener { v: View? -> wikipediaButtonClicked() }
|
||||
|
||||
/* Set a dialog indicating that the upload is being paused. This is needed because pausing
|
||||
an upload might take a dozen seconds. */
|
||||
AlertDialog.Builder builder = new Builder(parent.getContext());
|
||||
builder.setCancelable(false);
|
||||
builder.setView(R.layout.progress_dialog);
|
||||
pausingPopUp = builder.create();
|
||||
an upload might take a dozen seconds. */
|
||||
val builder = AlertDialog.Builder(
|
||||
parent.context
|
||||
)
|
||||
builder.setCancelable(false)
|
||||
builder.setView(R.layout.progress_dialog)
|
||||
pausingPopUp = builder.create()
|
||||
}
|
||||
|
||||
public void init(final int position, final Contribution contribution) {
|
||||
|
||||
fun init(position: Int, contribution: Contribution?) {
|
||||
//handling crashes when the contribution is null.
|
||||
|
||||
if (null == contribution) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
this.contribution = contribution;
|
||||
this.position = position;
|
||||
binding.contributionTitle.setText(contribution.getMedia().getMostRelevantCaption());
|
||||
binding.authorView.setText(contribution.getMedia().getAuthor());
|
||||
this.contribution = contribution
|
||||
this.position = position
|
||||
binding.contributionTitle.text = contribution.media.mostRelevantCaption
|
||||
binding.authorView.text = contribution.media.author
|
||||
|
||||
//Removes flicker of loading image.
|
||||
binding.contributionImage.getHierarchy().setFadeDuration(0);
|
||||
binding.contributionImage.hierarchy.fadeDuration = 0
|
||||
|
||||
binding.contributionImage.getHierarchy().setPlaceholderImage(R.drawable.image_placeholder);
|
||||
binding.contributionImage.getHierarchy().setFailureImage(R.drawable.image_placeholder);
|
||||
binding.contributionImage.hierarchy.setPlaceholderImage(R.drawable.image_placeholder)
|
||||
binding.contributionImage.hierarchy.setFailureImage(R.drawable.image_placeholder)
|
||||
|
||||
final String imageSource = chooseImageSource(contribution.getMedia().getThumbUrl(),
|
||||
contribution.getLocalUri());
|
||||
val imageSource = chooseImageSource(
|
||||
contribution.media.thumbUrl,
|
||||
contribution.localUri
|
||||
)
|
||||
if (!TextUtils.isEmpty(imageSource)) {
|
||||
if (URLUtil.isHttpsUrl(imageSource)) {
|
||||
imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageSource))
|
||||
.setProgressiveRenderingEnabled(true)
|
||||
.build();
|
||||
.build()
|
||||
} else if (URLUtil.isFileUrl(imageSource)) {
|
||||
imageRequest = ImageRequest.fromUri(Uri.parse(imageSource));
|
||||
imageRequest = ImageRequest.fromUri(Uri.parse(imageSource))
|
||||
} else if (imageSource != null) {
|
||||
final File file = new File(imageSource);
|
||||
imageRequest = ImageRequest.fromFile(file);
|
||||
val file = File(imageSource)
|
||||
imageRequest = ImageRequest.fromFile(file)
|
||||
}
|
||||
|
||||
if (imageRequest != null) {
|
||||
binding.contributionImage.setImageRequest(imageRequest);
|
||||
binding.contributionImage.setImageRequest(imageRequest)
|
||||
}
|
||||
}
|
||||
|
||||
binding.contributionSequenceNumber.setText(String.valueOf(position + 1));
|
||||
binding.contributionSequenceNumber.setVisibility(View.VISIBLE);
|
||||
binding.wikipediaButton.setVisibility(View.GONE);
|
||||
binding.contributionState.setVisibility(View.GONE);
|
||||
binding.contributionProgress.setVisibility(View.GONE);
|
||||
binding.imageOptions.setVisibility(View.GONE);
|
||||
binding.contributionState.setText("");
|
||||
checkIfMediaExistsOnWikipediaPage(contribution);
|
||||
|
||||
binding.contributionSequenceNumber.text = (position + 1).toString()
|
||||
binding.contributionSequenceNumber.visibility = View.VISIBLE
|
||||
binding.wikipediaButton.visibility = View.GONE
|
||||
binding.contributionState.visibility = View.GONE
|
||||
binding.contributionProgress.visibility = View.GONE
|
||||
binding.imageOptions.visibility = View.GONE
|
||||
binding.contributionState.text = ""
|
||||
checkIfMediaExistsOnWikipediaPage(contribution)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,18 +99,20 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
*
|
||||
* @param contribution
|
||||
*/
|
||||
private void checkIfMediaExistsOnWikipediaPage(final Contribution contribution) {
|
||||
if (contribution.getWikidataPlace() == null
|
||||
|| contribution.getWikidataPlace().getWikipediaArticle() == null) {
|
||||
return;
|
||||
private fun checkIfMediaExistsOnWikipediaPage(contribution: Contribution) {
|
||||
if (contribution.wikidataPlace == null
|
||||
|| contribution.wikidataPlace!!.wikipediaArticle == null
|
||||
) {
|
||||
return
|
||||
}
|
||||
final String wikipediaArticle = contribution.getWikidataPlace().getWikipediaPageTitle();
|
||||
compositeDisposable.add(mediaClient.doesPageContainMedia(wikipediaArticle)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(mediaExists -> {
|
||||
displayWikipediaButton(mediaExists);
|
||||
}));
|
||||
val wikipediaArticle = contribution.wikidataPlace!!.getWikipediaPageTitle()
|
||||
compositeDisposable.add(
|
||||
mediaClient.doesPageContainMedia(wikipediaArticle)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { mediaExists: Boolean ->
|
||||
displayWikipediaButton(mediaExists)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -134,11 +122,11 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
*
|
||||
* @param mediaExists
|
||||
*/
|
||||
private void displayWikipediaButton(Boolean mediaExists) {
|
||||
private fun displayWikipediaButton(mediaExists: Boolean) {
|
||||
if (!mediaExists) {
|
||||
binding.wikipediaButton.setVisibility(View.VISIBLE);
|
||||
isWikipediaButtonDisplayed = true;
|
||||
binding.imageOptions.setVisibility(View.VISIBLE);
|
||||
binding.wikipediaButton.visibility = View.VISIBLE
|
||||
isWikipediaButtonDisplayed = true
|
||||
binding.imageOptions.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,22 +138,15 @@ public class ContributionViewHolder extends RecyclerView.ViewHolder {
|
|||
* @param localUri
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private String chooseImageSource(final String thumbUrl, final Uri localUri) {
|
||||
return !TextUtils.isEmpty(thumbUrl) ? thumbUrl :
|
||||
localUri != null ? localUri.toString() :
|
||||
null;
|
||||
private fun chooseImageSource(thumbUrl: String?, localUri: Uri?): String? {
|
||||
return if (!TextUtils.isEmpty(thumbUrl)) thumbUrl else localUri?.toString()
|
||||
}
|
||||
|
||||
public void imageClicked() {
|
||||
callback.openMediaDetail(position, isWikipediaButtonDisplayed);
|
||||
fun imageClicked() {
|
||||
callback.openMediaDetail(position, isWikipediaButtonDisplayed)
|
||||
}
|
||||
|
||||
public void wikipediaButtonClicked() {
|
||||
callback.addImageToWikipedia(contribution);
|
||||
}
|
||||
|
||||
public ImageRequest getImageRequest() {
|
||||
return imageRequest;
|
||||
fun wikipediaButtonClicked() {
|
||||
callback.addImageToWikipedia(contribution)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@ class ContributionsFragment
|
|||
|
||||
private fun setUploadCount() {
|
||||
okHttpJsonApiClient
|
||||
?.getUploadCount((activity as MainActivity).sessionManager.currentAccount!!.name)
|
||||
?.getUploadCount((activity as MainActivity).sessionManager?.currentAccount!!.name)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())?.let {
|
||||
compositeDisposable.add(
|
||||
|
|
@ -838,7 +838,7 @@ class ContributionsFragment
|
|||
mediaDetailPagerFragment!!.showImage(position, isWikipediaButtonDisplayed)
|
||||
}
|
||||
|
||||
override fun getMediaAtPosition(i: Int): Media {
|
||||
override fun getMediaAtPosition(i: Int): Media? {
|
||||
return contributionsListFragment!!.getMediaAtPosition(i)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,273 +1,286 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.LinearLayout;
|
||||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
|
||||
import androidx.recyclerview.widget.RecyclerView.ItemAnimator;
|
||||
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListAdapter.Callback;
|
||||
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import fr.free.nrw.commons.profile.ProfileActivity;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.utils.SystemThemeUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import fr.free.nrw.commons.wikidata.model.WikiSite;
|
||||
import android.Manifest.permission
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.LinearLayout
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions
|
||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.paging.PagedList
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
|
||||
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.Utils
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.contributions.WikipediaInstructionsDialogFragment.Companion.newInstance
|
||||
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||
import fr.free.nrw.commons.di.NetworkingModule
|
||||
import fr.free.nrw.commons.filepicker.FilePicker
|
||||
import fr.free.nrw.commons.media.MediaClient
|
||||
import fr.free.nrw.commons.profile.ProfileActivity
|
||||
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
|
||||
import fr.free.nrw.commons.utils.SystemThemeUtils
|
||||
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
|
||||
import fr.free.nrw.commons.wikidata.model.WikiSite
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
|
||||
/**
|
||||
* Created by root on 01.06.2018.
|
||||
*/
|
||||
class ContributionsListFragment : CommonsDaggerSupportFragment(), ContributionsListContract.View,
|
||||
ContributionsListAdapter.Callback, WikipediaInstructionsDialogFragment.Callback {
|
||||
@JvmField
|
||||
@Inject
|
||||
var systemThemeUtils: SystemThemeUtils? = null
|
||||
|
||||
public class ContributionsListFragment extends CommonsDaggerSupportFragment implements
|
||||
ContributionsListContract.View, Callback,
|
||||
WikipediaInstructionsDialogFragment.Callback {
|
||||
@JvmField
|
||||
@Inject
|
||||
var controller: ContributionController? = null
|
||||
|
||||
private static final String RV_STATE = "rv_scroll_state";
|
||||
@JvmField
|
||||
@Inject
|
||||
var mediaClient: MediaClient? = null
|
||||
|
||||
@JvmField
|
||||
@Named(NetworkingModule.NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE)
|
||||
@Inject
|
||||
SystemThemeUtils systemThemeUtils;
|
||||
@Inject
|
||||
ContributionController controller;
|
||||
@Inject
|
||||
MediaClient mediaClient;
|
||||
@Named(NAMED_LANGUAGE_WIKI_PEDIA_WIKI_SITE)
|
||||
@Inject
|
||||
WikiSite languageWikipediaSite;
|
||||
@Inject
|
||||
ContributionsListPresenter contributionsListPresenter;
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
var languageWikipediaSite: WikiSite? = null
|
||||
|
||||
private FragmentContributionsListBinding binding;
|
||||
private Animation fab_close;
|
||||
private Animation fab_open;
|
||||
private Animation rotate_forward;
|
||||
private Animation rotate_backward;
|
||||
private boolean isFabOpen;
|
||||
@VisibleForTesting
|
||||
protected RecyclerView rvContributionsList;
|
||||
@JvmField
|
||||
@Inject
|
||||
var contributionsListPresenter: ContributionsListPresenter? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var sessionManager: SessionManager? = null
|
||||
|
||||
private var binding: FragmentContributionsListBinding? = null
|
||||
private var fab_close: Animation? = null
|
||||
private var fab_open: Animation? = null
|
||||
private var rotate_forward: Animation? = null
|
||||
private var rotate_backward: Animation? = null
|
||||
private var isFabOpen = false
|
||||
|
||||
private lateinit var inAppCameraLocationPermissionLauncher: ActivityResultLauncher<Array<String>>
|
||||
|
||||
@VisibleForTesting
|
||||
protected ContributionsListAdapter adapter;
|
||||
var rvContributionsList: RecyclerView? = null
|
||||
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
protected Callback callback;
|
||||
var adapter: ContributionsListAdapter? = null
|
||||
|
||||
private final int SPAN_COUNT_LANDSCAPE = 3;
|
||||
private final int SPAN_COUNT_PORTRAIT = 1;
|
||||
@VisibleForTesting
|
||||
var callback: Callback? = null
|
||||
|
||||
private int contributionsSize;
|
||||
private String userName;
|
||||
private val SPAN_COUNT_LANDSCAPE = 3
|
||||
private val SPAN_COUNT_PORTRAIT = 1
|
||||
|
||||
private final ActivityResultLauncher<Intent> galleryPickLauncherForResult =
|
||||
registerForActivityResult(new StartActivityForResult(),
|
||||
result -> {
|
||||
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||
controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks);
|
||||
});
|
||||
});
|
||||
private var contributionsSize = 0
|
||||
private var userName: String? = null
|
||||
|
||||
private final ActivityResultLauncher<Intent> customSelectorLauncherForResult =
|
||||
registerForActivityResult(new StartActivityForResult(),
|
||||
result -> {
|
||||
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||
controller.onPictureReturnedFromCustomSelector(result, requireActivity(), callbacks);
|
||||
});
|
||||
});
|
||||
private val galleryPickLauncherForResult = registerForActivityResult<Intent, ActivityResult>(
|
||||
StartActivityForResult()
|
||||
) { result: ActivityResult? ->
|
||||
controller!!.handleActivityResultWithCallback(requireActivity()
|
||||
) { callbacks: FilePicker.Callbacks? ->
|
||||
controller!!.onPictureReturnedFromGallery(
|
||||
result!!, requireActivity(), callbacks!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private final ActivityResultLauncher<Intent> cameraPickLauncherForResult =
|
||||
registerForActivityResult(new StartActivityForResult(),
|
||||
result -> {
|
||||
controller.handleActivityResultWithCallback(requireActivity(), callbacks -> {
|
||||
controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks);
|
||||
});
|
||||
});
|
||||
private val customSelectorLauncherForResult = registerForActivityResult<Intent, ActivityResult>(
|
||||
StartActivityForResult()
|
||||
) { result: ActivityResult? ->
|
||||
controller!!.handleActivityResultWithCallback(requireActivity()
|
||||
) { callbacks: FilePicker.Callbacks? ->
|
||||
controller!!.onPictureReturnedFromCustomSelector(
|
||||
result!!, requireActivity(), callbacks!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private ActivityResultLauncher<String[]> inAppCameraLocationPermissionLauncher = registerForActivityResult(
|
||||
new RequestMultiplePermissions(),
|
||||
new ActivityResultCallback<Map<String, Boolean>>() {
|
||||
@Override
|
||||
public void onActivityResult(Map<String, Boolean> result) {
|
||||
boolean areAllGranted = true;
|
||||
for (final boolean b : result.values()) {
|
||||
areAllGranted = areAllGranted && b;
|
||||
}
|
||||
private val cameraPickLauncherForResult = registerForActivityResult<Intent, ActivityResult>(
|
||||
StartActivityForResult()
|
||||
) { result: ActivityResult? ->
|
||||
controller!!.handleActivityResultWithCallback(requireActivity()
|
||||
) { callbacks: FilePicker.Callbacks? ->
|
||||
controller!!.onPictureReturnedFromCamera(
|
||||
result!!, requireActivity(), callbacks!!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (areAllGranted) {
|
||||
controller.locationPermissionCallback.onLocationPermissionGranted();
|
||||
} else {
|
||||
if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
controller.handleShowRationaleFlowCameraLocation(getActivity(),
|
||||
inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
} else {
|
||||
controller.locationPermissionCallback.onLocationPermissionDenied(
|
||||
getActivity().getString(
|
||||
R.string.in_app_camera_location_permission_denied));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(
|
||||
@Nullable @org.jetbrains.annotations.Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@SuppressLint("NewApi")
|
||||
override fun onCreate(
|
||||
savedInstanceState: Bundle?
|
||||
) {
|
||||
super.onCreate(savedInstanceState)
|
||||
//Now that we are allowing this fragment to be started for
|
||||
// any userName- we expect it to be passed as an argument
|
||||
if (getArguments() != null) {
|
||||
userName = getArguments().getString(ProfileActivity.KEY_USERNAME);
|
||||
if (arguments != null) {
|
||||
userName = requireArguments().getString(ProfileActivity.KEY_USERNAME)
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(userName)) {
|
||||
userName = sessionManager.getUserName();
|
||||
userName = sessionManager!!.userName
|
||||
}
|
||||
inAppCameraLocationPermissionLauncher =
|
||||
registerForActivityResult(RequestMultiplePermissions()) { result ->
|
||||
val areAllGranted = result.values.all { it }
|
||||
|
||||
if (areAllGranted) {
|
||||
controller?.locationPermissionCallback?.onLocationPermissionGranted()
|
||||
} else {
|
||||
activity?.let { currentActivity ->
|
||||
if (currentActivity.shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) {
|
||||
controller?.handleShowRationaleFlowCameraLocation(
|
||||
currentActivity,
|
||||
inAppCameraLocationPermissionLauncher, // Pass launcher
|
||||
cameraPickLauncherForResult
|
||||
)
|
||||
} else {
|
||||
controller?.locationPermissionCallback?.onLocationPermissionDenied(
|
||||
currentActivity.getString(R.string.in_app_camera_location_permission_denied)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
final LayoutInflater inflater, @Nullable final ViewGroup container,
|
||||
@Nullable final Bundle savedInstanceState) {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = FragmentContributionsListBinding.inflate(
|
||||
inflater, container, false
|
||||
);
|
||||
rvContributionsList = binding.contributionsList;
|
||||
)
|
||||
rvContributionsList = binding!!.contributionsList
|
||||
|
||||
contributionsListPresenter.onAttachView(this);
|
||||
binding.fabCustomGallery.setOnClickListener(v -> launchCustomSelector());
|
||||
binding.fabCustomGallery.setOnLongClickListener(view -> {
|
||||
ViewUtil.showShortToast(getContext(), R.string.custom_selector_title);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (Objects.equals(sessionManager.getUserName(), userName)) {
|
||||
binding.tvContributionsOfUser.setVisibility(GONE);
|
||||
binding.fabLayout.setVisibility(VISIBLE);
|
||||
} else {
|
||||
binding.tvContributionsOfUser.setVisibility(VISIBLE);
|
||||
binding.tvContributionsOfUser.setText(
|
||||
getString(R.string.contributions_of_user, userName));
|
||||
binding.fabLayout.setVisibility(GONE);
|
||||
contributionsListPresenter!!.onAttachView(this)
|
||||
binding!!.fabCustomGallery.setOnClickListener { v: View? -> launchCustomSelector() }
|
||||
binding!!.fabCustomGallery.setOnLongClickListener { view: View? ->
|
||||
showShortToast(context, fr.free.nrw.commons.R.string.custom_selector_title)
|
||||
true
|
||||
}
|
||||
|
||||
initAdapter();
|
||||
if (sessionManager!!.userName == userName) {
|
||||
binding!!.tvContributionsOfUser.visibility = View.GONE
|
||||
binding!!.fabLayout.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding!!.tvContributionsOfUser.visibility = View.VISIBLE
|
||||
binding!!.tvContributionsOfUser.text =
|
||||
getString(fr.free.nrw.commons.R.string.contributions_of_user, userName)
|
||||
binding!!.fabLayout.visibility = View.GONE
|
||||
}
|
||||
|
||||
initAdapter()
|
||||
|
||||
// pull down to refresh only enabled for self user.
|
||||
if(Objects.equals(sessionManager.getUserName(), userName)){
|
||||
binding.swipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
contributionsListPresenter.refreshList(binding.swipeRefreshLayout);
|
||||
});
|
||||
if (sessionManager!!.userName == userName) {
|
||||
binding!!.swipeRefreshLayout.setOnRefreshListener {
|
||||
contributionsListPresenter!!.refreshList(
|
||||
binding!!.swipeRefreshLayout
|
||||
)
|
||||
}
|
||||
} else {
|
||||
binding.swipeRefreshLayout.setEnabled(false);
|
||||
binding!!.swipeRefreshLayout.isEnabled = false
|
||||
}
|
||||
|
||||
return binding.getRoot();
|
||||
return binding!!.root
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
binding = null;
|
||||
super.onDestroyView();
|
||||
override fun onDestroyView() {
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (getParentFragment() != null && getParentFragment() instanceof ContributionsFragment) {
|
||||
callback = ((ContributionsFragment) getParentFragment());
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
if (parentFragment != null && parentFragment is ContributionsFragment) {
|
||||
callback = (parentFragment as ContributionsFragment)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
callback = null;//To avoid possible memory leak
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
callback = null //To avoid possible memory leak
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
adapter = new ContributionsListAdapter(this, mediaClient);
|
||||
private fun initAdapter() {
|
||||
adapter = ContributionsListAdapter(this, mediaClient!!)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
initRecyclerView();
|
||||
initializeAnimations();
|
||||
setListeners();
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
initRecyclerView()
|
||||
initializeAnimations()
|
||||
setListeners()
|
||||
}
|
||||
|
||||
private void initRecyclerView() {
|
||||
final GridLayoutManager layoutManager = new GridLayoutManager(getContext(),
|
||||
getSpanCount(getResources().getConfiguration().orientation));
|
||||
rvContributionsList.setLayoutManager(layoutManager);
|
||||
private fun initRecyclerView() {
|
||||
val layoutManager = GridLayoutManager(
|
||||
context,
|
||||
getSpanCount(resources.configuration.orientation)
|
||||
)
|
||||
rvContributionsList!!.layoutManager = layoutManager
|
||||
|
||||
//Setting flicker animation of recycler view to false.
|
||||
final ItemAnimator animator = rvContributionsList.getItemAnimator();
|
||||
if (animator instanceof SimpleItemAnimator) {
|
||||
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
|
||||
val animator = rvContributionsList!!.itemAnimator
|
||||
if (animator is SimpleItemAnimator) {
|
||||
animator.supportsChangeAnimations = false
|
||||
}
|
||||
|
||||
contributionsListPresenter.setup(userName,
|
||||
Objects.equals(sessionManager.getUserName(), userName));
|
||||
contributionsListPresenter.contributionList.observe(getViewLifecycleOwner(), list -> {
|
||||
contributionsSize = list.size();
|
||||
adapter.submitList(list);
|
||||
if (callback != null) {
|
||||
callback.notifyDataSetChanged();
|
||||
contributionsListPresenter!!.setup(
|
||||
userName,
|
||||
sessionManager!!.userName == userName
|
||||
)
|
||||
contributionsListPresenter!!.contributionList?.observe(
|
||||
viewLifecycleOwner
|
||||
) { list: PagedList<Contribution>? ->
|
||||
if (list != null) {
|
||||
contributionsSize = list.size
|
||||
}
|
||||
});
|
||||
rvContributionsList.setAdapter(adapter);
|
||||
adapter.registerAdapterDataObserver(new AdapterDataObserver() {
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
super.onItemRangeInserted(positionStart, itemCount);
|
||||
contributionsSize = adapter.getItemCount();
|
||||
adapter!!.submitList(list)
|
||||
if (callback != null) {
|
||||
callback!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
rvContributionsList!!.adapter = adapter
|
||||
adapter!!.registerAdapterDataObserver(object : AdapterDataObserver() {
|
||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||
super.onItemRangeInserted(positionStart, itemCount)
|
||||
contributionsSize = adapter!!.itemCount
|
||||
if (callback != null) {
|
||||
callback.notifyDataSetChanged();
|
||||
callback!!.notifyDataSetChanged()
|
||||
}
|
||||
if (itemCount > 0 && positionStart == 0) {
|
||||
if (adapter.getContributionForPosition(positionStart) != null) {
|
||||
rvContributionsList
|
||||
.scrollToPosition(0);//Newly upload items are always added to the top
|
||||
if (adapter!!.getContributionForPosition(positionStart) != null) {
|
||||
rvContributionsList!!
|
||||
.scrollToPosition(0) //Newly upload items are always added to the top
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,146 +289,148 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
* Called whenever items in the list have changed
|
||||
* Calls viewPagerNotifyDataSetChanged() that will notify the viewpager
|
||||
*/
|
||||
@Override
|
||||
public void onItemRangeChanged(final int positionStart, final int itemCount) {
|
||||
super.onItemRangeChanged(positionStart, itemCount);
|
||||
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
|
||||
super.onItemRangeChanged(positionStart, itemCount)
|
||||
if (callback != null) {
|
||||
callback.viewPagerNotifyDataSetChanged();
|
||||
callback!!.viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
//Fab close on touch outside (Scrolling or taping on item triggers this action).
|
||||
rvContributionsList.addOnItemTouchListener(new OnItemTouchListener() {
|
||||
|
||||
rvContributionsList!!.addOnItemTouchListener(object : OnItemTouchListener {
|
||||
/**
|
||||
* Silently observe and/or take over touch events sent to the RecyclerView before
|
||||
* they are handled by either the RecyclerView itself or its child views.
|
||||
*/
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
|
||||
if (e.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
|
||||
if (e.action == MotionEvent.ACTION_DOWN) {
|
||||
if (isFabOpen) {
|
||||
animateFAB(isFabOpen);
|
||||
animateFAB(isFabOpen)
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a touch event as part of a gesture that was claimed by returning true
|
||||
* from a previous call to {@link #onInterceptTouchEvent}.
|
||||
* from a previous call to [.onInterceptTouchEvent].
|
||||
*
|
||||
* @param rv
|
||||
* @param e MotionEvent describing the touch event. All coordinates are in the
|
||||
* RecyclerView's coordinate system.
|
||||
* RecyclerView's coordinate system.
|
||||
*/
|
||||
@Override
|
||||
public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
|
||||
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
|
||||
//required abstract method DO NOT DELETE
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a child of RecyclerView does not want RecyclerView and its ancestors
|
||||
* to intercept touch events with {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}.
|
||||
* to intercept touch events with [ViewGroup.onInterceptTouchEvent].
|
||||
*
|
||||
* @param disallowIntercept True if the child does not want the parent to intercept
|
||||
* touch events.
|
||||
* touch events.
|
||||
*/
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
||||
//required abstract method DO NOT DELETE
|
||||
}
|
||||
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
private int getSpanCount(final int orientation) {
|
||||
return orientation == Configuration.ORIENTATION_LANDSCAPE ?
|
||||
SPAN_COUNT_LANDSCAPE : SPAN_COUNT_PORTRAIT;
|
||||
private fun getSpanCount(orientation: Int): Int {
|
||||
return if (orientation == Configuration.ORIENTATION_LANDSCAPE) SPAN_COUNT_LANDSCAPE else SPAN_COUNT_PORTRAIT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(final Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
// check orientation
|
||||
binding.fabLayout.setOrientation(
|
||||
newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ?
|
||||
LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
|
||||
binding!!.fabLayout.orientation =
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) LinearLayout.HORIZONTAL else LinearLayout.VERTICAL
|
||||
rvContributionsList
|
||||
.setLayoutManager(
|
||||
new GridLayoutManager(getContext(), getSpanCount(newConfig.orientation)));
|
||||
?.setLayoutManager(
|
||||
GridLayoutManager(context, getSpanCount(newConfig.orientation))
|
||||
)
|
||||
}
|
||||
|
||||
private void initializeAnimations() {
|
||||
fab_open = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_open);
|
||||
fab_close = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_close);
|
||||
rotate_forward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_forward);
|
||||
rotate_backward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_backward);
|
||||
private fun initializeAnimations() {
|
||||
fab_open = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.fab_open)
|
||||
fab_close = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.fab_close)
|
||||
rotate_forward = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.rotate_forward)
|
||||
rotate_backward = AnimationUtils.loadAnimation(activity, fr.free.nrw.commons.R.anim.rotate_backward)
|
||||
}
|
||||
|
||||
private void setListeners() {
|
||||
binding.fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
|
||||
binding.fabCamera.setOnClickListener(view -> {
|
||||
controller.initiateCameraPick(getActivity(), inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult);
|
||||
animateFAB(isFabOpen);
|
||||
});
|
||||
binding.fabCamera.setOnLongClickListener(view -> {
|
||||
ViewUtil.showShortToast(getContext(), R.string.add_contribution_from_camera);
|
||||
return true;
|
||||
});
|
||||
binding.fabGallery.setOnClickListener(view -> {
|
||||
controller.initiateGalleryPick(getActivity(), galleryPickLauncherForResult, true);
|
||||
animateFAB(isFabOpen);
|
||||
});
|
||||
binding.fabGallery.setOnLongClickListener(view -> {
|
||||
ViewUtil.showShortToast(getContext(), R.string.menu_from_gallery);
|
||||
return true;
|
||||
});
|
||||
private fun setListeners() {
|
||||
binding!!.fabPlus.setOnClickListener { view: View? -> animateFAB(isFabOpen) }
|
||||
binding!!.fabCamera.setOnClickListener { view: View? ->
|
||||
controller!!.initiateCameraPick(
|
||||
requireActivity(),
|
||||
inAppCameraLocationPermissionLauncher,
|
||||
cameraPickLauncherForResult
|
||||
)
|
||||
animateFAB(isFabOpen)
|
||||
}
|
||||
binding!!.fabCamera.setOnLongClickListener { view: View? ->
|
||||
showShortToast(
|
||||
context,
|
||||
fr.free.nrw.commons.R.string.add_contribution_from_camera
|
||||
)
|
||||
true
|
||||
}
|
||||
binding!!.fabGallery.setOnClickListener { view: View? ->
|
||||
controller!!.initiateGalleryPick(requireActivity(), galleryPickLauncherForResult, true)
|
||||
animateFAB(isFabOpen)
|
||||
}
|
||||
binding!!.fabGallery.setOnLongClickListener { view: View? ->
|
||||
showShortToast(context, fr.free.nrw.commons.R.string.menu_from_gallery)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch Custom Selector.
|
||||
*/
|
||||
protected void launchCustomSelector() {
|
||||
controller.initiateCustomGalleryPickWithPermission(getActivity(), customSelectorLauncherForResult);
|
||||
animateFAB(isFabOpen);
|
||||
protected fun launchCustomSelector() {
|
||||
controller!!.initiateCustomGalleryPickWithPermission(
|
||||
requireActivity(),
|
||||
customSelectorLauncherForResult
|
||||
)
|
||||
animateFAB(isFabOpen)
|
||||
}
|
||||
|
||||
public void scrollToTop() {
|
||||
rvContributionsList.smoothScrollToPosition(0);
|
||||
fun scrollToTop() {
|
||||
rvContributionsList!!.smoothScrollToPosition(0)
|
||||
}
|
||||
|
||||
private void animateFAB(final boolean isFabOpen) {
|
||||
this.isFabOpen = !isFabOpen;
|
||||
if (binding.fabPlus.isShown()) {
|
||||
private fun animateFAB(isFabOpen: Boolean) {
|
||||
this.isFabOpen = !isFabOpen
|
||||
if (binding!!.fabPlus.isShown) {
|
||||
if (isFabOpen) {
|
||||
binding.fabPlus.startAnimation(rotate_backward);
|
||||
binding.fabCamera.startAnimation(fab_close);
|
||||
binding.fabGallery.startAnimation(fab_close);
|
||||
binding.fabCustomGallery.startAnimation(fab_close);
|
||||
binding.fabCamera.hide();
|
||||
binding.fabGallery.hide();
|
||||
binding.fabCustomGallery.hide();
|
||||
binding!!.fabPlus.startAnimation(rotate_backward)
|
||||
binding!!.fabCamera.startAnimation(fab_close)
|
||||
binding!!.fabGallery.startAnimation(fab_close)
|
||||
binding!!.fabCustomGallery.startAnimation(fab_close)
|
||||
binding!!.fabCamera.hide()
|
||||
binding!!.fabGallery.hide()
|
||||
binding!!.fabCustomGallery.hide()
|
||||
} else {
|
||||
binding.fabPlus.startAnimation(rotate_forward);
|
||||
binding.fabCamera.startAnimation(fab_open);
|
||||
binding.fabGallery.startAnimation(fab_open);
|
||||
binding.fabCustomGallery.startAnimation(fab_open);
|
||||
binding.fabCamera.show();
|
||||
binding.fabGallery.show();
|
||||
binding.fabCustomGallery.show();
|
||||
binding!!.fabPlus.startAnimation(rotate_forward)
|
||||
binding!!.fabCamera.startAnimation(fab_open)
|
||||
binding!!.fabGallery.startAnimation(fab_open)
|
||||
binding!!.fabCustomGallery.startAnimation(fab_open)
|
||||
binding!!.fabCamera.show()
|
||||
binding!!.fabGallery.show()
|
||||
binding!!.fabCustomGallery.show()
|
||||
}
|
||||
this.isFabOpen = !isFabOpen;
|
||||
this.isFabOpen = !isFabOpen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows welcome message if user has no contributions yet i.e. new user.
|
||||
*/
|
||||
@Override
|
||||
public void showWelcomeTip(final boolean shouldShow) {
|
||||
binding.noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
|
||||
override fun showWelcomeTip(shouldShow: Boolean) {
|
||||
binding!!.noContributionsYet.visibility =
|
||||
if (shouldShow) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -423,37 +438,34 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
*
|
||||
* @param shouldShow True when contributions list should be hidden.
|
||||
*/
|
||||
@Override
|
||||
public void showProgress(final boolean shouldShow) {
|
||||
binding.loadingContributionsProgressBar.setVisibility(shouldShow ? VISIBLE : GONE);
|
||||
override fun showProgress(shouldShow: Boolean) {
|
||||
binding!!.loadingContributionsProgressBar.visibility =
|
||||
if (shouldShow) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showNoContributionsUI(final boolean shouldShow) {
|
||||
binding.noContributionsYet.setVisibility(shouldShow ? VISIBLE : GONE);
|
||||
override fun showNoContributionsUI(shouldShow: Boolean) {
|
||||
binding!!.noContributionsYet.visibility =
|
||||
if (shouldShow) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
final GridLayoutManager layoutManager = (GridLayoutManager) rvContributionsList
|
||||
.getLayoutManager();
|
||||
outState.putParcelable(RV_STATE, layoutManager.onSaveInstanceState());
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
val layoutManager = rvContributionsList
|
||||
?.getLayoutManager() as GridLayoutManager?
|
||||
outState.putParcelable(RV_STATE, layoutManager!!.onSaveInstanceState())
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
if (null != savedInstanceState) {
|
||||
final Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(RV_STATE);
|
||||
rvContributionsList.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState);
|
||||
val savedRecyclerLayoutState = savedInstanceState.getParcelable<Parcelable>(RV_STATE)
|
||||
rvContributionsList!!.layoutManager!!.onRestoreInstanceState(savedRecyclerLayoutState)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) {
|
||||
if (null != callback) {//Just being safe, ideally they won't be called when detached
|
||||
callback.showDetail(position, isWikipediaButtonDisplayed);
|
||||
override fun openMediaDetail(position: Int, isWikipediaButtonDisplayed: Boolean) {
|
||||
if (null != callback) { //Just being safe, ideally they won't be called when detached
|
||||
callback!!.showDetail(position, isWikipediaButtonDisplayed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -462,16 +474,16 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
*
|
||||
* @param contribution
|
||||
*/
|
||||
@Override
|
||||
public void addImageToWikipedia(Contribution contribution) {
|
||||
DialogUtil.showAlertDialog(getActivity(),
|
||||
getString(R.string.add_picture_to_wikipedia_article_title),
|
||||
getString(R.string.add_picture_to_wikipedia_article_desc),
|
||||
() -> {
|
||||
showAddImageToWikipediaInstructions(contribution);
|
||||
}, () -> {
|
||||
// do nothing
|
||||
});
|
||||
override fun addImageToWikipedia(contribution: Contribution?) {
|
||||
showAlertDialog(
|
||||
requireActivity(),
|
||||
getString(fr.free.nrw.commons.R.string.add_picture_to_wikipedia_article_title),
|
||||
getString(fr.free.nrw.commons.R.string.add_picture_to_wikipedia_article_desc),
|
||||
{
|
||||
if (contribution != null) {
|
||||
showAddImageToWikipediaInstructions(contribution)
|
||||
}
|
||||
}, {})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -479,56 +491,61 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
|
|||
*
|
||||
* @param contribution
|
||||
*/
|
||||
private void showAddImageToWikipediaInstructions(Contribution contribution) {
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
WikipediaInstructionsDialogFragment fragment = WikipediaInstructionsDialogFragment
|
||||
.newInstance(contribution);
|
||||
fragment.setCallback(this::onConfirmClicked);
|
||||
fragment.show(fragmentManager, "WikimediaFragment");
|
||||
private fun showAddImageToWikipediaInstructions(contribution: Contribution) {
|
||||
val fragmentManager = fragmentManager
|
||||
val fragment = newInstance(contribution)
|
||||
fragment.callback =
|
||||
WikipediaInstructionsDialogFragment.Callback { contribution: Contribution?, copyWikicode: Boolean ->
|
||||
this.onConfirmClicked(
|
||||
contribution,
|
||||
copyWikicode
|
||||
)
|
||||
}
|
||||
fragment.show(fragmentManager!!, "WikimediaFragment")
|
||||
}
|
||||
|
||||
|
||||
public Media getMediaAtPosition(final int i) {
|
||||
if (adapter.getContributionForPosition(i) != null) {
|
||||
return adapter.getContributionForPosition(i).getMedia();
|
||||
fun getMediaAtPosition(i: Int): Media? {
|
||||
if (adapter!!.getContributionForPosition(i) != null) {
|
||||
return adapter!!.getContributionForPosition(i)!!.media
|
||||
}
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
public int getTotalMediaCount() {
|
||||
return contributionsSize;
|
||||
}
|
||||
val totalMediaCount: Int
|
||||
get() = contributionsSize
|
||||
|
||||
/**
|
||||
* Open the editor for the language Wikipedia
|
||||
*
|
||||
* @param contribution
|
||||
*/
|
||||
@Override
|
||||
public void onConfirmClicked(@Nullable Contribution contribution, boolean copyWikicode) {
|
||||
override fun onConfirmClicked(contribution: Contribution?, copyWikicode: Boolean) {
|
||||
if (copyWikicode) {
|
||||
String wikicode = contribution.getMedia().getWikiCode();
|
||||
Utils.copy("wikicode", wikicode, getContext());
|
||||
val wikicode = contribution!!.media.wikiCode
|
||||
Utils.copy("wikicode", wikicode, context)
|
||||
}
|
||||
|
||||
final String url =
|
||||
languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace()
|
||||
.getWikipediaPageTitle();
|
||||
Utils.handleWebUrl(getContext(), Uri.parse(url));
|
||||
val url =
|
||||
languageWikipediaSite!!.mobileUrl() + "/wiki/" + (contribution!!.wikidataPlace
|
||||
?.getWikipediaPageTitle())
|
||||
Utils.handleWebUrl(context, Uri.parse(url))
|
||||
}
|
||||
|
||||
public Integer getContributionStateAt(int position) {
|
||||
return adapter.getContributionForPosition(position).getState();
|
||||
fun getContributionStateAt(position: Int): Int {
|
||||
return adapter!!.getContributionForPosition(position)!!.state
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
interface Callback {
|
||||
fun notifyDataSetChanged()
|
||||
|
||||
void notifyDataSetChanged();
|
||||
|
||||
void showDetail(int position, boolean isWikipediaButtonDisplayed);
|
||||
fun showDetail(position: Int, isWikipediaButtonDisplayed: Boolean)
|
||||
|
||||
// Notify the viewpager that number of items have changed.
|
||||
void viewPagerNotifyDataSetChanged();
|
||||
fun viewPagerNotifyDataSetChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val RV_STATE = "rv_scroll_state"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,30 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.paging.DataSource;
|
||||
import androidx.paging.DataSource.Factory;
|
||||
import androidx.paging.LivePagedListBuilder;
|
||||
import androidx.paging.PagedList;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import fr.free.nrw.commons.contributions.ContributionsListContract.UserActionListener;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import java.util.Collections;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.paging.DataSource
|
||||
import androidx.paging.LivePagedListBuilder
|
||||
import androidx.paging.PagedList
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||
import io.reactivex.Scheduler
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* The presenter class for Contributions
|
||||
*/
|
||||
public class ContributionsListPresenter implements UserActionListener {
|
||||
class ContributionsListPresenter @Inject internal constructor(
|
||||
private val contributionBoundaryCallback: ContributionBoundaryCallback,
|
||||
private val contributionsRemoteDataSource: ContributionsRemoteDataSource,
|
||||
private val repository: ContributionsRepository,
|
||||
@param:Named(CommonsApplicationModule.IO_THREAD) private val ioThreadScheduler: Scheduler
|
||||
) : ContributionsListContract.UserActionListener {
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
private final ContributionBoundaryCallback contributionBoundaryCallback;
|
||||
private final ContributionsRepository repository;
|
||||
private final Scheduler ioThreadScheduler;
|
||||
var contributionList: LiveData<PagedList<Contribution>>? = null
|
||||
|
||||
private final CompositeDisposable compositeDisposable;
|
||||
private final ContributionsRemoteDataSource contributionsRemoteDataSource;
|
||||
|
||||
LiveData<PagedList<Contribution>> contributionList;
|
||||
|
||||
@Inject
|
||||
ContributionsListPresenter(
|
||||
final ContributionBoundaryCallback contributionBoundaryCallback,
|
||||
final ContributionsRemoteDataSource contributionsRemoteDataSource,
|
||||
final ContributionsRepository repository,
|
||||
@Named(IO_THREAD) final Scheduler ioThreadScheduler) {
|
||||
this.contributionBoundaryCallback = contributionBoundaryCallback;
|
||||
this.repository = repository;
|
||||
this.ioThreadScheduler = ioThreadScheduler;
|
||||
this.contributionsRemoteDataSource = contributionsRemoteDataSource;
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachView(final ContributionsListContract.View view) {
|
||||
override fun onAttachView(view: ContributionsListContract.View) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -54,46 +32,46 @@ public class ContributionsListPresenter implements UserActionListener {
|
|||
* the live data object. This method can be tweaked to update the lazy loading behavior of the
|
||||
* contributions list
|
||||
*/
|
||||
void setup(String userName, boolean isSelf) {
|
||||
final PagedList.Config pagedListConfig =
|
||||
(new PagedList.Config.Builder())
|
||||
fun setup(userName: String?, isSelf: Boolean) {
|
||||
val pagedListConfig =
|
||||
(PagedList.Config.Builder())
|
||||
.setPrefetchDistance(50)
|
||||
.setPageSize(10).build();
|
||||
Factory<Integer, Contribution> factory;
|
||||
boolean shouldSetBoundaryCallback;
|
||||
.setPageSize(10).build()
|
||||
val factory: DataSource.Factory<Int, Contribution>
|
||||
val shouldSetBoundaryCallback: Boolean
|
||||
if (!isSelf) {
|
||||
//We don't want to persist contributions for other user's, therefore
|
||||
// creating a new DataSource for them
|
||||
contributionsRemoteDataSource.setUserName(userName);
|
||||
factory = new Factory<Integer, Contribution>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public DataSource<Integer, Contribution> create() {
|
||||
return contributionsRemoteDataSource;
|
||||
contributionsRemoteDataSource.userName = userName
|
||||
factory = object : DataSource.Factory<Int, Contribution>() {
|
||||
override fun create(): DataSource<Int, Contribution> {
|
||||
return contributionsRemoteDataSource
|
||||
}
|
||||
};
|
||||
shouldSetBoundaryCallback = false;
|
||||
}
|
||||
shouldSetBoundaryCallback = false
|
||||
} else {
|
||||
contributionBoundaryCallback.setUserName(userName);
|
||||
shouldSetBoundaryCallback = true;
|
||||
contributionBoundaryCallback.userName = userName
|
||||
shouldSetBoundaryCallback = true
|
||||
factory = repository.fetchContributionsWithStates(
|
||||
Collections.singletonList(Contribution.STATE_COMPLETED));
|
||||
listOf(Contribution.STATE_COMPLETED)
|
||||
)
|
||||
}
|
||||
|
||||
LivePagedListBuilder livePagedListBuilder = new LivePagedListBuilder(factory,
|
||||
pagedListConfig);
|
||||
val livePagedListBuilder: LivePagedListBuilder<Int, Contribution> = LivePagedListBuilder(
|
||||
factory,
|
||||
pagedListConfig
|
||||
)
|
||||
if (shouldSetBoundaryCallback) {
|
||||
livePagedListBuilder.setBoundaryCallback(contributionBoundaryCallback);
|
||||
livePagedListBuilder.setBoundaryCallback(contributionBoundaryCallback)
|
||||
}
|
||||
|
||||
contributionList = livePagedListBuilder.build();
|
||||
contributionList = livePagedListBuilder.build()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachView() {
|
||||
compositeDisposable.clear();
|
||||
contributionsRemoteDataSource.dispose();
|
||||
contributionBoundaryCallback.dispose();
|
||||
override fun onDetachView() {
|
||||
compositeDisposable.clear()
|
||||
contributionsRemoteDataSource.dispose()
|
||||
contributionBoundaryCallback.dispose()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -102,11 +80,12 @@ public class ContributionsListPresenter implements UserActionListener {
|
|||
* @param swipeRefreshLayout used to stop refresh animation when
|
||||
* refresh finishes.
|
||||
*/
|
||||
@Override
|
||||
public void refreshList(final SwipeRefreshLayout swipeRefreshLayout) {
|
||||
contributionBoundaryCallback.refreshList(() -> {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
override fun refreshList(swipeRefreshLayout: SwipeRefreshLayout?) {
|
||||
contributionBoundaryCallback.refreshList {
|
||||
if (swipeRefreshLayout != null) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,31 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import androidx.paging.DataSource.Factory;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Single;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import androidx.paging.DataSource
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* The LocalDataSource class for Contributions
|
||||
*/
|
||||
class ContributionsLocalDataSource {
|
||||
|
||||
private final ContributionDao contributionDao;
|
||||
private final JsonKvStore defaultKVStore;
|
||||
|
||||
@Inject
|
||||
public ContributionsLocalDataSource(
|
||||
@Named("default_preferences") final JsonKvStore defaultKVStore,
|
||||
final ContributionDao contributionDao) {
|
||||
this.defaultKVStore = defaultKVStore;
|
||||
this.contributionDao = contributionDao;
|
||||
class ContributionsLocalDataSource @Inject constructor(
|
||||
@param:Named("default_preferences") private val defaultKVStore: JsonKvStore,
|
||||
private val contributionDao: ContributionDao
|
||||
) {
|
||||
/**
|
||||
* Fetch default number of contributions to be show, based on user preferences
|
||||
*/
|
||||
fun getString(key: String): String? {
|
||||
return defaultKVStore.getString(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch default number of contributions to be show, based on user preferences
|
||||
*/
|
||||
public String getString(final String key) {
|
||||
return defaultKVStore.getString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch default number of contributions to be show, based on user preferences
|
||||
*/
|
||||
public long getLong(final String key) {
|
||||
return defaultKVStore.getLong(key);
|
||||
fun getLong(key: String): Long {
|
||||
return defaultKVStore.getLong(key)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,13 +34,14 @@ class ContributionsLocalDataSource {
|
|||
* @param uri
|
||||
* @return
|
||||
*/
|
||||
public Contribution getContributionWithFileName(final String uri) {
|
||||
final List<Contribution> contributionWithUri = contributionDao.getContributionWithTitle(
|
||||
uri);
|
||||
fun getContributionWithFileName(uri: String): Contribution? {
|
||||
val contributionWithUri = contributionDao.getContributionWithTitle(
|
||||
uri
|
||||
)
|
||||
if (!contributionWithUri.isEmpty()) {
|
||||
return contributionWithUri.get(0);
|
||||
return contributionWithUri[0]
|
||||
}
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -60,8 +50,8 @@ class ContributionsLocalDataSource {
|
|||
* @param contribution
|
||||
* @return
|
||||
*/
|
||||
public Completable deleteContribution(final Contribution contribution) {
|
||||
return contributionDao.delete(contribution);
|
||||
fun deleteContribution(contribution: Contribution): Completable {
|
||||
return contributionDao.delete(contribution)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -70,13 +60,12 @@ class ContributionsLocalDataSource {
|
|||
* @param states The states of the contributions to delete.
|
||||
* @return A Completable indicating the result of the operation.
|
||||
*/
|
||||
public Completable deleteContributionsWithStates(List<Integer> states) {
|
||||
return contributionDao.deleteContributionsWithStates(states);
|
||||
fun deleteContributionsWithStates(states: List<Int>): Completable {
|
||||
return contributionDao.deleteContributionsWithStates(states)
|
||||
}
|
||||
|
||||
public Factory<Integer, Contribution> getContributions() {
|
||||
return contributionDao.fetchContributions();
|
||||
}
|
||||
val contributions: DataSource.Factory<Int, Contribution>
|
||||
get() = contributionDao.fetchContributions()
|
||||
|
||||
/**
|
||||
* Fetches contributions with specific states.
|
||||
|
|
@ -84,8 +73,8 @@ class ContributionsLocalDataSource {
|
|||
* @param states The states of the contributions to fetch.
|
||||
* @return A DataSource factory for paginated contributions with the specified states.
|
||||
*/
|
||||
public Factory<Integer, Contribution> getContributionsWithStates(List<Integer> states) {
|
||||
return contributionDao.getContributions(states);
|
||||
fun getContributionsWithStates(states: List<Int>): DataSource.Factory<Int, Contribution> {
|
||||
return contributionDao.getContributions(states)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,37 +84,39 @@ class ContributionsLocalDataSource {
|
|||
* @return A DataSource factory for paginated contributions with the specified states sorted by
|
||||
* date upload started.
|
||||
*/
|
||||
public Factory<Integer, Contribution> getContributionsWithStatesSortedByDateUploadStarted(
|
||||
List<Integer> states) {
|
||||
return contributionDao.getContributionsSortedByDateUploadStarted(states);
|
||||
fun getContributionsWithStatesSortedByDateUploadStarted(
|
||||
states: List<Int>
|
||||
): DataSource.Factory<Int, Contribution> {
|
||||
return contributionDao.getContributionsSortedByDateUploadStarted(states)
|
||||
}
|
||||
|
||||
public Single<List<Long>> saveContributions(final List<Contribution> contributions) {
|
||||
final List<Contribution> contributionList = new ArrayList<>();
|
||||
for (final Contribution contribution : contributions) {
|
||||
final Contribution oldContribution = contributionDao.getContribution(
|
||||
contribution.getPageId());
|
||||
fun saveContributions(contributions: List<Contribution>): Single<List<Long>> {
|
||||
val contributionList: MutableList<Contribution> = ArrayList()
|
||||
for (contribution in contributions) {
|
||||
val oldContribution = contributionDao.getContribution(
|
||||
contribution.pageId
|
||||
)
|
||||
if (oldContribution != null) {
|
||||
contribution.setWikidataPlace(oldContribution.getWikidataPlace());
|
||||
contribution.wikidataPlace = oldContribution.wikidataPlace
|
||||
}
|
||||
contributionList.add(contribution);
|
||||
contributionList.add(contribution)
|
||||
}
|
||||
return contributionDao.save(contributionList);
|
||||
return contributionDao.save(contributionList)
|
||||
}
|
||||
|
||||
public Completable saveContributions(Contribution contribution) {
|
||||
return contributionDao.save(contribution);
|
||||
fun saveContributions(contribution: Contribution): Completable {
|
||||
return contributionDao.save(contribution)
|
||||
}
|
||||
|
||||
public void set(final String key, final long value) {
|
||||
defaultKVStore.putLong(key, value);
|
||||
fun set(key: String, value: Long) {
|
||||
defaultKVStore.putLong(key, value)
|
||||
}
|
||||
|
||||
public Completable updateContribution(final Contribution contribution) {
|
||||
return contributionDao.update(contribution);
|
||||
fun updateContribution(contribution: Contribution): Completable {
|
||||
return contributionDao.update(contribution)
|
||||
}
|
||||
|
||||
public Completable updateContributionsWithStates(List<Integer> states, int newState) {
|
||||
return contributionDao.updateContributionsWithStates(states, newState);
|
||||
fun updateContributionsWithStates(states: List<Int>, newState: Int): Completable {
|
||||
return contributionDao.updateContributionsWithStates(states, newState)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,16 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import javax.inject.Named;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
||||
/**
|
||||
* The Dagger Module for contributions-related presenters and other dependencies
|
||||
*/
|
||||
@Module
|
||||
public abstract class ContributionsModule {
|
||||
abstract class ContributionsModule {
|
||||
|
||||
@Binds
|
||||
public abstract ContributionsContract.UserActionListener bindsContributionsPresenter(
|
||||
ContributionsPresenter presenter
|
||||
);
|
||||
|
||||
@Provides
|
||||
static JsonKvStore providesApplicationKvStore(
|
||||
@Named("default_preferences") JsonKvStore kvStore
|
||||
) {
|
||||
return kvStore;
|
||||
}
|
||||
}
|
||||
abstract fun bindsContributionsPresenter(
|
||||
presenter: ContributionsPresenter?
|
||||
): ContributionsContract.UserActionListener?
|
||||
}
|
||||
|
|
@ -1,58 +1,45 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import static fr.free.nrw.commons.di.CommonsApplicationModule.IO_THREAD;
|
||||
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
|
||||
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import fr.free.nrw.commons.MediaDataExtractor;
|
||||
import fr.free.nrw.commons.contributions.ContributionsContract.UserActionListener;
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
||||
import fr.free.nrw.commons.repository.UploadRepository;
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
import fr.free.nrw.commons.utils.ImageUtils
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import fr.free.nrw.commons.MediaDataExtractor
|
||||
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||
import fr.free.nrw.commons.repository.UploadRepository
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest
|
||||
import io.reactivex.Scheduler
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* The presenter class for Contributions
|
||||
*/
|
||||
public class ContributionsPresenter implements UserActionListener {
|
||||
|
||||
private final ContributionsRepository contributionsRepository;
|
||||
private final UploadRepository uploadRepository;
|
||||
private final Scheduler ioThreadScheduler;
|
||||
private CompositeDisposable compositeDisposable;
|
||||
private ContributionsContract.View view;
|
||||
class ContributionsPresenter @Inject internal constructor(
|
||||
private val contributionsRepository: ContributionsRepository,
|
||||
private val uploadRepository: UploadRepository,
|
||||
@param:Named(CommonsApplicationModule.IO_THREAD) private val ioThreadScheduler: Scheduler
|
||||
) : ContributionsContract.UserActionListener {
|
||||
private var compositeDisposable: CompositeDisposable? = null
|
||||
private var view: ContributionsContract.View? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
MediaDataExtractor mediaDataExtractor;
|
||||
var mediaDataExtractor: MediaDataExtractor? = null
|
||||
|
||||
@Inject
|
||||
ContributionsPresenter(ContributionsRepository repository,
|
||||
UploadRepository uploadRepository,
|
||||
@Named(IO_THREAD) Scheduler ioThreadScheduler) {
|
||||
this.contributionsRepository = repository;
|
||||
this.uploadRepository = uploadRepository;
|
||||
this.ioThreadScheduler = ioThreadScheduler;
|
||||
override fun onAttachView(view: ContributionsContract.View) {
|
||||
this.view = view
|
||||
compositeDisposable = CompositeDisposable()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachView(ContributionsContract.View view) {
|
||||
this.view = view;
|
||||
compositeDisposable = new CompositeDisposable();
|
||||
override fun onDetachView() {
|
||||
this.view = null
|
||||
compositeDisposable!!.clear()
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachView() {
|
||||
this.view = null;
|
||||
compositeDisposable.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contribution getContributionsWithTitle(String title) {
|
||||
return contributionsRepository.getContributionWithFileName(title);
|
||||
override fun getContributionsWithTitle(title: String): Contribution {
|
||||
return contributionsRepository.getContributionWithFileName(title)
|
||||
?: throw IllegalArgumentException("Contribution not found for title: $title")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -60,22 +47,25 @@ public class ContributionsPresenter implements UserActionListener {
|
|||
*
|
||||
* @param contribution The contribution to check and potentially restart.
|
||||
*/
|
||||
public void checkDuplicateImageAndRestartContribution(Contribution contribution) {
|
||||
compositeDisposable.add(uploadRepository
|
||||
.checkDuplicateImage(contribution.getLocalUriPath().getPath())
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe(imageCheckResult -> {
|
||||
if (imageCheckResult == IMAGE_OK) {
|
||||
contribution.setState(Contribution.STATE_QUEUED);
|
||||
saveContribution(contribution);
|
||||
} else {
|
||||
Timber.e("Contribution already exists");
|
||||
compositeDisposable.add(contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
}));
|
||||
fun checkDuplicateImageAndRestartContribution(contribution: Contribution) {
|
||||
compositeDisposable!!.add(
|
||||
uploadRepository
|
||||
.checkDuplicateImage(contribution.localUriPath!!.path)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe { imageCheckResult: Int ->
|
||||
if (imageCheckResult == ImageUtils.IMAGE_OK) {
|
||||
contribution.state = Contribution.STATE_QUEUED
|
||||
saveContribution(contribution)
|
||||
} else {
|
||||
Timber.e("Contribution already exists")
|
||||
compositeDisposable!!.add(
|
||||
contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe()
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,11 +74,14 @@ public class ContributionsPresenter implements UserActionListener {
|
|||
*
|
||||
* @param contribution
|
||||
*/
|
||||
public void saveContribution(Contribution contribution) {
|
||||
compositeDisposable.add(contributionsRepository
|
||||
fun saveContribution(contribution: Contribution) {
|
||||
compositeDisposable!!.add(contributionsRepository
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest(
|
||||
view.getContext().getApplicationContext(), ExistingWorkPolicy.KEEP)));
|
||||
.subscribe {
|
||||
makeOneTimeWorkRequest(
|
||||
view!!.getContext().applicationContext, ExistingWorkPolicy.KEEP
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.wikidata.model.WikiSite
|
||||
import javax.inject.Named
|
||||
|
||||
/**
|
||||
* The Dagger Module for contributions-related providers
|
||||
*/
|
||||
@Module
|
||||
class ContributionsProvidesModule {
|
||||
|
||||
@Provides
|
||||
fun providesApplicationKvStore(
|
||||
@Named("default_preferences") kvStore: JsonKvStore
|
||||
): JsonKvStore {
|
||||
return kvStore
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun providesLanguageWikipediaSite(
|
||||
@Named("language-wikipedia-wikisite") languageWikipediaSite: WikiSite
|
||||
): WikiSite {
|
||||
return languageWikipediaSite
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +1,19 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import androidx.paging.DataSource.Factory;
|
||||
import io.reactivex.Completable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import androidx.paging.DataSource
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The repository class for contributions
|
||||
*/
|
||||
public class ContributionsRepository {
|
||||
|
||||
private ContributionsLocalDataSource localDataSource;
|
||||
|
||||
@Inject
|
||||
public ContributionsRepository(ContributionsLocalDataSource localDataSource) {
|
||||
this.localDataSource = localDataSource;
|
||||
}
|
||||
|
||||
class ContributionsRepository @Inject constructor(private val localDataSource: ContributionsLocalDataSource) {
|
||||
/**
|
||||
* Fetch default number of contributions to be show, based on user preferences
|
||||
*/
|
||||
public String getString(String key) {
|
||||
return localDataSource.getString(key);
|
||||
fun getString(key: String): String? {
|
||||
return localDataSource.getString(key)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -33,8 +22,8 @@ public class ContributionsRepository {
|
|||
* @param contribution
|
||||
* @return
|
||||
*/
|
||||
public Completable deleteContributionFromDB(Contribution contribution) {
|
||||
return localDataSource.deleteContribution(contribution);
|
||||
fun deleteContributionFromDB(contribution: Contribution): Completable {
|
||||
return localDataSource.deleteContribution(contribution)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -43,8 +32,8 @@ public class ContributionsRepository {
|
|||
* @param states The states of the contributions to delete.
|
||||
* @return A Completable indicating the result of the operation.
|
||||
*/
|
||||
public Completable deleteContributionsFromDBWithStates(List<Integer> states) {
|
||||
return localDataSource.deleteContributionsWithStates(states);
|
||||
fun deleteContributionsFromDBWithStates(states: List<Int>): Completable {
|
||||
return localDataSource.deleteContributionsWithStates(states)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -53,12 +42,12 @@ public class ContributionsRepository {
|
|||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public Contribution getContributionWithFileName(String fileName) {
|
||||
return localDataSource.getContributionWithFileName(fileName);
|
||||
fun getContributionWithFileName(fileName: String): Contribution? {
|
||||
return localDataSource.getContributionWithFileName(fileName)
|
||||
}
|
||||
|
||||
public Factory<Integer, Contribution> fetchContributions() {
|
||||
return localDataSource.getContributions();
|
||||
fun fetchContributions(): DataSource.Factory<Int, Contribution> {
|
||||
return localDataSource.contributions
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,8 +56,8 @@ public class ContributionsRepository {
|
|||
* @param states The states of the contributions to fetch.
|
||||
* @return A DataSource factory for paginated contributions with the specified states.
|
||||
*/
|
||||
public Factory<Integer, Contribution> fetchContributionsWithStates(List<Integer> states) {
|
||||
return localDataSource.getContributionsWithStates(states);
|
||||
fun fetchContributionsWithStates(states: List<Int>): DataSource.Factory<Int, Contribution> {
|
||||
return localDataSource.getContributionsWithStates(states)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -78,25 +67,26 @@ public class ContributionsRepository {
|
|||
* @return A DataSource factory for paginated contributions with the specified states sorted by
|
||||
* date upload started.
|
||||
*/
|
||||
public Factory<Integer, Contribution> fetchContributionsWithStatesSortedByDateUploadStarted(
|
||||
List<Integer> states) {
|
||||
return localDataSource.getContributionsWithStatesSortedByDateUploadStarted(states);
|
||||
fun fetchContributionsWithStatesSortedByDateUploadStarted(
|
||||
states: List<Int>
|
||||
): DataSource.Factory<Int, Contribution> {
|
||||
return localDataSource.getContributionsWithStatesSortedByDateUploadStarted(states)
|
||||
}
|
||||
|
||||
public Single<List<Long>> save(List<Contribution> contributions) {
|
||||
return localDataSource.saveContributions(contributions);
|
||||
fun save(contributions: List<Contribution>): Single<List<Long>> {
|
||||
return localDataSource.saveContributions(contributions)
|
||||
}
|
||||
|
||||
public Completable save(Contribution contributions) {
|
||||
return localDataSource.saveContributions(contributions);
|
||||
fun save(contributions: Contribution): Completable {
|
||||
return localDataSource.saveContributions(contributions)
|
||||
}
|
||||
|
||||
public void set(String key, long value) {
|
||||
localDataSource.set(key, value);
|
||||
operator fun set(key: String, value: Long) {
|
||||
localDataSource.set(key, value)
|
||||
}
|
||||
|
||||
public Completable updateContribution(Contribution contribution) {
|
||||
return localDataSource.updateContribution(contribution);
|
||||
fun updateContribution(contribution: Contribution): Completable {
|
||||
return localDataSource.updateContribution(contribution)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +96,7 @@ public class ContributionsRepository {
|
|||
* @param newState The new state to set.
|
||||
* @return A Completable indicating the result of the operation.
|
||||
*/
|
||||
public Completable updateContributionsWithStates(List<Integer> states, int newState) {
|
||||
return localDataSource.updateContributionsWithStates(states, newState);
|
||||
fun updateContributionsWithStates(states: List<Int>, newState: Int): Completable {
|
||||
return localDataSource.updateContributionsWithStates(states, newState)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,159 +1,156 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.work.ExistingWorkPolicy;
|
||||
import fr.free.nrw.commons.databinding.MainBinding;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.WelcomeActivity;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.bookmarks.BookmarkFragment;
|
||||
import fr.free.nrw.commons.explore.ExploreFragment;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||
import fr.free.nrw.commons.navtab.MoreBottomSheetFragment;
|
||||
import fr.free.nrw.commons.navtab.MoreBottomSheetLoggedOutFragment;
|
||||
import fr.free.nrw.commons.navtab.NavTab;
|
||||
import fr.free.nrw.commons.navtab.NavTabLayout;
|
||||
import fr.free.nrw.commons.navtab.NavTabLoggedOut;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment;
|
||||
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment.NearbyParentFragmentInstanceReadyCallback;
|
||||
import fr.free.nrw.commons.notification.NotificationActivity;
|
||||
import fr.free.nrw.commons.notification.NotificationController;
|
||||
import fr.free.nrw.commons.quiz.QuizChecker;
|
||||
import fr.free.nrw.commons.settings.SettingsFragment;
|
||||
import fr.free.nrw.commons.theme.BaseActivity;
|
||||
import fr.free.nrw.commons.upload.UploadProgressActivity;
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper;
|
||||
import fr.free.nrw.commons.utils.PermissionUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import timber.log.Timber;
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.WelcomeActivity
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.bookmarks.BookmarkFragment
|
||||
import fr.free.nrw.commons.contributions.ContributionsFragment.Companion.newInstance
|
||||
import fr.free.nrw.commons.databinding.MainBinding
|
||||
import fr.free.nrw.commons.explore.ExploreFragment
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.location.LocationServiceManager
|
||||
import fr.free.nrw.commons.media.MediaDetailPagerFragment
|
||||
import fr.free.nrw.commons.navtab.MoreBottomSheetFragment
|
||||
import fr.free.nrw.commons.navtab.MoreBottomSheetLoggedOutFragment
|
||||
import fr.free.nrw.commons.navtab.NavTab
|
||||
import fr.free.nrw.commons.navtab.NavTabLayout
|
||||
import fr.free.nrw.commons.navtab.NavTabLoggedOut
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment
|
||||
import fr.free.nrw.commons.notification.NotificationActivity.Companion.startYourself
|
||||
import fr.free.nrw.commons.notification.NotificationController
|
||||
import fr.free.nrw.commons.quiz.QuizChecker
|
||||
import fr.free.nrw.commons.settings.SettingsFragment
|
||||
import fr.free.nrw.commons.theme.BaseActivity
|
||||
import fr.free.nrw.commons.upload.UploadProgressActivity
|
||||
import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest
|
||||
import fr.free.nrw.commons.utils.ViewUtilWrapper
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import java.util.Calendar
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
public class MainActivity extends BaseActivity
|
||||
implements FragmentManager.OnBackStackChangedListener {
|
||||
|
||||
class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener {
|
||||
@JvmField
|
||||
@Inject
|
||||
SessionManager sessionManager;
|
||||
@Inject
|
||||
ContributionController controller;
|
||||
@Inject
|
||||
ContributionDao contributionDao;
|
||||
var sessionManager: SessionManager? = null
|
||||
|
||||
private ContributionsFragment contributionsFragment;
|
||||
private NearbyParentFragment nearbyParentFragment;
|
||||
private ExploreFragment exploreFragment;
|
||||
private BookmarkFragment bookmarkFragment;
|
||||
public ActiveFragment activeFragment;
|
||||
private MediaDetailPagerFragment mediaDetailPagerFragment;
|
||||
private NavTabLayout.OnNavigationItemSelectedListener navListener;
|
||||
@JvmField
|
||||
@Inject
|
||||
var controller: ContributionController? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
public LocationServiceManager locationManager;
|
||||
var contributionDao: ContributionDao? = null
|
||||
|
||||
private var contributionsFragment: ContributionsFragment? = null
|
||||
private var nearbyParentFragment: NearbyParentFragment? = null
|
||||
private var exploreFragment: ExploreFragment? = null
|
||||
private var bookmarkFragment: BookmarkFragment? = null
|
||||
@JvmField
|
||||
var activeFragment: ActiveFragment? = null
|
||||
private val mediaDetailPagerFragment: MediaDetailPagerFragment? = null
|
||||
var navListener: BottomNavigationView.OnNavigationItemSelectedListener? = null
|
||||
private set
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
NotificationController notificationController;
|
||||
var locationManager: LocationServiceManager? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
QuizChecker quizChecker;
|
||||
var notificationController: NotificationController? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
var quizChecker: QuizChecker? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
@Named("default_preferences")
|
||||
public
|
||||
JsonKvStore applicationKvStore;
|
||||
var applicationKvStore: JsonKvStore? = null
|
||||
|
||||
@JvmField
|
||||
@Inject
|
||||
ViewUtilWrapper viewUtilWrapper;
|
||||
var viewUtilWrapper: ViewUtilWrapper? = null
|
||||
|
||||
public Menu menu;
|
||||
var menu: Menu? = null
|
||||
|
||||
public MainBinding binding;
|
||||
@JvmField
|
||||
var binding: MainBinding? = null
|
||||
|
||||
NavTabLayout tabLayout;
|
||||
var tabLayout: NavTabLayout? = null
|
||||
|
||||
|
||||
/**
|
||||
* Consumers should be simply using this method to use this activity.
|
||||
*
|
||||
* @param context A Context of the application package implementing this class.
|
||||
*/
|
||||
public static void startYourself(Context context) {
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
if (activeFragment == ActiveFragment.CONTRIBUTIONS) {
|
||||
if (!contributionsFragment.backButtonClicked()) {
|
||||
return false;
|
||||
if (!contributionsFragment!!.backButtonClicked()) {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
onBackPressed();
|
||||
showTabs();
|
||||
onBackPressed()
|
||||
showTabs()
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = MainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
setSupportActionBar(binding.toolbarBinding.toolbar);
|
||||
tabLayout = binding.fragmentMainNavTabLayout;
|
||||
loadLocale();
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = MainBinding.inflate(layoutInflater)
|
||||
setContentView(binding!!.root)
|
||||
setSupportActionBar(binding!!.toolbarBinding.toolbar)
|
||||
tabLayout = binding!!.fragmentMainNavTabLayout
|
||||
loadLocale()
|
||||
|
||||
binding.toolbarBinding.toolbar.setNavigationOnClickListener(view -> {
|
||||
onSupportNavigateUp();
|
||||
});
|
||||
binding!!.toolbarBinding.toolbar.setNavigationOnClickListener { view: View? ->
|
||||
onSupportNavigateUp()
|
||||
}
|
||||
/*
|
||||
"first_edit_depict" is a key for getting information about opening the depiction editor
|
||||
screen for the first time after opening the app.
|
||||
"first_edit_depict" is a key for getting information about opening the depiction editor
|
||||
screen for the first time after opening the app.
|
||||
|
||||
Getting true by the key means the depiction editor screen is opened for the first time
|
||||
after opening the app.
|
||||
Getting false by the key means the depiction editor screen is not opened for the first time
|
||||
after opening the app.
|
||||
*/
|
||||
applicationKvStore.putBoolean("first_edit_depict", true);
|
||||
if (applicationKvStore.getBoolean("login_skipped") == true) {
|
||||
setTitle(getString(R.string.navigation_item_explore));
|
||||
setUpLoggedOutPager();
|
||||
Getting true by the key means the depiction editor screen is opened for the first time
|
||||
after opening the app.
|
||||
Getting false by the key means the depiction editor screen is not opened for the first time
|
||||
after opening the app.
|
||||
*/
|
||||
applicationKvStore!!.putBoolean("first_edit_depict", true)
|
||||
if (applicationKvStore!!.getBoolean("login_skipped") == true) {
|
||||
title = getString(R.string.navigation_item_explore)
|
||||
setUpLoggedOutPager()
|
||||
} else {
|
||||
if (applicationKvStore.getBoolean("firstrun", true)) {
|
||||
applicationKvStore.putBoolean("hasAlreadyLaunchedBigMultiupload", false);
|
||||
applicationKvStore.putBoolean("hasAlreadyLaunchedCategoriesDialog", false);
|
||||
if (applicationKvStore!!.getBoolean("firstrun", true)) {
|
||||
applicationKvStore!!.putBoolean("hasAlreadyLaunchedBigMultiupload", false)
|
||||
applicationKvStore!!.putBoolean("hasAlreadyLaunchedCategoriesDialog", false)
|
||||
}
|
||||
if (savedInstanceState == null) {
|
||||
//starting a fresh fragment.
|
||||
// Open Last opened screen if it is Contributions or Nearby, otherwise Contributions
|
||||
if (applicationKvStore.getBoolean("last_opened_nearby")) {
|
||||
setTitle(getString(R.string.nearby_fragment));
|
||||
showNearby();
|
||||
loadFragment(NearbyParentFragment.newInstance(), false);
|
||||
if (applicationKvStore!!.getBoolean("last_opened_nearby")) {
|
||||
title = getString(R.string.nearby_fragment)
|
||||
showNearby()
|
||||
loadFragment(NearbyParentFragment.newInstance(), false)
|
||||
} else {
|
||||
setTitle(getString(R.string.contributions_fragment));
|
||||
loadFragment(ContributionsFragment.newInstance(), false);
|
||||
title = getString(R.string.contributions_fragment)
|
||||
loadFragment(newInstance(), false)
|
||||
}
|
||||
}
|
||||
setUpPager();
|
||||
setUpPager()
|
||||
/**
|
||||
* Ask the user for media location access just after login
|
||||
* so that location in the EXIF metadata of the images shared by the user
|
||||
|
|
@ -169,99 +166,107 @@ public class MainActivity extends BaseActivity
|
|||
// R.string.add_location_manually,
|
||||
// permission.ACCESS_MEDIA_LOCATION);
|
||||
// }
|
||||
checkAndResumeStuckUploads();
|
||||
checkAndResumeStuckUploads()
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedItemId(int id) {
|
||||
binding.fragmentMainNavTabLayout.setSelectedItemId(id);
|
||||
fun setSelectedItemId(id: Int) {
|
||||
binding!!.fragmentMainNavTabLayout.selectedItemId = id
|
||||
}
|
||||
|
||||
private void setUpPager() {
|
||||
binding.fragmentMainNavTabLayout.setOnNavigationItemSelectedListener(
|
||||
navListener = (item) -> {
|
||||
if (!item.getTitle().equals(getString(R.string.more))) {
|
||||
private fun setUpPager() {
|
||||
binding!!.fragmentMainNavTabLayout.setOnNavigationItemSelectedListener(
|
||||
BottomNavigationView.OnNavigationItemSelectedListener { item: MenuItem ->
|
||||
if (item.title != getString(R.string.more)) {
|
||||
// do not change title for more fragment
|
||||
setTitle(item.getTitle());
|
||||
title = item.title
|
||||
}
|
||||
// set last_opened_nearby true if item is nearby screen else set false
|
||||
applicationKvStore.putBoolean("last_opened_nearby",
|
||||
item.getTitle().equals(getString(R.string.nearby_fragment)));
|
||||
final Fragment fragment = NavTab.of(item.getOrder()).newInstance();
|
||||
return loadFragment(fragment, true);
|
||||
});
|
||||
applicationKvStore!!.putBoolean(
|
||||
"last_opened_nearby",
|
||||
item.title == getString(R.string.nearby_fragment)
|
||||
)
|
||||
val fragment = NavTab.of(item.order).newInstance()
|
||||
loadFragment(fragment, true)
|
||||
}.also { navListener = it })
|
||||
}
|
||||
|
||||
private void setUpLoggedOutPager() {
|
||||
loadFragment(ExploreFragment.newInstance(), false);
|
||||
binding.fragmentMainNavTabLayout.setOnNavigationItemSelectedListener(item -> {
|
||||
if (!item.getTitle().equals(getString(R.string.more))) {
|
||||
private fun setUpLoggedOutPager() {
|
||||
loadFragment(ExploreFragment.newInstance(), false)
|
||||
binding!!.fragmentMainNavTabLayout.setOnNavigationItemSelectedListener { item: MenuItem ->
|
||||
if (item.title != getString(R.string.more)) {
|
||||
// do not change title for more fragment
|
||||
setTitle(item.getTitle());
|
||||
title = item.title
|
||||
}
|
||||
Fragment fragment = NavTabLoggedOut.of(item.getOrder()).newInstance();
|
||||
return loadFragment(fragment, true);
|
||||
});
|
||||
val fragment =
|
||||
NavTabLoggedOut.of(item.order).newInstance()
|
||||
loadFragment(fragment, true)
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadFragment(Fragment fragment, boolean showBottom) {
|
||||
private fun loadFragment(fragment: Fragment?, showBottom: Boolean): Boolean {
|
||||
//showBottom so that we do not show the bottom tray again when constructing
|
||||
//from the saved instance state.
|
||||
if (fragment instanceof ContributionsFragment) {
|
||||
if (fragment is ContributionsFragment) {
|
||||
if (activeFragment == ActiveFragment.CONTRIBUTIONS) {
|
||||
// scroll to top if already on the Contributions tab
|
||||
contributionsFragment.scrollToTop();
|
||||
return true;
|
||||
contributionsFragment!!.scrollToTop()
|
||||
return true
|
||||
}
|
||||
contributionsFragment = (ContributionsFragment) fragment;
|
||||
activeFragment = ActiveFragment.CONTRIBUTIONS;
|
||||
} else if (fragment instanceof NearbyParentFragment) {
|
||||
contributionsFragment = fragment
|
||||
activeFragment = ActiveFragment.CONTRIBUTIONS
|
||||
} else if (fragment is NearbyParentFragment) {
|
||||
if (activeFragment == ActiveFragment.NEARBY) { // Do nothing if same tab
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
nearbyParentFragment = (NearbyParentFragment) fragment;
|
||||
activeFragment = ActiveFragment.NEARBY;
|
||||
} else if (fragment instanceof ExploreFragment) {
|
||||
nearbyParentFragment = fragment
|
||||
activeFragment = ActiveFragment.NEARBY
|
||||
} else if (fragment is ExploreFragment) {
|
||||
if (activeFragment == ActiveFragment.EXPLORE) { // Do nothing if same tab
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
exploreFragment = (ExploreFragment) fragment;
|
||||
activeFragment = ActiveFragment.EXPLORE;
|
||||
} else if (fragment instanceof BookmarkFragment) {
|
||||
exploreFragment = fragment
|
||||
activeFragment = ActiveFragment.EXPLORE
|
||||
} else if (fragment is BookmarkFragment) {
|
||||
if (activeFragment == ActiveFragment.BOOKMARK) { // Do nothing if same tab
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
bookmarkFragment = (BookmarkFragment) fragment;
|
||||
activeFragment = ActiveFragment.BOOKMARK;
|
||||
bookmarkFragment = fragment
|
||||
activeFragment = ActiveFragment.BOOKMARK
|
||||
} else if (fragment == null && showBottom) {
|
||||
if (applicationKvStore.getBoolean("login_skipped")
|
||||
== true) { // If logged out, more sheet is different
|
||||
MoreBottomSheetLoggedOutFragment bottomSheet = new MoreBottomSheetLoggedOutFragment();
|
||||
bottomSheet.show(getSupportFragmentManager(),
|
||||
"MoreBottomSheetLoggedOut");
|
||||
if (applicationKvStore!!.getBoolean("login_skipped")
|
||||
== true
|
||||
) { // If logged out, more sheet is different
|
||||
val bottomSheet = MoreBottomSheetLoggedOutFragment()
|
||||
bottomSheet.show(
|
||||
supportFragmentManager,
|
||||
"MoreBottomSheetLoggedOut"
|
||||
)
|
||||
} else {
|
||||
MoreBottomSheetFragment bottomSheet = new MoreBottomSheetFragment();
|
||||
bottomSheet.show(getSupportFragmentManager(),
|
||||
"MoreBottomSheet");
|
||||
val bottomSheet = MoreBottomSheetFragment()
|
||||
bottomSheet.show(
|
||||
supportFragmentManager,
|
||||
"MoreBottomSheet"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (fragment != null) {
|
||||
getSupportFragmentManager()
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragmentContainer, fragment)
|
||||
.commit();
|
||||
return true;
|
||||
.commit()
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
public void hideTabs() {
|
||||
binding.fragmentMainNavTabLayout.setVisibility(View.GONE);
|
||||
fun hideTabs() {
|
||||
binding!!.fragmentMainNavTabLayout.visibility = View.GONE
|
||||
}
|
||||
|
||||
public void showTabs() {
|
||||
binding.fragmentMainNavTabLayout.setVisibility(View.VISIBLE);
|
||||
fun showTabs() {
|
||||
binding!!.fragmentMainNavTabLayout.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -270,120 +275,121 @@ public class MainActivity extends BaseActivity
|
|||
*
|
||||
* @param uploadCount
|
||||
*/
|
||||
public void setNumOfUploads(int uploadCount) {
|
||||
fun setNumOfUploads(uploadCount: Int) {
|
||||
if (activeFragment == ActiveFragment.CONTRIBUTIONS) {
|
||||
setTitle(getResources().getString(R.string.contributions_fragment) + " " + (
|
||||
!(uploadCount == 0) ?
|
||||
getResources()
|
||||
.getQuantityString(R.plurals.contributions_subtitle,
|
||||
uploadCount, uploadCount)
|
||||
: getString(R.string.contributions_subtitle_zero)));
|
||||
title =
|
||||
resources.getString(R.string.contributions_fragment) + " " + (if (uploadCount != 0)
|
||||
resources
|
||||
.getQuantityString(
|
||||
R.plurals.contributions_subtitle,
|
||||
uploadCount, uploadCount
|
||||
)
|
||||
else
|
||||
getString(R.string.contributions_subtitle_zero))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume the uploads that got stuck because of the app being killed or the device being
|
||||
* rebooted.
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* When the app is terminated or the device is restarted, contributions remain in the
|
||||
* 'STATE_IN_PROGRESS' state. This status persists and doesn't change during these events. So,
|
||||
* retrieving contributions labeled as 'STATE_IN_PROGRESS' from the database will provide the
|
||||
* list of uploads that appear as stuck on opening the app again
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private void checkAndResumeStuckUploads() {
|
||||
List<Contribution> stuckUploads = contributionDao.getContribution(
|
||||
Collections.singletonList(Contribution.STATE_IN_PROGRESS))
|
||||
private fun checkAndResumeStuckUploads() {
|
||||
val stuckUploads = contributionDao!!.getContribution(
|
||||
listOf(Contribution.STATE_IN_PROGRESS)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.blockingGet();
|
||||
Timber.d("Resuming " + stuckUploads.size() + " uploads...");
|
||||
.blockingGet()
|
||||
Timber.d("Resuming " + stuckUploads.size + " uploads...")
|
||||
if (!stuckUploads.isEmpty()) {
|
||||
for (Contribution contribution : stuckUploads) {
|
||||
contribution.setState(Contribution.STATE_QUEUED);
|
||||
contribution.setDateUploadStarted(Calendar.getInstance().getTime());
|
||||
Completable.fromAction(() -> contributionDao.saveSynchronous(contribution))
|
||||
for (contribution in stuckUploads) {
|
||||
contribution.state = Contribution.STATE_QUEUED
|
||||
contribution.dateUploadStarted = Calendar.getInstance().time
|
||||
Completable.fromAction { contributionDao!!.saveSynchronous(contribution) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe();
|
||||
.subscribe()
|
||||
}
|
||||
WorkRequestHelper.Companion.makeOneTimeWorkRequest(
|
||||
this, ExistingWorkPolicy.APPEND_OR_REPLACE);
|
||||
makeOneTimeWorkRequest(
|
||||
this, ExistingWorkPolicy.APPEND_OR_REPLACE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
override fun onPostCreate(savedInstanceState: Bundle?) {
|
||||
super.onPostCreate(savedInstanceState)
|
||||
//quizChecker.initQuizCheck(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt("viewPagerCurrentItem", binding.pager.getCurrentItem());
|
||||
outState.putString("activeFragment", activeFragment.name());
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putInt("viewPagerCurrentItem", binding!!.pager.currentItem)
|
||||
outState.putString("activeFragment", activeFragment!!.name)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
String activeFragmentName = savedInstanceState.getString("activeFragment");
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
super.onRestoreInstanceState(savedInstanceState)
|
||||
val activeFragmentName = savedInstanceState.getString("activeFragment")
|
||||
if (activeFragmentName != null) {
|
||||
restoreActiveFragment(activeFragmentName);
|
||||
restoreActiveFragment(activeFragmentName)
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreActiveFragment(@NonNull String fragmentName) {
|
||||
if (fragmentName.equals(ActiveFragment.CONTRIBUTIONS.name())) {
|
||||
setTitle(getString(R.string.contributions_fragment));
|
||||
loadFragment(ContributionsFragment.newInstance(), false);
|
||||
} else if (fragmentName.equals(ActiveFragment.NEARBY.name())) {
|
||||
setTitle(getString(R.string.nearby_fragment));
|
||||
loadFragment(NearbyParentFragment.newInstance(), false);
|
||||
} else if (fragmentName.equals(ActiveFragment.EXPLORE.name())) {
|
||||
setTitle(getString(R.string.navigation_item_explore));
|
||||
loadFragment(ExploreFragment.newInstance(), false);
|
||||
} else if (fragmentName.equals(ActiveFragment.BOOKMARK.name())) {
|
||||
setTitle(getString(R.string.bookmarks));
|
||||
loadFragment(BookmarkFragment.newInstance(), false);
|
||||
private fun restoreActiveFragment(fragmentName: String) {
|
||||
if (fragmentName == ActiveFragment.CONTRIBUTIONS.name) {
|
||||
title = getString(R.string.contributions_fragment)
|
||||
loadFragment(newInstance(), false)
|
||||
} else if (fragmentName == ActiveFragment.NEARBY.name) {
|
||||
title = getString(R.string.nearby_fragment)
|
||||
loadFragment(NearbyParentFragment.newInstance(), false)
|
||||
} else if (fragmentName == ActiveFragment.EXPLORE.name) {
|
||||
title = getString(R.string.navigation_item_explore)
|
||||
loadFragment(ExploreFragment.newInstance(), false)
|
||||
} else if (fragmentName == ActiveFragment.BOOKMARK.name) {
|
||||
title = getString(R.string.bookmarks)
|
||||
loadFragment(BookmarkFragment.newInstance(), false)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
override fun onBackPressed() {
|
||||
if (contributionsFragment != null && activeFragment == ActiveFragment.CONTRIBUTIONS) {
|
||||
// Means that contribution fragment is visible
|
||||
if (!contributionsFragment.backButtonClicked()) {//If this one does not wan't to handle
|
||||
if (!contributionsFragment!!.backButtonClicked()) { //If this one does not wan't to handle
|
||||
// the back press, let the activity do so
|
||||
super.onBackPressed();
|
||||
super.onBackPressed()
|
||||
}
|
||||
} else if (nearbyParentFragment != null && activeFragment == ActiveFragment.NEARBY) {
|
||||
// Means that nearby fragment is visible
|
||||
/* If function nearbyParentFragment.backButtonClick() returns false, it means that the bottomsheet is
|
||||
not expanded. So if the back button is pressed, then go back to the Contributions tab */
|
||||
if (!nearbyParentFragment.backButtonClicked()) {
|
||||
getSupportFragmentManager().beginTransaction().remove(nearbyParentFragment)
|
||||
.commit();
|
||||
setSelectedItemId(NavTab.CONTRIBUTIONS.code());
|
||||
if (!nearbyParentFragment!!.backButtonClicked()) {
|
||||
supportFragmentManager.beginTransaction().remove(nearbyParentFragment!!)
|
||||
.commit()
|
||||
setSelectedItemId(NavTab.CONTRIBUTIONS.code())
|
||||
}
|
||||
} else if (exploreFragment != null && activeFragment == ActiveFragment.EXPLORE) {
|
||||
// Means that explore fragment is visible
|
||||
if (!exploreFragment.onBackPressed()) {
|
||||
if (applicationKvStore.getBoolean("login_skipped")) {
|
||||
super.onBackPressed();
|
||||
if (!exploreFragment!!.onBackPressed()) {
|
||||
if (applicationKvStore!!.getBoolean("login_skipped")) {
|
||||
super.onBackPressed()
|
||||
} else {
|
||||
setSelectedItemId(NavTab.CONTRIBUTIONS.code());
|
||||
setSelectedItemId(NavTab.CONTRIBUTIONS.code())
|
||||
}
|
||||
}
|
||||
} else if (bookmarkFragment != null && activeFragment == ActiveFragment.BOOKMARK) {
|
||||
// Means that bookmark fragment is visible
|
||||
bookmarkFragment.onBackPressed();
|
||||
bookmarkFragment!!.onBackPressed()
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
override fun onBackStackChanged() {
|
||||
//initBackButton();
|
||||
}
|
||||
|
||||
|
|
@ -391,77 +397,76 @@ public class MainActivity extends BaseActivity
|
|||
* Retry all failed uploads as soon as the user returns to the app
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private void retryAllFailedUploads() {
|
||||
contributionDao.
|
||||
getContribution(Collections.singletonList(Contribution.STATE_FAILED))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(failedUploads -> {
|
||||
for (Contribution contribution : failedUploads) {
|
||||
contributionsFragment.retryUpload(contribution);
|
||||
private fun retryAllFailedUploads() {
|
||||
contributionDao
|
||||
?.getContribution(listOf(Contribution.STATE_FAILED))
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.subscribe { failedUploads ->
|
||||
failedUploads.forEach { contribution ->
|
||||
contributionsFragment?.retryUpload(contribution)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles item selection in the options menu. This method is called when a user interacts with
|
||||
* the options menu in the Top Bar.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.upload_tab:
|
||||
startActivity(new Intent(this, UploadProgressActivity.class));
|
||||
return true;
|
||||
case R.id.notifications:
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.upload_tab -> {
|
||||
startActivity(Intent(this, UploadProgressActivity::class.java))
|
||||
return true
|
||||
}
|
||||
|
||||
R.id.notifications -> {
|
||||
// Starts notification activity on click to notification icon
|
||||
NotificationActivity.Companion.startYourself(this, "unread");
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
startYourself(this, "unread")
|
||||
return true
|
||||
}
|
||||
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
public void centerMapToPlace(Place place) {
|
||||
setSelectedItemId(NavTab.NEARBY.code());
|
||||
nearbyParentFragment.setNearbyParentFragmentInstanceReadyCallback(
|
||||
new NearbyParentFragmentInstanceReadyCallback() {
|
||||
@Override
|
||||
public void onReady() {
|
||||
nearbyParentFragment.centerMapToPlace(place);
|
||||
}
|
||||
});
|
||||
fun centerMapToPlace(place: Place?) {
|
||||
setSelectedItemId(NavTab.NEARBY.code())
|
||||
nearbyParentFragment!!.setNearbyParentFragmentInstanceReadyCallback {
|
||||
nearbyParentFragment!!.centerMapToPlace(
|
||||
place
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
if ((applicationKvStore.getBoolean("firstrun", true)) &&
|
||||
(!applicationKvStore.getBoolean("login_skipped"))) {
|
||||
defaultKvStore.putBoolean("inAppCameraFirstRun", true);
|
||||
WelcomeActivity.startYourself(this);
|
||||
if ((applicationKvStore!!.getBoolean("firstrun", true)) &&
|
||||
(!applicationKvStore!!.getBoolean("login_skipped"))
|
||||
) {
|
||||
defaultKvStore.putBoolean("inAppCameraFirstRun", true)
|
||||
WelcomeActivity.startYourself(this)
|
||||
}
|
||||
|
||||
retryAllFailedUploads();
|
||||
retryAllFailedUploads()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
quizChecker.cleanup();
|
||||
locationManager.unregisterLocationManager();
|
||||
override fun onDestroy() {
|
||||
quizChecker!!.cleanup()
|
||||
locationManager!!.unregisterLocationManager()
|
||||
// Remove ourself from hashmap to prevent memory leaks
|
||||
locationManager = null;
|
||||
super.onDestroy();
|
||||
locationManager = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* Public method to show nearby from the reference of this.
|
||||
*/
|
||||
public void showNearby() {
|
||||
binding.fragmentMainNavTabLayout.setSelectedItemId(NavTab.NEARBY.code());
|
||||
fun showNearby() {
|
||||
binding!!.fragmentMainNavTabLayout.selectedItemId = NavTab.NEARBY.code()
|
||||
}
|
||||
|
||||
public enum ActiveFragment {
|
||||
enum class ActiveFragment {
|
||||
CONTRIBUTIONS,
|
||||
NEARBY,
|
||||
EXPLORE,
|
||||
|
|
@ -472,15 +477,26 @@ public class MainActivity extends BaseActivity
|
|||
/**
|
||||
* Load default language in onCreate from SharedPreferences
|
||||
*/
|
||||
private void loadLocale() {
|
||||
final SharedPreferences preferences = getSharedPreferences("Settings",
|
||||
Activity.MODE_PRIVATE);
|
||||
final String language = preferences.getString("language", "");
|
||||
final SettingsFragment settingsFragment = new SettingsFragment();
|
||||
settingsFragment.setLocale(this, language);
|
||||
private fun loadLocale() {
|
||||
val preferences = getSharedPreferences(
|
||||
"Settings",
|
||||
MODE_PRIVATE
|
||||
)
|
||||
val language = preferences.getString("language", "")!!
|
||||
val settingsFragment = SettingsFragment()
|
||||
settingsFragment.setLocale(this, language)
|
||||
}
|
||||
|
||||
public NavTabLayout.OnNavigationItemSelectedListener getNavListener() {
|
||||
return navListener;
|
||||
companion object {
|
||||
/**
|
||||
* Consumers should be simply using this method to use this activity.
|
||||
*
|
||||
* @param context A Context of the application package implementing this class.
|
||||
*/
|
||||
fun startYourself(context: Context) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,126 +1,113 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import com.facebook.common.executors.CallerThreadExecutor;
|
||||
import com.facebook.common.references.CloseableReference;
|
||||
import com.facebook.datasource.DataSource;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.imagepipeline.core.ImagePipeline;
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||
import com.facebook.imagepipeline.image.CloseableImage;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import fr.free.nrw.commons.R;
|
||||
import timber.log.Timber;
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.WallpaperManager
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.facebook.common.executors.CallerThreadExecutor
|
||||
import com.facebook.common.references.CloseableReference
|
||||
import com.facebook.datasource.DataSource
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder
|
||||
import fr.free.nrw.commons.R
|
||||
import timber.log.Timber
|
||||
|
||||
public class SetWallpaperWorker extends Worker {
|
||||
class SetWallpaperWorker(context: Context, params: WorkerParameters) :
|
||||
Worker(context, params) {
|
||||
override fun doWork(): Result {
|
||||
val context = applicationContext
|
||||
createNotificationChannel(context)
|
||||
showProgressNotification(context)
|
||||
|
||||
private static final String NOTIFICATION_CHANNEL_ID = "set_wallpaper_channel";
|
||||
private static final int NOTIFICATION_ID = 1;
|
||||
val imageUrl = inputData.getString("imageUrl") ?: return Result.failure()
|
||||
|
||||
public SetWallpaperWorker(@NonNull Context context, @NonNull WorkerParameters params) {
|
||||
super(context, params);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Context context = getApplicationContext();
|
||||
createNotificationChannel(context);
|
||||
showProgressNotification(context);
|
||||
|
||||
String imageUrl = getInputData().getString("imageUrl");
|
||||
if (imageUrl == null) {
|
||||
return Result.failure();
|
||||
}
|
||||
|
||||
ImageRequest imageRequest = ImageRequestBuilder
|
||||
val imageRequest = ImageRequestBuilder
|
||||
.newBuilderWithSource(Uri.parse(imageUrl))
|
||||
.build();
|
||||
.build()
|
||||
|
||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||
final DataSource<CloseableReference<CloseableImage>>
|
||||
dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, context)
|
||||
|
||||
dataSource.subscribe(new BaseBitmapDataSubscriber() {
|
||||
@Override
|
||||
public void onNewResultImpl(@Nullable Bitmap bitmap) {
|
||||
if (dataSource.isFinished() && bitmap != null) {
|
||||
Timber.d("Bitmap loaded from url %s", imageUrl.toString());
|
||||
setWallpaper(context, Bitmap.createBitmap(bitmap));
|
||||
dataSource.close();
|
||||
dataSource.subscribe(object : BaseBitmapDataSubscriber() {
|
||||
public override fun onNewResultImpl(bitmap: Bitmap?) {
|
||||
if (dataSource.isFinished && bitmap != null) {
|
||||
Timber.d("Bitmap loaded from url %s", imageUrl.toString())
|
||||
setWallpaper(context, Bitmap.createBitmap(bitmap))
|
||||
dataSource.close()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureImpl(DataSource dataSource) {
|
||||
Timber.d("Error getting bitmap from image url %s", imageUrl.toString());
|
||||
showNotification(context, "Setting Wallpaper Failed", "Failed to download image.");
|
||||
if (dataSource != null) {
|
||||
dataSource.close();
|
||||
}
|
||||
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>?) {
|
||||
Timber.d("Error getting bitmap from image url %s", imageUrl.toString())
|
||||
showNotification(context, "Setting Wallpaper Failed", "Failed to download image.")
|
||||
dataSource?.close()
|
||||
}
|
||||
}, CallerThreadExecutor.getInstance());
|
||||
}, CallerThreadExecutor.getInstance())
|
||||
|
||||
return Result.success();
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private void setWallpaper(Context context, Bitmap bitmap) {
|
||||
WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
|
||||
private fun setWallpaper(context: Context, bitmap: Bitmap) {
|
||||
val wallpaperManager = WallpaperManager.getInstance(context)
|
||||
|
||||
try {
|
||||
wallpaperManager.setBitmap(bitmap);
|
||||
showNotification(context, "Wallpaper Set", "Wallpaper has been updated successfully.");
|
||||
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Error setting wallpaper");
|
||||
showNotification(context, "Setting Wallpaper Failed", " "+e.getLocalizedMessage());
|
||||
wallpaperManager.setBitmap(bitmap)
|
||||
showNotification(context, "Wallpaper Set", "Wallpaper has been updated successfully.")
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Error setting wallpaper")
|
||||
showNotification(context, "Setting Wallpaper Failed", " " + e.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private void showProgressNotification(Context context) {
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
private fun showProgressNotification(context: Context) {
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.commons_logo)
|
||||
.setContentTitle("Setting Wallpaper")
|
||||
.setContentText("Please wait...")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setOngoing(true)
|
||||
.setProgress(0, 0, true);
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build());
|
||||
.setProgress(0, 0, true)
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
private void showNotification(Context context, String title, String content) {
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
private fun showNotification(context: Context, title: String, content: String) {
|
||||
val notificationManager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.commons_logo)
|
||||
.setContentTitle(title)
|
||||
.setContentText(content)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setOngoing(false);
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build());
|
||||
.setOngoing(false)
|
||||
notificationManager.notify(NOTIFICATION_ID, builder.build())
|
||||
}
|
||||
|
||||
private void createNotificationChannel(Context context) {
|
||||
private fun createNotificationChannel(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
CharSequence name = "Wallpaper Setting";
|
||||
String description = "Notifications for wallpaper setting progress";
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name, importance);
|
||||
channel.setDescription(description);
|
||||
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
val name: CharSequence = "Wallpaper Setting"
|
||||
val description = "Notifications for wallpaper setting progress"
|
||||
val importance = NotificationManager.IMPORTANCE_HIGH
|
||||
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, name, importance)
|
||||
channel.description = description
|
||||
val notificationManager = context.getSystemService(
|
||||
NotificationManager::class.java
|
||||
)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NOTIFICATION_CHANNEL_ID = "set_wallpaper_channel"
|
||||
private const val NOTIFICATION_ID = 1
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,22 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
package fr.free.nrw.commons.contributions
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
class UnswipableViewPager : ViewPager {
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
public class UnswipableViewPager extends ViewPager{
|
||||
public UnswipableViewPager(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
|
||||
public UnswipableViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
||||
// Unswipable
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
// Unswipable
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class WikipediaInstructionsDialogFragment : DialogFragment() {
|
|||
/**
|
||||
* Callback for handling confirm button clicked
|
||||
*/
|
||||
interface Callback {
|
||||
fun interface Callback {
|
||||
fun onConfirmClicked(
|
||||
contribution: Contribution?,
|
||||
copyWikicode: Boolean,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import fr.free.nrw.commons.CommonsApplication
|
|||
import fr.free.nrw.commons.activity.SingleWebViewActivity
|
||||
import fr.free.nrw.commons.auth.LoginActivity
|
||||
import fr.free.nrw.commons.contributions.ContributionsModule
|
||||
import fr.free.nrw.commons.contributions.ContributionsProvidesModule
|
||||
import fr.free.nrw.commons.explore.SearchModule
|
||||
import fr.free.nrw.commons.explore.categories.CategoriesModule
|
||||
import fr.free.nrw.commons.explore.depictions.DepictionModule
|
||||
|
|
@ -40,6 +41,7 @@ import javax.inject.Singleton
|
|||
ContentProviderBuilderModule::class,
|
||||
UploadModule::class,
|
||||
ContributionsModule::class,
|
||||
ContributionsProvidesModule::class,
|
||||
SearchModule::class,
|
||||
DepictionModule::class,
|
||||
CategoriesModule::class
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ object FilePicker : Constants {
|
|||
fun onCanceled(source: ImageSource, type: Int)
|
||||
}
|
||||
|
||||
interface HandleActivityResult {
|
||||
fun interface HandleActivityResult {
|
||||
fun onHandleActivityResult(callbacks: Callbacks)
|
||||
}
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ class NavTabLayout : BottomNavigationView {
|
|||
|
||||
private fun setTabViews() {
|
||||
val isLoginSkipped = (context as MainActivity)
|
||||
.applicationKvStore.getBoolean("login_skipped")
|
||||
if (isLoginSkipped) {
|
||||
.applicationKvStore?.getBoolean("login_skipped")
|
||||
if (isLoginSkipped == true) {
|
||||
for (i in 0 until NavTabLoggedOut.size()) {
|
||||
val navTab = NavTabLoggedOut.of(i)
|
||||
menu.add(Menu.NONE, i, i, navTab.text()).setIcon(navTab.icon())
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ import javax.inject.Named
|
|||
|
||||
/**
|
||||
* The presenter class for PendingUploadsFragment and FailedUploadsFragment
|
||||
*/
|
||||
class PendingUploadsPresenter @Inject internal constructor(
|
||||
*/ class PendingUploadsPresenter @Inject internal constructor(
|
||||
private val contributionBoundaryCallback: ContributionBoundaryCallback,
|
||||
private val contributionsRemoteDataSource: ContributionsRemoteDataSource,
|
||||
private val contributionsRepository: ContributionsRepository,
|
||||
|
|
@ -89,12 +88,16 @@ class PendingUploadsPresenter @Inject internal constructor(
|
|||
* @param context The context in which the operation is being performed.
|
||||
*/
|
||||
override fun deleteUpload(contribution: Contribution?, context: Context?) {
|
||||
compositeDisposable.add(
|
||||
contribution?.let {
|
||||
contributionsRepository
|
||||
.deleteContributionFromDB(contribution)
|
||||
.deleteContributionFromDB(it)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.subscribe()
|
||||
)
|
||||
}?.let {
|
||||
compositeDisposable.add(
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue