Resolved conflicts

This commit is contained in:
Saifuddin 2024-12-14 12:15:57 +05:30
parent 7b799227ba
commit 16eb639b31
9 changed files with 664 additions and 734 deletions

View file

@ -1,105 +1,109 @@
package fr.free.nrw.commons.bookmarks; package fr.free.nrw.commons.bookmarks
import android.os.Bundle; import android.os.Bundle
import android.view.LayoutInflater; import android.view.LayoutInflater
import android.view.View; import android.view.View
import android.view.ViewGroup; import android.view.ViewGroup
import androidx.annotation.NonNull; import androidx.fragment.app.FragmentManager
import androidx.annotation.Nullable; import fr.free.nrw.commons.contributions.MainActivity
import androidx.fragment.app.FragmentManager; import fr.free.nrw.commons.databinding.FragmentBookmarksBinding
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.databinding.FragmentBookmarksBinding; import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.kvstore.JsonKvStore; import javax.inject.Inject
import fr.free.nrw.commons.theme.BaseActivity; import fr.free.nrw.commons.contributions.ContributionController
import javax.inject.Inject; import javax.inject.Named
import fr.free.nrw.commons.contributions.ContributionController;
import javax.inject.Named;
public class BookmarkFragment extends CommonsDaggerSupportFragment {
private FragmentManager supportFragmentManager; class BookmarkFragment : CommonsDaggerSupportFragment() {
private BookmarksPagerAdapter adapter;
FragmentBookmarksBinding binding; var binding: FragmentBookmarksBinding? = null
private var adapter: BookmarksPagerAdapter? = null
@Inject @Inject
ContributionController controller; lateinit var controller: ContributionController
/** /**
* To check if the user is loggedIn or not. * To check if the user is loggedIn or not.
*/ */
@Inject @Inject
@Named("default_preferences") @field: Named("default_preferences")
public lateinit var applicationKvStore: JsonKvStore
JsonKvStore applicationKvStore;
@NonNull companion object {
public static BookmarkFragment newInstance() { fun newInstance(): BookmarkFragment {
BookmarkFragment fragment = new BookmarkFragment(); val fragment = BookmarkFragment()
fragment.setRetainInstance(true); fragment.retainInstance = true
return fragment; return fragment
}
public void setScroll(boolean canScroll) {
if (binding!=null) {
binding.viewPagerBookmarks.setCanScroll(canScroll);
} }
} }
@Override fun setScroll(canScroll: Boolean) {
public void onCreate(@Nullable final Bundle savedInstanceState) { binding?.viewPagerBookmarks?.isCanScroll = canScroll
super.onCreate(savedInstanceState);
} }
@Nullable override fun onCreate(savedInstanceState: Bundle?) {
@Override super.onCreate(savedInstanceState)
public View onCreateView(@NonNull final LayoutInflater inflater, }
@Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) { override fun onCreateView(
super.onCreateView(inflater, container, savedInstanceState); inflater: LayoutInflater,
binding = FragmentBookmarksBinding.inflate(inflater, container, false); container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentBookmarksBinding.inflate(inflater, container, false)
// Activity can call methods in the fragment by acquiring a // Activity can call methods in the fragment by acquiring a
// reference to the Fragment from FragmentManager, using findFragmentById() // reference to the Fragment from FragmentManager, using findFragmentById()
supportFragmentManager = getChildFragmentManager(); val supportFragmentManager = childFragmentManager
adapter = new BookmarksPagerAdapter(supportFragmentManager, getContext(), adapter = BookmarksPagerAdapter(
applicationKvStore.getBoolean("login_skipped")); supportFragmentManager,
binding.viewPagerBookmarks.setAdapter(adapter); requireContext(),
binding.tabLayout.setupWithViewPager(binding.viewPagerBookmarks); applicationKvStore.getBoolean("login_skipped")
)
binding?.apply {
viewPagerBookmarks.adapter = adapter
tabLayout.setupWithViewPager(viewPagerBookmarks)
}
((MainActivity) getActivity()).showTabs(); (requireActivity() as MainActivity).showTabs()
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false); (requireActivity() as BaseActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false)
setupTabLayout(); setupTabLayout()
return binding.getRoot(); return binding?.root
} }
/** /**
* This method sets up the tab layout. If the adapter has only one element it sets the * This method sets up the tab layout. If the adapter has only one element it sets the
* visibility of tabLayout to gone. * visibility of tabLayout to gone.
*/ */
public void setupTabLayout() { fun setupTabLayout() {
binding.tabLayout.setVisibility(View.VISIBLE); binding?.apply {
if (adapter.getCount() == 1) { tabLayout.visibility = View.VISIBLE
binding.tabLayout.setVisibility(View.GONE); if (adapter?.count == 1) {
tabLayout.visibility = View.GONE
}
} }
} }
fun onBackPressed() {
val selectedFragment = adapter?.getItem(binding?.tabLayout?.selectedTabPosition ?: 0)
as? BookmarkListRootFragment
public void onBackPressed() { if (selectedFragment?.backPressed() == true) {
if (((BookmarkListRootFragment) (adapter.getItem(binding.tabLayout.getSelectedTabPosition()))) // The event is handled internally by the adapter, no further action required.
.backPressed()) { return
// The event is handled internally by the adapter , no further action required.
return;
} }
// Event is not handled by the adapter ( performed back action ) change action bar.
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false); // Event is not handled by the adapter (performed back action) change action bar.
(requireActivity() as BaseActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false)
} }
@Override override fun onDestroy() {
public void onDestroy() { super.onDestroy()
super.onDestroy(); binding = null
binding = null;
} }
} }

View file

