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 @@
-
+