From e94fa5fabb425d59a680544b1bd1e4f536512c27 Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 13 Dec 2018 13:02:15 +0530 Subject: [PATCH 1/7] Show campaigns on home screen * Added a ui util class SwipableCardView which passes the onSwipe event to its children * NearbyCardView & CampaignView extend SwipableCardView * Fetch campaigns in ContributionsFragment * Added an option to enable disable campaign in Settings/Preferences --- .../fr/free/nrw/commons/BasePresenter.java | 9 ++ .../java/fr/free/nrw/commons/MvpView.java | 6 ++ .../free/nrw/commons/campaigns/Campaign.java | 52 +++++++++++ .../nrw/commons/campaigns/CampaignConfig.java | 11 +++ .../campaigns/CampaignResponseDTO.java | 21 +++++ .../nrw/commons/campaigns/CampaignView.java | 78 ++++++++++++++++ .../commons/campaigns/CampaignsPresenter.java | 84 +++++++++++++++++ .../nrw/commons/campaigns/ICampaignsView.java | 12 +++ .../contributions/ContributionsFragment.java | 55 +++++++++++- .../mwapi/ApacheHttpClientMediaWikiApi.java | 17 ++++ .../free/nrw/commons/mwapi/MediaWikiApi.java | 3 + .../nearby/NearbyNoificationCardView.java | 49 ++-------- .../nrw/commons/utils/SwipableCardView.java | 69 ++++++++++++++ .../res/layout/fragment_contributions.xml | 18 +++- app/src/main/res/layout/layout_campagin.xml | 89 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 + app/src/main/res/xml/preferences.xml | 5 ++ 17 files changed, 536 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/BasePresenter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/MvpView.java create mode 100644 app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java create mode 100644 app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java create mode 100644 app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java create mode 100644 app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java create mode 100644 app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java create mode 100644 app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java create mode 100644 app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java create mode 100644 app/src/main/res/layout/layout_campagin.xml diff --git a/app/src/main/java/fr/free/nrw/commons/BasePresenter.java b/app/src/main/java/fr/free/nrw/commons/BasePresenter.java new file mode 100644 index 0000000000..8863c7c6ea --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/BasePresenter.java @@ -0,0 +1,9 @@ +package fr.free.nrw.commons; + +import android.content.Context; + +public interface BasePresenter { + void onAttachView(MvpView view); + + void onDetachView(); +} diff --git a/app/src/main/java/fr/free/nrw/commons/MvpView.java b/app/src/main/java/fr/free/nrw/commons/MvpView.java new file mode 100644 index 0000000000..87dc894c7d --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/MvpView.java @@ -0,0 +1,6 @@ +package fr.free.nrw.commons; + +import fr.free.nrw.commons.mwapi.MediaWikiApi; + +public interface MvpView { +} diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java b/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java new file mode 100644 index 0000000000..1bb6d04752 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java @@ -0,0 +1,52 @@ +package fr.free.nrw.commons.campaigns; + +import com.google.gson.annotations.SerializedName; + +public class Campaign { + + @SerializedName("title") private String title; + @SerializedName("description") private String description; + @SerializedName("startDate") private String startDate; + @SerializedName("endDate") private String endDate; + @SerializedName("link") private String link; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getStartDate() { + return startDate; + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java new file mode 100644 index 0000000000..fbeb112f92 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java @@ -0,0 +1,11 @@ +package fr.free.nrw.commons.campaigns; + +import com.google.gson.annotations.SerializedName; + +class CampaignConfig { + + @SerializedName("showOnlyLiveCampaigns") + private boolean showOnlyLiveCampaigns; + @SerializedName("sortBy") + private String sortBy; +} diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java new file mode 100644 index 0000000000..4015ea2b08 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java @@ -0,0 +1,21 @@ +package fr.free.nrw.commons.campaigns; + +import com.google.gson.annotations.SerializedName; +import java.util.List; + +public class CampaignResponseDTO { + + @SerializedName("config") + private CampaignConfig campaignConfig; + + @SerializedName("campaigns") + private List campaigns; + + public CampaignConfig getCampaignConfig() { + return campaignConfig; + } + + public List getCampaigns() { + return campaigns; + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java new file mode 100644 index 0000000000..084e14737f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java @@ -0,0 +1,78 @@ +package fr.free.nrw.commons.campaigns; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; +import butterknife.BindView; +import butterknife.ButterKnife; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.contributions.MainActivity; +import fr.free.nrw.commons.utils.SwipableCardView; +import fr.free.nrw.commons.utils.ViewUtil; + +public class CampaignView extends SwipableCardView { + Campaign campaign = null; + private ViewHolder viewHolder; + + public CampaignView(@NonNull Context context) { + super(context); + init(); + } + + public CampaignView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public CampaignView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public void setCampaign(Campaign campaign) { + this.campaign = campaign; + if (campaign != null) { + this.setVisibility(View.VISIBLE); + viewHolder.init(); + } else { + this.setVisibility(View.GONE); + } + } + + @Override public boolean onSwipe(View view) { + view.setVisibility(View.GONE); + ((MainActivity) getContext()).prefs.edit().putBoolean("displayCampaignsCardView", false).apply(); + ViewUtil.showLongToast(getContext(), + getResources().getString(R.string.nearby_campaign_dismiss_message)); + return true; + } + + private void init() { + View rootView = inflate(getContext(), R.layout.layout_campagin, this); + viewHolder = new ViewHolder(rootView); + } + + public class ViewHolder { + + @BindView(R.id.tv_title) TextView tvTitle; + @BindView(R.id.tv_description) TextView tvDescription; + @BindView(R.id.tv_start_date) TextView tvStartDate; + @BindView(R.id.tv_end_date) TextView tvEndDate; + + public ViewHolder(View itemView) { + ButterKnife.bind(this, itemView); + } + + public void init() { + if (campaign != null) { + tvTitle.setText(campaign.getTitle()); + tvDescription.setText(campaign.getDescription()); + tvStartDate.setText(campaign.getStartDate()); + tvEndDate.setText(campaign.getEndDate()); + } + } + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java new file mode 100644 index 0000000000..855157b9ac --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java @@ -0,0 +1,84 @@ +package fr.free.nrw.commons.campaigns; + +import android.util.Log; +import fr.free.nrw.commons.BasePresenter; +import fr.free.nrw.commons.MvpView; +import fr.free.nrw.commons.mwapi.MediaWikiApi; +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +public class CampaignsPresenter implements BasePresenter { + private final String TAG = "#CampaignsPresenter#"; + private ICampaignsView view; + private MediaWikiApi mediaWikiApi; + private Disposable disposable; + + @Override public void onAttachView(MvpView view) { + this.view = (ICampaignsView) view; + this.mediaWikiApi = ((ICampaignsView) view).getMediaWikiApi(); + } + + @Override public void onDetachView() { + this.view = null; + disposable.dispose(); + } + + public void getCampaigns() { + if (view != null && mediaWikiApi != null) { + Single campaigns = mediaWikiApi.getCampaigns(); + campaigns.observeOn(AndroidSchedulers.mainThread()) + .subscribeOn(Schedulers.io()) + .subscribeWith(new SingleObserver() { + @Override public void onSubscribe(Disposable d) { + disposable = d; + } + + @Override public void onSuccess(CampaignResponseDTO campaignResponseDTO) { + List campaigns = campaignResponseDTO.getCampaigns(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + if (campaigns == null || campaigns.isEmpty()) { + Log.e(TAG, "The campaigns list is empty"); + view.showCampaigns(null); + } + Collections.sort(campaigns, (campaign, t1) -> { + Date date1, date2 = null; + try { + date1 = dateFormat.parse(campaign.getStartDate()); + date2 = dateFormat.parse(t1.getStartDate()); + } catch (ParseException e) { + e.printStackTrace(); + return -1; + } + return date1.compareTo(date2); + }); + Date campaignEndDate = null; + try { + campaignEndDate = dateFormat.parse(campaigns.get(0).getEndDate()); + } catch (ParseException e) { + e.printStackTrace(); + } + if (campaignEndDate == null) { + view.showCampaigns(null); + } else if (campaignEndDate.compareTo(new Date()) > 0) { + view.showCampaigns(campaigns.get(0)); + } else { + Log.e(TAG, "The campaigns has already finished"); + view.showCampaigns(null); + } + } + + @Override public void onError(Throwable e) { + Log.e(TAG, "could not fetch campaigns: " + e.getMessage()); + } + }); + } + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java b/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java new file mode 100644 index 0000000000..c5f90a7e69 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java @@ -0,0 +1,12 @@ +package fr.free.nrw.commons.campaigns; + +import fr.free.nrw.commons.MvpView; +import fr.free.nrw.commons.mwapi.MediaWikiApi; + +public interface ICampaignsView extends MvpView { + void showMessage(String message); + + MediaWikiApi getMediaWikiApi(); + + void showCampaigns(Campaign campaign); +} diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 50666e65a3..719aa8c22b 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -22,6 +22,7 @@ import android.support.v4.app.LoaderManager; import android.support.v4.widget.CursorAdapter; import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -30,6 +31,14 @@ import android.widget.CheckBox; import android.widget.CompoundButton; +import android.widget.Toast; +import butterknife.BindView; +import butterknife.ButterKnife; +import fr.free.nrw.commons.campaigns.Campaign; +import fr.free.nrw.commons.campaigns.CampaignResponseDTO; +import fr.free.nrw.commons.campaigns.CampaignView; +import fr.free.nrw.commons.campaigns.CampaignsPresenter; +import fr.free.nrw.commons.campaigns.ICampaignsView; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; @@ -60,6 +69,7 @@ import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.acra.util.ToastSender; import timber.log.Timber; import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED; @@ -76,7 +86,7 @@ public class ContributionsFragment MediaDetailPagerFragment.MediaDetailProvider, FragmentManager.OnBackStackChangedListener, ContributionsListFragment.SourceRefresher, - LocationUpdateListener + LocationUpdateListener,ICampaignsView { @Inject @Named("default_preferences") @@ -112,6 +122,9 @@ public class ContributionsFragment private boolean isFragmentAttachedBefore = false; private View checkBoxView; private CheckBox checkBox; + private CampaignsPresenter presenter; + + @BindView(R.id.campaigns_view) CampaignView campaignView; /** * Since we will need to use parent activity on onAuthCookieAcquired, we have to wait @@ -142,6 +155,11 @@ public void onCreate(@Nullable Bundle savedInstanceState) { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_contributions, container, false); + ButterKnife.bind(this, view); + presenter = new CampaignsPresenter(); + presenter = new CampaignsPresenter(); + presenter.onAttachView(this); + campaignView.setVisibility(View.GONE); nearbyNoificationCardView = view.findViewById(R.id.card_view_nearby); checkBoxView = View.inflate(getActivity(), R.layout.nearby_permission_dialog, null); checkBox = (CheckBox) checkBoxView.findViewById(R.id.never_ask_again); @@ -537,7 +555,7 @@ public void onResume() { nearbyNoificationCardView.setVisibility(View.GONE); } - + fetchCampaigns(); } /** @@ -694,5 +712,38 @@ public void onLocationChangedMedium(LatLng latLng) { // Update closest nearby card view if location changed more than 500 meters updateClosestNearbyCardViewInfo(); } + + @Override public void onViewCreated(@NonNull View view, + @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + /** + * ask the presenter to fetch the campaigns only if user has not manually disabled it + */ + private void fetchCampaigns() { + if (prefs.getBoolean("displayCampaignsCardView", true)) { + presenter.getCampaigns(); + } + } + + @Override public void showMessage(String message) { + Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show(); + } + + @Override public MediaWikiApi getMediaWikiApi() { + return mediaWikiApi; + } + + @Override public void showCampaigns(Campaign campaign) { + if (campaign != null) { + campaignView.setCampaign(campaign); + } + } + + @Override public void onDestroyView() { + super.onDestroyView(); + presenter.onDetachView(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index f35bb7f24e..6d7e770de7 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -11,6 +11,7 @@ import com.google.gson.Gson; +import fr.free.nrw.commons.campaigns.CampaignResponseDTO; import org.apache.http.HttpResponse; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; @@ -1056,4 +1057,20 @@ public void logout() { } } + @Override public Single getCampaigns() { + return Single.fromCallable(() -> { + Request request = new Request.Builder().url( + "https://raw.githubusercontent.com/ashishkumar468/campaigns/master/campaigns.json") + .build(); + Response response = okHttpClient.newCall(request).execute(); + if (response != null && response.body() != null && response.isSuccessful()) { + String json = response.body().string(); + if (json == null) { + return null; + } + return gson.fromJson(json, CampaignResponseDTO.class); + } + return null; + }); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java index d7bf658027..46d71dc268 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java @@ -4,6 +4,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import fr.free.nrw.commons.campaigns.CampaignResponseDTO; import java.io.IOException; import java.io.InputStream; import java.util.List; @@ -105,6 +106,8 @@ public interface MediaWikiApi { void logout(); + Single getCampaigns(); + interface ProgressListener { void onProgress(long transferred, long total); } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java index 61798a95a8..78478abd69 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java @@ -6,12 +6,8 @@ import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.design.widget.SwipeDismissBehavior; import android.support.v7.app.AlertDialog; -import android.support.v7.widget.CardView; import android.util.AttributeSet; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; @@ -20,17 +16,16 @@ import android.widget.RelativeLayout; import android.widget.TextView; -import android.widget.Toast; - import fr.free.nrw.commons.R; import fr.free.nrw.commons.contributions.MainActivity; +import fr.free.nrw.commons.utils.SwipableCardView; import fr.free.nrw.commons.utils.ViewUtil; import timber.log.Timber; /** * Custom card view for nearby notification card view on main screen, above contributions list */ -public class NearbyNoificationCardView extends CardView{ +public class NearbyNoificationCardView extends SwipableCardView { private static final float MINIMUM_THRESHOLD_FOR_SWIPE = 100; private Context context; @@ -99,41 +94,15 @@ protected void onAttachedToWindow() { private void setActionListeners() { this.setOnClickListener(view -> ((MainActivity)context).viewPager.setCurrentItem(1)); - - this.setOnTouchListener( - (v, event) -> { - boolean isSwipe = false; - float deltaX=0.0f; - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - x1 = event.getX(); - break; - case MotionEvent.ACTION_UP: - x2 = event.getX(); - deltaX = x2 - x1; - if (deltaX < 0) { - //Right to left swipe - isSwipe = true; - } else if (deltaX > 0) { - //Left to right swipe - isSwipe = true; - } - break; - } - if (isSwipe && (pixelToDp(Math.abs(deltaX)) > MINIMUM_THRESHOLD_FOR_SWIPE)) { - v.setVisibility(GONE); - // Save shared preference for nearby card view accordingly - ((MainActivity) context).prefs.edit() - .putBoolean("displayNearbyCardView", false).apply(); - ViewUtil.showLongToast(context, getResources().getString(R.string.nearby_notification_dismiss_message)); - return true; - } - return false; - }); } - private float pixelToDp(float pixels) { - return (pixels / Resources.getSystem().getDisplayMetrics().density); + @Override public boolean onSwipe(View view) { + view.setVisibility(GONE); + // Save shared preference for nearby card view accordingly + ((MainActivity) context).prefs.edit().putBoolean("displayNearbyCardView", false).apply(); + ViewUtil.showLongToast(context, + getResources().getString(R.string.nearby_notification_dismiss_message)); + return true; } /** diff --git a/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java b/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java new file mode 100644 index 0000000000..4011dd689c --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java @@ -0,0 +1,69 @@ +package fr.free.nrw.commons.utils; + +import android.content.Context; +import android.content.res.Resources; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.CardView; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +/** + * A card view which informs onSwipe events to its child + */ +public abstract class SwipableCardView extends CardView { + float x1, x2; + private static final float MINIMUM_THRESHOLD_FOR_SWIPE = 100; + + public SwipableCardView(@NonNull Context context) { + super(context); + interceptOnTouchListener(); + } + + public SwipableCardView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + interceptOnTouchListener(); + } + + public SwipableCardView(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + interceptOnTouchListener(); + } + + private void interceptOnTouchListener() { + this.setOnTouchListener((v, event) -> { + boolean isSwipe = false; + float deltaX = 0.0f; + Log.e("#SwipableCardView#", event.getAction() + ""); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + x1 = event.getX(); + break; + case MotionEvent.ACTION_UP: + x2 = event.getX(); + deltaX = x2 - x1; + if (deltaX < 0) { + //Right to left swipe + isSwipe = true; + } else if (deltaX > 0) { + //Left to right swipe + isSwipe = true; + } + break; + } + if (isSwipe && (pixelToDp(Math.abs(deltaX)) > MINIMUM_THRESHOLD_FOR_SWIPE)) { + return onSwipe(v); + } + return true; + }); + } + + public abstract boolean onSwipe(View view); + + private float pixelToDp(float pixels) { + return (pixels / Resources.getSystem().getDisplayMetrics().density); + } +} diff --git a/app/src/main/res/layout/fragment_contributions.xml b/app/src/main/res/layout/fragment_contributions.xml index dd19591782..5fc1a74dc9 100644 --- a/app/src/main/res/layout/fragment_contributions.xml +++ b/app/src/main/res/layout/fragment_contributions.xml @@ -12,11 +12,21 @@ app:cardBackgroundColor="?attr/mainCardBackground" /> + + + android:id="@+id/root_frame" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginTop="2dp" + android:background="#000" + > \ No newline at end of file diff --git a/app/src/main/res/layout/layout_campagin.xml b/app/src/main/res/layout/layout_campagin.xml new file mode 100644 index 0000000000..64511d6ec0 --- /dev/null +++ b/app/src/main/res/layout/layout_campagin.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 22feaa82ab..5b6f18e235 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -421,5 +421,9 @@ Upload your first media by touching the camera or gallery icon above. Display location permission Ask for location permission when needed for nearby notification card view feature. Something went wrong, We could not fetch your achievements + Ends on: + Display campaigns + Tap here to see the ongoing campaigns + You won\'t see the campaigns anymore. However, you can re-enable this notification in Settings if you wish. diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index e272e02af9..39d0f38726 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -47,6 +47,11 @@ android:title="@string/display_location_permission_title" android:defaultValue="true" android:summary="@string/display_location_permission_explanation" /> + From 3cfdc45a385b7413a1d48fe9f7fd6743ae9943cf Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 13 Dec 2018 14:03:00 +0530 Subject: [PATCH 2/7] added click listener to a campaign --- .../free/nrw/commons/campaigns/CampaignView.java | 14 ++++++++++++++ .../free/nrw/commons/utils/SwipableCardView.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java index 084e14737f..1f1b341501 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java @@ -1,6 +1,8 @@ package fr.free.nrw.commons.campaigns; import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; @@ -53,6 +55,18 @@ public void setCampaign(Campaign campaign) { private void init() { View rootView = inflate(getContext(), R.layout.layout_campagin, this); viewHolder = new ViewHolder(rootView); + setOnClickListener(view -> { + if(campaign!=null){ + showCampaignInBrowser(campaign.getLink()); + } + }); + } + + private void showCampaignInBrowser(String link) { + Intent view = new Intent(); + view.setAction(Intent.ACTION_VIEW); + view.setData(Uri.parse(link)); + getContext().startActivity(view); } public class ViewHolder { diff --git a/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java b/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java index 4011dd689c..e7845fd8f9 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java @@ -57,7 +57,7 @@ private void interceptOnTouchListener() { if (isSwipe && (pixelToDp(Math.abs(deltaX)) > MINIMUM_THRESHOLD_FOR_SWIPE)) { return onSwipe(v); } - return true; + return false; }); } From 6d44a03e76dc006a5df416193055e9eab9937717 Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 13 Dec 2018 16:00:48 +0530 Subject: [PATCH 3/7] * Added JavaDocs * Update ui for CampaignView --- .../fr/free/nrw/commons/BasePresenter.java | 11 ++- .../java/fr/free/nrw/commons/MvpView.java | 6 +- .../free/nrw/commons/campaigns/Campaign.java | 3 + .../nrw/commons/campaigns/CampaignConfig.java | 9 +- .../campaigns/CampaignResponseDTO.java | 3 + .../nrw/commons/campaigns/CampaignView.java | 34 +++++-- .../commons/campaigns/CampaignsPresenter.java | 3 + .../nrw/commons/campaigns/ICampaignsView.java | 5 +- .../nrw/commons/utils/SwipableCardView.java | 3 + .../main/res/drawable-hdpi/ic_campaign.png | Bin 0 -> 428 bytes .../main/res/drawable-mdpi/ic_campaign.png | Bin 0 -> 293 bytes .../main/res/drawable-xhdpi/ic_campaign.png | Bin 0 -> 515 bytes .../main/res/drawable-xxhdpi/ic_campaign.png | Bin 0 -> 720 bytes .../main/res/drawable-xxxhdpi/ic_campaign.png | Bin 0 -> 942 bytes app/src/main/res/layout/layout_campagin.xml | 88 ++++++------------ 15 files changed, 89 insertions(+), 76 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_campaign.png create mode 100644 app/src/main/res/drawable-mdpi/ic_campaign.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_campaign.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_campaign.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_campaign.png diff --git a/app/src/main/java/fr/free/nrw/commons/BasePresenter.java b/app/src/main/java/fr/free/nrw/commons/BasePresenter.java index 8863c7c6ea..041fde6b2a 100644 --- a/app/src/main/java/fr/free/nrw/commons/BasePresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/BasePresenter.java @@ -1,9 +1,16 @@ package fr.free.nrw.commons; -import android.content.Context; - +/** + * Base presenter, enforcing contracts to atach and detach view + */ public interface BasePresenter { + /** + * Until a view is attached, it is open to listen events from the presenter + */ void onAttachView(MvpView view); + /** + * Detaching a view makes sure that the view no more receives events from the presenter + */ void onDetachView(); } diff --git a/app/src/main/java/fr/free/nrw/commons/MvpView.java b/app/src/main/java/fr/free/nrw/commons/MvpView.java index 87dc894c7d..7485b2aaf8 100644 --- a/app/src/main/java/fr/free/nrw/commons/MvpView.java +++ b/app/src/main/java/fr/free/nrw/commons/MvpView.java @@ -1,6 +1,8 @@ package fr.free.nrw.commons; -import fr.free.nrw.commons.mwapi.MediaWikiApi; - +/** + * Base interface for all the views + */ public interface MvpView { + void showMessage(String message); } diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java b/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java index 1bb6d04752..2bd4893b8b 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/Campaign.java @@ -2,6 +2,9 @@ import com.google.gson.annotations.SerializedName; +/** + * A data class to hold a campaign + */ public class Campaign { @SerializedName("title") private String title; diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java index fbeb112f92..a715aaf638 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignConfig.java @@ -2,10 +2,11 @@ import com.google.gson.annotations.SerializedName; +/** + * A data class to hold the campaign configs + */ class CampaignConfig { - @SerializedName("showOnlyLiveCampaigns") - private boolean showOnlyLiveCampaigns; - @SerializedName("sortBy") - private String sortBy; + @SerializedName("showOnlyLiveCampaigns") private boolean showOnlyLiveCampaigns; + @SerializedName("sortBy") private String sortBy; } diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java index 4015ea2b08..dd0bd51ce8 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignResponseDTO.java @@ -3,6 +3,9 @@ import com.google.gson.annotations.SerializedName; import java.util.List; +/** + * Data class to hold the response from the campaigns api + */ public class CampaignResponseDTO { @SerializedName("config") diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java index 1f1b341501..dec62cc1be 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java @@ -14,7 +14,13 @@ import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.utils.SwipableCardView; import fr.free.nrw.commons.utils.ViewUtil; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +/** + * A view which represents a single campaign + */ public class CampaignView extends SwipableCardView { Campaign campaign = null; private ViewHolder viewHolder; @@ -46,7 +52,9 @@ public void setCampaign(Campaign campaign) { @Override public boolean onSwipe(View view) { view.setVisibility(View.GONE); - ((MainActivity) getContext()).prefs.edit().putBoolean("displayCampaignsCardView", false).apply(); + ((MainActivity) getContext()).prefs.edit() + .putBoolean("displayCampaignsCardView", false) + .apply(); ViewUtil.showLongToast(getContext(), getResources().getString(R.string.nearby_campaign_dismiss_message)); return true; @@ -56,12 +64,15 @@ private void init() { View rootView = inflate(getContext(), R.layout.layout_campagin, this); viewHolder = new ViewHolder(rootView); setOnClickListener(view -> { - if(campaign!=null){ - showCampaignInBrowser(campaign.getLink()); - } + if (campaign != null) { + showCampaignInBrowser(campaign.getLink()); + } }); } + /** + * open the url associated with the campaign in the system's default browser + */ private void showCampaignInBrowser(String link) { Intent view = new Intent(); view.setAction(Intent.ACTION_VIEW); @@ -73,8 +84,7 @@ public class ViewHolder { @BindView(R.id.tv_title) TextView tvTitle; @BindView(R.id.tv_description) TextView tvDescription; - @BindView(R.id.tv_start_date) TextView tvStartDate; - @BindView(R.id.tv_end_date) TextView tvEndDate; + @BindView(R.id.tv_dates) TextView tvDates; public ViewHolder(View itemView) { ButterKnife.bind(this, itemView); @@ -84,8 +94,16 @@ public void init() { if (campaign != null) { tvTitle.setText(campaign.getTitle()); tvDescription.setText(campaign.getDescription()); - tvStartDate.setText(campaign.getStartDate()); - tvEndDate.setText(campaign.getEndDate()); + SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat outputDateFormat = new SimpleDateFormat("dd MMM"); + try { + Date startDate = inputDateFormat.parse(campaign.getStartDate()); + Date endDate = inputDateFormat.parse(campaign.getEndDate()); + tvDates.setText(String.format("%1s - %2s", outputDateFormat.format(startDate), + outputDateFormat.format(endDate))); + } catch (ParseException e) { + e.printStackTrace(); + } } } } diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java index 855157b9ac..95fca8a17c 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java @@ -15,6 +15,9 @@ import java.util.Date; import java.util.List; +/** + * The presenter for the campaigns view, fetches the campaigns from the api and informs the view on success and error + */ public class CampaignsPresenter implements BasePresenter { private final String TAG = "#CampaignsPresenter#"; private ICampaignsView view; diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java b/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java index c5f90a7e69..8610728b30 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/ICampaignsView.java @@ -3,9 +3,10 @@ import fr.free.nrw.commons.MvpView; import fr.free.nrw.commons.mwapi.MediaWikiApi; +/** + * Interface which defines the view contracts of the campaign view + */ public interface ICampaignsView extends MvpView { - void showMessage(String message); - MediaWikiApi getMediaWikiApi(); void showCampaigns(Campaign campaign); diff --git a/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java b/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java index e7845fd8f9..a65033d159 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/SwipableCardView.java @@ -61,6 +61,9 @@ private void interceptOnTouchListener() { }); } + /** + * abstract function which informs swipe events to those who have inherited from it + */ public abstract boolean onSwipe(View view); private float pixelToDp(float pixels) { diff --git a/app/src/main/res/drawable-hdpi/ic_campaign.png b/app/src/main/res/drawable-hdpi/ic_campaign.png new file mode 100644 index 0000000000000000000000000000000000000000..183ec8f7068f00c3fcc578e06249febd3369e3a9 GIT binary patch literal 428 zcmV;d0aN~oP)sKi<06u_=Mn-a>m_baDI`9S*S430_8dHxUv~dto*@TvvdB{j+p=8>?w_#a+ ziEGP=bF@PUtqgB2fQ%4^*i{Ijqv0Vri_HzOM_-waVSBp@;anXbp`k^xx(FddAEAjR zfdxHSGG_5(<(|+a`ou?Qs!WDEDRUT~(HK6*^sa>pT8ekZh{cbTd%0%Gf(nI5>W5Hr zA>7(6LfnE7ChZSVL=&RcW*4CBP}w=ROjI3iBgja$)>R~ZnV2$Ms$nCvs6a-tun}6b z3NSWn8=)qv0Ate(-4-pW#N{lbv^|zm2TfiaQug*(QJ$F0$*Up^B-I68iSFI~{Q3vI W%%okRelu$T0000_^Yf_V1L@OT= z(VfIPf?N`QL`0HYM^H)x5h4R*vDthV4N{p_EvL|0F8G=mM1> ra)Igg-2!i<_3_EffCrN8=C9%dEv}(OTUVoL00000NkvXXu0mjfCINj! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_campaign.png b/app/src/main/res/drawable-xhdpi/ic_campaign.png new file mode 100644 index 0000000000000000000000000000000000000000..e1fa99eafbd4de039a70a0faa69f3ef37e9a8049 GIT binary patch literal 515 zcmV+e0{s1nP)NSC9*7mM25hTv)Uj&fmvnj z4EGhB)#)fhAmykw1Qd8&89T;(^mcXCDOD-p_pEGIpszpxOlcV7rwoFj1rRx2+gG_T zF5(MgyS!#jr2;a_s1>jR|3M(&s5aUP(A6n#IW`p?-W7Zk&vTRSihM-AR~Vjv_UVWS zzZ)PtVb@s#pEmme!&i@l+eJW!@P86r1nxS~MWE1$u4{E|u&+#8l-)CaM9AXYyS6Kk zI5b?02NRA$RP(9{^+l$fN=V`bhtBZl$kc1XvDKlW{Q@$f7=mhy>M8&L002ovPDHLk FV1idP=@tM0 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_campaign.png b/app/src/main/res/drawable-xxhdpi/ic_campaign.png new file mode 100644 index 0000000000000000000000000000000000000000..7ffb22f5682b8c30889a09f3f7ca9320c4f9c1d9 GIT binary patch literal 720 zcmV;>0x$iEP)N|Xq8r$URrMa*7;0GniCD$MC-d&p{m7<`aprD}OiOFQ*00kgTHhzoQ22Ozo;1RfF z+sMqfoCDwu_zb|d9oQ~s19+Js$A|6PuvyS?h#a3on+08Q2s*b}P?tkc*H$@M;EqEO zJ0@$3lnk&5)PQ?n%pquu$JVfI##Aw7;2QYgkTQ=CJV)6WQSe39fiuo*;bn~HT-RAl z8rTD#V-yqQ8LyGnu>dy&htnd%uAxmKM>!`6hzW9{yd*5fM}Q|mkcZdKs4Qq-f|wxt zs>&$=PYMWPeJH6oV_hg9$LB(+nGHI#BUn2|z%al_u$JwpRG3AwXN1GE7@&mvM6xKO zf}kzI^$yFH;*9eaai7TgXiEh_4Z(V`EJ2Kh3W9nH3+l<1vj)5?EQs}OO{SpT7^dW9 z3S#Wa6jaqfP*tX&x(0&kG6gmNxd@zQ5F%(0(Uxa1*_0`$_0L6Mko26NFH!Ay7LzTN z1`gU<`9E{OHfNm|Z|CfW0oMXb+B zW=>lpIX>;BXOf1QlUycY=5#cc;bxxv?>eDhmjz*eECm+;Yfa$K-6SMQ+5a z;cTC4d%@1*)3RNBmFWpTvu$~r(*FKy;E)LlbK(mUls>y_7U&2700000E&NsDItSrvcr2?$>i2g!3jgW+QN#7{ z>p6Sp|L;Gc?rQkU#7&OF*YFsZT?>Db_$nZL4UcuwmGJwB4}!wi@R<8t5U@i07ASzn zydpjPQR0Wd@HIU4QON>YmIHYpu80dCuGBI%x7m_Bxz@HE1_wMx)O?sz%h=pzTjb0Ddhqk_0pp+AGOQ0MnEt zV8=lLJ5s{u)5bdv3gFjNmLOm%!2_c#1u#<*1S~l$U`fiHzpDc35(G3I7SNO+V8i0v zPB&*k7hkB0IL-{#XF7MZAwj^V#krksszGz~>br-k!TL<+jy7Er5ZF>u7^`W^f&d7B z00@8p2!H?xup{7-m{wojhhZedZs>@?`li(w3M=42%`*NB$w`O2{$2sX*X-p+f@(Xv1q%P^e?kRqr>O0yfNdu~?Wn+Q zC;N7Uwv%x?LfZ*$M`;K^&;dXI1VBL20xp0*X$YtRe@ZA63Wc)uc{8AXFY+cLr}&}I z_!5p{>=qs&!T18UVhGqmg7F2+M!e}aKW7#R#uvaB-fc$^u0SERA9U*vn Q0RR9107*qoM6N<$g48mgh5!Hn literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/layout_campagin.xml b/app/src/main/res/layout/layout_campagin.xml index 64511d6ec0..864192f05f 100644 --- a/app/src/main/res/layout/layout_campagin.xml +++ b/app/src/main/res/layout/layout_campagin.xml @@ -5,85 +5,57 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="10dp" + android:paddingBottom="16dp" + android:paddingTop="16dp" > - - - - - - - - - - - - - - + From eb3a3df1cb58e2cbf460e5407fb5b5494670b406 Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 13 Dec 2018 18:24:55 +0530 Subject: [PATCH 4/7] * ui fixes * bug fix, campaign view should not be visible in MediaDetailPagerFragment * code formatting, few more java docs --- .../commons/campaigns/CampaignsPresenter.java | 18 ++++++++++--- .../contributions/ContributionsFragment.java | 24 ++++++++++++++++++ .../main/res/drawable-hdpi/ic_campaign.png | Bin 428 -> 807 bytes .../main/res/drawable-mdpi/ic_campaign.png | Bin 293 -> 542 bytes .../main/res/drawable-xhdpi/ic_campaign.png | Bin 515 -> 1051 bytes .../main/res/drawable-xxhdpi/ic_campaign.png | Bin 720 -> 1590 bytes .../main/res/drawable-xxxhdpi/ic_campaign.png | Bin 942 -> 2157 bytes app/src/main/res/layout/layout_campagin.xml | 13 +++++++--- 8 files changed, 49 insertions(+), 6 deletions(-) mode change 100644 => 100755 app/src/main/res/drawable-hdpi/ic_campaign.png mode change 100644 => 100755 app/src/main/res/drawable-mdpi/ic_campaign.png mode change 100644 => 100755 app/src/main/res/drawable-xhdpi/ic_campaign.png mode change 100644 => 100755 app/src/main/res/drawable-xxhdpi/ic_campaign.png mode change 100644 => 100755 app/src/main/res/drawable-xxxhdpi/ic_campaign.png diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java index 95fca8a17c..98ef7e6de8 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignsPresenter.java @@ -16,13 +16,15 @@ import java.util.List; /** - * The presenter for the campaigns view, fetches the campaigns from the api and informs the view on success and error + * The presenter for the campaigns view, fetches the campaigns from the api and informs the view on + * success and error */ public class CampaignsPresenter implements BasePresenter { private final String TAG = "#CampaignsPresenter#"; private ICampaignsView view; private MediaWikiApi mediaWikiApi; private Disposable disposable; + private Campaign campaign; @Override public void onAttachView(MvpView view) { this.view = (ICampaignsView) view; @@ -34,12 +36,21 @@ public class CampaignsPresenter implements BasePresenter { disposable.dispose(); } + /** + * make the api call to fetch the campaigns + */ public void getCampaigns() { if (view != null && mediaWikiApi != null) { + //If we already have a campaign, lets not make another call + if (this.campaign != null) { + view.showCampaigns(campaign); + return; + } Single campaigns = mediaWikiApi.getCampaigns(); campaigns.observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribeWith(new SingleObserver() { + @Override public void onSubscribe(Disposable d) { disposable = d; } @@ -52,7 +63,7 @@ public void getCampaigns() { view.showCampaigns(null); } Collections.sort(campaigns, (campaign, t1) -> { - Date date1, date2 = null; + Date date1, date2; try { date1 = dateFormat.parse(campaign.getStartDate()); date2 = dateFormat.parse(t1.getStartDate()); @@ -71,7 +82,8 @@ public void getCampaigns() { if (campaignEndDate == null) { view.showCampaigns(null); } else if (campaignEndDate.compareTo(new Date()) > 0) { - view.showCampaigns(campaigns.get(0)); + campaign = campaigns.get(0); + view.showCampaigns(campaign); } else { Log.e(TAG, "The campaigns has already finished"); view.showCampaigns(null); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 719aa8c22b..d781a98679 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -14,6 +14,7 @@ import android.os.IBinder; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; @@ -23,6 +24,7 @@ import android.support.v4.widget.CursorAdapter; import android.support.v7.app.AlertDialog; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -124,6 +126,7 @@ public class ContributionsFragment private CheckBox checkBox; private CampaignsPresenter presenter; + @BindView(R.id.campaigns_view) CampaignView campaignView; /** @@ -191,6 +194,27 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { setUploadCount(); } + getChildFragmentManager().registerFragmentLifecycleCallbacks( + new FragmentManager.FragmentLifecycleCallbacks() { + @Override public void onFragmentResumed(FragmentManager fm, Fragment f) { + super.onFragmentResumed(fm, f); + //If media detail pager fragment is visible, hide the campaigns view [might not be the best way to do, this but yeah, this proves to work for now] + Log.e("#CF#", "onFragmentResumed" + f.getClass().getName()); + if (f instanceof MediaDetailPagerFragment) { + campaignView.setVisibility(View.GONE); + } + } + + @Override public void onFragmentDetached(FragmentManager fm, Fragment f) { + super.onFragmentDetached(fm, f); + Log.e("#CF#", "onFragmentDetached" + f.getClass().getName()); + //If media detail pager fragment is detached, ContributionsList fragment is gonna be visible, [becomes tightly coupled though] + if (f instanceof MediaDetailPagerFragment) { + fetchCampaigns(); + } + } + }, true); + return view; } diff --git a/app/src/main/res/drawable-hdpi/ic_campaign.png b/app/src/main/res/drawable-hdpi/ic_campaign.png old mode 100644 new mode 100755 index 183ec8f7068f00c3fcc578e06249febd3369e3a9..315ec45d3debf032b26a9d3079e8d93e3cc14696 GIT binary patch literal 807 zcmV+?1K9kDP)-gW$C2Ed+TpTq; zKRl^!)C^PbhT2gRyaMizn&1k+c~SlB2Vl3TZq@`aN3W<}dH~=vb)q_HB+>~N*u#U2(XcVP$ANa{Ck(bK>d<@{o zD3w6~c8EOGGYv3ZUrPbMMyWgjV5H`elgj|y6X9_Hn?@=0k@TU~QI5T3088|YFjxlg zT$IAKvW>K>RkD)jCIDO)|MC`Ku6mJ{24*U6r0X1D3rBgxJOKQvLHx_n0Jey<>i4MPE( z8OvDLt;Pdb=w0XQ9_84k#PoM4fOR8_mIhf}ceNwI-Uh`ox&SyO(r_bSu?A6;?Jco? ztYA9e;Zimxeu^Tra&Ot(^A6yhNW=Glmm@FrZ08Yk03XE)UIcs-X_yGOGjdSZwjMEC z(zsZ`gMiVIhIxSNa&GrimA4>A#AinumH;k`GMpu!rm>7m0ZStd<8yzb5i;^=8Oyj6 zFh0`odF}*pCs5=YUj}?0X?PXzTV(ORd|rq;z}eQ(TN91-ww|-R zZz%wlIw~s8*5*oUu8pH|4EKpNJ~2G1f{lHkkauhnRmlj~nXIgdt}`O4gWA@ylS7>D lbcfp6I{q3n!>|UU008^E{!MYjLN@>a002ovPDHLkV1l)zdDj2{ literal 428 zcmV;d0aN~oP)sKi<06u_=Mn-a>m_baDI`9S*S430_8dHxUv~dto*@TvvdB{j+p=8>?w_#a+ ziEGP=bF@PUtqgB2fQ%4^*i{Ijqv0Vri_HzOM_-waVSBp@;anXbp`k^xx(FddAEAjR zfdxHSGG_5(<(|+a`ou?Qs!WDEDRUT~(HK6*^sa>pT8ekZh{cbTd%0%Gf(nI5>W5Hr zA>7(6LfnE7ChZSVL=&RcW*4CBP}w=ROjI3iBgja$)>R~ZnV2$Ms$nCvs6a-tun}6b z3NSWn8=)qv0Ate(-4-pW#N{lbv^|zm2TfiaQug*(QJ$F0$*Up^B-I68iSFI~{Q3vI W%%okRelu$T00005)cv@MX?CS$@kLom?<jLT^7}05J;Aq;#^r!VlKFh| z0Pssv9|2qu=`;ZIos-Nb`P*D{_E1vJu>drPY+PU?81L+q-`;qz(FKv6=K#~(8wI%6 zG{7^ld%gxRz<2I)y3^d_I|BiH9ec)0wn($Z^Ree#qOz?D+M==xV{bXb$2yp7y>+H& gXV+4I6~aga0Br8YdJxYUO#lD@07*qoM6N<$g3tB_SpWb4 literal 293 zcmV+=0owkFP)_^Yf_V1L@OT= z(VfIPf?N`QL`0HYM^H)x5h4R*vDthV4N{p_EvL|0F8G=mM1> ra)Igg-2!i<_3_EffCrN8=C9%dEv}(OTUVoL00000NkvXXu0mjfCINj! diff --git a/app/src/main/res/drawable-xhdpi/ic_campaign.png b/app/src/main/res/drawable-xhdpi/ic_campaign.png old mode 100644 new mode 100755 index e1fa99eafbd4de039a70a0faa69f3ef37e9a8049..8b93f79779b831b4acdc976571d06dff60665376 GIT binary patch literal 1051 zcmV+$1mydPP)|bV4?eRM1GsaY{ zaSN_%RBN0;*p{j-_9Lv78C6ScL)80>q`a|+%EZRR?V^0KD%Yt@tV7)2jII1I3k^J` zGO-;=PE%eOi8q1IRVEH4Ne5Hs-D@USS-6*EH!BZJLo);IpfWHj4VX7E-As}1xcd#G zs3f+;v@#`~m{XM%a}r<s+h?* zfEVc@tPl6FLD3n}1dJ|UOpR;Ggci02Td^<4uos)K7$e6ARfW(8;~zk>DduZ=<1}tp z2v1;klrN6N+?49*pJTUZ&X+H)#vCONOu^#}G>sf=jk#C8cn-6%%EVagZ*7IGh-6#jEV!oFzp1|y$7>$&+pB(Ilc|yK84|9)Vc!SbrjXy&Asbh0YYdp%} z8P6s?I&GNE<%?;O0vf~llrp~@td47H`QszZLyBMliaSLiJcRjJX|OM@r4_;56!uhj z!N!uf_Ej2;M{7JRHcZMNBs)9W=6D~|#CS@F3veB+2xi~~qJCz@geis$JVD)eGHm|p2|GOh+@lP6}S0oTdOf-(3C*Z(Xn4=m09xW3As zu$q%LT-|Krk`VXv literal 515 zcmV+e0{s1nP)NSC9*7mM25hTv)Uj&fmvnj z4EGhB)#)fhAmykw1Qd8&89T;(^mcXCDOD-p_pEGIpszpxOlcV7rwoFj1rRx2+gG_T zF5(MgyS!#jr2;a_s1>jR|3M(&s5aUP(A6n#IW`p?-W7Zk&vTRSihM-AR~Vjv_UVWS zzZ)PtVb@s#pEmme!&i@l+eJW!@P86r1nxS~MWE1$u4{E|u&+#8l-)CaM9AXYyS6Kk zI5b?02NRA$RP(9{^+l$fN=V`bhtBZl$kc1XvDKlW{Q@$f7=mhy>M8&L002ovPDHLk FV1idP=@tM0 diff --git a/app/src/main/res/drawable-xxhdpi/ic_campaign.png b/app/src/main/res/drawable-xxhdpi/ic_campaign.png old mode 100644 new mode 100755 index 7ffb22f5682b8c30889a09f3f7ca9320c4f9c1d9..069ad8e1e86588718b83601b012da31d767c88a3 GIT binary patch literal 1590 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 jkw_#Gi9{liSgZU2fD00000NkvXXu0mjf?QH-L literal 942 zcmV;f15x~mP)0E&NsDItSrvcr2?$>i2g!3jgW+QN#7{ z>p6Sp|L;Gc?rQkU#7&OF*YFsZT?>Db_$nZL4UcuwmGJwB4}!wi@R<8t5U@i07ASzn zydpjPQR0Wd@HIU4QON>YmIHYpu80dCuGBI%x7m_Bxz@HE1_wMx)O?sz%h=pzTjb0Ddhqk_0pp+AGOQ0MnEt zV8=lLJ5s{u)5bdv3gFjNmLOm%!2_c#1u#<*1S~l$U`fiHzpDc35(G3I7SNO+V8i0v zPB&*k7hkB0IL-{#XF7MZAwj^V#krksszGz~>br-k!TL<+jy7Er5ZF>u7^`W^f&d7B z00@8p2!H?xup{7-m{wojhhZedZs>@?`li(w3M=42%`*NB$w`O2{$2sX*X-p+f@(Xv1q%P^e?kRqr>O0yfNdu~?Wn+Q zC;N7Uwv%x?LfZ*$M`;K^&;dXI1VBL20xp0*X$YtRe@ZA63Wc)uc{8AXFY+cLr}&}I z_!5p{>=qs&!T18UVhGqmg7F2+M!e}aKW7#R#uvaB-fc$^u0SERA9U*vn Q0RR9107*qoM6N<$g48mgh5!Hn diff --git a/app/src/main/res/layout/layout_campagin.xml b/app/src/main/res/layout/layout_campagin.xml index 864192f05f..91916b6512 100644 --- a/app/src/main/res/layout/layout_campagin.xml +++ b/app/src/main/res/layout/layout_campagin.xml @@ -5,8 +5,10 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="16dp" - android:paddingTop="16dp" + android:paddingBottom="10dp" + android:paddingEnd="10dp" + android:paddingRight="10dp" + android:paddingTop="10dp" > Date: Thu, 13 Dec 2018 18:30:19 +0530 Subject: [PATCH 5/7] removed unused constant --- .../fr/free/nrw/commons/nearby/NearbyNoificationCardView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java index 78478abd69..c9f0e0ff25 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java @@ -27,7 +27,6 @@ */ public class NearbyNoificationCardView extends SwipableCardView { - private static final float MINIMUM_THRESHOLD_FOR_SWIPE = 100; private Context context; private Button permissionRequestButton; From 3da6417581a2504656e90d69bbfeaaa6893b4d69 Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 13 Dec 2018 19:55:49 +0530 Subject: [PATCH 6/7] ui fixes, description for a campaign is temporarily hidden --- app/src/main/res/layout/layout_campagin.xml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/layout_campagin.xml b/app/src/main/res/layout/layout_campagin.xml index 91916b6512..47824f5a3c 100644 --- a/app/src/main/res/layout/layout_campagin.xml +++ b/app/src/main/res/layout/layout_campagin.xml @@ -5,10 +5,10 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="10dp" + android:paddingBottom="16dp" android:paddingEnd="10dp" android:paddingRight="10dp" - android:paddingTop="10dp" + android:paddingTop="16dp" > Date: Fri, 14 Dec 2018 10:27:17 +0530 Subject: [PATCH 7/7] updated campaigns base url, switched to the prod url --- .../nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java index 6d7e770de7..5ad6b52fcd 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java @@ -78,6 +78,8 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi { private SharedPreferences categoryPreferences; private Gson gson; private final OkHttpClient okHttpClient; + private final String WIKIMEDIA_CAMPAIGNS_BASE_URL = + "https://raw.githubusercontent.com/commons-app/campaigns/master/campaigns.json"; public ApacheHttpClientMediaWikiApi(Context context, String apiURL, @@ -1059,9 +1061,7 @@ public void logout() { @Override public Single getCampaigns() { return Single.fromCallable(() -> { - Request request = new Request.Builder().url( - "https://raw.githubusercontent.com/ashishkumar468/campaigns/master/campaigns.json") - .build(); + Request request = new Request.Builder().url(WIKIMEDIA_CAMPAIGNS_BASE_URL).build(); Response response = okHttpClient.newCall(request).execute(); if (response != null && response.body() != null && response.isSuccessful()) { String json = response.body().string();