@ -1,266 +1,192 @@
package fr.free.nrw.commons.bookmarks; package fr.free.nrw.commons.bookmarks
import android.content.Context; import android.os.Bundle
import android.os.Bundle; import android.view.LayoutInflater
import android.view.LayoutInflater; import android.view.View
import android.view.View; import android.view.ViewGroup
import android.view.ViewGroup; import android.widget.AdapterView
import android.widget.AdapterView; import androidx.fragment.app.Fragment
import androidx.annotation.NonNull; import androidx.fragment.app.FragmentManager
import androidx.annotation.Nullable; import fr.free.nrw.commons.Media
import androidx.fragment.app.Fragment; import fr.free.nrw.commons.R
import androidx.fragment.app.FragmentManager; import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesFragment
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment
import fr.free.nrw.commons.R; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment
import fr.free.nrw.commons.bookmarks.category.BookmarkCategoriesFragment; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsFragment; import fr.free.nrw.commons.category.CategoryImagesCallback
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsFragment; import fr.free.nrw.commons.category.GridViewAdapter
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment; import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.category.CategoryImagesCallback; import fr.free.nrw.commons.databinding.FragmentFeaturedRootBinding
import fr.free.nrw.commons.category.GridViewAdapter; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.databinding.FragmentFeaturedRootBinding; import fr.free.nrw.commons.navtab.NavTab
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import timber.log.Timber
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.navtab.NavTab;
import java.util.ArrayList;
import java.util.Iterator;
import timber.log.Timber;
public class BookmarkListRootFragment extends CommonsDaggerSupportFragment implements
class BookmarkListRootFragment : CommonsDaggerSupportFragment,
FragmentManager.OnBackStackChangedListener, FragmentManager.OnBackStackChangedListener,
MediaDetailPagerFragment.MediaDetailProvider, MediaDetailPagerFragment.MediaDetailProvider,
AdapterView.OnItemClickListener, CategoryImagesCallback { AdapterView.OnItemClickListener,
CategoryImagesCallback {
private MediaDetailPagerFragment mediaDetails; private var mediaDetails: MediaDetailPagerFragment? = null
//private BookmarkPicturesFragment bookmarkPicturesFragment; private var bookmarkLocationsFragment: BookmarkLocationsFragment? = null
private BookmarkLocationsFragment bookmarkLocationsFragment; var listFragment: Fragment? = null
public Fragment listFragment; private var bookmarksPagerAdapter: BookmarksPagerAdapter? = null
private BookmarksPagerAdapter bookmarksPagerAdapter;
FragmentFeaturedRootBinding binding; private var binding: FragmentFeaturedRootBinding? = null
public BookmarkListRootFragment() { constructor() : super() {
//empty constructor necessary otherwise crashes on recreate // Empty constructor necessary otherwise crashes on recreate
} }
public BookmarkListRootFragment(Bundle bundle, BookmarksPagerAdapter bookmarksPagerAdapter) { constructor(bundle: Bundle, bookmarksPagerAdapter: BookmarksPagerAdapter) : this() {
String title = bundle.getString("categoryName"); val title = bundle.getString("categoryName")
int order = bundle.getInt("order"); val order = bundle.getInt("order")
final int orderItem = bundle.getInt("orderItem"); val orderItem = bundle.getInt("orderItem")
listFragment = when (order) {
switch (order){ 0 -> BookmarkPicturesFragment()
case 0: listFragment = new BookmarkPicturesFragment(); 1 -> BookmarkLocationsFragment()
break; 3 -> BookmarkCategoriesFragment()
else -> null
case 1: listFragment = new BookmarkLocationsFragment();
break;
case 3: listFragment = new BookmarkCategoriesFragment();
break;
} }
if(orderItem == 2) {
listFragment = new BookmarkItemsFragment();
}
Bundle featuredArguments = new Bundle(); if(orderItem == 2) {
featuredArguments.putString("categoryName", title); listFragment = BookmarkItemsFragment()
listFragment.setArguments(featuredArguments); }
this.bookmarksPagerAdapter = bookmarksPagerAdapter;
val featuredArguments = Bundle().apply {
putString("categoryName", title)
}
listFragment?.arguments = featuredArguments
this.bookmarksPagerAdapter = bookmarksPagerAdapter
} }
@Nullable override fun onCreateView(
@Override inflater: LayoutInflater,
public View onCreateView(@NonNull final LayoutInflater inflater, container: ViewGroup?,
@Nullable final ViewGroup container, savedInstanceState: Bundle?
@Nullable final Bundle savedInstanceState) { ): View? {
super.onCreate(savedInstanceState); super.onCreateView(inflater, container, savedInstanceState)
binding = FragmentFeaturedRootBinding.inflate(inflater, container, false); binding = FragmentFeaturedRootBinding.inflate(inflater, container, false)
return binding.getRoot(); return binding?.root
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState == null) { if (savedInstanceState == null) {
setFragment(listFragment, mediaDetails); setFragment(listFragment, mediaDetails)
} }
} }
public void setFragment(Fragment fragment, Fragment otherFragment) { fun setFragment(fragment: Fragment?, otherFragment: Fragment?) {
if (fragment.isAdded() && otherFragment != null) { val transaction = childFragmentManager.beginTransaction()
getChildFragmentManager() when {
.beginTransaction() fragment?.isAdded == true && otherFragment != null -> {
.hide(otherFragment) transaction.hide(otherFragment).show(fragment)
.show(fragment) }
.addToBackStack("CONTRIBUTION_LIST_FRAGMENT_TAG") fragment?.isAdded == true && otherFragment == null -> {
.commit(); transaction.show(fragment)
getChildFragmentManager().executePendingTransactions(); }
} else if (fragment.isAdded() && otherFragment == null) { fragment?.isAdded == false && otherFragment != null -> {
getChildFragmentManager() transaction.hide(otherFragment).add(R.id.explore_container, fragment)
.beginTransaction() }
.show(fragment) fragment?.isAdded == false -> {
.addToBackStack("CONTRIBUTION_LIST_FRAGMENT_TAG") transaction.replace(R.id.explore_container, fragment)
.commit(); }
getChildFragmentManager().executePendingTransactions(); }
} else if (!fragment.isAdded() && otherFragment != null) { transaction.addToBackStack("CONTRIBUTION_LIST_FRAGMENT_TAG").commit()
getChildFragmentManager() childFragmentManager.executePendingTransactions()
.beginTransaction() }
.hide(otherFragment)
.add(R.id.explore_container, fragment) fun removeFragment(fragment: Fragment) {
.addToBackStack("CONTRIBUTION_LIST_FRAGMENT_TAG") childFragmentManager.beginTransaction().remove(fragment).commit()
.commit(); childFragmentManager.executePendingTransactions()
getChildFragmentManager().executePendingTransactions(); }
} else if (!fragment.isAdded()) {
getChildFragmentManager() override fun onMediaClicked(position: Int) {
.beginTransaction() Timber.tag("deneme8").d("on media clicked")
.replace(R.id.explore_container, fragment) // container.setVisibility(View.VISIBLE);
.addToBackStack("CONTRIBUTION_LIST_FRAGMENT_TAG") // ((BookmarkFragment)getParentFragment()).tabLayout.setVisibility(View.GONE);
.commit(); // mediaDetails = new MediaDetailPagerFragment(false, true, position);
getChildFragmentManager().executePendingTransactions(); // setFragment(mediaDetails, bookmarkPicturesFragment);
}
override fun getMediaAtPosition(i: Int): Media? {
return bookmarksPagerAdapter?.getMediaAdapter()?.let {
it.getItem(i) as? Media
} }
} }
public void removeFragment(Fragment fragment) { override fun getTotalMediaCount(): Int {
getChildFragmentManager() return bookmarksPagerAdapter?.getMediaAdapter()?.count ?: 0
.beginTransaction()
.remove(fragment)
.commit();
getChildFragmentManager().executePendingTransactions();
} }
@Override override fun getContributionStateAt(position: Int): Int? {
public void onAttach(final Context context) { return null
super.onAttach(context);
} }
@Override override fun refreshNominatedMedia(index: Int) {
public void onMediaClicked(int position) { if (mediaDetails != null && listFragment?.isVisible == false) {
Timber.d("on media clicked"); removeFragment(mediaDetails!!)
/*container.setVisibility(View.VISIBLE); mediaDetails = MediaDetailPagerFragment.newInstance(false, true)
((BookmarkFragment)getParentFragment()).tabLayout.setVisibility(View.GONE); (parentFragment as? BookmarkFragment)?.setScroll(false)
mediaDetails = new MediaDetailPagerFragment(false, true, position); setFragment(mediaDetails, listFragment)
setFragment(mediaDetails, bookmarkPicturesFragment);*/ mediaDetails?.showImage(index)
}
/**
* This method is called mediaDetailPagerFragment. It returns the Media Object at that Index
*
* @param i It is the index of which media object is to be returned which is same as current
* index of viewPager.
* @return Media Object
*/
@Override
public Media getMediaAtPosition(int i) {
if (bookmarksPagerAdapter.getMediaAdapter() == null) {
// not yet ready to return data
return null;
} else {
return (Media) bookmarksPagerAdapter.getMediaAdapter().getItem(i);
} }
} }
/** override fun viewPagerNotifyDataSetChanged() {
* This method is called on from getCount of MediaDetailPagerFragment The viewpager will contain mediaDetails?.notifyDataSetChanged()
* same number of media items as that of media elements in adapter.
*
* @return Total Media count in the adapter
*/
@Override
public int getTotalMediaCount() {
if (bookmarksPagerAdapter.getMediaAdapter() == null) {
return 0;
}
return bookmarksPagerAdapter.getMediaAdapter().getCount();
} }
@Override fun backPressed(): Boolean {
public Integer getContributionStateAt(int position) {
return null;
}
/**
* Reload media detail fragment once media is nominated
*
* @param index item position that has been nominated
*/
@Override
public void refreshNominatedMedia(int index) {
if (mediaDetails != null && !listFragment.isVisible()) {
removeFragment(mediaDetails);
mediaDetails = MediaDetailPagerFragment.newInstance(false, true);
((BookmarkFragment) getParentFragment()).setScroll(false);
setFragment(mediaDetails, listFragment);
mediaDetails.showImage(index);
}
}
/**
* This method is called on success of API call for featured images or mobile uploads. The
* viewpager will notified that number of items have changed.
*/
@Override
public void viewPagerNotifyDataSetChanged() {
if (mediaDetails != null) { if (mediaDetails != null) {
mediaDetails.notifyDataSetChanged(); if (mediaDetails!!.isVisible) {
} (parentFragment as? BookmarkFragment)?.setupTabLayout()
} val removed = mediaDetails!!.removedItems
removeFragment(mediaDetails!!)
public boolean backPressed() { (parentFragment as? BookmarkFragment)?.setScroll(true)
//check mediaDetailPage fragment is not null then we check mediaDetail.is Visible or not to avoid NullPointerException setFragment(listFragment, mediaDetails)
if (mediaDetails != null) { (activity as? MainActivity)?.showTabs()
if (mediaDetails.isVisible()) { if (listFragment is BookmarkPicturesFragment) {
// todo add get list fragment val adapter = (listFragment as BookmarkPicturesFragment).getAdapter()
((BookmarkFragment) getParentFragment()).setupTabLayout(); as GridViewAdapter
ArrayList<Integer> removed = mediaDetails.getRemovedItems(); for (i in removed) {
removeFragment(mediaDetails); adapter.remove(adapter.getItem(i))
((BookmarkFragment) getParentFragment()).setScroll(true);
setFragment(listFragment, mediaDetails);
((MainActivity) getActivity()).showTabs();
if (listFragment instanceof BookmarkPicturesFragment) {
GridViewAdapter adapter = ((GridViewAdapter) ((BookmarkPicturesFragment) listFragment)
.getAdapter());
Iterator i = removed.iterator();
while (i.hasNext()) {
adapter.remove(adapter.getItem((int) i.next()));
} }
mediaDetails.clearRemoved(); mediaDetails!!.clearRemoved()
} }
} else { } else {
moveToContributionsFragment(); moveToContributionsFragment()
} }
} else { } else {
moveToContributionsFragment(); moveToContributionsFragment()
} }
// notify mediaDetails did not handled the backPressed further actions required. return false
return false;
} }
void moveToContributionsFragment() { private fun moveToContributionsFragment() {
((MainActivity) getActivity()).setSelectedItemId(NavTab.CONTRIBUTIONS.code()); (activity as? MainActivity)?.apply {
((MainActivity) getActivity()).showTabs(); setSelectedItemId(NavTab.CONTRIBUTIONS.code())
showTabs()
}
} }
@Override override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Timber.tag("deneme8").d("on media clicked")
Timber.d("on media clicked"); binding?.exploreContainer?.visibility = View.VISIBLE
binding.exploreContainer.setVisibility(View.VISIBLE); (parentFragment as? BookmarkFragment)?.binding?.tabLayout?.visibility = View.GONE
((BookmarkFragment) getParentFragment()).binding.tabLayout.setVisibility(View.GONE); mediaDetails = MediaDetailPagerFragment.newInstance(false, true)
mediaDetails = MediaDetailPagerFragment.newInstance(false, true); (parentFragment as? BookmarkFragment)?.setScroll(false)
((BookmarkFragment) getParentFragment()).setScroll(false); setFragment(mediaDetails, listFragment)
setFragment(mediaDetails, listFragment); mediaDetails?.showImage(position)
mediaDetails.showImage(position);
} }
@Override override fun onBackStackChanged() {}
public void onBackStackChanged() {
} override fun onDestroy() {
super.onDestroy()
@Override binding = null
public void onDestroy() {
super.onDestroy();
binding = null;
} }
} }

