[android] Added bookmarks catalog UI and descriptions, removed multiple JNI calls, replaced them with BookmarkCategory model methods

This commit is contained in:
Dmitry Donskoy 2018-06-14 16:54:03 +03:00 committed by Aleksandr Zatsepin
parent 608500150e
commit b66fe1c5f5
15 changed files with 475 additions and 168 deletions

View file

@ -74,12 +74,14 @@ void PrepareClassRefs(JNIEnv * env)
// String name,
// String authorId,
// String authorName,
// String annotation,
// String desc,
// int tracksCount,
// int bookmarksCount,
// boolean fromCatalog,
// boolean isVisible)
g_bookmarkCategoryConstructor =
jni::GetConstructorID(env, g_bookmarkCategoryClass, "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZZ)V");
jni::GetConstructorID(env, g_bookmarkCategoryClass, "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIZZ)V");
}
void OnAsyncLoadingStarted(JNIEnv * env)
@ -666,32 +668,36 @@ Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeIsCategoryFromCata
}
JNIEXPORT jobjectArray JNICALL
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(
JNIEnv *env, jobject thiz)
Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(JNIEnv *env, jobject thiz)
{
auto const & bm = frm()->GetBookmarkManager();
kml::GroupIdCollection const & categories = bm.GetBmGroupsIdList();
auto const & bm = frm()->GetBookmarkManager();
kml::GroupIdCollection const & categories = bm.GetBmGroupsIdList();
return ToJavaArray(env,
g_bookmarkCategoryClass,
categories,
[](JNIEnv * env, kml::MarkGroupId const & item) {
auto const & manager = frm()->GetBookmarkManager();
auto const & data = manager.GetCategoryData(item);
auto const isFromCatalog = manager.IsCategoryFromCatalog(item);
auto const tracksCount = manager.GetTrackIds(data.m_id).size();
auto const bookmarksCount = manager.GetUserMarkIds(data.m_id).size();
auto const isVisible = manager.IsVisible(data.m_id);
return env->NewObject(g_bookmarkCategoryClass,
g_bookmarkCategoryConstructor,
static_cast<jlong>(data.m_id),
jni::ToJavaString(env, kml::GetDefaultStr(data.m_name)),
jni::ToJavaString(env, data.m_authorId),
jni::ToJavaString(env, data.m_authorName),
static_cast<jint>(tracksCount),
static_cast<jint>(bookmarksCount),
static_cast<jboolean>(isFromCatalog),
static_cast<jboolean>(isVisible));
});
return ToJavaArray(env,
g_bookmarkCategoryClass,
categories,
[](JNIEnv * env, kml::MarkGroupId const & item)
{
auto const & manager = frm()->GetBookmarkManager();
auto const & data = manager.GetCategoryData(item);
auto const isFromCatalog = manager.IsCategoryFromCatalog(item);
auto const tracksCount = manager.GetTrackIds(data.m_id).size();
auto const bookmarksCount = manager.GetUserMarkIds(data.m_id).size();
auto const isVisible = manager.IsVisible(data.m_id);
return env->NewObject(g_bookmarkCategoryClass,
g_bookmarkCategoryConstructor,
static_cast<jlong>(data.m_id),
jni::ToJavaString(env, kml::GetDefaultStr(data.m_name)),
jni::ToJavaString(env, data.m_authorId),
jni::ToJavaString(env, data.m_authorName),
jni::ToJavaString(env, kml::GetDefaultStr(data.m_annotation)),
jni::ToJavaString(env, kml::GetDefaultStr(data.m_description)),
static_cast<jint>(tracksCount),
static_cast<jint>(bookmarksCount),
static_cast<jboolean>(isFromCatalog),
static_cast<jboolean>(isVisible));
});
}
} // extern "C"

View file

@ -4,34 +4,60 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/height_item_oneline"
android:gravity="center"
android:background="?clickableBackground">
<ImageView
android:id="@+id/iv__bookmark_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"/>
android:id="@+id/iv__bookmark_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_alignParentStart="true"/>
<TextView
<ImageView
android:id="@+id/more"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minHeight="@dimen/height_item_edit_bookmark"
android:paddingRight="@dimen/margin_base"
android:paddingEnd="@dimen/margin_base"
android:paddingLeft="@dimen/margin_double"
android:paddingStart="@dimen/margin_double"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_more"
android:background="?selectableItemBackgroundBorderless"
android:tint="?secondary"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:weightSum="2"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/iv__bookmark_color"
android:layout_toEndOf="@id/iv__bookmark_color"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:layout_toLeftOf="@id/more"
android:layout_toStartOf="@id/more">
<TextView
android:id="@+id/tv__bookmark_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/tv__bookmark_distance"
android:layout_toRightOf="@id/iv__bookmark_color"
android:layout_height="0dp"
android:layout_weight="1"
android:singleLine="true"
android:textAppearance="@style/MwmTextAppearance.Body1"/>
<TextView
<TextView
android:id="@+id/tv__bookmark_distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="@dimen/margin_base"
android:layout_height="0dp"
android:layout_weight="1"
android:textAppearance="@style/MwmTextAppearance.Body3"/>
</LinearLayout>
</RelativeLayout>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="@dimen/margin_base"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
app:layout_constraintTop_toTopOf="parent"
android:textAppearance="@style/MwmTextAppearance.Body2.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/author"
app:layout_constraintTop_toBottomOf="@id/title"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/description"
app:layout_constraintTop_toBottomOf="@id/author"
android:layout_marginTop="@dimen/margin_half_plus"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>

