From d7a10cffa8634dfaed9a6a7494fa848cccad6844 Mon Sep 17 00:00:00 2001 From: Dmitry Yunitsky Date: Thu, 28 Jan 2016 20:20:31 +0300 Subject: [PATCH] [android] Edit cuisine. --- android/res/layout/fragment_editor.xml | 11 +- android/res/layout/item_cuisine.xml | 26 +++ android/res/values/styles-editor.xml | 6 + .../maps/bookmarks/data/MapObject.java | 23 ++- .../maps/bookmarks/data/Metadata.java | 50 ++++++ .../maps/editor/CuisineAdapter.java | 156 ++++++++++++++++++ .../maps/editor/CuisineFragment.java | 36 ++++ .../maps/editor/EditorFragment.java | 10 +- .../maps/editor/EditorHostFragment.java | 14 +- .../maps/widget/placepage/PlacePageView.java | 6 +- 10 files changed, 311 insertions(+), 27 deletions(-) create mode 100644 android/res/layout/item_cuisine.xml create mode 100644 android/src/com/mapswithme/maps/editor/CuisineAdapter.java create mode 100644 android/src/com/mapswithme/maps/editor/CuisineFragment.java diff --git a/android/res/layout/fragment_editor.xml b/android/res/layout/fragment_editor.xml index 9c014d6d07..9264ce69da 100644 --- a/android/res/layout/fragment_editor.xml +++ b/android/res/layout/fragment_editor.xml @@ -77,8 +77,8 @@ tools:ignore="UnusedAttribute"/> @@ -100,7 +100,6 @@ style="@style/MwmWidget.Editor.FieldLayout" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/margin_base" - android:background="?clickableBackground" android:drawableEnd="@drawable/ic_arrow_down" android:drawableRight="@drawable/ic_arrow_down" android:gravity="center_vertical" @@ -252,7 +251,7 @@ @@ -265,6 +264,7 @@ style="@style/MwmWidget.Editor.FieldLayout" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/margin_base" + android:drawableEnd="@drawable/ic_arrow_down" android:drawableRight="@drawable/ic_arrow_down" android:gravity="center_vertical" android:textAppearance="@style/MwmTextAppearance.Body1" @@ -283,8 +283,7 @@ + style="@style/MwmWidget.Editor.MetadataBlock.Clickable"> + + + + + + + \ No newline at end of file diff --git a/android/res/values/styles-editor.xml b/android/res/values/styles-editor.xml index bc880e0a0a..abb56593b3 100644 --- a/android/res/values/styles-editor.xml +++ b/android/res/values/styles-editor.xml @@ -23,6 +23,10 @@ @dimen/margin_base + + diff --git a/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java b/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java index 36c95bdfa7..89d95737c9 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/MapObject.java @@ -140,25 +140,24 @@ public class MapObject implements Parcelable * @return properly formatted and translated cuisine string. */ @NonNull - public String getCuisine() + public String getFormattedCuisine() { - final String rawCuisine = mMetadata.getMetadata(Metadata.MetadataType.FMD_CUISINE); - if (TextUtils.isEmpty(rawCuisine)) + final String rawCuisines = mMetadata.getMetadata(Metadata.MetadataType.FMD_CUISINE); + if (TextUtils.isEmpty(rawCuisines)) return ""; - // cuisines translations can contain unsupported symbols, and res ids - // replace them with supported "_"( so ', ' and ' ' are replaced with underlines) - final String[] cuisines = rawCuisine.split(";"); - String result = ""; + final StringBuilder result = new StringBuilder(); // search translations for each cuisine final Resources resources = MwmApplication.get().getResources(); - for (String cuisineRaw : cuisines) + for (String rawCuisine : Metadata.splitCuisines(rawCuisines)) { - final String cuisineKey = cuisineRaw.replace(", ", "_").replace(' ', '_').toLowerCase(); - int resId = resources.getIdentifier("cuisine_" + cuisineKey, "string", BuildConfig.APPLICATION_ID); - result += resId == 0 ? cuisineRaw : resources.getString(resId); + int resId = resources.getIdentifier(Metadata.osmCuisineToStringName(Metadata.normalizeCuisine(rawCuisine)), "string", BuildConfig.APPLICATION_ID); + if (result.length() > 0) + result.append(", "); + result.append(resId == 0 ? rawCuisine : resources.getString(resId)); } - return result; + + return result.toString(); } public String getStreet() diff --git a/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java b/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java index 14261dbeec..afbc234a37 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/Metadata.java @@ -60,8 +60,58 @@ public class Metadata implements Parcelable } } + private static final String CUISINE_TRANSLATION_PREFIX = "cuisine_"; + private Map mMetadataMap = new HashMap<>(); + public static String osmCuisineToStringName(String cuisineKey) + { + return CUISINE_TRANSLATION_PREFIX + cuisineKey; + } + + public static String stringNameToOsmCuisine(String cuisineTranslation) + { + return cuisineTranslation.replace(CUISINE_TRANSLATION_PREFIX, ""); + } + + public static boolean isCuisineString(String cuisineTranslation) + { + return cuisineTranslation.startsWith(CUISINE_TRANSLATION_PREFIX); + } + + /** + * Cuisines translations can contain unsupported symbols, + * replace them with supported "_"( so ', ' and ' ' are replaced with underlines) + */ + public static String normalizeCuisine(String cuisineRaw) + { + return cuisineRaw.replace(", ", "_").replace(' ', '_').toLowerCase(); + } + + /** + * Splits cuisine from osm format. + */ + public static String[] splitCuisines(String cuisines) + { + return cuisines.split(";"); + } + + /** + * Combines cuisines to osm format. + */ + public static String combineCuisines(@NonNull String[] cuisines) + { + final StringBuilder builder = new StringBuilder(); + for (String cuisine : cuisines) + { + if (builder.length() > 0) + builder.append(";"); + builder.append(cuisine); + } + + return builder.toString(); + } + /** * Adds metadata with type code and value. Returns false if metaType is wrong or unknown * diff --git a/android/src/com/mapswithme/maps/editor/CuisineAdapter.java b/android/src/com/mapswithme/maps/editor/CuisineAdapter.java new file mode 100644 index 0000000000..e4c0badd48 --- /dev/null +++ b/android/src/com/mapswithme/maps/editor/CuisineAdapter.java @@ -0,0 +1,156 @@ +package com.mapswithme.maps.editor; + +import android.content.res.Resources; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.TextView; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import com.mapswithme.maps.MwmApplication; +import com.mapswithme.maps.R; +import com.mapswithme.maps.bookmarks.data.Metadata; + +public class CuisineAdapter extends RecyclerView.Adapter +{ + private static class Item implements Comparable + { + String translatedCuisine; + String cuisineStringName; + boolean selected; + + public Item(String cuisine, String cuisineKey, boolean selected) + { + this.translatedCuisine = cuisine; + this.cuisineStringName = cuisineKey; + this.selected = selected; + } + + @Override + public int compareTo(@NonNull Item another) + { + return translatedCuisine.compareTo(another.translatedCuisine); + } + } + + private List mTranslatedItems; + private List mItems; + + public CuisineAdapter(@NonNull String cuisine) + { + initAllCuisinesFromStrings(); + String[] selectedCuisines = Metadata.splitCuisines(cuisine); + Arrays.sort(selectedCuisines); + mItems = new ArrayList<>(mTranslatedItems.size()); + for (Item item : mTranslatedItems) + { + final String cuisineString = item.translatedCuisine; + mItems.add(new Item(cuisineString, item.cuisineStringName, + Arrays.binarySearch(selectedCuisines, Metadata.stringNameToOsmCuisine(item.cuisineStringName)) >= 0)); + } + } + + private void initAllCuisinesFromStrings() + { + if (mTranslatedItems != null) + return; + + mTranslatedItems = new ArrayList<>(); + final Resources resources = MwmApplication.get().getResources(); + for (Field stringField : R.string.class.getDeclaredFields()) + { + try + { + final String fieldName = stringField.getName(); + if (Metadata.isCuisineString(fieldName)) + { + int resId = stringField.getInt(stringField); + final String cuisine = resources.getString(resId); + mTranslatedItems.add(new Item(cuisine, fieldName, false)); + } + + } catch (IllegalAccessException ignored) { } + } + + Collections.sort(mTranslatedItems); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) + { + return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_cuisine, parent, false)); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) + { + holder.bind(position); + } + + @Override + public int getItemCount() + { + return mTranslatedItems.size(); + } + + public String getCuisine() + { + final List selectedList = new ArrayList<>(); + for (Item item : mItems) + { + if (item.selected) + selectedList.add(Metadata.stringNameToOsmCuisine(item.cuisineStringName)); + } + + String[] cuisines = new String[selectedList.size()]; + cuisines = selectedList.toArray(cuisines); + return Metadata.combineCuisines(cuisines); + } + + protected class ViewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener + { + final TextView cuisine; + final CheckBox selected; + + public ViewHolder(View itemView) + { + super(itemView); + cuisine = (TextView) itemView.findViewById(R.id.cuisine); + selected = (CheckBox) itemView.findViewById(R.id.selected); + selected.setOnCheckedChangeListener(this); + itemView.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View v) + { + selected.toggle(); + } + }); + } + + public void bind(int position) + { + final String text = mTranslatedItems.get(position).translatedCuisine; + cuisine.setText(text); + selected.setOnCheckedChangeListener(null); + selected.setChecked(mItems.get(position).selected); + selected.setOnCheckedChangeListener(this); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) + { + Item item = mItems.get(getAdapterPosition()); + item.selected = isChecked; + } + } +} diff --git a/android/src/com/mapswithme/maps/editor/CuisineFragment.java b/android/src/com/mapswithme/maps/editor/CuisineFragment.java new file mode 100644 index 0000000000..a138ee0285 --- /dev/null +++ b/android/src/com/mapswithme/maps/editor/CuisineFragment.java @@ -0,0 +1,36 @@ +package com.mapswithme.maps.editor; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.mapswithme.maps.base.BaseMwmRecyclerFragment; + +public class CuisineFragment extends BaseMwmRecyclerFragment +{ + public static final String EXTRA_CURRENT_CUISINE = "Cuisine"; + + private String mCurrentCuisine; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + mCurrentCuisine = getArguments().getString(EXTRA_CURRENT_CUISINE, ""); + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + protected RecyclerView.Adapter createAdapter() + { + return new CuisineAdapter(mCurrentCuisine); + } + + @NonNull + public String getCuisine() + { + return ((CuisineAdapter) getAdapter()).getCuisine(); + } +} diff --git a/android/src/com/mapswithme/maps/editor/EditorFragment.java b/android/src/com/mapswithme/maps/editor/EditorFragment.java index 54bc2e5a9f..73e70282b1 100644 --- a/android/src/com/mapswithme/maps/editor/EditorFragment.java +++ b/android/src/com/mapswithme/maps/editor/EditorFragment.java @@ -72,7 +72,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe mEtPhone.setText(mEditedPoi.getMetadata(Metadata.MetadataType.FMD_PHONE_NUMBER)); mEtWebsite.setText(mEditedPoi.getMetadata(Metadata.MetadataType.FMD_WEBSITE)); mEtEmail.setText(mEditedPoi.getMetadata(Metadata.MetadataType.FMD_EMAIL)); - mTvCuisine.setText(mEditedPoi.getCuisine()); + mTvCuisine.setText(mEditedPoi.getFormattedCuisine()); mSwWifi.setChecked(!TextUtils.isEmpty(mEditedPoi.getMetadata(Metadata.MetadataType.FMD_INTERNET))); refreshOpeningTime(); @@ -208,8 +208,8 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe mAddressBlock = view.findViewById(R.id.cv__address); mMetadataBlock = view.findViewById(R.id.cv__metadata); mEtName = findInput(view.findViewById(R.id.name)); + view.findViewById(R.id.block_street).setOnClickListener(this); mTvStreet = (TextView) view.findViewById(R.id.street); - mTvStreet.setOnClickListener(this); mEtHouseNumber = findInput(view.findViewById(R.id.building)); mPhoneBlock = view.findViewById(R.id.block_phone); mEtPhone = findInput(mPhoneBlock); @@ -218,6 +218,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe mEmailBlock = view.findViewById(R.id.block_email); mEtEmail = findInput(mEmailBlock); mCuisineBlock = view.findViewById(R.id.block_cuisine); + mCuisineBlock.setOnClickListener(this); mTvCuisine = (TextView) view.findViewById(R.id.tv__cuisine); mWifiBlock = view.findViewById(R.id.block_wifi); mSwWifi = (SwitchCompat) view.findViewById(R.id.sw__wifi); @@ -245,9 +246,12 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe case R.id.block_wifi: mSwWifi.toggle(); break; - case R.id.street: + case R.id.block_street: mParent.editStreet(); break; + case R.id.block_cuisine: + mParent.editCuisine(); + break; } } } diff --git a/android/src/com/mapswithme/maps/editor/EditorHostFragment.java b/android/src/com/mapswithme/maps/editor/EditorHostFragment.java index 954b65c7cd..8573e775aa 100644 --- a/android/src/com/mapswithme/maps/editor/EditorHostFragment.java +++ b/android/src/com/mapswithme/maps/editor/EditorHostFragment.java @@ -110,7 +110,13 @@ public class EditorHostFragment extends BaseMwmToolbarFragment protected void editCuisine() { mMode = Mode.CUISINE; - // TODO choose cuisine + mToolbarController.setTitle("Cuisine"); + final Bundle args = new Bundle(); + args.putString(CuisineFragment.EXTRA_CURRENT_CUISINE, mEditedObject.getMetadata(Metadata.MetadataType.FMD_CUISINE)); + final Fragment cuisineFragment = Fragment.instantiate(getActivity(), CuisineFragment.class.getName(), args); + getChildFragmentManager().beginTransaction() + .replace(R.id.fragment_container, cuisineFragment, CuisineFragment.class.getName()) + .commit(); } @Override @@ -131,14 +137,16 @@ public class EditorHostFragment extends BaseMwmToolbarFragment editMapObject(); break; case CUISINE: - // get cuisine + final String cuisine = ((CuisineFragment) getChildFragmentManager().findFragmentByTag(CuisineFragment.class.getName())).getCuisine(); + mEditedObject.addMetadata(Metadata.MetadataType.FMD_CUISINE.toInt(), cuisine); + editMapObject(); break; case MAP_OBJECT: final EditorFragment editorFragment = (EditorFragment) getChildFragmentManager().findFragmentByTag(EditorFragment.class.getName()); Editor.nativeSetMetadata(Metadata.MetadataType.FMD_PHONE_NUMBER.toInt(), editorFragment.getPhone()); Editor.nativeSetMetadata(Metadata.MetadataType.FMD_WEBSITE.toInt(), editorFragment.getWebsite()); Editor.nativeSetMetadata(Metadata.MetadataType.FMD_EMAIL.toInt(), editorFragment.getEmail()); - Editor.nativeSetMetadata(Metadata.MetadataType.FMD_CUISINE.toInt(), editorFragment.getCuisine()); + Editor.nativeSetMetadata(Metadata.MetadataType.FMD_CUISINE.toInt(), mEditedObject.getMetadata(Metadata.MetadataType.FMD_CUISINE)); Editor.nativeSetMetadata(Metadata.MetadataType.FMD_INTERNET.toInt(), editorFragment.getWifi()); Editor.nativeSetName(editorFragment.getName()); Editor.nativeEditFeature(editorFragment.getStreet(), editorFragment.getHouseNumber()); diff --git a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java index 1c381119bc..fe2a4a0648 100644 --- a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java +++ b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java @@ -418,8 +418,8 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene mTvTitle.setText(mMapObject.getName()); if (mToolbar != null) mToolbar.setTitle(mMapObject.getName()); - String subtitle = mMapObject.getCuisine().isEmpty() ? mMapObject.getTypeName() - : mMapObject.getTypeName() + ", " + mMapObject.getCuisine(); + String subtitle = mMapObject.getFormattedCuisine().isEmpty() ? mMapObject.getTypeName() + : mMapObject.getTypeName() + ", " + mMapObject.getFormattedCuisine(); mTvSubtitle.setText(subtitle); mAvDirection.setVisibility(View.GONE); } @@ -432,7 +432,7 @@ public class PlacePageView extends RelativeLayout implements View.OnClickListene refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_PHONE_NUMBER), mPhone, mTvPhone); refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_EMAIL), mEmail, mTvEmail); refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_OPERATOR), mOperator, mTvOperator); - refreshMetadataOrHide(mMapObject.getCuisine(), mCuisine, mTvCuisine); + refreshMetadataOrHide(mMapObject.getFormattedCuisine(), mCuisine, mTvCuisine); // TODO @yunikkk uncomment wiki display when data with correct wiki representation(urlencoded once) will be ready // refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA), mWiki, null); refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_INTERNET), mWifi, null);