View file

@ -1,94 +1,104 @@
package fr.free.nrw.commons.bookmarks; package fr.free.nrw.commons.bookmarks
import android.content.Context; import android.content.Context
import android.os.Bundle; import android.os.Bundle
import android.widget.ListAdapter; import android.widget.ListAdapter
import androidx.annotation.Nullable; import androidx.fragment.app.Fragment
import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.ArrayList; import java.util.ArrayList
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesFragment
public class BookmarksPagerAdapter extends FragmentPagerAdapter {
private ArrayList<BookmarkPages> pages; class BookmarksPagerAdapter(
fm: FragmentManager,
private val context: Context,
onlyPictures: Boolean
) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
/** private val pages: ArrayList<BookmarkPages> = ArrayList()
* Default Constructor
* @param fm
* @param context
* @param onlyPictures is true if the fragment requires only BookmarkPictureFragment
* (i.e. when no user is logged in).
*/
BookmarksPagerAdapter(FragmentManager fm, Context context,boolean onlyPictures) {
super(fm);
pages = new ArrayList<>();
Bundle picturesBundle = new Bundle();
picturesBundle.putString("categoryName", context.getString(R.string.title_page_bookmarks_pictures));
picturesBundle.putInt("order", 0);
pages.add(new BookmarkPages(
new BookmarkListRootFragment(picturesBundle, this),
context.getString(R.string.title_page_bookmarks_pictures)));
if (!onlyPictures) {
// if onlyPictures is false we also add the location fragment.
Bundle locationBundle = new Bundle();
locationBundle.putString("categoryName",
context.getString(R.string.title_page_bookmarks_locations));
locationBundle.putInt("order", 1);
pages.add(new BookmarkPages(
new BookmarkListRootFragment(locationBundle, this),
context.getString(R.string.title_page_bookmarks_locations)));
locationBundle.putInt("orderItem", 2); init {
pages.add(new BookmarkPages( val picturesBundle = Bundle().apply {
new BookmarkListRootFragment(locationBundle, this), putString("categoryName", context.getString(R.string.title_page_bookmarks_pictures))
context.getString(R.string.title_page_bookmarks_items))); putInt("order", 0)
} }
final Bundle categoriesBundle = new Bundle(); pages.add(
categoriesBundle.putString("categoryName", BookmarkPages(
context.getString(R.string.title_page_bookmarks_categories)); BookmarkListRootFragment(picturesBundle, this),
categoriesBundle.putInt("order", 3); context.getString(R.string.title_page_bookmarks_pictures)
pages.add(new BookmarkPages( )
new BookmarkListRootFragment(categoriesBundle, this), )
context.getString(R.string.title_page_bookmarks_categories)));
notifyDataSetChanged(); if (!onlyPictures) {
// Add the location fragment if onlyPictures is false
val locationBundle = Bundle().apply {
putString("categoryName", context.getString(
R.string.title_page_bookmarks_locations
))
putInt("order", 1)
}
pages.add(
BookmarkPages(
BookmarkListRootFragment(locationBundle, this),
context.getString(R.string.title_page_bookmarks_locations)
)
)
locationBundle.putInt("orderItem", 2)
pages.add(
BookmarkPages(
BookmarkListRootFragment(locationBundle, this),
context.getString(R.string.title_page_bookmarks_items)
)
)
}
val categoriesBundle = Bundle().apply {
putString("categoryName", context.getString(R.string.title_page_bookmarks_categories))
putInt("order", 3)
}
pages.add(
BookmarkPages(
BookmarkListRootFragment(categoriesBundle, this),
context.getString(R.string.title_page_bookmarks_categories)
)
)
notifyDataSetChanged()
} }
@Override override fun getItem(position: Int): Fragment {
public Fragment getItem(int position) { return pages[position].page!!
return pages.get(position).getPage();
} }
@Override override fun getCount(): Int {
public int getCount() { return pages.size
return pages.size();
} }
@Nullable override fun getPageTitle(position: Int): CharSequence? {
@Override return pages[position].title
public CharSequence getPageTitle(int position) {
return pages.get(position).getTitle();
} }
/** /**
* Return the Adapter used to display the picture gridview * Return the adapter used to display the picture gridview
* @return adapter * @return adapter
*/ */
public ListAdapter getMediaAdapter() { fun getMediaAdapter(): ListAdapter? {
BookmarkPicturesFragment fragment = (BookmarkPicturesFragment)(((BookmarkListRootFragment)pages.get(0).getPage()).listFragment); val fragment = (pages[0].page as BookmarkListRootFragment).listFragment
return fragment.getAdapter(); as BookmarkPicturesFragment
return fragment.getAdapter()
} }
/** /**
* Update the pictures list for the bookmark fragment * Update the pictures list for the bookmark fragment
*/ */
public void requestPictureListUpdate() { fun requestPictureListUpdate() {
BookmarkPicturesFragment fragment = (BookmarkPicturesFragment)(((BookmarkListRootFragment)pages.get(0).getPage()).listFragment); val fragment = (pages[0].page as BookmarkListRootFragment).listFragment as BookmarkPicturesFragment
fragment.onResume(); fragment.onResume()
} }
} }