View file

@ -1,11 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="@+id/text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/height_item_oneline"
android:gravity="left|center_vertical"
android:paddingLeft="@dimen/margin_base"
android:paddingTop="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:text="@string/bookmarks"/>
android:id="@+id/text"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/height_item_oneline"
android:gravity="left|center_vertical"
android:paddingLeft="@dimen/margin_base"
android:paddingTop="@dimen/margin_half"
android:background="@color/bookmarks_list_item_bg"
android:fontFamily="@string/robotoMedium"
tools:targetApi="JELLY_BEAN"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:text="@string/bookmarks"/>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/share_message"
android:title="@string/share_by_message"
android:icon="@drawable/ic_share_message"/>
<item android:id="@+id/share_email"
android:title="@string/share_by_email"
android:icon="@drawable/ic_share_email"/>
<item android:id="@+id/share"
android:title="@string/share"
android:icon="@drawable/ic_share"/>
</menu>

View file

@ -217,4 +217,6 @@
<color name="rating_horrible">#E53935</color>
<color name="rating_none">#FF888A82</color>
<color name="rating_coming_soon">#FF1E96F0</color>
<color name="bookmarks_list_item_bg">#1E000000</color>
</resources>

View file

@ -16,6 +16,7 @@ import android.view.ViewGroup;
import com.mapswithme.maps.R;
import com.mapswithme.maps.widget.PlaceholderView;
import com.mapswithme.maps.widget.recycler.ItemDecoratorFactory;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
@ -80,6 +81,9 @@ public abstract class BaseMwmRecyclerFragment extends Fragment
LinearLayoutManager manager = new LinearLayoutManager(view.getContext());
manager.setSmoothScrollbarEnabled(true);
mRecycler.setLayoutManager(manager);
RecyclerView.ItemDecoration decor = ItemDecoratorFactory
.createDefaultDecorator(getContext(), LinearLayoutManager.VERTICAL);
mRecycler.addItemDecoration(decor);
mRecycler.setAdapter(createAdapter());
mPlaceholder = view.findViewById(R.id.placeholder);

View file

@ -270,8 +270,14 @@ public abstract class BaseBookmarkCategoriesFragment extends BaseMwmRecyclerFrag
@Override
public void onItemClick(View v, BookmarkCategory category)
{
startActivity(new Intent(getActivity(), BookmarkListActivity.class)
.putExtra(BookmarksListFragment.EXTRA_CATEGORY, category));
startActivity(makeBookmarksListIntent(category));
}
@NonNull
private Intent makeBookmarksListIntent(BookmarkCategory category)
{
return new Intent(getActivity(), BookmarkListActivity.class)
.putExtra(BookmarksListFragment.EXTRA_CATEGORY, category);
}
@Override

View file

