diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java b/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java index 8b83c371b..9a4938425 100644 --- a/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/PlacePageView.java @@ -72,6 +72,7 @@ import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment; import app.organicmaps.util.bottomsheet.MenuBottomSheetItem; import app.organicmaps.widget.ArrowView; import app.organicmaps.widget.placepage.sections.PlacePageBookmarkFragment; +import app.organicmaps.widget.placepage.sections.PlacePageChargeSocketsFragment; import app.organicmaps.widget.placepage.sections.PlacePageLinksFragment; import app.organicmaps.widget.placepage.sections.PlacePageOpeningHoursFragment; import app.organicmaps.widget.placepage.sections.PlacePagePhoneFragment; @@ -98,6 +99,7 @@ public class PlacePageView extends Fragment private static final String BOOKMARK_FRAGMENT_TAG = "BOOKMARK_FRAGMENT_TAG"; private static final String TRACK_FRAGMENT_TAG = "TRACK_FRAGMENT_TAG"; private static final String WIKIPEDIA_FRAGMENT_TAG = "WIKIPEDIA_FRAGMENT_TAG"; + private static final String CHARGE_SOCKETS_FRAGMENT_TAG = "CHARGE_SOCKETS_FRAGMENT_TAG"; private static final String PHONE_FRAGMENT_TAG = "PHONE_FRAGMENT_TAG"; private static final String OPENING_HOURS_FRAGMENT_TAG = "OPENING_HOURS_FRAGMENT_TAG"; private static final String LINKS_FRAGMENT_TAG = "LINKS_FRAGMENT_TAG"; @@ -405,6 +407,12 @@ public class PlacePageView extends Fragment R.id.place_page_opening_hours_fragment, !TextUtils.isEmpty(ohStr)); } + private void updateChargeSocketsView() + { + updateViewFragment(PlacePageChargeSocketsFragment.class, CHARGE_SOCKETS_FRAGMENT_TAG, + R.id.place_page_charge_sockets_fragment, mMapObject.hasChargeSockets()); + } + private void updatePhoneView() { updateViewFragment(PlacePagePhoneFragment.class, PHONE_FRAGMENT_TAG, R.id.place_page_phone_fragment, @@ -663,7 +671,8 @@ public class PlacePageView extends Fragment if (!lastChecked.isEmpty()) { String periodSinceCheck = DateUtils.getRelativePeriodString(getResources(), lastChecked); - UiUtils.setTextAndShow(mTvLastChecked, requireContext().getString(R.string.existence_confirmed_time_ago, periodSinceCheck)); + UiUtils.setTextAndShow(mTvLastChecked, + requireContext().getString(R.string.existence_confirmed_time_ago, periodSinceCheck)); } else UiUtils.hide(mTvLastChecked); @@ -700,6 +709,7 @@ public class PlacePageView extends Fragment updateOpeningHoursView(); updateWikipediaView(); updateBookmarkView(); + updateChargeSocketsView(); updatePhoneView(); updateTrackView(); } diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java b/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java new file mode 100644 index 000000000..f9664def3 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java @@ -0,0 +1,118 @@ +package app.organicmaps.widget.placepage.sections; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.GridLayout; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; + +import com.google.android.material.imageview.ShapeableImageView; +import com.google.android.material.textview.MaterialTextView; + +import app.organicmaps.R; +import app.organicmaps.sdk.Framework; +import app.organicmaps.sdk.bookmarks.data.ChargeSocketDescriptor; +import app.organicmaps.sdk.bookmarks.data.MapObject; +import app.organicmaps.sdk.bookmarks.data.Metadata; +import app.organicmaps.widget.placepage.PlacePageViewModel; +import java.text.DecimalFormat; + +public class PlacePageChargeSocketsFragment extends Fragment implements Observer +{ + private GridLayout mGrid; + private PlacePageViewModel mViewModel; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) + { + mViewModel = new ViewModelProvider(requireActivity()).get(PlacePageViewModel.class); + return inflater.inflate(R.layout.place_page_charge_sockets_fragment, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) + { + super.onViewCreated(view, savedInstanceState); + + mGrid = view.findViewById(R.id.socket_grid); + } + + @Override + public void onStart() + { + super.onStart(); + mViewModel.getMapObject().observe(requireActivity(), this); + } + + @Override + public void onStop() + { + super.onStop(); + mViewModel.getMapObject().removeObserver(this); + } + + @Override + public void onChanged(@Nullable MapObject mapObject) + { + if (mapObject == null) + { + return; + } + + mGrid.removeAllViews(); + + ChargeSocketDescriptor[] sockets = Framework.nativeGetActiveObjectChargeSockets(); + + LayoutInflater inflater = LayoutInflater.from(requireContext()); + + for (ChargeSocketDescriptor socket : sockets) + { + View itemView = inflater.inflate(R.layout.item_charge_socket, mGrid, false); + + MaterialTextView type = itemView.findViewById(R.id.socket_type); + ShapeableImageView icon = itemView.findViewById(R.id.socket_icon); + MaterialTextView power = itemView.findViewById(R.id.socket_power); + MaterialTextView count = itemView.findViewById(R.id.socket_count); + + // load SVG icon converted into VectorDrawable in res/drawable + @SuppressLint("DiscouragedApi") + int resIconId = getResources().getIdentifier("ic_charge_socket_" + socket.type(), "drawable", + requireContext().getPackageName()); + if (resIconId != 0) + { + icon.setImageResource(resIconId); + } + + @SuppressLint("DiscouragedApi") + int resTypeId = + getResources().getIdentifier("charge_socket_" + socket.type(), "string", requireContext().getPackageName()); + if (resTypeId != 0) + { + type.setText(resTypeId); + } + + if (socket.power() != 0) + { + DecimalFormat df = new DecimalFormat("#.##"); + power.setText(getString(R.string.kw_label, df.format(socket.power()))); + } + + if (socket.count() != 0) + { + count.setText(getString(R.string.count_label, socket.count())); + } + + mGrid.addView(itemView); + } + } +} diff --git a/android/app/src/main/res/drawable/bg_badge.xml b/android/app/src/main/res/drawable/bg_badge.xml new file mode 100644 index 000000000..e2d2dbab8 --- /dev/null +++ b/android/app/src/main/res/drawable/bg_badge.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/item_charge_socket.xml b/android/app/src/main/res/layout/item_charge_socket.xml new file mode 100644 index 000000000..fbe15cc6d --- /dev/null +++ b/android/app/src/main/res/layout/item_charge_socket.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout/place_page_charge_sockets_fragment.xml b/android/app/src/main/res/layout/place_page_charge_sockets_fragment.xml new file mode 100644 index 000000000..c35b1e321 --- /dev/null +++ b/android/app/src/main/res/layout/place_page_charge_sockets_fragment.xml @@ -0,0 +1,9 @@ + diff --git a/android/app/src/main/res/layout/place_page_details.xml b/android/app/src/main/res/layout/place_page_details.xml index ec3f9f88f..3f81fa3a8 100644 --- a/android/app/src/main/res/layout/place_page_details.xml +++ b/android/app/src/main/res/layout/place_page_details.xml @@ -16,6 +16,12 @@ android:background="?ppBackground" android:orientation="vertical"> + + Confirmado %s Compartir traza No se ha encontrado ningún motor de texto-a-voz, comprueba la configuración de la aplicación + potencia desconocida + Tipo 2 (sin cable) + Tipo 2 (con cable) + Tipo 2 combo + Tipo 1 + NACS + CHAdeMO diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml index cdc331db0..c5350713b 100644 --- a/android/app/src/main/res/values-fr/strings.xml +++ b/android/app/src/main/res/values-fr/strings.xml @@ -879,4 +879,11 @@ Existence confirmée %s Confirmé %s Impossible de lire ce texte à voix haute, vérifiez les paramètres de l’application + puissance inconnue + Type 2 (sans câble) + Type 2 (avec câble) + Type 2 combo + Type 1 + NACS + CHAdeMO diff --git a/android/app/src/main/res/values/donottranslate.xml b/android/app/src/main/res/values/donottranslate.xml index fbc33ea82..d44eca1d5 100644 --- a/android/app/src/main/res/values/donottranslate.xml +++ b/android/app/src/main/res/values/donottranslate.xml @@ -98,4 +98,6 @@ VK Lemmy Pixelfed + × %d + %s kW diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 0837abd5a..bf447c230 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -915,4 +915,12 @@ Share Track Delete %s? No text-to-speech engine found, check the app settings + unknown power + Type 2 (no cable) + Type 2 (w/ cable) + Type 2 combo + Type 1 + NACS + CHAdeMO + unknown socket diff --git a/android/sdk/src/main/cpp/app/organicmaps/sdk/Framework.cpp b/android/sdk/src/main/cpp/app/organicmaps/sdk/Framework.cpp index fac992985..8df90e5b5 100644 --- a/android/sdk/src/main/cpp/app/organicmaps/sdk/Framework.cpp +++ b/android/sdk/src/main/cpp/app/organicmaps/sdk/Framework.cpp @@ -1592,6 +1592,33 @@ JNIEXPORT jstring JNICALL Java_app_organicmaps_sdk_Framework_nativeGetActiveObje return jni::ToJavaString(env, g_framework->GetPlacePageInfo().FormatCuisines()); } +JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_sdk_Framework_nativeGetActiveObjectChargeSockets(JNIEnv * env, + jclass) +{ + auto sockets = g_framework->GetPlacePageInfo().GetChargeSockets(); + + jclass descClass = env->FindClass("app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor"); + jmethodID ctor = env->GetMethodID(descClass, "", "(Ljava/lang/String;ID)V"); + + // Create a Java array + jobjectArray result = env->NewObjectArray(sockets.size(), descClass, nullptr); + + for (size_t i = 0; i < sockets.size(); ++i) + { + auto const & s = sockets[i]; + + jstring jType = env->NewStringUTF(s.type.c_str()); + jobject jDesc = env->NewObject(descClass, ctor, jType, (jint)s.count, (jdouble)s.power); + + env->SetObjectArrayElement(result, i, jDesc); + + env->DeleteLocalRef(jType); + env->DeleteLocalRef(jDesc); + } + + return result; +} + JNIEXPORT void JNICALL Java_app_organicmaps_sdk_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, jint left, jint top, jint right, jint bottom) { diff --git a/android/sdk/src/main/java/app/organicmaps/sdk/Framework.java b/android/sdk/src/main/java/app/organicmaps/sdk/Framework.java index 67a8dbc06..0373e40ad 100644 --- a/android/sdk/src/main/java/app/organicmaps/sdk/Framework.java +++ b/android/sdk/src/main/java/app/organicmaps/sdk/Framework.java @@ -8,6 +8,7 @@ import androidx.annotation.Size; import app.organicmaps.sdk.api.ParsedRoutingData; import app.organicmaps.sdk.api.ParsedSearchRequest; import app.organicmaps.sdk.api.RequestType; +import app.organicmaps.sdk.bookmarks.data.ChargeSocketDescriptor; import app.organicmaps.sdk.bookmarks.data.DistanceAndAzimut; import app.organicmaps.sdk.bookmarks.data.FeatureId; import app.organicmaps.sdk.bookmarks.data.MapObject; @@ -304,6 +305,8 @@ public class Framework public static native String nativeGetActiveObjectFormattedCuisine(); + public static native ChargeSocketDescriptor[] nativeGetActiveObjectChargeSockets(); + public static native void nativeSetVisibleRect(int left, int top, int right, int bottom); // Navigation. diff --git a/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java b/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java new file mode 100644 index 000000000..955464bc6 --- /dev/null +++ b/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java @@ -0,0 +1,7 @@ +package app.organicmaps.sdk.bookmarks.data; + +/** + * represents the details of the socket available on a particular charging station + * + */ +public record ChargeSocketDescriptor(String type, int count, double power) {} diff --git a/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/MapObject.java b/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/MapObject.java index fc097fe23..147bf2bff 100644 --- a/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/MapObject.java +++ b/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/MapObject.java @@ -296,6 +296,11 @@ public class MapObject implements PlacePageData mMetadata.addMetadata(type, value); } + public boolean hasChargeSockets() + { + return !TextUtils.isEmpty(getMetadata(Metadata.MetadataType.FMD_CHARGE_SOCKETS)); + } + public boolean hasPhoneNumber() { return !TextUtils.isEmpty(getMetadata(Metadata.MetadataType.FMD_PHONE_NUMBER)); diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_chademo.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_chademo.xml new file mode 100644 index 000000000..d76ab9d02 --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_chademo.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_nacs.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_nacs.xml new file mode 100644 index 000000000..dcd6d0e05 --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_nacs.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_type1.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_type1.xml new file mode 100644 index 000000000..2d249d390 --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_type1.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_type2.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_type2.xml new file mode 100644 index 000000000..4dbf661c8 --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_type2.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_type2_cable.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_type2_cable.xml new file mode 100644 index 000000000..6ddd56021 --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_type2_cable.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_type2_combo.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_type2_combo.xml new file mode 100644 index 000000000..af0dab217 --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_type2_combo.xml @@ -0,0 +1,11 @@ + + + diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_unknown.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_unknown.xml new file mode 100644 index 000000000..aa7ecd20b --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_unknown.xml @@ -0,0 +1,11 @@ + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_chademo.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_chademo.svg new file mode 100644 index 000000000..af56bbf0d --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_chademo.svg @@ -0,0 +1,53 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_nacs.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_nacs.svg new file mode 100644 index 000000000..212bedfce --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_nacs.svg @@ -0,0 +1,54 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_type1.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_type1.svg new file mode 100644 index 000000000..25c3886fe --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_type1.svg @@ -0,0 +1,54 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_type2.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_type2.svg new file mode 100644 index 000000000..0d2566f77 --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_type2.svg @@ -0,0 +1,54 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_type2_cable.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_type2_cable.svg new file mode 100644 index 000000000..40b14cc5d --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_type2_cable.svg @@ -0,0 +1,53 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_type2_combo.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_type2_combo.svg new file mode 100644 index 000000000..66e1f396d --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_type2_combo.svg @@ -0,0 +1,53 @@ + + + + + + + image/svg+xml + + + + + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_unknown.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_unknown.svg new file mode 100644 index 000000000..95bc60cfd --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_unknown.svg @@ -0,0 +1,52 @@ + + + + + + + image/svg+xml + + + + + + +