View file

@ -1,46 +1,42 @@
package fr.free.nrw.commons.bookmarks.pictures; package fr.free.nrw.commons.bookmarks.pictures
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
// We can get uri using java.Net.Uri, but andoid implimentation is faster (but it's forgiving with handling exceptions though)
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull; import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteQueryBuilder
import android.net.Uri
import fr.free.nrw.commons.BuildConfig
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.TABLE_NAME
import fr.free.nrw.commons.data.DBOpenHelper
import fr.free.nrw.commons.di.CommonsDaggerContentProvider
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Inject;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.data.DBOpenHelper;
import fr.free.nrw.commons.di.CommonsDaggerContentProvider;
import timber.log.Timber;
import static fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME;
import static fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao.Table.TABLE_NAME;
/** /**
* Handles private storage for Bookmark pictures * Handles private storage for Bookmark pictures
*/ */
public class BookmarkPicturesContentProvider extends CommonsDaggerContentProvider { class BookmarkPicturesContentProvider : CommonsDaggerContentProvider() {
private static final String BASE_PATH = "bookmarks"; companion object {
public static final Uri BASE_URI = Uri.parse("content://" + BuildConfig.BOOKMARK_AUTHORITY + "/" + BASE_PATH); private const val BASE_PATH = "bookmarks"
val BASE_URI: Uri = Uri
.parse("content://" + BuildConfig.BOOKMARK_AUTHORITY + "/" + BASE_PATH)
/** /**
* Append bookmark pictures name to the base uri * Append bookmark pictures name to the base uri
*/ */
public static Uri uriForName(String name) { fun uriForName(name: String): Uri {
return Uri.parse(BASE_URI.toString() + "/" + name); return Uri.parse("$BASE_URI/$name")
}
} }
@Inject @Inject
DBOpenHelper dbOpenHelper; lateinit var dbOpenHelper: DBOpenHelper
@Override override fun getType(uri: Uri): String? {
public String getType(@NonNull Uri uri) { return null
return null;
} }
/** /**
@ -51,70 +47,88 @@ public class BookmarkPicturesContentProvider extends CommonsDaggerContentProvide
* @param selectionArgs : the condition of Where clause * @param selectionArgs : the condition of Where clause
* @param sortOrder : ascending or descending * @param sortOrder : ascending or descending
*/ */
@SuppressWarnings("ConstantConditions") override fun query(
@Override uri: Uri,
public Cursor query(@NonNull Uri uri, String[] projection, String selection, projection: Array<out String>?,
String[] selectionArgs, String sortOrder) { selection: String?,
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); selectionArgs: Array<out String>?,
queryBuilder.setTables(TABLE_NAME); sortOrder: String?
): Cursor? {
val queryBuilder = SQLiteQueryBuilder().apply {
tables = TABLE_NAME
}
SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); val db = dbOpenHelper.readableDatabase
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder); val cursor = queryBuilder.query(
cursor.setNotificationUri(getContext().getContentResolver(), uri); db,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
)
cursor.setNotificationUri(context?.contentResolver, uri)
return cursor; return cursor
} }
/** /**
* Handles the update query of local SQLite Database * Handles the update query of local SQLite Database
* @param uri : contains the uri for bookmark pictures * @param uri : contains the uri for bookmark pictures
* @param contentValues : new values to be entered to db * @param contentValues : new values to be entered to db
* @param selection : handles Where * @param selection : handles Where
* @param selectionArgs : the condition of Where clause * @param selectionArgs : the condition of Where clause
*/ */
@SuppressWarnings("ConstantConditions") override fun update(
@Override uri: Uri,
public int update(@NonNull Uri uri, ContentValues contentValues, String selection, contentValues: ContentValues?,
String[] selectionArgs) { selection: String?,
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); selectionArgs: Array<out String>?
int rowsUpdated; ): Int {
if (TextUtils.isEmpty(selection)) { val sqlDB = dbOpenHelper.writableDatabase
int id = Integer.valueOf(uri.getLastPathSegment()); val rowsUpdated: Int
rowsUpdated = sqlDB.update(TABLE_NAME,
contentValues, if (selection.isNullOrEmpty()) {
COLUMN_MEDIA_NAME + " = ?", val id = uri.lastPathSegment?.toInt()
new String[]{String.valueOf(id)}); ?: throw IllegalArgumentException("Invalid ID in URI")
rowsUpdated = sqlDB.update(
TABLE_NAME,
contentValues,
"$COLUMN_MEDIA_NAME = ?",
arrayOf(id.toString())
)
} else { } else {
throw new IllegalArgumentException( throw IllegalArgumentException(
"Parameter `selection` should be empty when updating an ID"); "Parameter `selection` should be empty when updating an ID"
)
} }
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated; context?.contentResolver?.notifyChange(uri, null)
return rowsUpdated
} }
/** /**
* Handles the insertion of new bookmark pictures record to local SQLite Database * Handles the insertion of new bookmark pictures record to local SQLite Database
*/ */
@SuppressWarnings("ConstantConditions") override fun insert(uri: Uri, contentValues: ContentValues?): Uri? {
@Override val sqlDB = dbOpenHelper.writableDatabase
public Uri insert(@NonNull Uri uri, ContentValues contentValues) { val id = sqlDB.insert(TABLE_NAME, null, contentValues)
SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); context?.contentResolver?.notifyChange(uri, null)
long id = sqlDB.insert(BookmarkPicturesDao.Table.TABLE_NAME, null, contentValues); return Uri.parse("$BASE_URI/$id")
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_URI + "/" + id);
} }
@SuppressWarnings("ConstantConditions") override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
@Override val db = dbOpenHelper.readableDatabase
public int delete(@NonNull Uri uri, String s, String[] strings) { Timber.d("Deleting bookmark name %s", uri.lastPathSegment)
int rows;
SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); val rows = db.delete(
Timber.d("Deleting bookmark name %s", uri.getLastPathSegment()); TABLE_NAME,
rows = db.delete(TABLE_NAME, "media_name = ?",
"media_name = ?", arrayOf(uri.lastPathSegment)
new String[]{uri.getLastPathSegment()} )
);
getContext().getContentResolver().notifyChange(uri, null); context?.contentResolver?.notifyChange(uri, null)
return rows; return rows
} }
} }