@ -14,6 +14,7 @@ import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import static com.mapswithme.maps.bookmarks.Holders.CategoryViewHolder;
import static com.mapswithme.maps.bookmarks.Holders.HeaderViewHolder;
import static com.mapswithme.util.UiUtils.PHRASE_SEPARATOR;
public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<RecyclerView.ViewHolder>
{
@ -151,10 +152,16 @@ public class BookmarkCategoriesAdapter extends BaseBookmarkCategoryAdapter<Recyc
BookmarkCategory.Author author = category.getAuthor();
CharSequence authorName = author == null
? null
: BookmarkCategory.Author.getRepresentation(getContext(), author);
: getAuthorRepresentation(author);
categoryHolder.getAuthorName().setText(authorName);
}
@NonNull
private String getAuthorRepresentation(@NonNull BookmarkCategory.Author author)
{
return PHRASE_SEPARATOR + BookmarkCategory.Author.getRepresentation(getContext(), author);
}
@Override
public int getItemViewType(int position)
{

View file

@ -1,14 +1,15 @@
package com.mapswithme.maps.bookmarks;
import android.app.Activity;
import android.location.Location;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.maps.bookmarks.data.BookmarkCategory;
import com.mapswithme.maps.bookmarks.data.BookmarkManager;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.location.LocationListener;
@ -16,21 +17,24 @@ import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import com.mapswithme.maps.widget.recycler.RecyclerLongClickListener;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.SECTION_BMKS;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.SECTION_DESC;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.SECTION_TRACKS;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.getBookmarksSectionPosition;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.getDescItemCount;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.getDescSectionPosition;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.getTracksSectionPosition;
import static com.mapswithme.maps.bookmarks.Holders.BaseBookmarkHolder.isSectionEmpty;
import static com.mapswithme.maps.bookmarks.Holders.BookmarkViewHolder.calculateBookmarkPosition;
public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookmarkHolder>
{
private final Activity mActivity;
private final long mCategoryId;
private final BookmarkCategory mCategory;
// view types
static final int TYPE_TRACK = 0;
static final int TYPE_BOOKMARK = 1;
static final int TYPE_SECTION = 2;
static final int TYPE_DESC = 3;
private final LocationListener mLocationListener = new LocationListener.Simple()
{
@ -46,10 +50,9 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
@Nullable
private RecyclerClickListener mClickListener;
BookmarkListAdapter(Activity activity, long catId)
BookmarkListAdapter(BookmarkCategory category)
{
mActivity = activity;
mCategoryId = catId;
mCategory = category;
}
public void setOnClickListener(@Nullable RecyclerClickListener listener)
@ -75,21 +78,25 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
@Override
public Holders.BaseBookmarkHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
LayoutInflater inflater = LayoutInflater.from(mActivity);
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
Holders.BaseBookmarkHolder holder = null;
switch (viewType)
{
case TYPE_TRACK:
holder = new Holders.TrackViewHolder(inflater.inflate(R.layout.item_track, parent,
false), mCategoryId);
false), mCategory);
break;
case TYPE_BOOKMARK:
holder = new Holders.BookmarkViewHolder(inflater.inflate(R.layout.item_bookmark, parent,
false), mCategoryId);
false), mCategory);
break;
case TYPE_SECTION:
TextView tv = (TextView) inflater.inflate(R.layout.item_category_title, parent, false);
holder = new Holders.SectionViewHolder(tv, mCategoryId);
holder = new Holders.SectionViewHolder(tv, mCategory);
break;
case TYPE_DESC:
View desc = inflater.inflate(R.layout.item_category_description, parent, false);
holder = new Holders.DescriptionViewHolder(desc, mCategory);
break;
}
@ -110,16 +117,19 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
@Override
public int getItemViewType(int position)
{
final int bmkPos = getBookmarksSectionPosition(mCategoryId);
final int trackPos = getTracksSectionPosition(mCategoryId);
final int descPos = getDescSectionPosition(mCategory);
final int bmkPos = getBookmarksSectionPosition(mCategory);
final int trackPos = getTracksSectionPosition(mCategory);
if (position == bmkPos || position == trackPos)
if (position == bmkPos || position == trackPos || position == descPos)
return TYPE_SECTION;
if (position > bmkPos && !isSectionEmpty(mCategoryId, SECTION_BMKS))
if (position > bmkPos && !isSectionEmpty(mCategory, SECTION_BMKS))
return TYPE_BOOKMARK;
else if (position > trackPos && !isSectionEmpty(mCategoryId, SECTION_TRACKS))
else if (position > trackPos && !isSectionEmpty(mCategory, SECTION_TRACKS))
return TYPE_TRACK;
else if (position > descPos && !isSectionEmpty(mCategory, SECTION_DESC))
return TYPE_DESC;
throw new IllegalArgumentException("Position not found: " + position);
}
@ -133,23 +143,27 @@ public class BookmarkListAdapter extends RecyclerView.Adapter<Holders.BaseBookma
@Override
public int getItemCount()
{
return BookmarkManager.INSTANCE.getCategorySize(mCategoryId)
+ (isSectionEmpty(mCategoryId, SECTION_TRACKS) ? 0 : 1)
+ (isSectionEmpty(mCategoryId, SECTION_BMKS) ? 0 : 1);
return mCategory.size()
+ (isSectionEmpty(mCategory, SECTION_TRACKS) ? 0 : 1)
+ (isSectionEmpty(mCategory, SECTION_BMKS) ? 0 : 1)
+ getDescItemCount(mCategory);
}
// FIXME: remove this heavy method and use BoomarkInfo class instead.
public Object getItem(int position)
{
if (getItemViewType(position) == TYPE_DESC)
throw new UnsupportedOperationException("Not supported here!");
if (getItemViewType(position) == TYPE_TRACK)
{
final long trackId = BookmarkManager.INSTANCE.getTrackIdByPosition(mCategoryId, position - 1);
final long trackId = BookmarkManager.INSTANCE.getTrackIdByPosition(mCategory.getId(), position - 1);
return BookmarkManager.INSTANCE.getTrack(trackId);
}
else
{
final int pos = calculateBookmarkPosition(mCategoryId, position);
final long bookmarkId = BookmarkManager.INSTANCE.getBookmarkIdByPosition(mCategoryId, pos);
final int pos = calculateBookmarkPosition(mCategory, position);
final long bookmarkId = BookmarkManager.INSTANCE.getBookmarkIdByPosition(mCategory.getId(), pos);
return BookmarkManager.INSTANCE.getBookmark(bookmarkId);
}
}

