From 3b422963a4cf3dfe48f70bb64b7195c588a732a7 Mon Sep 17 00:00:00 2001 From: Sean Mac Gillicuddy Date: Thu, 14 May 2020 07:23:37 +0100 Subject: [PATCH] #3468 Switch from RvRenderer to AdapterDelegates - replace PlaceRenderer --- app/build.gradle | 4 +- .../free/nrw/commons/CommonsApplication.java | 5 +- .../locations/BookmarkLocationsFragment.java | 32 +- .../di/BookmarkLocationsFragmentModule.kt | 12 + .../di/CommonsApplicationComponent.java | 4 - .../nrw/commons/di/FragmentBuilderModule.java | 4 +- .../commons/di/NearbyParentFragmentModule.kt | 13 + .../commons/nearby/NearbyAdapterFactory.java | 57 --- .../commons/nearby/PlaceAdapterDelegate.kt | 84 +++++ .../nrw/commons/nearby/PlaceRenderer.java | 292 ---------------- .../fragments/CommonPlaceClickActions.kt | 99 ++++++ .../fragments/NearbyParentFragment.java | 326 +++++++++--------- .../commons/nearby/fragments/PlaceAdapter.kt | 25 ++ .../upload/categories/BaseDelegateAdapter.kt | 14 +- .../depictions/DepictionRenderer.java | 56 --- gradle.properties | 2 +- 16 files changed, 430 insertions(+), 599 deletions(-) create mode 100644 app/src/main/java/fr/free/nrw/commons/di/BookmarkLocationsFragmentModule.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/di/NearbyParentFragmentModule.kt delete mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/NearbyAdapterFactory.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt delete mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt create mode 100644 app/src/main/java/fr/free/nrw/commons/nearby/fragments/PlaceAdapter.kt delete mode 100644 app/src/main/java/fr/free/nrw/commons/upload/structure/depictions/DepictionRenderer.java diff --git a/app/build.gradle b/app/build.gradle index 8c5e6dae5..0bf8ec3fc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,7 +35,6 @@ dependencies { // UI implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar' implementation 'com.github.chrisbanes:PhotoView:2.0.0' - implementation 'com.github.pedrovgs:renderers:3.3.3' implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.6.2' implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v8:0.11.0' implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-scalebar-v9:0.4.0' @@ -105,6 +104,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation "androidx.exifinterface:exifinterface:1.0.0" implementation "androidx.core:core-ktx:$CORE_KTX_VERSION" + implementation "androidx.multidex:multidex:2.0.1" //swipe_layout implementation 'com.daimajia.swipelayout:library:1.2.0@aar' @@ -143,7 +143,7 @@ android { testOptions { execution 'ANDROIDX_TEST_ORCHESTRATOR' } - + multiDexEnabled true vectorDrawables.useSupportLibrary = true } diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index b2f281dd5..dc37db26c 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -9,7 +9,6 @@ import static org.acra.ReportField.STACK_TRACE; import static org.acra.ReportField.USER_COMMENT; import android.annotation.SuppressLint; -import android.app.Application; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; @@ -18,13 +17,13 @@ import android.os.Build; import android.os.Process; import android.util.Log; import androidx.annotation.NonNull; +import androidx.multidex.MultiDexApplication; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.mapbox.mapboxsdk.Mapbox; import com.squareup.leakcanary.LeakCanary; import com.squareup.leakcanary.RefWatcher; - import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao; @@ -77,7 +76,7 @@ import timber.log.Timber; resCommentPrompt = R.string.crash_dialog_comment_prompt ) -public class CommonsApplication extends Application { +public class CommonsApplication extends MultiDexApplication { @Inject SessionManager sessionManager; @Inject DBOpenHelper dbOpenHelper; diff --git a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java index d3f193784..21d4d7460 100644 --- a/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/bookmarks/locations/BookmarkLocationsFragment.java @@ -8,26 +8,21 @@ import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; - -import com.pedrogomez.renderers.RVRendererAdapter; - -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - import butterknife.BindView; import butterknife.ButterKnife; import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; import fr.free.nrw.commons.contributions.ContributionController; -import fr.free.nrw.commons.nearby.NearbyAdapterFactory; import fr.free.nrw.commons.nearby.Place; +import fr.free.nrw.commons.nearby.fragments.CommonPlaceClickActions; +import fr.free.nrw.commons.nearby.fragments.PlaceAdapter; +import java.util.List; +import javax.inject.Inject; +import kotlin.Unit; public class BookmarkLocationsFragment extends DaggerFragment { @@ -37,8 +32,10 @@ public class BookmarkLocationsFragment extends DaggerFragment { @BindView(R.id.parentLayout) RelativeLayout parentLayout; @Inject BookmarkLocationsController controller; - private NearbyAdapterFactory adapterFactory; @Inject ContributionController contributionController; + @Inject BookmarkLocationsDao bookmarkLocationDao; + @Inject CommonPlaceClickActions commonPlaceClickActions; + private PlaceAdapter adapter; /** * Create an instance of the fragment with the right bundle parameters @@ -56,7 +53,6 @@ public class BookmarkLocationsFragment extends DaggerFragment { ) { View v = inflater.inflate(R.layout.fragment_bookmarks_locations, container, false); ButterKnife.bind(this, v); - adapterFactory = new NearbyAdapterFactory(this, contributionController); return v; } @@ -65,7 +61,15 @@ public class BookmarkLocationsFragment extends DaggerFragment { super.onViewCreated(view, savedInstanceState); progressBar.setVisibility(View.VISIBLE); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - recyclerView.setAdapter(adapterFactory.create(new ArrayList<>(), this::initList)); + adapter = new PlaceAdapter(bookmarkLocationDao, + place -> Unit.INSTANCE, + (place, isBookmarked) -> { + adapter.remove(place); + return Unit.INSTANCE; + }, + commonPlaceClickActions + ); + recyclerView.setAdapter(adapter); } @Override @@ -79,7 +83,7 @@ public class BookmarkLocationsFragment extends DaggerFragment { */ private void initList() { List places = controller.loadFavoritesLocations(); - adapterFactory.updateAdapterData(places, (RVRendererAdapter) recyclerView.getAdapter()); + adapter.setItems(places); progressBar.setVisibility(View.GONE); if (places.size() <= 0) { statusTextView.setText(R.string.bookmark_empty); diff --git a/app/src/main/java/fr/free/nrw/commons/di/BookmarkLocationsFragmentModule.kt b/app/src/main/java/fr/free/nrw/commons/di/BookmarkLocationsFragmentModule.kt new file mode 100644 index 000000000..7570fbedc --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/di/BookmarkLocationsFragmentModule.kt @@ -0,0 +1,12 @@ +package fr.free.nrw.commons.di + +import android.app.Activity +import dagger.Module +import dagger.Provides +import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment + +@Module +class BookmarkLocationsFragmentModule { + @Provides + fun BookmarkLocationsFragment.providesActivity(): Activity = activity!! +} diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index f813de762..5c97ce9d9 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -10,11 +10,9 @@ import dagger.android.AndroidInjector; import dagger.android.support.AndroidSupportInjectionModule; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.auth.LoginActivity; -import fr.free.nrw.commons.contributions.ContributionViewHolder; import fr.free.nrw.commons.contributions.ContributionsModule; import fr.free.nrw.commons.depictions.DepictionModule; import fr.free.nrw.commons.explore.SearchModule; -import fr.free.nrw.commons.nearby.PlaceRenderer; import fr.free.nrw.commons.review.ReviewController; import fr.free.nrw.commons.settings.SettingsFragment; import fr.free.nrw.commons.upload.FileProcessor; @@ -49,8 +47,6 @@ public interface CommonsApplicationComponent extends AndroidInjector create(List placeList) { - return create(placeList, null); - } - - public RVRendererAdapter create( - List placeList, - PlaceRenderer.OnBookmarkClick onBookmarkClick - ) { - RendererBuilder builder = new RendererBuilder() - .bind(Place.class, new PlaceRenderer(fragment, controller, onBookmarkClick)); - ListAdapteeCollection collection = new ListAdapteeCollection<>( - placeList != null ? placeList : Collections.emptyList()); - return new RVRendererAdapter<>(builder, collection); - } - - public void updateAdapterData(List newPlaceList, RVRendererAdapter rendererAdapter) { - rendererAdapter.notifyDataSetChanged(); - rendererAdapter.diffUpdate(newPlaceList); - } - - public void clear(RVRendererAdapter rendererAdapter){ - rendererAdapter.clear(); - } - - public void add(Place place, RVRendererAdapter rendererAdapter){ - rendererAdapter.add(place); - } - - public void update(RVRendererAdapter rendererAdapter){ - rendererAdapter.notifyDataSetChanged(); - } - -} diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt new file mode 100644 index 000000000..b01997972 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceAdapterDelegate.kt @@ -0,0 +1,84 @@ +package fr.free.nrw.commons.nearby + +import android.view.View +import android.view.View.* +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.transition.TransitionManager +import com.hannesdorfmann.adapterdelegates4.dsl.AdapterDelegateLayoutContainerViewHolder +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer +import fr.free.nrw.commons.R +import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao +import kotlinx.android.synthetic.main.item_place.* +import kotlinx.android.synthetic.main.nearby_row_button.* + + +fun placeAdapterDelegate( + bookmarkLocationDao: BookmarkLocationsDao, + onItemClick: ((Place) -> Unit)? = null, + onCameraClicked: (Place) -> Unit, + onGalleryClicked: (Place) -> Unit, + onBookmarkClicked: (Place, Boolean) -> Unit, + onOverflowIconClicked: (Place, View) -> Unit, + onDirectionsClicked: (Place) -> Unit +) = + adapterDelegateLayoutContainer(R.layout.item_place) { + containerView.setOnClickListener { _: View? -> + showOrHideAndScrollToIfLast() + onItemClick?.invoke(item) + } + containerView.setOnFocusChangeListener { view1: View?, hasFocus: Boolean -> + if (!hasFocus && buttonLayout.isShown) { + buttonLayout.visibility = GONE + } else if (hasFocus && !buttonLayout.isShown) { + showOrHideAndScrollToIfLast() + onItemClick?.invoke(item) + } + } + cameraButton.setOnClickListener { onCameraClicked(item) } + galleryButton.setOnClickListener { onGalleryClicked(item) } + bookmarkRowButton.setOnClickListener { + val isBookmarked = bookmarkLocationDao.updateBookmarkLocation(item) + bookmarkRowButtonImage.setImageResource(if (isBookmarked) R.drawable.ic_round_star_filled_24px else R.drawable.ic_round_star_border_24px) + onBookmarkClicked(item, isBookmarked) + } + iconOverflow.setOnClickListener { onOverflowIconClicked(item, it) } + directionsButton.setOnClickListener { onDirectionsClicked(item) } + bind { + tvName.text = item.name + val descriptionText: String = item.longDescription + if (descriptionText == "?") { + tvDesc.setText(R.string.no_description_found) + tvDesc.visibility = INVISIBLE + } else { + tvDesc.text = descriptionText + } + distance.text = item.distance + icon.setImageResource(item.label.icon) + iconOverflow.visibility = + if (item.hasCommonsLink() || item.hasWikidataLink()) VISIBLE + else GONE + + bookmarkRowButtonImage.setImageResource( + if (bookmarkLocationDao.findBookmarkLocation(item)) + R.drawable.ic_round_star_filled_24px + else + R.drawable.ic_round_star_border_24px + ) + } + } + +private fun AdapterDelegateLayoutContainerViewHolder.showOrHideAndScrollToIfLast() { + TransitionManager.beginDelayedTransition(buttonLayout) + if (buttonLayout.isShown) { + buttonLayout.visibility = GONE + } else { + buttonLayout.visibility = VISIBLE + val recyclerView = containerView.parent as RecyclerView + val lastPosition = recyclerView.adapter!!.itemCount - 1 + if (recyclerView.getChildLayoutPosition(containerView) == lastPosition) { + (recyclerView.layoutManager as LinearLayoutManager?) + ?.scrollToPositionWithOffset(lastPosition, buttonLayout.height) + } + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java b/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java deleted file mode 100644 index e8f2cf974..000000000 --- a/app/src/main/java/fr/free/nrw/commons/nearby/PlaceRenderer.java +++ /dev/null @@ -1,292 +0,0 @@ -package fr.free.nrw.commons.nearby; - -import android.content.Intent; -import android.net.Uri; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.PopupMenu; -import androidx.fragment.app.Fragment; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.transition.TransitionManager; - -import com.facebook.drawee.view.SimpleDraweeView; -import com.pedrogomez.renderers.Renderer; - -import java.util.ArrayList; - -import javax.inject.Inject; -import javax.inject.Named; - -import butterknife.BindView; -import butterknife.ButterKnife; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.Utils; -import fr.free.nrw.commons.auth.LoginActivity; -import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; -import fr.free.nrw.commons.contributions.ContributionController; -import fr.free.nrw.commons.di.ApplicationlessInjection; -import fr.free.nrw.commons.kvstore.JsonKvStore; -import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment; -import timber.log.Timber; - -import static fr.free.nrw.commons.theme.NavigationBaseActivity.startActivityWithFlags; -import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; - -public class PlaceRenderer extends Renderer { - - @BindView(R.id.tvName) TextView tvName; - @BindView(R.id.tvDesc) TextView tvDesc; - @BindView(R.id.distance) TextView distance; - @BindView(R.id.icon) SimpleDraweeView icon; - @BindView(R.id.buttonLayout) LinearLayout buttonLayout; - @BindView(R.id.cameraButton) LinearLayout cameraButton; - - @BindView(R.id.galleryButton) LinearLayout galleryButton; - @BindView(R.id.directionsButton) LinearLayout directionsButton; - @BindView(R.id.iconOverflow) LinearLayout iconOverflow; - @BindView(R.id.cameraButtonText) TextView cameraButtonText; - @BindView(R.id.galleryButtonText) TextView galleryButtonText; - @BindView(R.id.bookmarkRowButton) LinearLayout bookmarkButton; - @BindView(R.id.bookmarkButtonText) TextView bookmarkButtonText; - @BindView(R.id.bookmarkRowButtonImage) ImageView bookmarkButtonImage; - - @BindView(R.id.directionsButtonText) TextView directionsButtonText; - @BindView(R.id.iconOverflowText) TextView iconOverflowText; - - private View view; - private static ArrayList openedItems; - private Place place; - - private Fragment fragment; - private ContributionController controller; - private OnBookmarkClick onBookmarkClick; - - @Inject BookmarkLocationsDao bookmarkLocationDao; - @Inject - @Named("default_preferences") - JsonKvStore applicationKvStore; - - public PlaceRenderer(){ - openedItems = new ArrayList<>(); - } - - public PlaceRenderer( - Fragment fragment, - ContributionController controller, - OnBookmarkClick onBookmarkClick - ) { - this.fragment = fragment; - this.controller = controller; - openedItems = new ArrayList<>(); - this.onBookmarkClick = onBookmarkClick; - } - - @Override - protected View inflate(LayoutInflater layoutInflater, ViewGroup viewGroup) { - view = layoutInflater.inflate(R.layout.item_place, viewGroup, false); - return view; - } - - @Override - protected void setUpView(View view) { - ButterKnife.bind(this, view); - closeLayout(buttonLayout); - } - - @Override - protected void hookListeners(View view) { - - final View.OnClickListener listener = view12 -> { - Timber.d("Renderer clicked"); - TransitionManager.beginDelayedTransition(buttonLayout); - - if (buttonLayout.isShown()) { - closeLayout(buttonLayout); - } else { - openLayout(buttonLayout); - RecyclerView recyclerView = (RecyclerView) view.getParent(); - int lastPosition = recyclerView.getAdapter().getItemCount() - 1; - if (recyclerView.getChildLayoutPosition(view) == lastPosition) { - ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(lastPosition, buttonLayout.getHeight()); - } - } - if (onBookmarkClick == null) { - ((NearbyParentFragment) fragment).centerMapToPlace(place); - } - }; - view.setOnClickListener(listener); - - view.requestFocus(); - view.setOnFocusChangeListener((view1, hasFocus) -> { - if (!hasFocus && buttonLayout.isShown()) { - closeLayout(buttonLayout); - } else if (hasFocus && !buttonLayout.isShown()) { - listener.onClick(view1); - } - }); - - cameraButton.setOnClickListener(view2 -> { - if (applicationKvStore.getBoolean("login_skipped", false)) { - // prompt the user to login - new AlertDialog.Builder(getContext()) - .setMessage(R.string.login_alert_message) - .setPositiveButton(R.string.login, (dialog, which) -> { - startActivityWithFlags( getContext(), LoginActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, - Intent.FLAG_ACTIVITY_SINGLE_TOP); - applicationKvStore.putBoolean("login_skipped", false); - fragment.getActivity().finish(); - }) - .show(); - } else { - Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription()); - storeSharedPrefs(); - controller.initiateCameraPick(fragment.getActivity()); - } - }); - - - galleryButton.setOnClickListener(view3 -> { - if (applicationKvStore.getBoolean("login_skipped", false)) { - // prompt the user to login - new AlertDialog.Builder(getContext()) - .setMessage(R.string.login_alert_message) - .setPositiveButton(R.string.login, (dialog, which) -> { - startActivityWithFlags( getContext(), LoginActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, - Intent.FLAG_ACTIVITY_SINGLE_TOP); - applicationKvStore.putBoolean("login_skipped", false); - fragment.getActivity().finish(); - }) - .show(); - }else { - Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription()); - storeSharedPrefs(); - controller.initiateGalleryPick(fragment.getActivity(), false); - } - }); - - bookmarkButton.setOnClickListener(view4 -> { - if (applicationKvStore.getBoolean("login_skipped", false)) { - // prompt the user to login - new AlertDialog.Builder(getContext()) - .setMessage(R.string.login_alert_message) - .setPositiveButton(R.string.login, (dialog, which) -> { - startActivityWithFlags( getContext(), LoginActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP, - Intent.FLAG_ACTIVITY_SINGLE_TOP); - applicationKvStore.putBoolean("login_skipped", false); - fragment.getActivity().finish(); - }) - .show(); - } else { - boolean isBookmarked = bookmarkLocationDao.updateBookmarkLocation(place); - int icon = isBookmarked ? R.drawable.ic_round_star_filled_24px : R.drawable.ic_round_star_border_24px; - bookmarkButtonImage.setImageResource(icon); - if (onBookmarkClick != null) { - onBookmarkClick.onClick(); - } - else { - ((NearbyParentFragment) (fragment.getParentFragment())). - updateMarker(isBookmarked, place, null); - } - } - }); - } - - private void storeSharedPrefs() { - Timber.d("Store place object %s", place.toString()); - applicationKvStore.putJson(PLACE_OBJECT, place); - } - - private void closeLayout(LinearLayout buttonLayout){ - buttonLayout.setVisibility(View.GONE); - } - - private void openLayout(LinearLayout buttonLayout){ - buttonLayout.setVisibility(View.VISIBLE); - } - - @Override - public void render() { - ApplicationlessInjection.getInstance(getContext().getApplicationContext()) - .getCommonsApplicationComponent().inject(this); - place = getContent(); - tvName.setText(place.name); - String descriptionText = place.getLongDescription(); - if (descriptionText.equals("?")) { - descriptionText = getContext().getString(R.string.no_description_found); - tvDesc.setVisibility(View.INVISIBLE); - } - tvDesc.setText(descriptionText); - distance.setText(place.distance); - - - icon.setImageResource(place.getLabel().getIcon()); - - directionsButton.setOnClickListener(view -> Utils.handleGeoCoordinates(getContext(), this.place.getLocation())); - - iconOverflow.setVisibility(showMenu() ? View.VISIBLE : View.GONE); - iconOverflow.setOnClickListener(v -> popupMenuListener()); - - int icon; - if (bookmarkLocationDao.findBookmarkLocation(place)) { - icon = R.drawable.ic_round_star_filled_24px; - } else { - icon = R.drawable.ic_round_star_border_24px; - } - bookmarkButtonImage.setImageResource(icon); - } - - private void popupMenuListener() { - PopupMenu popupMenu = new PopupMenu(view.getContext(), iconOverflow); - popupMenu.inflate(R.menu.nearby_info_dialog_options); - - MenuItem commonsArticle = popupMenu.getMenu() - .findItem(R.id.nearby_info_menu_commons_article); - MenuItem wikiDataArticle = popupMenu.getMenu() - .findItem(R.id.nearby_info_menu_wikidata_article); - MenuItem wikipediaArticle = popupMenu.getMenu() - .findItem(R.id.nearby_info_menu_wikipedia_article); - - commonsArticle.setEnabled(place.hasCommonsLink()); - wikiDataArticle.setEnabled(place.hasWikidataLink()); - wikipediaArticle.setEnabled(place.hasWikipediaLink()); - - popupMenu.setOnMenuItemClickListener(item -> { - switch (item.getItemId()) { - case R.id.nearby_info_menu_commons_article: - openWebView(place.siteLinks.getCommonsLink()); - return true; - case R.id.nearby_info_menu_wikidata_article: - openWebView(place.siteLinks.getWikidataLink()); - return true; - case R.id.nearby_info_menu_wikipedia_article: - openWebView(place.siteLinks.getWikipediaLink()); - return true; - default: - break; - } - return false; - }); - popupMenu.show(); - } - - private void openWebView(Uri link) { - Utils.handleWebUrl(getContext(), link); - } - - private boolean showMenu() { - return place.hasCommonsLink() || place.hasWikidataLink(); - } - - public interface OnBookmarkClick { - void onClick(); - } - -} diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt new file mode 100644 index 000000000..15186de56 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/CommonPlaceClickActions.kt @@ -0,0 +1,99 @@ +package fr.free.nrw.commons.nearby.fragments + +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.view.MenuItem +import android.view.View +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.widget.PopupMenu +import fr.free.nrw.commons.R +import fr.free.nrw.commons.Utils +import fr.free.nrw.commons.auth.LoginActivity +import fr.free.nrw.commons.contributions.ContributionController +import fr.free.nrw.commons.kvstore.JsonKvStore +import fr.free.nrw.commons.nearby.Place +import fr.free.nrw.commons.theme.NavigationBaseActivity +import fr.free.nrw.commons.wikidata.WikidataConstants +import timber.log.Timber +import javax.inject.Inject +import javax.inject.Named + + +class CommonPlaceClickActions @Inject constructor( + @Named("default_preferences") private val applicationKvStore: JsonKvStore, + private val activity: Activity, + private val contributionController: ContributionController +) { + + fun onCameraClicked(): (Place) -> Unit = { + if (applicationKvStore.getBoolean("login_skipped", false)) { + showLoginDialog() + } else { + Timber.d("Camera button tapped. Image title: ${it.getName()}Image desc: ${it.longDescription}") + storeSharedPrefs(it) + contributionController.initiateCameraPick(activity) + } + } + + fun onGalleryClicked(): (Place) -> Unit = { + if (applicationKvStore.getBoolean("login_skipped", false)) { + showLoginDialog() + } else { + Timber.d("Gallery button tapped. Image title: ${it.getName()}Image desc: ${it.getLongDescription()}") + storeSharedPrefs(it) + contributionController.initiateGalleryPick(activity, false) + } + } + + fun onOverflowClicked(): (Place, View) -> Unit = { place, view -> + PopupMenu(view.context, view).apply { + inflate(R.menu.nearby_info_dialog_options) + enableBy(R.id.nearby_info_menu_commons_article, place.hasCommonsLink()) + enableBy(R.id.nearby_info_menu_wikidata_article, place.hasWikidataLink()) + enableBy(R.id.nearby_info_menu_wikipedia_article, place.hasWikipediaLink()) + setOnMenuItemClickListener { item: MenuItem -> + when (item.itemId) { + R.id.nearby_info_menu_commons_article -> openWebView(place.siteLinks.commonsLink) + R.id.nearby_info_menu_wikidata_article -> openWebView(place.siteLinks.wikidataLink) + R.id.nearby_info_menu_wikipedia_article -> openWebView(place.siteLinks.wikipediaLink) + else -> false + } + } + }.show() + } + + fun onDirectionsClicked(): (Place) -> Unit = { + Utils.handleGeoCoordinates(activity, it.getLocation()) + } + + private fun storeSharedPrefs(selectedPlace: Place) { + Timber.d("Store place object %s", selectedPlace.toString()) + applicationKvStore.putJson(WikidataConstants.PLACE_OBJECT, selectedPlace) + } + + private fun openWebView(link: Uri): Boolean { + Utils.handleWebUrl(activity, link) + return true; + } + + private fun PopupMenu.enableBy(menuId: Int, hasLink: Boolean) { + menu.findItem(menuId).isEnabled = hasLink + } + + private fun showLoginDialog() { + AlertDialog.Builder(activity) + .setMessage(R.string.login_alert_message) + .setPositiveButton(R.string.login) { dialog, which -> + NavigationBaseActivity.startActivityWithFlags( + activity, + LoginActivity::class.java, + Intent.FLAG_ACTIVITY_CLEAR_TOP, + Intent.FLAG_ACTIVITY_SINGLE_TOP + ) + applicationKvStore.putBoolean("login_skipped", false) + activity.finish() + } + .show() + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java index 4e156ca34..f75d2f3c9 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java @@ -1,7 +1,14 @@ package fr.free.nrw.commons.nearby.fragments; +import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION; +import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; +import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; +import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; +import static fr.free.nrw.commons.nearby.Label.TEXT_TO_DESCRIPTION; +import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; +import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; + import android.Manifest; -import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -26,14 +33,16 @@ import android.widget.RelativeLayout; import android.widget.SearchView; import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; - +import butterknife.BindView; +import butterknife.ButterKnife; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.chip.Chip; import com.google.android.material.chip.ChipGroup; @@ -57,18 +66,6 @@ import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.maps.UiSettings; import com.mapbox.pluginscalebar.ScaleBarOptions; import com.mapbox.pluginscalebar.ScaleBarPlugin; -import com.pedrogomez.renderers.RVRendererAdapter; - -import fr.free.nrw.commons.utils.DialogUtil; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import javax.inject.Inject; -import javax.inject.Named; - -import butterknife.BindView; -import butterknife.ButterKnife; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; @@ -76,6 +73,7 @@ import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.contributions.MainActivity; +import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.location.LocationServiceManager; @@ -83,7 +81,6 @@ import fr.free.nrw.commons.location.LocationUpdateListener; import fr.free.nrw.commons.nearby.CheckBoxTriStates; import fr.free.nrw.commons.nearby.Label; import fr.free.nrw.commons.nearby.MarkerPlaceGroup; -import fr.free.nrw.commons.nearby.NearbyAdapterFactory; import fr.free.nrw.commons.nearby.NearbyBaseMarker; import fr.free.nrw.commons.nearby.NearbyController; import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter; @@ -92,6 +89,7 @@ import fr.free.nrw.commons.nearby.NearbyMarker; import fr.free.nrw.commons.nearby.Place; import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract; import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; +import fr.free.nrw.commons.utils.DialogUtil; import fr.free.nrw.commons.utils.ExecutorUtils; import fr.free.nrw.commons.utils.LayoutUtils; import fr.free.nrw.commons.utils.LocationUtils; @@ -104,17 +102,16 @@ import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.wikidata.WikidataEditListener; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; +import javax.inject.Named; +import kotlin.Unit; import timber.log.Timber; -import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; -import static fr.free.nrw.commons.nearby.Label.TEXT_TO_DESCRIPTION; -import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; -import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; - public class NearbyParentFragment extends CommonsDaggerSupportFragment implements NearbyParentFragmentContract.View, @@ -164,6 +161,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment @Inject SystemThemeUtils systemThemeUtils; + @Inject + CommonPlaceClickActions commonPlaceClickActions; private NearbyFilterSearchRecyclerViewAdapter nearbyFilterSearchRecyclerViewAdapter; @@ -177,7 +176,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private static final float ZOOM_LEVEL = 14f; private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private BroadcastReceiver broadcastReceiver; - private boolean isNetworkErrorOccurred = false; + private boolean isNetworkErrorOccurred; private Snackbar snackbar; private View view; private NearbyParentFragmentPresenter presenter; @@ -189,25 +188,22 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.005; private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.004; - private boolean isMapBoxReady=false; + private boolean isMapBoxReady; private MapboxMap mapBox; IntentFilter intentFilter = new IntentFilter(NETWORK_INTENT_ACTION); private Marker currentLocationMarker; private Polygon currentLocationPolygon; private Place lastPlaceToCenter; private fr.free.nrw.commons.location.LatLng lastKnownLocation; - private fr.free.nrw.commons.location.LatLng currentLocation=null; - private NearbyController.NearbyPlacesInfo nearbyPlacesInfo; - private NearbyAdapterFactory adapterFactory; private boolean isVisibleToUser; private MapboxMap.OnCameraMoveListener cameraMoveListener; private fr.free.nrw.commons.location.LatLng lastFocusLocation; private LatLngBounds latLngBounds; - + private PlaceAdapter adapter; @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, + final Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_nearby_parent, container, false); ButterKnife.bind(this, view); initNetworkBroadCastReceiver(); @@ -218,7 +214,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); isDarkTheme = systemThemeUtils.isDeviceInNightMode(); cameraMoveListener= () -> presenter.onCameraMove(mapBox.getCameraPosition().target); @@ -228,28 +224,28 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment initThemePreferences(); mapView.onCreate(savedInstanceState); mapView.getMapAsync(mapBoxMap -> { - this.mapBox=mapBoxMap; + mapBox =mapBoxMap; initViews(); presenter.setActionListeners(applicationKvStore); initNearbyFilter(); mapBoxMap.setStyle(isDarkTheme?Style.DARK:Style.OUTDOORS, style -> { - UiSettings uiSettings = mapBoxMap.getUiSettings(); + final UiSettings uiSettings = mapBoxMap.getUiSettings(); uiSettings.setCompassGravity(Gravity.BOTTOM | Gravity.LEFT); uiSettings.setCompassMargins(12, 0, 0, 24); uiSettings.setLogoEnabled(true); uiSettings.setAttributionEnabled(true); uiSettings.setRotateGesturesEnabled(false); - NearbyParentFragment.this.isMapBoxReady=true; + isMapBoxReady =true; performMapReadyActions(); - CameraPosition cameraPosition = new CameraPosition.Builder() + final CameraPosition cameraPosition = new CameraPosition.Builder() .target(new LatLng(51.50550, -0.07520)) .zoom(ZOOM_LEVEL) .build(); mapBoxMap.setCameraPosition(cameraPosition); - ScaleBarPlugin scaleBarPlugin = new ScaleBarPlugin(mapView, mapBoxMap); - int color = isDarkTheme ? R.color.bottom_bar_light : R.color.bottom_bar_dark; - ScaleBarOptions scaleBarOptions = new ScaleBarOptions(getContext()) + final ScaleBarPlugin scaleBarPlugin = new ScaleBarPlugin(mapView, mapBoxMap); + final int color = isDarkTheme ? R.color.bottom_bar_light : R.color.bottom_bar_dark; + final ScaleBarOptions scaleBarOptions = new ScaleBarOptions(getContext()) .setTextColor(color) .setTextSize(R.dimen.description_text_size) .setBarHeight(R.dimen.tiny_gap) @@ -281,8 +277,18 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private void initRvNearbyList() { rvNearbyList.setLayoutManager(new LinearLayoutManager(getContext())); - adapterFactory = new NearbyAdapterFactory(this, controller); - rvNearbyList.setAdapter(adapterFactory.create(null)); + adapter = new PlaceAdapter(bookmarkLocationDao, + place -> { + centerMapToPlace(place); + return Unit.INSTANCE; + }, + (place, isBookmarked) -> { + updateMarker(isBookmarked, place, null); + return Unit.INSTANCE; + }, + commonPlaceClickActions + ); + rvNearbyList.setAdapter(adapter); } private void addCheckBoxCallback() { @@ -292,13 +298,13 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment private void performMapReadyActions() { if (isVisible() && isVisibleToUser && isMapBoxReady) { checkPermissionsAndPerformAction(() -> { - this.lastKnownLocation = locationManager.getLastLocation(); + lastKnownLocation = locationManager.getLastLocation(); fr.free.nrw.commons.location.LatLng target=lastFocusLocation; if(null==lastFocusLocation){ target=lastKnownLocation; } if (lastKnownLocation != null) { - CameraPosition position = new CameraPosition.Builder() + final CameraPosition position = new CameraPosition.Builder() .target(LocationUtils.commonsLatLngToMapBoxLatLng(target)) // Sets the new camera position .zoom(ZOOM_LEVEL) // Same zoom level .build(); @@ -325,8 +331,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } private void registerNetworkReceiver() { - if (getActivity() != null) + if (getActivity() != null) { getActivity().registerReceiver(broadcastReceiver, intentFilter); + } } @@ -349,7 +356,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment if (null != mapBox) { mapBox.removeOnCameraMoveListener(cameraMoveListener); } - }catch (Exception e){ + }catch (final Exception e){ Timber.e(e); //Broadcast receivers should always be unregistered inside catch, you never know if they were already registered or not } @@ -362,7 +369,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } @Override - public void onSaveInstanceState(Bundle outState) { + public void onSaveInstanceState(final Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); } @@ -415,7 +422,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL)); - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); + final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); recyclerView.setLayoutManager(linearLayoutManager); @@ -427,7 +434,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment } @Override - public void filterByMarkerType(ArrayList