diff --git a/android/res/values-nb/strings.xml b/android/res/values-nb/strings.xml index 156093c373..c74b5f6a2c 100644 --- a/android/res/values-nb/strings.xml +++ b/android/res/values-nb/strings.xml @@ -80,20 +80,8 @@ Velg hvor du vil at kartene skal lastes ned til Kart - - Intern privat lagring - - Intern delt lagring - - SD-kort - - Ekstern delt lagring - - %1$s ledig av %2$s Flytt kart? - - Kunne ikke flytte kart Dette kan ta flere minutter. Vent et øyeblikk … @@ -150,7 +138,6 @@ Merknader Delte Organic Maps-bokmerker - Hei!\n\nVedlagt er mine bokmerker fra Organic Maps-appen. Åpne de dersom du har Organic Maps installert. Har du ikke har det, last ned appen til iOS eller Android ved å trykke på denne linken: https://omaps.app/get?kmz\n\nNyt reisen med Organic Maps! Laster inn bokmerker @@ -190,10 +177,6 @@ Lengde Del posisjonen min - - Generelle instillinger - - Informasjon Navigasjon Zoom-knapper Vis på skjermen @@ -223,8 +206,6 @@ 12 timer 1 dag Vis på kartet - - Meny Nettside @@ -399,8 +380,6 @@ Fridag i dag Fridag I dag - Åpner om %s - Stenger om %s Stengt Rediger åpningstider Har du ingen konto hos OpenStreetMap? @@ -418,8 +397,6 @@ Detaljer Legg til en gate - - Legg til en gateadresse Velg et språk Velg en gate Postnummer @@ -427,7 +404,6 @@ Velg matrett E-postadresse eller brukernavn - Legg til telefon Gulv Alle endringer i kartet vil slettes sammen med kartet. Oppdater kart @@ -451,8 +427,6 @@ Logg inn slik at andre brukere kan se endringene du har utført. %1$d av %2$d - Last ned med mobildata? - Dette kan medføre store kostnader med enkelte dataplaner eller om du roamer. Skriv riktig husnummer Antall etasjer (maks. %d) @@ -493,17 +467,10 @@ Fjerne et tilføyd sted? Fjern Sted finnes ikke - - Forklar hvorfor stedet skal slettes Skriv riktig telefonnummer Oppgi en gyldig nettadresse Oppgi en gyldig epostadresse - Skriv inn en gyldig Facebook-adresse, -konto eller -side. - Skriv inn en gyldig Instagram-adresse eller -kontonavn - Skriv inn en gyldig Twitter-adresse eller -brukernavn. - Skriv inn en gyldig VB-adresse eller -kontonavn - Skriv inn en gyldig LINE-adresse eller -ID. Legg til en plass på kartet Vil du sende det til alle brukere? @@ -557,8 +524,6 @@ Skjul alle Vis alle Opprett ny liste - - Importer bokmerker Kan ikke dele på grunn av en programfeil Delingsfeil Kan ikke dele en tom liste @@ -694,22 +659,9 @@ Avstand: I rute Forstørr kartet for å se høydekurver - Last ned verdenskart - - Klarte ikke opprette mappe og flytte filer i enhetens minne eller SD-kort - - Diskfeil - - Tilkoblingsfeil - - Fjern USB-kabelen La skjermen sove Når den er aktivert, får skjermen lov til å sove etter en periode med inaktivitet. - - Vis på låseskjerm - - Når dette er aktivert trenger du ikke låse opp enheten hver gang når appen kjører. Kartdata fra OpenStreetMap diff --git a/android/src/app/organicmaps/MwmActivity.java b/android/src/app/organicmaps/MwmActivity.java index a2d6e41b40..8a667c522f 100644 --- a/android/src/app/organicmaps/MwmActivity.java +++ b/android/src/app/organicmaps/MwmActivity.java @@ -11,7 +11,6 @@ import android.text.TextUtils; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.WindowInsets; import android.view.WindowManager; import android.widget.TextView; @@ -22,6 +21,8 @@ import androidx.annotation.StyleRes; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentFactory; import androidx.fragment.app.FragmentManager; @@ -77,12 +78,6 @@ import app.organicmaps.settings.RoadType; import app.organicmaps.settings.SettingsActivity; import app.organicmaps.settings.UnitLocale; import app.organicmaps.sound.TtsPlayer; -import app.organicmaps.util.log.Logger; -import app.organicmaps.widget.menu.MainMenu; -import app.organicmaps.widget.placepage.PlacePageButtons; -import app.organicmaps.widget.placepage.PlacePageController; -import app.organicmaps.widget.placepage.PlacePageData; -import app.organicmaps.widget.placepage.PlacePageView; import app.organicmaps.util.Config; import app.organicmaps.util.Counters; import app.organicmaps.util.SharingUtils; @@ -92,6 +87,12 @@ import app.organicmaps.util.UiUtils; import app.organicmaps.util.Utils; import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment; import app.organicmaps.util.bottomsheet.MenuBottomSheetItem; +import app.organicmaps.util.log.Logger; +import app.organicmaps.widget.menu.MainMenu; +import app.organicmaps.widget.placepage.PlacePageButtons; +import app.organicmaps.widget.placepage.PlacePageController; +import app.organicmaps.widget.placepage.PlacePageData; +import app.organicmaps.widget.placepage.PlacePageView; import java.util.ArrayList; import java.util.Objects; @@ -192,7 +193,8 @@ public class MwmActivity extends BaseMwmFragmentActivity private int mNavBarHeight; - private WindowInsets mCurrentWindowInsets; + @Nullable + private WindowInsetsCompat mCurrentWindowInsets; public interface LeftAnimationTrackListener { @@ -416,21 +418,21 @@ public class MwmActivity extends BaseMwmFragmentActivity )); } - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 private void updateViewsInsets() { - mPointChooser.setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(mPointChooser, (view, windowInsets) -> { UiUtils.setViewInsetsPaddingBottom(mPointChooser, windowInsets); UiUtils.extendViewWithStatusBar(mPointChooserToolbar, windowInsets); - mNavBarHeight = mIsFullscreen ? 0 : windowInsets.getSystemWindowInsetBottom(); + mNavBarHeight = mIsFullscreen ? 0 : windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; // For the first loading, set compass top margin to status bar size + // The top inset will be then be updated by the routing controller if (mCurrentWindowInsets == null) - adjustCompass(windowInsets.getSystemWindowInsetTop(), windowInsets.getSystemWindowInsetRight()); + adjustCompass(windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).top, windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).right); else - adjustCompass(-1, windowInsets.getSystemWindowInsetRight()); + adjustCompass(-1, windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).right); refreshLightStatusBar(); - adjustBottomWidgets(windowInsets.getSystemWindowInsetLeft()); + adjustBottomWidgets(windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).left); mCurrentWindowInsets = windowInsets; return windowInsets; }); @@ -1389,10 +1391,14 @@ public class MwmActivity extends BaseMwmFragmentActivity } @Override - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 public void onRoutingPlanStartAnimate(boolean show) { - int offset = mCurrentWindowInsets.getSystemWindowInsetTop(); + // TODO This code section may be called when insets are not yet initialized + // This is only a workaround to prevent crashes but a proper fix should be implemented + if (mCurrentWindowInsets == null) { + return; + } + int offset = mCurrentWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).top; if (show && mRoutingPlanInplaceController != null) { final int height = mRoutingPlanInplaceController.calcHeight(); @@ -1427,14 +1433,10 @@ public class MwmActivity extends BaseMwmFragmentActivity } else { - if (mIsTabletLayout) - { - adjustCompassAndTraffic(mCurrentWindowInsets.getSystemWindowInsetTop()); - } - else - { + if (mIsTabletLayout && mCurrentWindowInsets != null) + adjustCompassAndTraffic(mCurrentWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).top); + else if (!mIsTabletLayout) mRoutingPlanInplaceController.show(false); - } closeAllFloatingPanelsTablet(); diff --git a/android/src/app/organicmaps/downloader/OnmapDownloader.java b/android/src/app/organicmaps/downloader/OnmapDownloader.java index 913bd8788e..5de160e23a 100644 --- a/android/src/app/organicmaps/downloader/OnmapDownloader.java +++ b/android/src/app/organicmaps/downloader/OnmapDownloader.java @@ -9,6 +9,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; import app.organicmaps.MwmActivity; import app.organicmaps.R; import app.organicmaps.background.Notifier; @@ -223,7 +224,7 @@ public class OnmapDownloader implements MwmActivity.LeftAnimationTrackListener MapManager.nativeDownload(mCurrentCountry.id); })); - mFrame.setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(mFrame, (view, windowInsets) -> { UiUtils.setViewInsetsPadding(view, windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/maplayer/MapButtonsController.java b/android/src/app/organicmaps/maplayer/MapButtonsController.java index 6db0dfdd0b..ddde63e2ea 100644 --- a/android/src/app/organicmaps/maplayer/MapButtonsController.java +++ b/android/src/app/organicmaps/maplayer/MapButtonsController.java @@ -11,6 +11,7 @@ import android.view.ViewTreeObserver; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.OptIn; +import androidx.core.view.ViewCompat; import androidx.fragment.app.Fragment; import com.google.android.material.badge.BadgeDrawable; @@ -128,7 +129,7 @@ public class MapButtonsController extends Fragment if (helpButton != null) mButtonsMap.put(MapButtons.help, helpButton); - mFrame.setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(mFrame, (view, windowInsets) -> { UiUtils.setViewInsetsPadding(view, windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/routing/NavigationController.java b/android/src/app/organicmaps/routing/NavigationController.java index 34252cd316..df1a61e74b 100644 --- a/android/src/app/organicmaps/routing/NavigationController.java +++ b/android/src/app/organicmaps/routing/NavigationController.java @@ -18,6 +18,8 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import com.google.android.material.bottomsheet.BottomSheetBehavior; import app.organicmaps.Framework; import app.organicmaps.MwmActivity; @@ -79,12 +81,11 @@ public class NavigationController implements Application.ActivityLifecycleCallba } }; - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 private void addWindowsInsets(@NonNull View topFrame) { - topFrame.findViewById(R.id.nav_next_turn_container).setOnApplyWindowInsetsListener((view, windowInsets) -> { - view.setPadding(windowInsets.getSystemWindowInsetLeft(), view.getPaddingTop(), - view.getPaddingRight(), view.getPaddingBottom()); + ViewCompat.setOnApplyWindowInsetsListener(topFrame.findViewById(R.id.nav_next_turn_container), (view, windowInsets) -> { + view.setPadding(windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).left, view.getPaddingTop(), + view.getPaddingRight(), view.getPaddingBottom()); return windowInsets; }); } @@ -114,11 +115,11 @@ public class NavigationController implements Application.ActivityLifecycleCallba // Show a blank view below the navbar to hide the menu content final View navigationBarBackground = mFrame.findViewById(R.id.nav_bottom_sheet_nav_bar); final View nextTurnContainer = mFrame.findViewById(R.id.nav_next_turn_container); - mStreetFrame.setOnApplyWindowInsetsListener((v, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(mStreetFrame, (v, windowInsets) -> { UiUtils.extendViewWithStatusBar(v, windowInsets); - nextTurnContainer.setPadding(windowInsets.getSystemWindowInsetLeft(), nextTurnContainer.getPaddingTop(), + nextTurnContainer.setPadding(windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).left, nextTurnContainer.getPaddingTop(), nextTurnContainer.getPaddingRight(), nextTurnContainer.getPaddingBottom()); - navigationBarBackground.getLayoutParams().height = windowInsets.getSystemWindowInsetBottom(); + navigationBarBackground.getLayoutParams().height = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; // The gesture navigation bar stays at the bottom in landscape // We need to add a background only above the nav menu navigationBarBackground.getLayoutParams().width = mFrame.findViewById(R.id.nav_bottom_sheet).getWidth(); diff --git a/android/src/app/organicmaps/routing/RoutingPlanController.java b/android/src/app/organicmaps/routing/RoutingPlanController.java index ea567fba72..f3ca006bf4 100644 --- a/android/src/app/organicmaps/routing/RoutingPlanController.java +++ b/android/src/app/organicmaps/routing/RoutingPlanController.java @@ -13,6 +13,7 @@ import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; import app.organicmaps.Framework; import app.organicmaps.MwmApplication; import app.organicmaps.R; @@ -105,7 +106,7 @@ public class RoutingPlanController extends ToolbarController mAnimToggle = MwmApplication.from(activity.getApplicationContext()) .getResources().getInteger(R.integer.anim_default); - mFrame.setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(mFrame, (view, windowInsets) -> { UiUtils.setViewInsetsPaddingNoTop(activity.findViewById(R.id.menu_frame), windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/search/FloatingSearchToolbarController.java b/android/src/app/organicmaps/search/FloatingSearchToolbarController.java index 345375b5d9..78828d0f6e 100644 --- a/android/src/app/organicmaps/search/FloatingSearchToolbarController.java +++ b/android/src/app/organicmaps/search/FloatingSearchToolbarController.java @@ -5,6 +5,7 @@ import android.app.Activity; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; import app.organicmaps.widget.SearchToolbarController; import app.organicmaps.util.UiUtils; @@ -27,7 +28,7 @@ public class FloatingSearchToolbarController extends SearchToolbarController mListener = listener; // We only want to detect a click on the input and not allow editing. disableQueryEditing(); - getToolbar().setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(getToolbar(), (view, windowInsets) -> { UiUtils.setViewInsetsPaddingNoTop(view, windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/util/UiUtils.java b/android/src/app/organicmaps/util/UiUtils.java index 64b1fb4983..871f0b30cd 100644 --- a/android/src/app/organicmaps/util/UiUtils.java +++ b/android/src/app/organicmaps/util/UiUtils.java @@ -36,6 +36,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; +import androidx.core.graphics.Insets; import androidx.core.view.WindowCompat; import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsControllerCompat; @@ -410,9 +411,9 @@ public final class UiUtils } } - public static void extendViewWithStatusBar(@NonNull View view, WindowInsets windowInsets) + public static void extendViewWithStatusBar(@NonNull View view, WindowInsetsCompat windowInsets) { - final int height = windowInsets.getSystemWindowInsetTop(); + final int height = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).top; final ViewGroup.LayoutParams lp = view.getLayoutParams(); // Extend the height only when necessary if (lp.height != ViewGroup.LayoutParams.WRAP_CONTENT && view.getPaddingTop() < height) @@ -423,39 +424,31 @@ public final class UiUtils setViewInsetsPaddingNoBottom(view, windowInsets); } - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 - public static void setViewInsetsPadding(View view, WindowInsets windowInsets) + public static void setViewInsetsPadding(View view, WindowInsetsCompat windowInsets) { - view.setPadding(windowInsets.getSystemWindowInsetLeft(), windowInsets.getSystemWindowInsetTop(), - windowInsets.getSystemWindowInsetRight(), windowInsets.getSystemWindowInsetBottom()); + final Insets systemInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); + view.setPadding(systemInsets.left, systemInsets.top, + systemInsets.right, systemInsets.bottom); } - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 - public static void setViewInsetsPaddingNoTop(View view, WindowInsets windowInsets) + public static void setViewInsetsPaddingNoTop(View view, WindowInsetsCompat windowInsets) { - view.setPadding(windowInsets.getSystemWindowInsetLeft(), view.getPaddingTop(), - windowInsets.getSystemWindowInsetRight(), windowInsets.getSystemWindowInsetBottom()); + final Insets systemInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); + view.setPadding(systemInsets.left, view.getPaddingTop(), + systemInsets.right, systemInsets.bottom); } - - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 - public static void setViewInsetsPaddingSides(View view, WindowInsets windowInsets) - { - view.setPadding(windowInsets.getSystemWindowInsetLeft(), view.getPaddingTop(), - windowInsets.getSystemWindowInsetRight(), view.getPaddingBottom()); - } - - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 - public static void setViewInsetsPaddingBottom(View view, WindowInsets windowInsets) + public static void setViewInsetsPaddingBottom(View view, WindowInsetsCompat windowInsets) { + final Insets systemInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), - view.getPaddingRight(), windowInsets.getSystemWindowInsetBottom()); + view.getPaddingRight(), systemInsets.bottom); } - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 - public static void setViewInsetsPaddingNoBottom(View view, WindowInsets windowInsets) + public static void setViewInsetsPaddingNoBottom(View view, WindowInsetsCompat windowInsets) { - view.setPadding(windowInsets.getSystemWindowInsetLeft(), windowInsets.getSystemWindowInsetTop(), - windowInsets.getSystemWindowInsetRight(), view.getPaddingBottom()); + final Insets systemInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); + view.setPadding(systemInsets.left, systemInsets.top, + systemInsets.right, view.getPaddingBottom()); } public static void setupNavigationIcon(@NonNull Toolbar toolbar, diff --git a/android/src/app/organicmaps/widget/ToolbarController.java b/android/src/app/organicmaps/widget/ToolbarController.java index 76983e7d27..468eef81d1 100644 --- a/android/src/app/organicmaps/widget/ToolbarController.java +++ b/android/src/app/organicmaps/widget/ToolbarController.java @@ -11,6 +11,7 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import androidx.core.view.ViewCompat; import app.organicmaps.R; import app.organicmaps.base.Detachable; import app.organicmaps.util.UiUtils; @@ -32,7 +33,7 @@ public class ToolbarController implements Detachable if (useExtendedToolbar()) { - getToolbar().setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(getToolbar(), (view, windowInsets) -> { UiUtils.extendViewWithStatusBar(getToolbar(), windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/widget/placepage/EditBookmarkFragment.java b/android/src/app/organicmaps/widget/placepage/EditBookmarkFragment.java index a5229925bc..edeadfbe2e 100644 --- a/android/src/app/organicmaps/widget/placepage/EditBookmarkFragment.java +++ b/android/src/app/organicmaps/widget/placepage/EditBookmarkFragment.java @@ -14,6 +14,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; +import androidx.core.view.ViewCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentFactory; import androidx.fragment.app.FragmentManager; @@ -106,7 +107,7 @@ public class EditBookmarkFragment extends BaseMwmDialogFragment implements View. private void initToolbar(View view) { Toolbar toolbar = view.findViewById(R.id.toolbar); - toolbar.setOnApplyWindowInsetsListener((v, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, windowInsets) -> { UiUtils.extendViewWithStatusBar(v, windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/widget/placepage/PlacePageButtons.java b/android/src/app/organicmaps/widget/placepage/PlacePageButtons.java index 6e527250ca..4c093ea529 100644 --- a/android/src/app/organicmaps/widget/placepage/PlacePageButtons.java +++ b/android/src/app/organicmaps/widget/placepage/PlacePageButtons.java @@ -11,6 +11,7 @@ import android.widget.TextView; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; @@ -43,7 +44,7 @@ public final class PlacePageButtons extends Fragment implements Observer { + ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> { UiUtils.setViewInsetsPaddingNoTop(v, windowInsets); return windowInsets; }); diff --git a/android/src/app/organicmaps/widget/placepage/PlacePageController.java b/android/src/app/organicmaps/widget/placepage/PlacePageController.java index 9899ce23d9..ca81ca99c9 100644 --- a/android/src/app/organicmaps/widget/placepage/PlacePageController.java +++ b/android/src/app/organicmaps/widget/placepage/PlacePageController.java @@ -7,11 +7,12 @@ import android.content.res.Resources; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; -import android.view.WindowInsets; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.core.widget.NestedScrollViewClickFixed; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -68,7 +69,7 @@ public class PlacePageController implements Initializable, private boolean mDeactivateMapSelection = true; @Nullable private MapObject mMapObject; - private WindowInsets mCurrentWindowInsets; + private WindowInsetsCompat mCurrentWindowInsets; private boolean mShouldCollapse; private int mDistanceToTop; @@ -142,7 +143,7 @@ public class PlacePageController implements Initializable, mMaxButtons = mMwmActivity.getResources().getInteger(R.integer.pp_buttons_max); viewModel = new ViewModelProvider(mMwmActivity).get(PlacePageViewModel.class); - mPlacePage.setOnApplyWindowInsetsListener((view, windowInsets) -> { + ViewCompat.setOnApplyWindowInsetsListener(mPlacePage, (view, windowInsets) -> { mCurrentWindowInsets = windowInsets; return windowInsets; }); @@ -229,7 +230,6 @@ public class PlacePageController implements Initializable, * Set the min and max height of the place page to prevent jumps when switching from one map object * to the other. */ - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 private void setPlacePageHeightBounds() { final int peekHeight = calculatePeekHeight(); @@ -240,7 +240,7 @@ public class PlacePageController implements Initializable, mPlacePageContainer.setMinimumHeight(height); // Set the maximum height of the place page to prevent jumps when new data results in BIGGER content // It does not take into account the navigation bar height so we need to add it manually - mPlacePageBehavior.setMaxHeight(height + mCurrentWindowInsets.getSystemWindowInsetBottom()); + mPlacePageBehavior.setMaxHeight(height + mCurrentWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom); } /** @@ -274,13 +274,13 @@ public class PlacePageController implements Initializable, * Using the animate param in setPeekHeight does not work when adding removing fragments * from inside the place page so we manually animate the peek height with ValueAnimator */ - @SuppressWarnings("deprecation") // https://github.com/organicmaps/organicmaps/issues/3631 private void animatePeekHeight(int peekHeight) { + final int bottomInsets = mCurrentWindowInsets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom; // Make sure to start from the current height of the place page final int parentHeight = ((View) mPlacePage.getParent()).getHeight(); // Make sure to remove the navbar height because the peek height already takes it into account - int initialHeight = parentHeight - mDistanceToTop - mCurrentWindowInsets.getSystemWindowInsetBottom(); + int initialHeight = parentHeight - mDistanceToTop - bottomInsets; if (mCustomPeekHeightAnimator != null) mCustomPeekHeightAnimator.cancel(); @@ -290,10 +290,10 @@ public class PlacePageController implements Initializable, int value = (Integer) valueAnimator.getAnimatedValue(); // Make sure the place page can reach the animated peek height to prevent jumps // maxHeight does not take the navbar height into account so we manually add it - mPlacePageBehavior.setMaxHeight(value + mCurrentWindowInsets.getSystemWindowInsetBottom()); + mPlacePageBehavior.setMaxHeight(value + bottomInsets); mPlacePageBehavior.setPeekHeight(value); // The place page is not firing the slide callbacks when using this animation, so we must call them manually - mDistanceToTop = parentHeight - value - mCurrentWindowInsets.getSystemWindowInsetBottom(); + mDistanceToTop = parentHeight - value - bottomInsets; mSlideListener.onPlacePageSlide(mDistanceToTop); if (value == peekHeight) { diff --git a/data/categories.txt b/data/categories.txt index f3e1ddf3e3..046a02c159 100644 --- a/data/categories.txt +++ b/data/categories.txt @@ -4500,7 +4500,7 @@ it:Cimitero ja:1墓地|墓場|お墓|墓苑|霊場 ko:묘지|묘소|공동묘지 mr:स्मशानभूमी -nb:Gravlund|Gravplass +nb:Gravplass pl:3Cmentarz|pochówek pt:Sepultura|5Cemitério pt-BR:5Cemitério diff --git a/data/strings/strings.txt b/data/strings/strings.txt index f799cac2e2..b4c505c934 100644 --- a/data/strings/strings.txt +++ b/data/strings/strings.txt @@ -1991,7 +1991,6 @@ es = Almacenamiento interno privado et = Sisemine privaatne salvestusruum fr = Stockage interne privé - nb = Intern privat lagring nl = Intern persoonlijk geheugen pl = Wewnętrzna pamięć prywatna pt-BR = Armazenamento interno privado @@ -2010,7 +2009,6 @@ es = Almacenamiento interno compartido et = Sisemine jagatud salvestusruum fr = Stockage interne partagé - nb = Intern delt lagring nl = Intern gedeeld geheugen pl = Wewnętrzna pamięć współdzielona pt-BR = Armazenamento interno compartilhado @@ -2029,7 +2027,6 @@ es = Tarjeta SD et = SD-kaart fr = Carte SD - nb = SD-kort nl = SD-kaart pl = Karta SD pt-BR = Cartão SD @@ -2048,7 +2045,6 @@ es = Almacenamiento externo compartido et = Väline jagatud salvestusruum fr = Stockage externe partagé - nb = Ekstern delt lagring nl = Extern gedeeld geheugen pl = Zewnętrzna pamięć współdzielona pt-BR = Armazenamento externo compartilhado @@ -2067,7 +2063,6 @@ es = %1$@ libres de %2$@ et = %1$@ vaba ruumist %2$@ fr = %1$@ libres sur %2$@ - nb = %1$@ ledig av %2$@ nl = %1$@ beschikbaar van %2$@ pl = %1$@ wolne z %2$@ pt-BR = %1$@ livre de %2$@ @@ -2126,7 +2121,6 @@ es = Error al mover los archivos de mapas et = Kaardipaanide teisaldamine ebaõnnestus fr = Erreur lors du déplacement des cartes - nb = Kunne ikke flytte kart nl = Fout bij het verplaatsen van kaartbestanden pl = Błąd przenoszenia plików map pt-BR = Erro ao mover arquivos de mapas @@ -3257,7 +3251,6 @@ fr = Bonjour !\n\nVous trouverez ci-joint mes signets de l'appli Organic Maps. Veuillez les ouvrir si vous avez installé Organic Maps. Si vous ne l'avez pas, téléchargez l'application pour votre appareil iOS ou Android en suivant ce lien : https://omaps.app/get?kmz\n\nBon voyage avec Organic Maps! it = Ciao!\n\nIn allegato ci sono i miei luoghi preferiti. Aprili se hai installato Organic Maps. Oppure, se non ce l'hai, scarica l'app per iOS o Android seguendo questo link: https://omaps.app/\n\nDivertiti a viaggiare con Organic Maps! mr = नमस्कार!\n\nOrganic Maps ऍप मधील माझे खूणपत्रे संलग्न केले आहेत. तुम्ही Organic Maps इन्स्टॉल केले असल्यास हे खूणपत्रे उघडा. इन्स्टॉल केले नसल्यास, पुढील दुव्यावर जाऊन तुमच्या iOS किंवा अँड्रॉइड उपकरणावर हे डाउनलोड करा: https://omaps.app/get?kmz\n\nOrganic Maps सह प्रवासाचा आनंद घ्या! - nb = Hei!\n\nVedlagt er mine bokmerker fra Organic Maps-appen. Åpne de dersom du har Organic Maps installert. Har du ikke har det, last ned appen til iOS eller Android ved å trykke på denne linken: https://omaps.app/get?kmz\n\nNyt reisen med Organic Maps! nl = Hallo!\n\nBijgesloten zijn mijn bladwijzers uit de Organic Maps app. Open ze als je Organic Maps geïnstalleerd hebt. Of, als je dat niet hebt, download de app voor je iOS- of Android-apparaat door deze link te volgen: https://omaps.app/get?kmz\n\nGeniet van het reizen met Organic Maps! pl = Cześć!\n\nZałączam moje zakładki z aplikacji Organic Maps. Proszę otwórz je jeżeli masz zaintalowane Organic Maps. Lub, jeżeli nie masz, pobierz aplikację na swoje urządzenie iOS/Android za pomocą tego linka: https://omaps.app/get?kmz\n\nMiłego podróżowania z Organic Maps! pt = Olá!\n\nSegue em anexo os meus favoritos da aplicação Organic Maps. Por favor abra-os se tiver o Organic Maps instalado. Caso não tenha, descarregue a aplicação para o seu dispositivo iOS ou Android com a hiperligação https://omaps.app/get?kmz\n\nDivirta-se a viajar com o Organic Maps! @@ -4182,7 +4175,6 @@ fr = Paramètres généraux it = Opzioni generali mr = सर्वसामान्य सेटिंग - nb = Generelle instillinger nl = Algemene instellingen pl = Ustawienia ogólne pt = Configurações gerais @@ -4211,7 +4203,6 @@ fr = Information it = Informazioni mr = माहिती - nb = Informasjon nl = Informatie pl = Informacje pt = Informação @@ -5179,7 +5170,6 @@ ca = Menú es = Menú fr = Menu - nb = Meny pl = Menu ru = Меню uk = Меню @@ -10746,7 +10736,6 @@ eu = Bihar %@ean irekiko da fr = Ouvre demain à %@ it = Apre domani alle %@ - nb = Åpner i morgen klokka %@ nl = Opent morgen om %@ pl = Otwarcie jutro o %@ pt = Abre amanhã às %@ @@ -10765,7 +10754,6 @@ eu = %1$@ean %2$@ean irekiko da fr = Ouvre le %1$@ à %2$@ it = Apre %1$@ alle %2$@ - nb = Åpner %1$@ klokka %2$@ nl = Opent %1$@ om %2$@ pl = Otwarcie %1$@ o %2$@ pt = Abre %1$@ às %2$@ @@ -10784,7 +10772,6 @@ eu = %@ean irekiko da fr = Ouvre à %@ it = Apre alle %@ - nb = Åpner klokka %@ nl = Opent om %@ pl = Otwarcie o %@ pt = Abre às %@ @@ -10804,7 +10791,6 @@ eu = %@ barru irekitzen da fr = Ouvert dans %@ it = Apre tra %@ - nb = Åpner om %@ nl = Opent over %@ pl = Otwarcie za %@ pt-BR = Abre em %@ @@ -10823,7 +10809,6 @@ eu = %@ean itxiko da fr = Ferme à %@ it = Chiude alle %@ - nb = Stenger %@ nl = Sluit om %@ pl = Zamknięcie o %@ pt = Encerra às %@ @@ -10843,7 +10828,6 @@ eu = %@ barru ixten da fr = Fermé dans %@ it = Chiude tra %@ - nb = Stenger om %@ nl = Sluit over %@ pl = Zamknięcie za %@ pt-BR = Fecha em %@ @@ -11731,7 +11715,6 @@ fr = Veuillez entrer un nom de rue it = Inserire il nome della via mr = कृपया रस्त्याचे नाव जोडा - nb = Legg til en gateadresse nl = Voer een straatnaam in a.u.b. pl = Proszę wpisz nazwę ulicy pt-BR = Por favor, digite o nome da rua @@ -12024,7 +12007,6 @@ fr = Ajouter un numéro de téléphone it = Aggiungi numero mr = फोन जोडा - nb = Legg til telefon nl = Telefoonnummer toevoegen pl = Dodaj numer telefonu ro = Adaugă un număr @@ -13268,7 +13250,6 @@ ja = 携帯通信ネットワークで接続してダウンロードしますか? ko = 셀룰러 네트워크 접속을 사용하여 다운로드하시겠습니까? mr = मोबाईल डेटा वापरून डाउनलोड करायचे? - nb = Last ned med mobildata? nl = Downloaden via een mobiele gegevensverbinding? pl = Czy pobrać, używając połączenia z siecią komórkową? pt = Descarregar utilizando uma conexão de rede de telemóveis? @@ -13307,7 +13288,6 @@ ja = プランによって、またはローミングしている場合、非常に高額になる可能性があります。 ko = 이는 일부 플랜이나 로밍할 경우에 비싸다고 간주될 수 있습니다. mr = रोमिंग वर असल्यास हे बरेच महाग पडू शकते. - nb = Dette kan medføre store kostnader med enkelte dataplaner eller om du roamer. nl = Met sommige abonnementen of bij roaming kan dit behoorlijk duur zijn. pl = Może to być kosztowne przy niektórych planach taryfowych lub w roamingu. pt = Isto pode ser muito caro com alguns planos ou em roaming. @@ -15160,7 +15140,6 @@ fr = Veuillez indiquer la raison pour laquelle vous effacez cet endroit it = Indicare il motivo dell' eliminazione del luogo mr = कृपया ठिकाण हटवण्याचे कारण सूचित करा - nb = Forklar hvorfor stedet skal slettes nl = Graag de reden voor verwijdering aangeven pl = Proszę opisz powód usunięcia miejsca pt-BR = Por favor, explica o motivo pelo qual você está retirando o local @@ -15338,7 +15317,6 @@ fr = Saisissez une adresse web, un compte ou un nom de page Facebook valide it = Inserisci un indirizzo web, un account o un nome di pagina Facebook valido mr = वैध Facebook वेब पत्ता, खाते किंवा पृष्ठ नाव प्रविष्ट करा - nb = Skriv inn en gyldig Facebook-adresse, -konto eller -side. nl = Voer een geldig Facebook-webadres, een accountnaam of een paginanaam in pl = Wprowadź poprawny link, nazwę konta lub nazwę strony na Facebooku ro = Introdu o adresă web, un cont sau un nume de pagină Facebook valabil @@ -15359,7 +15337,6 @@ fr = Saisissez une adresse web, un nom de compte Instagram valide it = Inserisci un indirizzo web o un nome di account Instagram valido mr = वैध Instagram वेब पत्ता किंवा खाते नाव प्रविष्ट करा - nb = Skriv inn en gyldig Instagram-adresse eller -kontonavn nl = Voer een geldig Instagram-webadres of een accountnaam in pl = Wprowadź poprawny link lub nazwę konta na Instagramie ro = Introdu o adresă web sau un nume de cont Instagram valabil @@ -15380,7 +15357,6 @@ fr = Saisissez une adresse web, un nom de compte Twitter valide it = Inserisci un indirizzo web o un nome utente Twitter valido mr = वैध Twitter वेब पत्ता किंवा वापरकर्तानाव प्रविष्ट करा - nb = Skriv inn en gyldig Twitter-adresse eller -brukernavn. nl = Voer een geldig Twitter-webadres of een gebruikersnaam in pl = Wprowadź poprawny adres lub nazwę konta na Twitterze ro = Introdu o adresă web sau un nume de utilizator Twitter valabil @@ -15400,7 +15376,6 @@ eu = Mesedez, idatzi baliozko web helbide bat edo VK kontuaren izena fr = Saisissez une adresse web, un nom de compte VK valide it = Inserisci un indirizzo web o un nome di account VK valido - nb = Skriv inn en gyldig VB-adresse eller -kontonavn nl = Voer een geldig VB webadres of een accountnaam in pl = Wprowadź poprawny adres lub nazwę konta na VK ro = Introdu o adresă web sau un nume de cont VK valabil @@ -15420,7 +15395,6 @@ et = Sisesta kehtiv LINE veebiaadress või LINE ID fr = Entrez une adresse web ou un ID de LINE valide it = Inserisca un indirizzo web LINE valido o un ID LINE - nb = Skriv inn en gyldig LINE-adresse eller -ID. nl = Voer een geldig LINE-webadres of een LINE ID in pl = Wpisz prawidłowy url LINE lub LINE ID ro = Introdu o adresă web LINE valabilă sau un ID LINE @@ -17778,7 +17752,6 @@ fr = Importer des signets it = Importa luoghi preferiti mr = खूणपत्रे आयात करा - nb = Importer bokmerker nl = Bladwijzers importeren pl = Import zakładek pt = Importar favoritos @@ -19558,7 +19531,6 @@ fr = Populaire it = Popolare mr = लोकप्रिय - nb = Populær nl = Populair pl = Popularne pt = Popular @@ -24566,7 +24538,6 @@ fr = Télécharger la carte du monde it = Scarica la mappa del mondo mr = जगाचा नकाशा डाउनलोड करा - nb = Last ned verdenskart nl = Download de wereldkaart pl = Pobierz mapę świata pt = Descarregar o mapa mundial @@ -24586,7 +24557,6 @@ et = Seadme sisemällu või mälukaardile ei saa kausta luua ja faile teisaldada fr = Impossible de créer un dossier et de déplacer les fichiers vers la mémoire interne de l'appareil ou la carte SD mr = उपकरणाच्या अंतर्गत मेमरी किंवा SD-card वर फोल्डर तयार करण्यात आणि फायली हलविण्यात अक्षम - nb = Klarte ikke opprette mappe og flytte filer i enhetens minne eller SD-kort nl = Het lukt niet om een map aan te maken en bestanden naar het interne geheugen of een SD-kaart te verplaatsen pl = Nie udało się stworzyć folderu i przenieść plików do pamięci wewnętrznej lub karty SD pt-BR = Não foi possível criar a pasta e mover os arquivos à memória interna ou sdcard do dispositivo @@ -24604,7 +24574,6 @@ et = Salvestusseadme viga fr = Erreur disque mr = डिस्क त्रुटी - nb = Diskfeil nl = Schijffout pl = Błąd pamięci pt-BR = Erro do armazenamento @@ -24627,7 +24596,6 @@ fr = Erreur de connexion it = Errore di connessione mr = जोडणी अयशस्वी - nb = Tilkoblingsfeil nl = Verbindingsfout pl = Błąd połączenia pt = Falha na coneção @@ -24651,7 +24619,6 @@ fr = Déconnectez le câble USB it = Scollegare il cavo USB mr = USB केबल काढा - nb = Fjern USB-kabelen nl = USB-kabel losmaken pl = Odłącz kabel USB pt-BR = Desconecte o cabo USB @@ -24756,7 +24723,6 @@ hu = Megjelenítés a zárolt képernyőn it = Mostra sulla schermata di blocco mr = लॉक पटलावर (स्क्रीनवर) दाखवा - nb = Vis på låseskjerm nl = Toon op vergrendelscherm pl = Pokazuj na ekranie blokady pt-BR = Mostrar na tela de bloqueio @@ -24780,7 +24746,6 @@ hu = Ha engedélyezve van, nem kell minden alkalommal feloldanod a telefonod, amíg az alkalmazás fut. it = Quando è abilitata, non è necessario sbloccare il dispositivo ogni volta mentre l'app è in esecuzione. mr = चालू असल्यास, ऍप चालू असताना प्रत्येक वेळी तुम्हाला तुमचे उपकरण अनलॉक करण्याची आवश्यकता नाही. - nb = Når dette er aktivert trenger du ikke låse opp enheten hver gang når appen kjører. nl = Indien ingeschakeld, hoeft het scherm niet te worden ontgrendeld wanneer de app actief is. pl = Po włączeniu tej funkcji nie będziesz musieć odblokowywać urządzenia za każdym razem, gdy aplikacja jest uruchomiona. pt-BR = Quando ativado, você não precisará debloquear seu dispositivo toda vez que o aplicativo estiver funcionando @@ -24984,7 +24949,6 @@ fr = Supprimer la route it = Elimina percorso mr = ट्रॅक पुसून टाका - nb = Slett rute nl = Verwijder traject pl = Usuń trasę pt-BR = Apagar rota @@ -25008,7 +24972,6 @@ fr = Nom de la route it = Nome percorso mr = ट्रॅकचे नाव - nb = Rutenavn nl = Trajectnaam pl = Nazwa trasy pt-BR = Nome da rota @@ -25032,7 +24995,6 @@ fr = Déplacer it = Sposta mr = हलवा - nb = Flytt nl = Verplaats pl = Przenieś pt-BR = Mover diff --git a/iphone/Maps/Categories/UITextField+RuntimeAttributes.h b/iphone/Maps/Categories/UITextField+RuntimeAttributes.h index 5b7efdcdd4..d062027d7d 100644 --- a/iphone/Maps/Categories/UITextField+RuntimeAttributes.h +++ b/iphone/Maps/Categories/UITextField+RuntimeAttributes.h @@ -1,5 +1,9 @@ +#import "MWMInputValidator.h" + @interface UITextField (RuntimeAttributes) @property (copy, nonatomic) NSString * localizedPlaceholder; +@property (nonatomic) MWMInputValidator * validator; +@property (nonatomic, readonly) BOOL isValid; @end diff --git a/iphone/Maps/Categories/UITextField+RuntimeAttributes.m b/iphone/Maps/Categories/UITextField+RuntimeAttributes.m index e748ffc71f..95f760572b 100644 --- a/iphone/Maps/Categories/UITextField+RuntimeAttributes.m +++ b/iphone/Maps/Categories/UITextField+RuntimeAttributes.m @@ -1,4 +1,6 @@ +#import "MWMInputValidatorFactory.h" #import "UITextField+RuntimeAttributes.h" +#import @implementation UITextField (RuntimeAttributes) @@ -13,4 +15,30 @@ return L(placeholder); } +- (void)setValidator:(MWMInputValidator *)validator +{ + objc_setAssociatedObject(self, @selector(validator), validator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (MWMInputValidator *)validator +{ + return objc_getAssociatedObject(self, @selector(validator)); +} + +- (void)setValidatorName:(NSString *)validatorName +{ + objc_setAssociatedObject(self, @selector(validatorName), validatorName, OBJC_ASSOCIATION_COPY_NONATOMIC); + self.validator = [MWMInputValidatorFactory validator:validatorName]; +} + +- (MWMInputValidator *)validatorName +{ + return objc_getAssociatedObject(self, @selector(validatorName)); +} + +- (BOOL)isValid +{ + return [self.validator validateInput:self]; +} + @end diff --git a/iphone/Maps/Categories/UIWindow+InputLanguage.swift b/iphone/Maps/Categories/UIWindow+InputLanguage.swift new file mode 100644 index 0000000000..8782b2cbfb --- /dev/null +++ b/iphone/Maps/Categories/UIWindow+InputLanguage.swift @@ -0,0 +1,15 @@ +extension UIWindow { + private func findFirstResponder(view: UIView) -> UIResponder? { + guard !view.isFirstResponder else { return view } + for subView in view.subviews { + if let responder = findFirstResponder(view: subView) { + return responder + } + } + return nil + } + + @objc func firstResponder() -> UIResponder? { + return findFirstResponder(view: self) + } +} diff --git a/iphone/Maps/Classes/CustomViews/Login/MWMAuthorizationOSMLoginViewController.mm b/iphone/Maps/Classes/CustomViews/Login/MWMAuthorizationOSMLoginViewController.mm index 7d2c16d477..435bb330ce 100644 --- a/iphone/Maps/Classes/CustomViews/Login/MWMAuthorizationOSMLoginViewController.mm +++ b/iphone/Maps/Classes/CustomViews/Login/MWMAuthorizationOSMLoginViewController.mm @@ -10,6 +10,13 @@ #include "platform/platform.hpp" #include "private.h" +typedef NS_OPTIONS(NSUInteger, MWMFieldCorrect) { + MWMFieldCorrectNO = 0, + MWMFieldCorrectLogin = 1 << 0, + MWMFieldCorrectPassword = 1 << 1, + MWMFieldCorrectAll = MWMFieldCorrectLogin | MWMFieldCorrectPassword +}; + using namespace osm; @interface MWMAuthorizationOSMLoginViewController () @@ -20,6 +27,8 @@ using namespace osm; @property(weak, nonatomic) IBOutlet UIButton * forgotButton; @property(weak, nonatomic) IBOutlet UIView * spinnerView; +@property(nonatomic) MWMFieldCorrect isCorrect; + @property(nonatomic) MWMCircularProgress * spinner; @end @@ -30,6 +39,7 @@ using namespace osm; { [super viewDidLoad]; self.title = L(@"osm_account").capitalizedString; + self.isCorrect = MWMFieldCorrectNO; [self checkConnection]; [self stopSpinner]; } @@ -43,9 +53,34 @@ using namespace osm; - (BOOL)shouldAutorotate { return NO; } - (void)checkConnection { self.forgotButton.enabled = Platform::IsConnected(); } - #pragma mark - UITextFieldDelegate +- (BOOL)textField:(UITextField *)textField + shouldChangeCharactersInRange:(NSRange)range + replacementString:(NSString *)string +{ + NSString * newString = + [textField.text stringByReplacingCharactersInRange:range withString:string]; + BOOL const isValid = [textField.validator validateString:newString]; + + if ([textField isEqual:self.loginTextField]) + { + if (isValid) + self.isCorrect |= MWMFieldCorrectLogin; + else + self.isCorrect &= ~MWMFieldCorrectLogin; + } + else if ([textField isEqual:self.passwordTextField]) + { + if (isValid) + self.isCorrect |= MWMFieldCorrectPassword; + else + self.isCorrect &= ~MWMFieldCorrectPassword; + } + + return YES; +} + - (BOOL)textFieldShouldReturn:(UITextField *)textField { if ([textField isEqual:self.loginTextField]) @@ -144,4 +179,12 @@ using namespace osm; [self openUrl:@(OsmOAuth::ServerAuth().GetResetPasswordURL().c_str())]; } +#pragma mark - Properties + +- (void)setIsCorrect:(MWMFieldCorrect)isCorrect +{ + _isCorrect = isCorrect; + self.loginButton.enabled = isCorrect == MWMFieldCorrectAll; +} + @end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputEmailValidator.h b/iphone/Maps/Classes/InputValidators/MWMInputEmailValidator.h new file mode 100644 index 0000000000..462b5777a1 --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputEmailValidator.h @@ -0,0 +1,5 @@ +#import "MWMInputValidator.h" + +@interface MWMInputEmailValidator : MWMInputValidator + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputEmailValidator.m b/iphone/Maps/Classes/InputValidators/MWMInputEmailValidator.m new file mode 100644 index 0000000000..c1ba54adc1 --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputEmailValidator.m @@ -0,0 +1,32 @@ +#import "MWMInputEmailValidator.h" + +static NSString * const kEmailRegexPattern = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"; + +@implementation MWMInputEmailValidator + +- (BOOL)validateString:(NSString *)string +{ + if (![super validateString:string]) + return NO; + NSError * err; + NSRegularExpression * regex = + [NSRegularExpression regularExpressionWithPattern:kEmailRegexPattern + options:NSRegularExpressionCaseInsensitive + error:&err]; + NSAssert(!err, @"Invalid regular expression"); + NSMutableArray * matches = [@[] mutableCopy]; + NSRange range = NSMakeRange(0, string.length); + [regex enumerateMatchesInString:string + options:NSMatchingReportProgress + range:range + usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, + BOOL * _Nonnull stop) + { + [matches addObject:[string substringWithRange:result.range]]; + }]; + if (matches.count != 1) + return NO; + return [matches[0] isEqualToString:string]; +} + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputLoginValidator.h b/iphone/Maps/Classes/InputValidators/MWMInputLoginValidator.h new file mode 100644 index 0000000000..29c7f758aa --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputLoginValidator.h @@ -0,0 +1,5 @@ +#import "MWMInputValidator.h" + +@interface MWMInputLoginValidator : MWMInputValidator + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputLoginValidator.m b/iphone/Maps/Classes/InputValidators/MWMInputLoginValidator.m new file mode 100644 index 0000000000..dc92567b60 --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputLoginValidator.m @@ -0,0 +1,14 @@ +#import "MWMInputLoginValidator.h" + +static NSUInteger const minLoginLength = 3; + +@implementation MWMInputLoginValidator + +- (BOOL)validateString:(NSString *)string +{ + if (![super validateString:string]) + return NO; + return string.length >= minLoginLength; +} + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputPasswordValidator.h b/iphone/Maps/Classes/InputValidators/MWMInputPasswordValidator.h new file mode 100644 index 0000000000..1522c60c57 --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputPasswordValidator.h @@ -0,0 +1,5 @@ +#import "MWMInputValidator.h" + +@interface MWMInputPasswordValidator : MWMInputValidator + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputPasswordValidator.m b/iphone/Maps/Classes/InputValidators/MWMInputPasswordValidator.m new file mode 100644 index 0000000000..1df0d92def --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputPasswordValidator.m @@ -0,0 +1,14 @@ +#import "MWMInputPasswordValidator.h" + +static NSUInteger const minPasswordLength = 8; + +@implementation MWMInputPasswordValidator + +- (BOOL)validateString:(NSString *)string +{ + if (![super validateString:string]) + return NO; + return string.length >= minPasswordLength; +} + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputValidator.h b/iphone/Maps/Classes/InputValidators/MWMInputValidator.h new file mode 100644 index 0000000000..22e5852448 --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputValidator.h @@ -0,0 +1,6 @@ +@interface MWMInputValidator : NSObject + +- (BOOL)validateInput:(UITextField *)input; +- (BOOL)validateString:(NSString *)string; + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputValidator.m b/iphone/Maps/Classes/InputValidators/MWMInputValidator.m new file mode 100644 index 0000000000..b9a964e4eb --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputValidator.m @@ -0,0 +1,15 @@ +#import "MWMInputValidator.h" + +@implementation MWMInputValidator + +- (BOOL)validateInput:(UITextField *)input +{ + return [self validateString:input.text]; +} + +- (BOOL)validateString:(NSString *)string +{ + return YES; +} + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputValidatorFactory.h b/iphone/Maps/Classes/InputValidators/MWMInputValidatorFactory.h new file mode 100644 index 0000000000..66f43a806c --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputValidatorFactory.h @@ -0,0 +1,7 @@ +#import "MWMInputValidator.h" + +@interface MWMInputValidatorFactory : NSObject + ++ (MWMInputValidator *)validator:(NSString *)validator; + +@end diff --git a/iphone/Maps/Classes/InputValidators/MWMInputValidatorFactory.m b/iphone/Maps/Classes/InputValidators/MWMInputValidatorFactory.m new file mode 100644 index 0000000000..36dcd83583 --- /dev/null +++ b/iphone/Maps/Classes/InputValidators/MWMInputValidatorFactory.m @@ -0,0 +1,23 @@ +#import "MWMInputEmailValidator.h" +#import "MWMInputLoginValidator.h" +#import "MWMInputPasswordValidator.h" +#import "MWMInputValidator.h" +#import "MWMInputValidatorFactory.h" + +@implementation MWMInputValidatorFactory + ++ (MWMInputValidator *)validator:(NSString *)validator +{ + if ([validator isEqualToString:[MWMInputLoginValidator className]]) + return [[MWMInputLoginValidator alloc] init]; + if ([validator isEqualToString:[MWMInputPasswordValidator className]]) + return [[MWMInputPasswordValidator alloc] init]; + if ([validator isEqualToString:[MWMInputEmailValidator className]]) + return [[MWMInputEmailValidator alloc] init]; + if ([validator isEqualToString:[MWMInputValidator className]]) + return [[MWMInputValidator alloc] init]; + NSAssert(false, @"Invalid validator requested."); + return [[MWMInputValidator alloc] init]; +} + +@end diff --git a/iphone/Maps/Classes/MWMTextView.m b/iphone/Maps/Classes/MWMTextView.m index 7c95bcbd6b..b3c4426f39 100644 --- a/iphone/Maps/Classes/MWMTextView.m +++ b/iphone/Maps/Classes/MWMTextView.m @@ -21,7 +21,7 @@ } - (void)dealloc { - [NSNotificationCenter.defaultCenter removeObserver:self]; + [NSNotificationCenter.defaultCenter removeObserver:self name:UITextViewTextDidChangeNotification object:nil]; } - (UILabel *)placeholderView { diff --git a/iphone/Maps/Core/Location/MWMLocationManager.mm b/iphone/Maps/Core/Location/MWMLocationManager.mm index 9a3eca9a37..47a2130b24 100644 --- a/iphone/Maps/Core/Location/MWMLocationManager.mm +++ b/iphone/Maps/Core/Location/MWMLocationManager.mm @@ -465,7 +465,12 @@ void setShowLocationAlert(BOOL needShow) { } else { _started = NO; [self stop]; - [notificationCenter removeObserver:self]; + [notificationCenter removeObserver:self + name:UIDeviceOrientationDidChangeNotification + object:nil]; + [notificationCenter removeObserver:self + name:UIDeviceBatteryStateDidChangeNotification + object:nil]; } } diff --git a/iphone/Maps/LocalizedStrings/nb.lproj/Localizable.strings b/iphone/Maps/LocalizedStrings/nb.lproj/Localizable.strings index adf56819f1..0730b2ff7c 100644 --- a/iphone/Maps/LocalizedStrings/nb.lproj/Localizable.strings +++ b/iphone/Maps/LocalizedStrings/nb.lproj/Localizable.strings @@ -155,7 +155,7 @@ /* Search category for RV facilities; any changes should be duplicated in categories.txt @rv! */ "rv" = "Bobilanlegg"; -"share_bookmarks_email_body" = "Hei!\n\nVedlagt er mine bokmerker fra Organic Maps-appen. Åpne de dersom du har Organic Maps installert. Har du ikke har det, last ned appen til iOS eller Android ved å trykke på denne linken: https://omaps.app/get?kmz\n\nNyt reisen med Organic Maps!"; +"share_bookmarks_email_body" = "Hello!\n\nAttached are my bookmarks from Organic Maps app. Please open them if you have Organic Maps installed. Or, if you don't, download the app for your iOS or Android device by following this link: https://omaps.app/get?kmz\n\nEnjoy traveling with Organic Maps!"; /* message title of loading file */ "load_kmz_title" = "Laster inn bokmerker"; @@ -584,17 +584,17 @@ "today" = "I dag"; -"opens_tomorrow_at" = "Åpner i morgen klokka %@"; +"opens_tomorrow_at" = "Opens tomorrow at %@"; -"opens_dayoftheweek_at" = "Åpner %1$@ klokka %2$@"; +"opens_dayoftheweek_at" = "Opens %1$@ at %2$@"; -"opens_at" = "Åpner klokka %@"; +"opens_at" = "Opens at %@"; -"opens_in" = "Åpner om %@"; +"opens_in" = "Opens in %@"; -"closes_at" = "Stenger %@"; +"closes_at" = "Closes at %@"; -"closes_in" = "Stenger om %@"; +"closes_in" = "Closes in %@"; "closed" = "Stengt"; @@ -702,9 +702,9 @@ /* Downloaded 10 **of** 20 <- it is that "of" */ "downloader_of" = "%1$d av %2$d"; -"download_over_mobile_header" = "Last ned med mobildata?"; +"download_over_mobile_header" = "Download over a cellular network connection?"; -"download_over_mobile_message" = "Dette kan medføre store kostnader med enkelte dataplaner eller om du roamer."; +"download_over_mobile_message" = "This could be considerably expensive with some plans or if roaming."; "error_enter_correct_house_number" = "Skriv riktig husnummer"; @@ -970,7 +970,7 @@ "title_error_downloading_bookmarks" = "Det oppsto en feil"; -"popular_place" = "Populær"; +"popular_place" = "Popular"; "export_file" = "Eksporter fil"; @@ -1216,13 +1216,13 @@ "whats_new_auto_update_button_later" = "Oppdater manuelt senere"; /* Delete track button on track edit screen */ -"placepage_delete_track_button" = "Slett rute"; +"placepage_delete_track_button" = "Delete Track"; /* Placeholder for track name input on track edit screen */ -"placepage_track_name_hint" = "Rutenavn"; +"placepage_track_name_hint" = "Track Name"; /* move track or bookmark from the list button text */ -"move" = "Flytt"; +"move" = "Move"; /* edit track screen title */ "track_title" = "Rute"; diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index 9d4bcf5ada..aea2ab8a24 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -80,6 +80,7 @@ 3472B5E1200F86C800DC6CD5 /* MWMEditorHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3472B5DF200F86C800DC6CD5 /* MWMEditorHelper.mm */; }; 34763EE71F2F392300F4D2D3 /* MWMTextToSpeech.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34763EE51F2F392300F4D2D3 /* MWMTextToSpeech.mm */; }; 34763F071F3092E700F4D2D3 /* String+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34763F051F3092E700F4D2D3 /* String+Format.swift */; }; + 347E039A1FAC5F1D00426032 /* UIWindow+InputLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 347E03981FAC5F1D00426032 /* UIWindow+InputLanguage.swift */; }; 34845DAF1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34845DAD1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift */; }; 34845DB31E165E24003D55B9 /* SearchNoResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34845DB11E165E24003D55B9 /* SearchNoResultsViewController.swift */; }; 34845DB71E166084003D55B9 /* Common.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34845DB51E166084003D55B9 /* Common.swift */; }; @@ -137,6 +138,10 @@ 34AB66891FC5AA330078E451 /* NavigationControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34AB66021FC5AA320078E451 /* NavigationControlView.swift */; }; 34AB668C1FC5AA330078E451 /* NavigationStreetNameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34AB66031FC5AA320078E451 /* NavigationStreetNameView.swift */; }; 34ABA6171C2D185C00FE1BEC /* MWMAuthorizationOSMLoginViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA6151C2D185B00FE1BEC /* MWMAuthorizationOSMLoginViewController.mm */; }; + 34ABA6211C2D517500FE1BEC /* MWMInputValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA61F1C2D517500FE1BEC /* MWMInputValidator.m */; }; + 34ABA6251C2D551900FE1BEC /* MWMInputValidatorFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA6231C2D551900FE1BEC /* MWMInputValidatorFactory.m */; }; + 34ABA6291C2D567B00FE1BEC /* MWMInputLoginValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA6271C2D567B00FE1BEC /* MWMInputLoginValidator.m */; }; + 34ABA62D1C2D57D500FE1BEC /* MWMInputPasswordValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA62B1C2D57D500FE1BEC /* MWMInputPasswordValidator.m */; }; 34AC8FD11EFC02C000E7F910 /* MWMRoutePoint.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34AC8FC71EFC01F500E7F910 /* MWMRoutePoint.mm */; }; 34AC8FDB1EFC07FE00E7F910 /* UILabel+NumberOfVisibleLines.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34AC8FD91EFC062400E7F910 /* UILabel+NumberOfVisibleLines.swift */; }; 34B127EA1FBDD410008713D9 /* MWMRouterTransitStepInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34B127E81FBDD410008713D9 /* MWMRouterTransitStepInfo.mm */; }; @@ -260,6 +265,7 @@ 47F86CFF20C936FC00FEE291 /* TabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F86CFE20C936FC00FEE291 /* TabView.swift */; }; 47F86D0120C93D8D00FEE291 /* TabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F86D0020C93D8D00FEE291 /* TabViewController.swift */; }; 4A300ED51C6DCFD400140018 /* countries-strings in Resources */ = {isa = PBXBuildFile; fileRef = 4A300ED31C6DCFD400140018 /* countries-strings */; }; + 56C74C391C74A3BC00B71B9F /* MWMInputEmailValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABA62F1C2D58F300FE1BEC /* MWMInputEmailValidator.m */; }; 6741A9421BF340DE002C974C /* sound-strings in Resources */ = {isa = PBXBuildFile; fileRef = 5605022E1B6211E100169CAD /* sound-strings */; }; 6741A9451BF340DE002C974C /* classificator.txt in Resources */ = {isa = PBXBuildFile; fileRef = EE026F0511D6AC0D00645242 /* classificator.txt */; }; 6741A9491BF340DE002C974C /* countries.txt in Resources */ = {isa = PBXBuildFile; fileRef = FA46DA2B12D4166E00968C36 /* countries.txt */; }; @@ -814,6 +820,7 @@ 34763F051F3092E700F4D2D3 /* String+Format.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Format.swift"; sourceTree = ""; }; 34763F0B1F30CCAC00F4D2D3 /* MWMEditorCellType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMEditorCellType.h; sourceTree = ""; }; 347AD8081F28B4E6007ACB68 /* MWMSearchManagerObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMSearchManagerObserver.h; sourceTree = ""; }; + 347E03981FAC5F1D00426032 /* UIWindow+InputLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+InputLanguage.swift"; sourceTree = ""; }; 34845DAD1E1649F6003D55B9 /* DownloaderNoResultsEmbedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloaderNoResultsEmbedViewController.swift; sourceTree = ""; }; 34845DB11E165E24003D55B9 /* SearchNoResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchNoResultsViewController.swift; sourceTree = ""; }; 34845DB51E166084003D55B9 /* Common.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Common.swift; sourceTree = ""; }; @@ -892,6 +899,16 @@ 34AB66031FC5AA320078E451 /* NavigationStreetNameView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationStreetNameView.swift; sourceTree = ""; }; 34ABA6141C2D185B00FE1BEC /* MWMAuthorizationOSMLoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMAuthorizationOSMLoginViewController.h; sourceTree = ""; }; 34ABA6151C2D185B00FE1BEC /* MWMAuthorizationOSMLoginViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMAuthorizationOSMLoginViewController.mm; sourceTree = ""; }; + 34ABA61E1C2D517500FE1BEC /* MWMInputValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMInputValidator.h; sourceTree = ""; }; + 34ABA61F1C2D517500FE1BEC /* MWMInputValidator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMInputValidator.m; sourceTree = ""; }; + 34ABA6221C2D551900FE1BEC /* MWMInputValidatorFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMInputValidatorFactory.h; sourceTree = ""; }; + 34ABA6231C2D551900FE1BEC /* MWMInputValidatorFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMInputValidatorFactory.m; sourceTree = ""; }; + 34ABA6261C2D567B00FE1BEC /* MWMInputLoginValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMInputLoginValidator.h; sourceTree = ""; }; + 34ABA6271C2D567B00FE1BEC /* MWMInputLoginValidator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMInputLoginValidator.m; sourceTree = ""; }; + 34ABA62A1C2D57D500FE1BEC /* MWMInputPasswordValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMInputPasswordValidator.h; sourceTree = ""; }; + 34ABA62B1C2D57D500FE1BEC /* MWMInputPasswordValidator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMInputPasswordValidator.m; sourceTree = ""; }; + 34ABA62E1C2D58F300FE1BEC /* MWMInputEmailValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMInputEmailValidator.h; sourceTree = ""; }; + 34ABA62F1C2D58F300FE1BEC /* MWMInputEmailValidator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MWMInputEmailValidator.m; sourceTree = ""; }; 34AC8FC71EFC01F500E7F910 /* MWMRoutePoint.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMRoutePoint.mm; sourceTree = ""; }; 34AC8FC81EFC01F500E7F910 /* MWMRoutePoint+CPP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MWMRoutePoint+CPP.h"; sourceTree = ""; }; 34AC8FD91EFC062400E7F910 /* UILabel+NumberOfVisibleLines.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UILabel+NumberOfVisibleLines.swift"; sourceTree = ""; }; @@ -1686,6 +1703,7 @@ 458287C21AD3BE2000BA8940 /* DownloadIndicatorProtocol.h */, 46F26CD610F623BA00ECCA39 /* EAGLView.h */, 46F26CD710F623BA00ECCA39 /* EAGLView.mm */, + 34ABA61D1C2D514A00FE1BEC /* Input Validators */, 340475791E081B3300C92850 /* iosOGLContext.h */, 3404757A1E081B3300C92850 /* iosOGLContext.mm */, 3404757B1E081B3300C92850 /* iosOGLContextFactory.h */, @@ -2069,6 +2087,7 @@ 34F7422F1E0834F400AC1FD6 /* UIViewController+Navigation.h */, 34F742301E0834F400AC1FD6 /* UIViewController+Navigation.m */, 99012846243F0D6900C72B10 /* UIViewController+alternative.swift */, + 347E03981FAC5F1D00426032 /* UIWindow+InputLanguage.swift */, 4767CDA320AAF66B00BD8166 /* NSAttributedString+HTML.swift */, 47699A0621F08E37009E6585 /* NSDate+TimeDistance.h */, 47699A0721F08E37009E6585 /* NSDate+TimeDistance.m */, @@ -2360,6 +2379,24 @@ path = CustomViews/Login; sourceTree = ""; }; + 34ABA61D1C2D514A00FE1BEC /* Input Validators */ = { + isa = PBXGroup; + children = ( + 34ABA6221C2D551900FE1BEC /* MWMInputValidatorFactory.h */, + 34ABA6231C2D551900FE1BEC /* MWMInputValidatorFactory.m */, + 34ABA61E1C2D517500FE1BEC /* MWMInputValidator.h */, + 34ABA61F1C2D517500FE1BEC /* MWMInputValidator.m */, + 34ABA6261C2D567B00FE1BEC /* MWMInputLoginValidator.h */, + 34ABA6271C2D567B00FE1BEC /* MWMInputLoginValidator.m */, + 34ABA62A1C2D57D500FE1BEC /* MWMInputPasswordValidator.h */, + 34ABA62B1C2D57D500FE1BEC /* MWMInputPasswordValidator.m */, + 34ABA62E1C2D58F300FE1BEC /* MWMInputEmailValidator.h */, + 34ABA62F1C2D58F300FE1BEC /* MWMInputEmailValidator.m */, + ); + name = "Input Validators"; + path = InputValidators; + sourceTree = ""; + }; 34BC72091B0DECAE0012A34B /* MapViewControls */ = { isa = PBXGroup; children = ( @@ -3927,6 +3964,7 @@ 993DF10B23F6BDB100AC231A /* CheckmarkRenderer.swift in Sources */, F6E2FED01E097BA00083EBEC /* MWMSearchFilterViewController.mm in Sources */, 34D3B01B1E389D05004100F9 /* MWMButtonCell.m in Sources */, + 34ABA6291C2D567B00FE1BEC /* MWMInputLoginValidator.m in Sources */, 337F98B421D3C9F200C8AC27 /* SearchHistoryViewController.swift in Sources */, 3404F49D2028A2430090E401 /* BMCActionsCreateCell.swift in Sources */, F6E2FD8F1E097BA00083EBEC /* MWMNoMapsViewController.mm in Sources */, @@ -3996,6 +4034,7 @@ CDB4D5012231412900104869 /* ListTemplateBuilder.swift in Sources */, 99A906F323FA95AB0005872B /* PlacePageStyleSheet.swift in Sources */, 6741A9CF1BF340DE002C974C /* MWMLocationAlert.m in Sources */, + 34ABA62D1C2D57D500FE1BEC /* MWMInputPasswordValidator.m in Sources */, F6E2FDA11E097BA00083EBEC /* MWMEditorAdditionalNamesTableViewController.mm in Sources */, 4767CDA620AB1F6200BD8166 /* LeftAlignedIconButton.swift in Sources */, 3454D7D41E07F045004AF2AD /* UIImageView+Coloring.m in Sources */, @@ -4099,6 +4138,7 @@ 34D3AFEA1E378AF1004100F9 /* UINib+Init.swift in Sources */, F63AF5131EA6250F00A1DB98 /* FilterCollectionHolderCell.swift in Sources */, 34AB663E1FC5AA330078E451 /* RouteManagerTransitioning.swift in Sources */, + 56C74C391C74A3BC00B71B9F /* MWMInputEmailValidator.m in Sources */, 993DF0CB23F6BD0600AC231A /* ElevationDetailsRouter.swift in Sources */, 47CA68FC250F99E500671019 /* BookmarksListCellStrategy.swift in Sources */, B33D21B820E130D000BAD749 /* BookmarksTabViewController.swift in Sources */, @@ -4185,6 +4225,7 @@ 34AB66321FC5AA330078E451 /* RouteManagerHeaderView.swift in Sources */, 347040301EA6470700038379 /* BorderedButton.swift in Sources */, F6E2FF4B1E097BA00083EBEC /* SettingsTableViewSwitchCell.swift in Sources */, + 34ABA6211C2D517500FE1BEC /* MWMInputValidator.m in Sources */, 993DF12623F6BDB100AC231A /* SwizzleStyle.m in Sources */, 993DF10E23F6BDB100AC231A /* UIButtonRenderer.swift in Sources */, 99514BBB23E82B450085D3A7 /* ElevationProfileBuilder.swift in Sources */, @@ -4201,6 +4242,7 @@ 4767CDA820AB401000BD8166 /* LinkTextView.swift in Sources */, 34763EE71F2F392300F4D2D3 /* MWMTextToSpeech.mm in Sources */, 998927402449ECC200260CE2 /* BottomMenuItemCell.swift in Sources */, + 34ABA6251C2D551900FE1BEC /* MWMInputValidatorFactory.m in Sources */, F6E2FEE21E097BA00083EBEC /* MWMSearchManager.mm in Sources */, F6E2FE221E097BA00083EBEC /* MWMOpeningHoursEditorViewController.mm in Sources */, 999FC12B23ABB4B800B0E6F9 /* FontStyleSheet.swift in Sources */, @@ -4227,6 +4269,7 @@ 993DF10523F6BDB100AC231A /* UINavigationItem+styleName.swift in Sources */, 9977E69C247BFB510073780C /* SearchTextField.swift in Sources */, 4726254921C27D4B00C7BAAD /* PlacePageDescriptionViewController.swift in Sources */, + 347E039A1FAC5F1D00426032 /* UIWindow+InputLanguage.swift in Sources */, 340475711E081A4600C92850 /* MWMSettings.mm in Sources */, 33046832219C57180041F3A8 /* CategorySettingsViewController.swift in Sources */, 3404756E1E081A4600C92850 /* MWMSearch.mm in Sources */, diff --git a/iphone/Maps/UI/Editor/Cells/MWMEditorAdditionalNameTableViewCell.xib b/iphone/Maps/UI/Editor/Cells/MWMEditorAdditionalNameTableViewCell.xib index cbfefb54fa..d7bc2700ef 100644 --- a/iphone/Maps/UI/Editor/Cells/MWMEditorAdditionalNameTableViewCell.xib +++ b/iphone/Maps/UI/Editor/Cells/MWMEditorAdditionalNameTableViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -38,6 +38,7 @@ + diff --git a/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.m b/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.m index 881b916332..1fa604c39a 100644 --- a/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.m +++ b/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.m @@ -1,8 +1,10 @@ #import "MWMStreetEditorEditTableViewCell.h" +#import "UITextField+RuntimeAttributes.h" -@interface MWMStreetEditorEditTableViewCell () +@interface MWMStreetEditorEditTableViewCell () @property (weak, nonatomic) IBOutlet UITextField * textField; + @property (weak, nonatomic) id delegate; @end @@ -13,21 +15,17 @@ { self.delegate = delegate; self.textField.text = street; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(textDidChange:) - name:UITextFieldTextDidChangeNotification - object:self.textField]; } -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} +#pragma mark - UITextFieldDelegate -- (void)textDidChange:(NSNotification*)notification +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { - UITextField * textField = (UITextField *)[notification object]; - [self.delegate editCellTextChanged:textField.text]; + NSString * newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; + BOOL const isCorrect = [textField.validator validateString:newString]; + if (isCorrect) + [self.delegate editCellTextChanged:newString]; + return YES; } @end diff --git a/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.xib b/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.xib index 8eee4a6560..34f54f743c 100644 --- a/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.xib +++ b/iphone/Maps/UI/Editor/Street/MWMStreetEditorEditTableViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -25,6 +25,7 @@ + diff --git a/iphone/Maps/UI/Search/MWMSearchManager+Layout.h b/iphone/Maps/UI/Search/MWMSearchManager+Layout.h index c39e4c5980..f5c19347f4 100644 --- a/iphone/Maps/UI/Search/MWMSearchManager+Layout.h +++ b/iphone/Maps/UI/Search/MWMSearchManager+Layout.h @@ -3,6 +3,5 @@ @interface MWMSearchManager (Layout) - (void)layoutTopViews; -- (void)removeKeyboardObservers; @end diff --git a/iphone/Maps/UI/Search/MWMSearchManager+Layout.m b/iphone/Maps/UI/Search/MWMSearchManager+Layout.m index f5ed87b18f..f397ff84c9 100644 --- a/iphone/Maps/UI/Search/MWMSearchManager+Layout.m +++ b/iphone/Maps/UI/Search/MWMSearchManager+Layout.m @@ -85,10 +85,6 @@ static CGFloat const changeModeViewOffsetKeyboard = -12; object:nil]; } -- (void)removeKeyboardObservers { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - #pragma mark - keyboard movements - (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; diff --git a/iphone/Maps/UI/Search/MWMSearchManager.mm b/iphone/Maps/UI/Search/MWMSearchManager.mm index afabe94d26..d78d39a872 100644 --- a/iphone/Maps/UI/Search/MWMSearchManager.mm +++ b/iphone/Maps/UI/Search/MWMSearchManager.mm @@ -485,7 +485,6 @@ using Observers = NSHashTable; [contentView removeFromSuperview]; [actionBarView removeFromSuperview]; [searchBarView removeFromSuperview]; - [self removeKeyboardObservers]; }]; } diff --git a/iphone/Maps/UI/Storyboard/Authorization.storyboard b/iphone/Maps/UI/Storyboard/Authorization.storyboard index 9c4873491a..0e9b02eb07 100644 --- a/iphone/Maps/UI/Storyboard/Authorization.storyboard +++ b/iphone/Maps/UI/Storyboard/Authorization.storyboard @@ -1,9 +1,9 @@ - + - + @@ -36,6 +36,7 @@ + @@ -58,6 +59,7 @@ + @@ -184,10 +186,10 @@ - +