View file

@ -1,63 +1,53 @@
package fr.free.nrw.commons.bookmarks.pictures; package fr.free.nrw.commons.bookmarks.pictures
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.bookmarks.models.Bookmark
import fr.free.nrw.commons.media.MediaClient
import io.reactivex.Observable
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.bookmarks.models.Bookmark;
import fr.free.nrw.commons.media.MediaClient;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Single;
import io.reactivex.functions.Function;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton @Singleton
public class BookmarkPicturesController { class BookmarkPicturesController @Inject constructor(
private val mediaClient: MediaClient,
private val bookmarkDao: BookmarkPicturesDao
) {
private final MediaClient mediaClient; private var currentBookmarks: List<Bookmark> = emptyList()
private final BookmarkPicturesDao bookmarkDao;
private List<Bookmark> currentBookmarks;
@Inject
public BookmarkPicturesController(MediaClient mediaClient, BookmarkPicturesDao bookmarkDao) {
this.mediaClient = mediaClient;
this.bookmarkDao = bookmarkDao;
currentBookmarks = new ArrayList<>();
}
/** /**
* Loads the Media objects from the raw data stored in DB and the API. * Loads the Media objects from the raw data stored in DB and the API.
* @return a list of bookmarked Media object * @return a list of bookmarked Media object
*/ */
Single<List<Media>> loadBookmarkedPictures() { fun loadBookmarkedPictures(): Single<List<Media>> {
List<Bookmark> bookmarks = bookmarkDao.getAllBookmarks(); val bookmarks = bookmarkDao.getAllBookmarks()
currentBookmarks = bookmarks; currentBookmarks = bookmarks
return Observable.fromIterable(bookmarks) return Observable.fromIterable(bookmarks)
.flatMap((Function<Bookmark, ObservableSource<Media>>) this::getMediaFromBookmark) .flatMap { bookmark -> getMediaFromBookmark(bookmark) }
.toList(); .toList()
} }
private Observable<Media> getMediaFromBookmark(Bookmark bookmark) { private fun getMediaFromBookmark(bookmark: Bookmark): Observable<Media> {
return mediaClient.getMedia(bookmark.getMediaName()) return mediaClient.getMedia(bookmark.mediaName)
.toObservable() .toObservable()
.onErrorResumeNext(Observable.empty()); .onErrorResumeNext(Observable.empty())
} }
/** /**
* Loads the Media objects from the raw data stored in DB and the API. * Loads the Media objects from the raw data stored in DB and the API.
* @return a list of bookmarked Media object * @return a list of bookmarked Media object
*/ */
boolean needRefreshBookmarkedPictures() { fun needRefreshBookmarkedPictures(): Boolean {
List<Bookmark> bookmarks = bookmarkDao.getAllBookmarks(); val bookmarks = bookmarkDao.getAllBookmarks()
return bookmarks.size() != currentBookmarks.size(); return bookmarks.size != currentBookmarks.size
} }
/** /**
* Cancels the requests to the API and the DB * Cancels the requests to the API and the DB
*/ */
void stop() { fun stop() {
//noop // noop
} }
} }

View file