View file

@ -53,7 +53,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment
@Override
protected RecyclerView.Adapter createAdapter()
{
return new BookmarkListAdapter(getActivity(), mCategory.getId());
return new BookmarkListAdapter(mCategory);
}
@Override
@ -133,6 +133,7 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment
switch (adapter.getItemViewType(position))
{
case BookmarkListAdapter.TYPE_SECTION:
case BookmarkListAdapter.TYPE_DESC:
return;
case BookmarkListAdapter.TYPE_BOOKMARK:
final Bookmark bookmark = (Bookmark) adapter.getItem(position);
@ -159,18 +160,20 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment
return;
mSelectedPosition = position;
final Object item = adapter.getItem(mSelectedPosition);
int type = adapter.getItemViewType(mSelectedPosition);
switch (type)
{
case BookmarkListAdapter.TYPE_SECTION:
case BookmarkListAdapter.TYPE_DESC:
// Do nothing here?
break;
case BookmarkListAdapter.TYPE_BOOKMARK:
BottomSheetHelper.Builder bs = BottomSheetHelper.create(getActivity(), ((Bookmark) item).getTitle())
.sheet(R.menu.menu_bookmarks)
final Bookmark bookmark = (Bookmark) adapter.getItem(mSelectedPosition);
int menuResId = isCatalogCategory() ? R.menu.menu_bookmarks_catalog : R.menu.menu_bookmarks;
BottomSheetHelper.Builder bs = BottomSheetHelper.create(getActivity(), bookmark.getTitle())
.sheet(menuResId)
.listener(this);
if (!ShareOption.SMS.isSupported(getActivity()))
bs.getMenu().removeItem(R.id.share_message);
@ -182,14 +185,15 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment
break;
case BookmarkListAdapter.TYPE_TRACK:
BottomSheetHelper.create(getActivity(), ((Track) item).getName())
final Track track = (Track) adapter.getItem(mSelectedPosition);
BottomSheetHelper.create(getActivity(), track.getName())
.sheet(Menu.NONE, R.drawable.ic_delete, R.string.delete)
.listener(new MenuItem.OnMenuItemClickListener()
{
@Override
public boolean onMenuItemClick(MenuItem menuItem)
{
BookmarkManager.INSTANCE.deleteTrack(((Track) item).getTrackId());
BookmarkManager.INSTANCE.deleteTrack(track.getTrackId());
adapter.notifyDataSetChanged();
return false;
}
@ -250,9 +254,16 @@ public class BookmarksListFragment extends BaseMwmRecyclerFragment
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
if (isCatalogCategory())
return;
inflater.inflate(R.menu.option_menu_bookmarks, menu);
}
private boolean isCatalogCategory()
{
return mCategory.getType() == BookmarkCategory.Type.CATALOG;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{

View file

@ -1,5 +1,6 @@
package com.mapswithme.maps.bookmarks;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.support.annotation.IntDef;
@ -7,6 +8,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.PluralsRes;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
@ -197,62 +199,89 @@ public class Holders
{
static final int SECTION_TRACKS = 0;
static final int SECTION_BMKS = 1;
static final int SECTION_DESC = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ SECTION_TRACKS, SECTION_BMKS })
@IntDef({ SECTION_TRACKS, SECTION_BMKS, SECTION_DESC})
public @interface Section {}
final long mCategoryId;
@NonNull
final BookmarkCategory mCategory;
@NonNull
private final View mView;
BaseBookmarkHolder(@NonNull View itemView, long categoryId)
BaseBookmarkHolder(@NonNull View itemView, @NonNull BookmarkCategory category)
{
super(itemView);
mCategoryId = categoryId;
mCategory = category;
mView = itemView;
}
abstract void bind(int position);
static boolean isSectionEmpty(long categoryId, @Section int section)
static boolean isSectionEmpty(BookmarkCategory category, @Section int section)
{
switch (section)
{
case SECTION_TRACKS:
return BookmarkManager.INSTANCE.getTracksCount(categoryId) == 0;
return category.getTracksCount() == 0;
case SECTION_BMKS:
return BookmarkManager.INSTANCE.getBookmarksCount(categoryId) == 0;
return category.getBookmarksCount() == 0;
case SECTION_DESC:
return TextUtils.isEmpty(category.getDescription()) && TextUtils.isEmpty(category.getAnnotation());
default:
throw new IllegalArgumentException("There is no section with index " + section);
}
}
static int getSectionForPosition(long categoryId, int position)
static int getSectionForPosition(BookmarkCategory category, int position)
{
if (position == getTracksSectionPosition(categoryId))
if (position == getDescSectionPosition(category))
return SECTION_DESC;
if (position == getTracksSectionPosition(category))
return SECTION_TRACKS;
if (position == getBookmarksSectionPosition(categoryId))
if (position == getBookmarksSectionPosition(category))
return SECTION_BMKS;
throw new IllegalArgumentException("There is no section in position " + position);
}
static int getTracksSectionPosition(long categoryId)
static int getDescSectionPosition(BookmarkCategory category)
{
if (isSectionEmpty(categoryId, SECTION_TRACKS))
if (isSectionEmpty(category, SECTION_DESC))
return -1;
return 0;
}
static int getBookmarksSectionPosition(long categoryId)
static int getTracksSectionPosition(BookmarkCategory category)
{
if (isSectionEmpty(categoryId, SECTION_BMKS))
if (isSectionEmpty(category, SECTION_TRACKS))
return -1;
return BookmarkManager.INSTANCE.getTracksCount(categoryId)
+ (isSectionEmpty(categoryId, SECTION_TRACKS) ? 0 : 1);
return getDescItemCount(category);
}
static int getBookmarksSectionPosition(BookmarkCategory category)
{
if (isSectionEmpty(category, SECTION_BMKS))
return -1;
int beforeCurrentSectionItemsCount = getTracksSectionPosition(category);
return (beforeCurrentSectionItemsCount == -1
? getDescItemCount(category)
: beforeCurrentSectionItemsCount)
+ getTrackItemCount(category);
}
private static int getTrackItemCount(BookmarkCategory category)
{
return category.getTracksCount() + (isSectionEmpty(category, SECTION_TRACKS) ? 0 : 1);
}
static int getDescItemCount(BookmarkCategory category)
{
return isSectionEmpty(category, SECTION_DESC) ? 0 : /* section header */ 1 + /* non empty desc */ 1;
}
void setOnClickListener(@Nullable RecyclerClickListener listener)
@ -265,11 +294,14 @@ public class Holders
void setOnLongClickListener(@Nullable RecyclerLongClickListener listener)
{
mView.setOnLongClickListener(v -> {
if (listener != null)
listener.onLongItemClick(v, getAdapterPosition());
return true;
});
mView.setOnLongClickListener(v -> onOpenActionMenu(v, listener));
}
boolean onOpenActionMenu(View v, @Nullable RecyclerLongClickListener listener)
{
if (listener != null)
listener.onLongItemClick(v, getAdapterPosition());
return true;
}
}
@ -281,21 +313,31 @@ public class Holders
private final TextView mName;
@NonNull
private final TextView mDistance;
@NonNull
private final View mMore;
BookmarkViewHolder(@NonNull View itemView, long categoryId)
BookmarkViewHolder(@NonNull View itemView, BookmarkCategory categoryId)
{
super(itemView, categoryId);
mIcon = itemView.findViewById(R.id.iv__bookmark_color);
mName = itemView.findViewById(R.id.tv__bookmark_name);
mDistance = itemView.findViewById(R.id.tv__bookmark_distance);
mMore = itemView.findViewById(R.id.more);
}
@Override
void setOnLongClickListener(@Nullable RecyclerLongClickListener listener)
{
super.setOnLongClickListener(listener);
mMore.setOnClickListener(v -> onOpenActionMenu(v, listener));
}
@Override
void bind(int position)
{
int pos = calculateBookmarkPosition(mCategoryId, position);
final long bookmarkId = BookmarkManager.INSTANCE.getBookmarkIdByPosition(mCategoryId, pos);
BookmarkInfo bookmark = new BookmarkInfo(mCategoryId, bookmarkId);
int pos = calculateBookmarkPosition(mCategory, position);
final long bookmarkId = BookmarkManager.INSTANCE.getBookmarkIdByPosition(mCategory.getId(), pos);
BookmarkInfo bookmark = new BookmarkInfo(mCategory.getId(), bookmarkId);
mName.setText(bookmark.getTitle());
final Location loc = LocationHelper.INSTANCE.getSavedLocation();
if (loc != null)
@ -309,12 +351,13 @@ public class Holders
mIcon.setImageResource(bookmark.getIcon().getSelectedResId());
}
static int calculateBookmarkPosition(long categoryId, int position)
static int calculateBookmarkPosition(BookmarkCategory category, int position)
{
// Since bookmarks are always below tracks and header we should take it into account
// during the bookmark's position calculation.
return position - 1 - (isSectionEmpty(categoryId, SECTION_TRACKS)
? 0 : BookmarkManager.INSTANCE.getTracksCount(categoryId) + 1);
return position - 1
- (isSectionEmpty(category, SECTION_TRACKS) ? 0 : category.getTracksCount() + 1)
- getDescItemCount(category);
}
}
@ -327,7 +370,7 @@ public class Holders
@NonNull
private final TextView mDistance;
TrackViewHolder(@NonNull View itemView, long categoryId)
TrackViewHolder(@NonNull View itemView, BookmarkCategory categoryId)
{
super(itemView, categoryId);
mIcon = itemView.findViewById(R.id.iv__bookmark_color);
@ -338,7 +381,7 @@ public class Holders
@Override
void bind(int position)
{
final long trackId = BookmarkManager.INSTANCE.getTrackIdByPosition(mCategoryId,
final long trackId = BookmarkManager.INSTANCE.getTrackIdByPosition(mCategory.getId(),
position - 1);
Track track = BookmarkManager.INSTANCE.getTrack(trackId);
mName.setText(track.getName());
@ -358,7 +401,7 @@ public class Holders
@NonNull
private final TextView mView;
SectionViewHolder(@NonNull TextView itemView, long categoryId)
SectionViewHolder(@NonNull TextView itemView, BookmarkCategory categoryId)
{
super(itemView, categoryId);
mView = itemView;
@ -367,7 +410,7 @@ public class Holders
@Override
void bind(int position)
{
final int sectionIndex = getSectionForPosition(mCategoryId, position);
final int sectionIndex = getSectionForPosition(mCategory, position);
mView.setText(getSections().get(sectionIndex));
mView.setText(getSections().get(sectionIndex));
}
@ -377,7 +420,39 @@ public class Holders
final List<String> sections = new ArrayList<>();
sections.add(mView.getContext().getString(R.string.tracks));
sections.add(mView.getContext().getString(R.string.bookmarks));
sections.add(mView.getContext().getString(R.string.description));
return sections;
}
}
static class DescriptionViewHolder extends BaseBookmarkHolder
{
@NonNull
private final TextView mContentView;
@NonNull
private final TextView mTitle;
@NonNull
private final TextView mAuthor;
DescriptionViewHolder(@NonNull View itemView, @NonNull BookmarkCategory category)
{
super(itemView, category);
mContentView = itemView.findViewById(R.id.description);
mTitle = itemView.findViewById(R.id.title);
mAuthor = itemView.findViewById(R.id.author);
}
@Override
void bind(int position)
{
mTitle.setText(mCategory.getName());
mContentView.setText(mCategory.getDescription());
BookmarkCategory.Author author = mCategory.getAuthor();
Context c = itemView.getContext();
CharSequence authorName = author == null
? null
: BookmarkCategory.Author.getRepresentation(c, author);
mAuthor.setText(authorName);
}
}
}

View file

@ -15,22 +15,115 @@ import com.mapswithme.util.TypeConverter;
public class BookmarkCategory implements Parcelable
{
public static final String DESCRIPTION = "\n" +
"Владимир Семёнович Высоцкий\n" +
"Vladimir Vysotsky.jpg\n" +
"Владимир Высоцкий на концерте 23 апреля 1979 года. Фото Игоря Пальмина\n" +
"Дата рождения:\t25 января 1938\n" +
"Место рождения:\tМосква, СССР\n" +
"Дата смерти:\t25 июля 1980 (42 года)\n" +
"Место смерти:\tМосква, СССР\n" +
"Страна:\t\n" +
"Flag of the Soviet Union (19551980).svg СССР\n" +
"Род деятельности:\t\n" +
"поэт, поэт-песенник, автор-исполнитель, прозаик, актёр театра и кино, певец, " +
"композитор, гитарист\n" +
"Место работы:\t\n" +
"Московский драматический театр имени А. С. Пушкина\n" +
"Театр на Таганке\n" +
"Высшее образование:\t\n" +
"Школа-студия МХАТ\n" +
"Награды и премии:\осударственная премия СССР — 1987 Premia mvd.jpg[1][2]\n" +
"Подпись:\одпись\n" +
"Отец:\tСемён Владимирович Высоцкий\n" +
"Мать:\tНина Максимовна Высоцкая\n" +
"Супруг(а):\t\n" +
"• Изольда Жукова (Мешкова)[⇨], \n" +
"• Людмила Абрамова[⇨], \n" +
"• Марина Влади[⇨]\n" +
"Дети:\tАркадий Высоцкий, Никита Высоцкий[⇨]\n" +
"Похоронен\t\n" +
"Ваганьковское кладбище\n" +
"IMDb:\tID 0904584\n" +
"Логотип Викицитатника Цитаты в Викицитатнике\n" +
"Commons-logo.svg Владимир Семёнович Высоцкий на Викискладе\n" +
"Влади́мир Семёнович Высо́цкий (25 января 1938, Москва — 25 июля 1980, Москва)" +
" — советский поэт, актёр театра и кино, автор-исполнитель песен (бард); автор" +
" прозаических произведений и сценариев. Лауреат Государственной премии СССР " +
"(«за создание образа Жеглова в телевизионном художественном фильме „Место " +
"встречи изменить нельзя“ и авторское исполнение песен», 1987, посмертно).\n" +
"\n" +
"Как поэт Высоцкий реализовал себя прежде всего в жанре авторской песни. " +
"Первые из написанных им произведений относятся к началу 1960-х годов. " +
"Изначально они исполнялись в кругу друзей; позже получили широкую известность" +
" благодаря распространявшимся по стране магнитофонным записям. Поэзия " +
"Высоцкого отличалась многообразием тем (уличные, лагерные, военные, " +
"сатирические, бытовые, сказочные, «спортивные» песни), остротой смыслового " +
"подтекста и акцентированной социально-нравственной позицией автора. В его " +
"произведениях, рассказывающих о внутреннем выборе людей, поставленных в " +
"экстремальные обстоятельства, прослеживались экзистенциальные мотивы. " +
"Творческая эволюция Высоцкого ознаменовалась несколькими этапами. В его " +
"раннем творчестве преобладали уличные и дворовые песни. С середины 1960-х " +
"годов тематика произведений начала расширяться, а песенные циклы складываться" +
" в новую «энциклопедию русской жизни». В 1970-х годах значительную часть " +
"творчества Высоцкого составляли песни и стихотворения " +
"исповедально-философского характера, поэт часто обращался к вечным вопросам " +
"бытия.\n" +
"\n" +
"Театральная биография Высоцкого, окончившего в 1960 году Школу-студию МХАТ, " +
"связана главным образом с работой в Театре на Таганке. На его сцене актёр " +
"играл Галилея (спектакль «Жизнь Галилея», 1966), Хлопушу («Пугачёв», 1967), " +
"Гамлета («Гамлет», 1971), Лопахина («Вишнёвый сад», 1975), Свидригайлова " +
"(«Преступление и наказание», 1979). Дебют Высоцкого в кино состоялся в 1959 " +
"году, когда он сыграл эпизодическую роль в фильме «Сверстницы». За годы " +
"работы в кинематографе актёр снялся более чем в двадцати пяти фильмах. " +
"Кинобиография Высоцкого включает роли подпольщика Бродского («Интервенция», " +
"1968), зоолога фон Корена («Плохой хороший человек», 1973), капитана Жеглова " +
"(«Место встречи изменить нельзя», 1979), Дон Гуана («Маленькие трагедии», " +
"1979) и другие. Исследователи отмечали, что в сценических и экранных работах " +
"Высоцкого экспрессивность сочеталась с психологической достоверностью. В ряде" +
" спектаклей, а также в художественных фильмах, теле- и радиопостановках он " +
"выступал и как автор песен.\n" +
"\n" +
"При жизни Высоцкого его песни не получили в СССР официального признания. В " +
"1968 году в рамках газетной кампании, дискредитирующей его " +
"музыкально-поэтическое творчество, они были подвергнуты резкой критике. " +
"Вплоть до 1981 года ни одно советское издательство не выпустило книгу с его " +
"текстами. Цензурные ограничения частично были сняты только после смерти " +
"Высоцкого, когда вышел в свет сборник его поэтических произведений «Нерв» " +
"(составитель — Роберт Рождественский). Тем не менее цензорский контроль за " +
"публикациями стихов и песен Высоцкого, а также посвящённых ему " +
"газетно-журнальных статей продолжал действовать вплоть до перестройки. " +
"Легализация его творчества началась в Советском Союзе в 1986 году, когда при " +
"Союзе писателей СССР была создана комиссия по литературному наследию " +
"Высоцкого. Со второй половины 1980-х годов начался выпуск книг и собраний " +
"сочинений поэта, ведётся исследовательская работа, посвящённая его творчеству" +
". По некоторым оценкам, Высоцкий, занимающий одно из центральных мест в " +
"истории русской культуры XX века, «оказал сильное влияние на формирование " +
"взглядов своих современников и последующих поколений».";
private final long mId;
@NonNull
private final String mName;
@Nullable
private final Author mAuthor;
@NonNull
private final String mAnnotation;
@NonNull
private final String mDescription;
private final int mTracksCount;
private final int mBookmarksCount;
private final int mTypeIndex;
private final boolean mIsVisible;
public BookmarkCategory(long id, @NonNull String name, @NonNull String authorId,
@NonNull String authorName, int tracksCount, int bookmarksCount,
@NonNull String authorName, @NonNull String annotation,
@NonNull String description, int tracksCount, int bookmarksCount,
boolean fromCatalog, boolean isVisible)
{
mId = id;
mName = name;
mAnnotation = "asdasdasdasdasdasdasdasdasdasdasdasd";
mDescription = DESCRIPTION;
mTracksCount = tracksCount;
mBookmarksCount = bookmarksCount;
mTypeIndex = fromCatalog ? Type.CATALOG.ordinal() : Type.PRIVATE.ordinal();
@ -102,6 +195,18 @@ public class BookmarkCategory implements Parcelable
return getBookmarksCount() + getTracksCount();
}
@NonNull
public String getAnnotation()
{
return mAnnotation;
}
@NonNull
public String getDescription()
{
return mDescription;
}
@NonNull
public CountAndPlurals getPluralsCountTemplate()
{
@ -141,7 +246,6 @@ public class BookmarkCategory implements Parcelable
public static class Author implements Parcelable
{
private static final String PHRASE_SEPARATOR = "";
@NonNull
private final String mId;
@NonNull
@ -199,10 +303,7 @@ public class BookmarkCategory implements Parcelable
public static String getRepresentation(@NonNull Context context, @NonNull Author author)
{
Resources res = context.getResources();
return new StringBuilder()
.append(PHRASE_SEPARATOR)
.append(String.format(res.getString(R.string.author_name_by_prefix), author.getName()))
.toString();
return String.format(res.getString(R.string.author_name_by_prefix), author.getName());
}
@Override
@ -241,58 +342,16 @@ public class BookmarkCategory implements Parcelable
sb.append("mId=").append(mId);
sb.append(", mName='").append(mName).append('\'');
sb.append(", mAuthor=").append(mAuthor);
sb.append(", mAnnotation='").append(mAnnotation).append('\'');
sb.append(", mDescription='").append(mDescription).append('\'');
sb.append(", mTracksCount=").append(mTracksCount);
sb.append(", mBookmarksCount=").append(mBookmarksCount);
sb.append(", mFromCatalog=").append(isFromCatalog());
sb.append(", mTypeIndex=").append(mTypeIndex);
sb.append(", mIsVisible=").append(mIsVisible);
sb.append('}');
return sb.toString();
}
@Override
public int describeContents()
{
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeLong(this.mId);
dest.writeString(this.mName);
dest.writeParcelable(this.mAuthor, flags);
dest.writeInt(this.mTracksCount);
dest.writeInt(this.mBookmarksCount);
dest.writeInt(this.mTypeIndex);
dest.writeByte(this.mIsVisible ? (byte) 1 : (byte) 0);
}
protected BookmarkCategory(Parcel in)
{
this.mId = in.readLong();
this.mName = in.readString();
this.mAuthor = in.readParcelable(Author.class.getClassLoader());
this.mTracksCount = in.readInt();
this.mBookmarksCount = in.readInt();
this.mTypeIndex = in.readInt();
this.mIsVisible = in.readByte() != 0;
}
public static final Creator<BookmarkCategory> CREATOR = new Creator<BookmarkCategory>()
{
@Override
public BookmarkCategory createFromParcel(Parcel source)
{
return new BookmarkCategory(source);
}
@Override
public BookmarkCategory[] newArray(int size)
{
return new BookmarkCategory[size];
}
};
public static class IsFromCatalog implements TypeConverter<BookmarkCategory, Boolean>
{
@Override
@ -328,4 +387,52 @@ public class BookmarkCategory implements Parcelable
return mFilterStrategy;
}
}
@Override
public int describeContents()
{
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeLong(this.mId);
dest.writeString(this.mName);
dest.writeParcelable(this.mAuthor, flags);
dest.writeString(this.mAnnotation);
dest.writeString(this.mDescription);
dest.writeInt(this.mTracksCount);
dest.writeInt(this.mBookmarksCount);
dest.writeInt(this.mTypeIndex);
dest.writeByte(this.mIsVisible ? (byte) 1 : (byte) 0);
}
protected BookmarkCategory(Parcel in)
{
this.mId = in.readLong();
this.mName = in.readString();
this.mAuthor = in.readParcelable(Author.class.getClassLoader());
this.mAnnotation = in.readString();
this.mDescription = in.readString();
this.mTracksCount = in.readInt();
this.mBookmarksCount = in.readInt();
this.mTypeIndex = in.readInt();
this.mIsVisible = in.readByte() != 0;
}
public static final Creator<BookmarkCategory> CREATOR = new Creator<BookmarkCategory>()
{
@Override
public BookmarkCategory createFromParcel(Parcel source)
{
return new BookmarkCategory(source);
}
@Override
public BookmarkCategory[] newArray(int size)
{
return new BookmarkCategory[size];
}
};
}

View file

@ -283,10 +283,13 @@ public enum BookmarkManager
/**
* @return total count - tracks + bookmarks
* @param catId
* should be used BookmarkCategory.size() - without JNI method call overhead
*/
public int getCategorySize(long catId)
@Deprecated
public int getCategorySize(BookmarkCategory catId)
{
return nativeGetBookmarksCount(catId) + nativeGetTracksCount(catId);
return nativeGetBookmarksCount(catId.getId()) + nativeGetTracksCount(catId.getId());
}
public int getCategoriesCount() { return nativeGetCategoriesCount(); }

View file

@ -45,6 +45,7 @@ public final class UiUtils
{
private static final int DEFAULT_TINT_COLOR = Color.parseColor("#20000000");
public static final int NO_ID = -1;
public static final String PHRASE_SEPARATOR = "";
private static float sScreenDensity;
public static class SimpleAnimationListener implements AnimationListener