@ -1,83 +1,67 @@
package fr.free.nrw.commons.bookmarks.pictures; package fr.free.nrw.commons.bookmarks.pictures
import android.annotation.SuppressLint;
import android.content.ContentProviderClient;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.RemoteException;
import androidx.annotation.NonNull; import android.annotation.SuppressLint
import android.content.ContentProviderClient
import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.os.RemoteException
import fr.free.nrw.commons.bookmarks.models.Bookmark
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Provider
import javax.inject.Singleton
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import fr.free.nrw.commons.bookmarks.models.Bookmark;
import static fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider.BASE_URI;
@Singleton @Singleton
public class BookmarkPicturesDao { class BookmarkPicturesDao @Inject constructor(
@Named("bookmarks") private val clientProvider: Provider<ContentProviderClient>
private final Provider<ContentProviderClient> clientProvider; ) {
@Inject
public BookmarkPicturesDao(@Named("bookmarks") Provider<ContentProviderClient> clientProvider) {
this.clientProvider = clientProvider;
}
/** /**
* Find all persisted pictures bookmarks on database * Find all persisted pictures bookmarks on database
* *
* @return list of bookmarks * @return list of bookmarks
*/ */
@NonNull fun getAllBookmarks(): List<Bookmark> {
public List<Bookmark> getAllBookmarks() { val items = mutableListOf<Bookmark>()
List<Bookmark> items = new ArrayList<>(); var cursor: Cursor? = null
Cursor cursor = null; val db = clientProvider.get()
ContentProviderClient db = clientProvider.get();
try { try {
cursor = db.query( cursor = db.query(
BookmarkPicturesContentProvider.BASE_URI, BookmarkPicturesContentProvider.BASE_URI,
Table.ALL_FIELDS, Table.ALL_FIELDS,
null, null,
new String[]{}, emptyArray(),
null); null
while (cursor != null && cursor.moveToNext()) { )
items.add(fromCursor(cursor)); while (cursor?.moveToNext() == true) {
items.add(fromCursor(cursor))
} }
} catch (RemoteException e) { } catch (e: RemoteException) {
throw new RuntimeException(e); throw RuntimeException(e)
} finally { } finally {
if (cursor != null) { cursor?.close()
cursor.close(); db.close()
}
db.release();
} }
return items; return items
} }
/** /**
* Look for a bookmark in database and in order to insert or delete it * Look for a bookmark in database and in order to insert or delete it
* *
* @param bookmark : Bookmark object * @param bookmark : Bookmark object
* @return boolean : is bookmark now fav ? * @return boolean : is bookmark now fav?
*/ */
public boolean updateBookmark(Bookmark bookmark) { fun updateBookmark(bookmark: Bookmark): Boolean {
boolean bookmarkExists = findBookmark(bookmark); val bookmarkExists = findBookmark(bookmark)
if (bookmarkExists) { if (bookmarkExists) {
deleteBookmark(bookmark); deleteBookmark(bookmark)
} else { } else {
addBookmark(bookmark); addBookmark(bookmark)
} }
return !bookmarkExists; return !bookmarkExists
} }
/** /**
@ -85,14 +69,14 @@ public class BookmarkPicturesDao {
* *
* @param bookmark : Bookmark to add * @param bookmark : Bookmark to add
*/ */
private void addBookmark(Bookmark bookmark) { private fun addBookmark(bookmark: Bookmark) {
ContentProviderClient db = clientProvider.get(); val db = clientProvider.get()
try { try {
db.insert(BASE_URI, toContentValues(bookmark)); db.insert(BookmarkPicturesContentProvider.BASE_URI, toContentValues(bookmark))
} catch (RemoteException e) { } catch (e: RemoteException) {
throw new RuntimeException(e); throw RuntimeException(e)
} finally { } finally {
db.release(); db.close()
} }
} }
@ -101,18 +85,19 @@ public class BookmarkPicturesDao {
* *
* @param bookmark : Bookmark to delete * @param bookmark : Bookmark to delete
*/ */
private void deleteBookmark(Bookmark bookmark) { private fun deleteBookmark(bookmark: Bookmark) {
ContentProviderClient db = clientProvider.get(); val db = clientProvider.get()
try { try {
if (bookmark.getContentUri() == null) { val contentUri = bookmark.contentUri
throw new RuntimeException("tried to delete item with no content URI"); if (contentUri == null) {
throw RuntimeException("Tried to delete item with no content URI")
} else { } else {
db.delete(bookmark.getContentUri(), null, null); db.delete(contentUri, null, null)
} }
} catch (RemoteException e) { } catch (e: RemoteException) {
throw new RuntimeException(e); throw RuntimeException(e)
} finally { } finally {
db.release(); db.close()
} }
} }
@ -120,107 +105,102 @@ public class BookmarkPicturesDao {
* Find a bookmark from database based on its name * Find a bookmark from database based on its name
* *
* @param bookmark : Bookmark to find * @param bookmark : Bookmark to find
* @return boolean : is bookmark in database ? * @return boolean : is bookmark in database?
*/ */
public boolean findBookmark(Bookmark bookmark) { fun findBookmark(bookmark: Bookmark?): Boolean {
if (bookmark == null) {//Avoiding NPE's if (bookmark == null) {
return false; // Avoiding NPEs
return false
} }
Cursor cursor = null; var cursor: Cursor? = null
ContentProviderClient db = clientProvider.get(); val db = clientProvider.get()
try { try {
cursor = db.query( cursor = db.query(
BookmarkPicturesContentProvider.BASE_URI, BookmarkPicturesContentProvider.BASE_URI,
Table.ALL_FIELDS, Table.ALL_FIELDS,
Table.COLUMN_MEDIA_NAME + "=?", "${Table.COLUMN_MEDIA_NAME} = ?",
new String[]{bookmark.getMediaName()}, arrayOf(bookmark.mediaName),
null); null
if (cursor != null && cursor.moveToFirst()) { )
return true; if (cursor?.moveToFirst() == true) {
return true
} }
} catch (RemoteException e) { } catch (e: RemoteException) {
// This feels lazy, but to hell with checked exceptions. :) // This feels lazy, but to hell with checked exceptions. :)
throw new RuntimeException(e); throw RuntimeException(e)
} finally { } finally {
if (cursor != null) { cursor?.close()
cursor.close(); db.close()
}
db.release();
} }
return false; return false
} }
@SuppressLint("Range") @SuppressLint("Range")
@NonNull private fun fromCursor(cursor: Cursor): Bookmark {
Bookmark fromCursor(Cursor cursor) { val fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_MEDIA_NAME))
String fileName = cursor.getString(cursor.getColumnIndex(Table.COLUMN_MEDIA_NAME)); return Bookmark(
return new Bookmark( fileName,
fileName, cursor.getString(cursor.getColumnIndex(Table.COLUMN_CREATOR)),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_CREATOR)), BookmarkPicturesContentProvider.uriForName(fileName)
BookmarkPicturesContentProvider.uriForName(fileName) )
);
} }
private ContentValues toContentValues(Bookmark bookmark) { private fun toContentValues(bookmark: Bookmark): ContentValues {
ContentValues cv = new ContentValues(); return ContentValues().apply {
cv.put(BookmarkPicturesDao.Table.COLUMN_MEDIA_NAME, bookmark.getMediaName()); put(Table.COLUMN_MEDIA_NAME, bookmark.mediaName)
cv.put(BookmarkPicturesDao.Table.COLUMN_CREATOR, bookmark.getMediaCreator()); put(Table.COLUMN_CREATOR, bookmark.mediaCreator)
return cv; }
} }
object Table {
const val TABLE_NAME = "bookmarks"
public static class Table { const val COLUMN_MEDIA_NAME = "media_name"
public static final String TABLE_NAME = "bookmarks"; const val COLUMN_CREATOR = "media_creator"
public static final String COLUMN_MEDIA_NAME = "media_name";
public static final String COLUMN_CREATOR = "media_creator";
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES. // NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
public static final String[] ALL_FIELDS = { val ALL_FIELDS = arrayOf(
COLUMN_MEDIA_NAME, COLUMN_MEDIA_NAME,
COLUMN_CREATOR COLUMN_CREATOR
}; )
public static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME; const val DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS $TABLE_NAME"
public static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " (" const val CREATE_TABLE_STATEMENT = """
+ COLUMN_MEDIA_NAME + " STRING PRIMARY KEY," CREATE TABLE $TABLE_NAME (
+ COLUMN_CREATOR + " STRING" $COLUMN_MEDIA_NAME STRING PRIMARY KEY,
+ ");"; $COLUMN_CREATOR STRING
);
"""
public static void onCreate(SQLiteDatabase db) { fun onCreate(db: SQLiteDatabase) {
db.execSQL(CREATE_TABLE_STATEMENT); db.execSQL(CREATE_TABLE_STATEMENT)
} }
public static void onDelete(SQLiteDatabase db) { fun onDelete(db: SQLiteDatabase) {
db.execSQL(DROP_TABLE_STATEMENT); db.execSQL(DROP_TABLE_STATEMENT)
onCreate(db); onCreate(db)
} }
public static void onUpdate(SQLiteDatabase db, int from, int to) { fun onUpdate(db: SQLiteDatabase, from: Int, to: Int) {
if (from == to) { if (from == to) return
return;
}
if (from < 7) { if (from < 7) {
// doesn't exist yet // doesn't exist yet
from++; onUpdate(db, from + 1, to)
onUpdate(db, from, to); return
return;
} }
if (from == 7) { if (from == 7) {
// table added in version 8 // table added in version 8
onCreate(db); onCreate(db)
from++; onUpdate(db, from + 1, to)
onUpdate(db, from, to); return
return;
} }
if (from == 8) { if (from == 8) {
from++; onUpdate(db, from + 1, to)
onUpdate(db, from, to);
return;
} }
} }
} }

View file

@ -1,89 +1,82 @@
package fr.free.nrw.commons.bookmarks.pictures; package fr.free.nrw.commons.bookmarks.pictures
import static android.view.View.GONE; import android.annotation.SuppressLint
import static android.view.View.VISIBLE; import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ListAdapter
import dagger.android.support.DaggerFragment
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.bookmarks.BookmarkListRootFragment
import fr.free.nrw.commons.category.GridViewAdapter
import fr.free.nrw.commons.databinding.FragmentBookmarksPicturesBinding
import fr.free.nrw.commons.utils.NetworkUtils
import fr.free.nrw.commons.utils.ViewUtil
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import javax.inject.Inject
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import dagger.android.support.DaggerFragment;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.bookmarks.BookmarkListRootFragment;
import fr.free.nrw.commons.category.GridViewAdapter;
import fr.free.nrw.commons.databinding.FragmentBookmarksPicturesBinding;
import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.util.List;
import javax.inject.Inject;
import timber.log.Timber;
public class BookmarkPicturesFragment extends DaggerFragment { class BookmarkPicturesFragment : DaggerFragment() {
private GridViewAdapter gridAdapter; private var gridAdapter: GridViewAdapter? = null
private CompositeDisposable compositeDisposable = new CompositeDisposable(); private val compositeDisposable = CompositeDisposable()
private var binding: FragmentBookmarksPicturesBinding? = null
private FragmentBookmarksPicturesBinding binding;
@Inject @Inject
BookmarkPicturesController controller; lateinit var controller: BookmarkPicturesController
/** /**
* Create an instance of the fragment with the right bundle parameters * Create an instance of the fragment with the right bundle parameters
* @return an instance of the fragment * @return an instance of the fragment
*/ */
public static BookmarkPicturesFragment newInstance() { companion object {
return new BookmarkPicturesFragment(); fun newInstance(): BookmarkPicturesFragment {
return BookmarkPicturesFragment()
}
} }
@Override override fun onCreateView(
public View onCreateView( inflater: LayoutInflater,
@NonNull LayoutInflater inflater, container: ViewGroup?,
ViewGroup container, savedInstanceState: Bundle?
Bundle savedInstanceState ): View? {
) { binding = FragmentBookmarksPicturesBinding.inflate(inflater, container, false)
binding = FragmentBookmarksPicturesBinding.inflate(inflater, container, false); return binding?.root
return binding.getRoot();
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState); binding?.bookmarkedPicturesList?.onItemClickListener = parentFragment as? AdapterView.OnItemClickListener
binding.bookmarkedPicturesList.setOnItemClickListener((AdapterView.OnItemClickListener) getParentFragment()); initList()
initList();
} }
@Override override fun onStop() {
public void onStop() { super.onStop()
super.onStop(); controller.stop()
controller.stop();
} }
@Override override fun onDestroy() {
public void onDestroy() { super.onDestroy()
super.onDestroy(); compositeDisposable.clear()
compositeDisposable.clear(); binding = null
binding = null;
} }
@Override override fun onResume() {
public void onResume() { super.onResume()
super.onResume();
if (controller.needRefreshBookmarkedPictures()) { if (controller.needRefreshBookmarkedPictures()) {
binding.bookmarkedPicturesList.setVisibility(GONE); binding?.bookmarkedPicturesList?.visibility = View.GONE
if (gridAdapter != null) { gridAdapter?.let {
gridAdapter.clear(); it.clear()
((BookmarkListRootFragment)getParentFragment()).viewPagerNotifyDataSetChanged(); (parentFragment as? BookmarkListRootFragment)?.viewPagerNotifyDataSetChanged()
} }
initList(); initList()
} }
} }
@ -92,31 +85,37 @@ public class BookmarkPicturesFragment extends DaggerFragment {
* the recycler view with bookmarked pictures * the recycler view with bookmarked pictures
*/ */
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
private void initList() { private fun initList() {
if (!NetworkUtils.isInternetConnectionEstablished(getContext())) { if (!NetworkUtils.isInternetConnectionEstablished(requireContext())) {
handleNoInternet(); handleNoInternet()
return; return
} }
binding.loadingImagesProgressBar.setVisibility(VISIBLE); binding?.apply {
binding.statusMessage.setVisibility(GONE); loadingImagesProgressBar.visibility = View.VISIBLE
statusMessage.visibility = View.GONE
}
compositeDisposable.add(controller.loadBookmarkedPictures() compositeDisposable.add(
controller.loadBookmarkedPictures()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleSuccess, this::handleError)); .subscribe(::handleSuccess, ::handleError)
)
} }
/** /**
* Handles the UI updates for no internet scenario * Handles the UI updates for no internet scenario
*/ */
private void handleNoInternet() { private fun handleNoInternet() {
binding.loadingImagesProgressBar.setVisibility(GONE); binding?.apply {
if (gridAdapter == null || gridAdapter.isEmpty()) { loadingImagesProgressBar.visibility = View.GONE
binding.statusMessage.setVisibility(VISIBLE); if (gridAdapter == null || gridAdapter?.isEmpty == true) {
binding.statusMessage.setText(getString(R.string.no_internet)); statusMessage.visibility = View.VISIBLE
} else { statusMessage.text = getString(R.string.no_internet)
ViewUtil.showShortSnackbar(binding.parentLayout, R.string.no_internet); } else {
ViewUtil.showShortSnackbar(parentLayout, R.string.no_internet)
}
} }
} }
@ -124,39 +123,43 @@ public class BookmarkPicturesFragment extends DaggerFragment {
* Logs and handles API error scenario * Logs and handles API error scenario
* @param throwable * @param throwable
*/ */
private void handleError(Throwable throwable) { private fun handleError(throwable: Throwable) {
Timber.e(throwable, "Error occurred while loading images inside a category"); Timber.e(throwable, "Error occurred while loading images inside a category")
try{ try {
ViewUtil.showShortSnackbar(binding.getRoot(), R.string.error_loading_images); ViewUtil.showShortSnackbar(binding?.root ?: return, R.string.error_loading_images)
initErrorView(); initErrorView()
}catch (Exception e){ } catch (e: Exception) {
e.printStackTrace(); e.printStackTrace()
} }
} }
/** /**
* Handles the UI updates for a error scenario * Handles the UI updates for an error scenario
*/ */
private void initErrorView() { private fun initErrorView() {
binding.loadingImagesProgressBar.setVisibility(GONE); binding?.apply {
if (gridAdapter == null || gridAdapter.isEmpty()) { loadingImagesProgressBar.visibility = View.GONE
binding.statusMessage.setVisibility(VISIBLE); if (gridAdapter == null || gridAdapter?.isEmpty == true) {
binding.statusMessage.setText(getString(R.string.no_images_found)); statusMessage.visibility = View.VISIBLE
} else { statusMessage.text = getString(R.string.no_images_found)
binding.statusMessage.setVisibility(GONE); } else {
statusMessage.visibility = View.GONE
}
} }
} }
/** /**
* Handles the UI updates when there is no bookmarks * Handles the UI updates when there are no bookmarks
*/ */
private void initEmptyBookmarkListView() { private fun initEmptyBookmarkListView() {
binding.loadingImagesProgressBar.setVisibility(GONE); binding?.apply {
if (gridAdapter == null || gridAdapter.isEmpty()) { loadingImagesProgressBar.visibility = View.GONE
binding.statusMessage.setVisibility(VISIBLE); if (gridAdapter == null || gridAdapter?.isEmpty == true) {
binding.statusMessage.setText(getString(R.string.bookmark_empty)); statusMessage.visibility = View.VISIBLE
} else { statusMessage.text = getString(R.string.bookmark_empty)
binding.statusMessage.setVisibility(GONE); } else {
statusMessage.visibility = View.GONE
}
} }
} }
@ -165,54 +168,57 @@ public class BookmarkPicturesFragment extends DaggerFragment {
* On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter * On first load, it initializes the grid view. On subsequent loads, it adds items to the adapter
* @param collection List of new Media to be displayed * @param collection List of new Media to be displayed
*/ */
private void handleSuccess(List<Media> collection) { private fun handleSuccess(collection: List<Media>?) {
if (collection == null) { if (collection == null) {
initErrorView(); initErrorView()
return; return
} }
if (collection.isEmpty()) { if (collection.isEmpty()) {
initEmptyBookmarkListView(); initEmptyBookmarkListView()
return; return
} }
if (gridAdapter == null) { if (gridAdapter == null) {
setAdapter(collection); setAdapter(collection)
} else { } else {
if (gridAdapter.containsAll(collection)) { if (gridAdapter?.containsAll(collection) == true) {
binding.loadingImagesProgressBar.setVisibility(GONE); binding?.apply {
binding.statusMessage.setVisibility(GONE); loadingImagesProgressBar.visibility = View.GONE
binding.bookmarkedPicturesList.setVisibility(VISIBLE); statusMessage.visibility = View.GONE
binding.bookmarkedPicturesList.setAdapter(gridAdapter); bookmarkedPicturesList.visibility = View.VISIBLE
return; bookmarkedPicturesList.adapter = gridAdapter
}
return
} }
gridAdapter.addItems(collection); gridAdapter?.addItems(collection)
((BookmarkListRootFragment) getParentFragment()).viewPagerNotifyDataSetChanged(); (parentFragment as? BookmarkListRootFragment)?.viewPagerNotifyDataSetChanged()
}
binding?.apply {
loadingImagesProgressBar.visibility = View.GONE
statusMessage.visibility = View.GONE
bookmarkedPicturesList.visibility = View.VISIBLE
} }
binding.loadingImagesProgressBar.setVisibility(GONE);
binding.statusMessage.setVisibility(GONE);
binding.bookmarkedPicturesList.setVisibility(VISIBLE);
} }
/** /**
* Initializes the adapter with a list of Media objects * Initializes the adapter with a list of Media objects
* @param mediaList List of new Media to be displayed * @param mediaList List of new Media to be displayed
*/ */
private void setAdapter(List<Media> mediaList) { private fun setAdapter(mediaList: List<Media>) {
gridAdapter = new GridViewAdapter( gridAdapter = GridViewAdapter(
this.getContext(), requireContext(),
R.layout.layout_category_images, R.layout.layout_category_images,
mediaList mediaList.toMutableList()
); )
binding.bookmarkedPicturesList.setAdapter(gridAdapter); binding?.bookmarkedPicturesList?.adapter = gridAdapter
} }
/** /**
* It return an instance of gridView adapter which helps in extracting media details * It returns an instance of gridView adapter which helps in extracting media details
* used by the gridView * used by the gridView
* @return GridView Adapter * @return GridView Adapter
*/ */
public ListAdapter getAdapter() { fun getAdapter(): ListAdapter? {
return binding.bookmarkedPicturesList.getAdapter(); return binding?.bookmarkedPicturesList?.adapter
} }
} }

View file

@ -344,7 +344,7 @@ public class MainActivity extends BaseActivity
loadFragment(ExploreFragment.newInstance(), false); loadFragment(ExploreFragment.newInstance(), false);
} else if (fragmentName.equals(ActiveFragment.BOOKMARK.name())) { } else if (fragmentName.equals(ActiveFragment.BOOKMARK.name())) {
setTitle(getString(R.string.bookmarks)); setTitle(getString(R.string.bookmarks));
loadFragment(BookmarkFragment.newInstance(), false); loadFragment(BookmarkFragment.Companion.newInstance(), false);
} }
} }

View file

@ -422,7 +422,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
bookmark = new Bookmark( bookmark = new Bookmark(
m.getFilename(), m.getFilename(),
m.getAuthor(), m.getAuthor(),
BookmarkPicturesContentProvider.uriForName(m.getFilename()) BookmarkPicturesContentProvider.Companion.uriForName(m.getFilename())
); );
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_image)); updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_image));
final Integer contributionState = provider.getContributionStateAt(position); final Integer contributionState = provider.getContributionStateAt(position);