diff --git a/app/qmlV2/Style.js b/app/qmlV2/Style.js
index 18ac9208a..b0de33685 100644
--- a/app/qmlV2/Style.js
+++ b/app/qmlV2/Style.js
@@ -81,9 +81,18 @@ const moreIcon = "qrc:/More.svg"
const uploadImage = "qrc:/UploadImage.svg"
const ReachedDataLimitImage = "qrc:/ReachedDataLimitImage.svg"
+// Shadow
+const shadowVerticalOffset = 3 * __dp
+const shadowHorizontalOffset = 2 * __dp
+const shadowRadius = 7 * __dp
+const shadowColor = "#66777777"
+
// Spacing
const commonSpacing = 20 * __dp
+// Map items
+const mapItemHeight = 50 * __dp
+
// Notification
const notificationRadius = 12 * __dp
const notificationSpace = 3 * __dp
diff --git a/app/qmlV2/component/MMMapButton.qml b/app/qmlV2/component/MMMapButton.qml
new file mode 100644
index 000000000..7bb75c9ba
--- /dev/null
+++ b/app/qmlV2/component/MMMapButton.qml
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import "../Style.js" as Style
+import "."
+
+Item {
+ id: control
+
+ width: height
+ height: Style.mapItemHeight
+
+ property alias iconSource: icon.source
+
+ signal clicked
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ radius: control.height / 2
+ color: Style.white
+
+ layer.enabled: true
+ layer.effect: MMShadow {}
+
+ MMIcon {
+ id: icon
+
+ anchors.centerIn: parent
+ color: Style.forest
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: control.clicked()
+ }
+ }
+}
diff --git a/app/qmlV2/component/MMMapLabel.qml b/app/qmlV2/component/MMMapLabel.qml
new file mode 100644
index 000000000..9432b237f
--- /dev/null
+++ b/app/qmlV2/component/MMMapLabel.qml
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import "../Style.js" as Style
+import "."
+
+Item {
+ id: control
+
+ width: text.width
+ height: Style.mapItemHeight
+
+ signal clicked
+
+ required property string text
+ property url iconSource: ""
+ property color bgColor: Style.positive
+ property color textColor: Style.forest
+
+ Rectangle {
+ width: row.width
+ height: parent.height
+ radius: control.height / 2
+ color: control.bgColor
+
+ layer.enabled: true
+ layer.effect: MMShadow {}
+
+ Row {
+ id: row
+
+ anchors.centerIn: parent
+ leftPadding: 20 * __dp
+ rightPadding: leftPadding
+ spacing: 4 * __dp
+ height: parent.height
+
+ MMIcon {
+ id: icon
+
+ source: control.iconSource ? control.iconSource : ""
+ color: text.color
+ height: parent.height
+ }
+
+ Text {
+ id: text
+
+ color: control.textColor
+ text: control.text
+ font: Qt.font(Style.t3)
+ verticalAlignment: Text.AlignVCenter
+ height: parent.height
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: control.clicked()
+ }
+ }
+}
diff --git a/app/qmlV2/component/MMShadow.qml b/app/qmlV2/component/MMShadow.qml
new file mode 100644
index 000000000..6c1be3cd1
--- /dev/null
+++ b/app/qmlV2/component/MMShadow.qml
@@ -0,0 +1,21 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import Qt5Compat.GraphicalEffects
+import "../Style.js" as Style
+
+DropShadow {
+ id: shadow
+ horizontalOffset: Style.shadowHorizontalOffset
+ verticalOffset: Style.shadowVerticalOffset
+ radius: Style.shadowRadius
+ color: Style.shadowColor
+ transparentBorder: true
+}
diff --git a/gallery/qml.qrc b/gallery/qml.qrc
index 8c331b7bc..2b17f0e0b 100644
--- a/gallery/qml.qrc
+++ b/gallery/qml.qrc
@@ -27,6 +27,10 @@
qml/pages/ChecksPage.qml
../app/qmlV2/component/MMComponent_reachedDataLimit.qml
../app/qmlV2/component/MMProgressBar.qml
+ qml/pages/MapPage.qml
+ ../app/qmlV2/component/MMMapButton.qml
+ ../app/qmlV2/component/MMShadow.qml
+ ../app/qmlV2/component/MMMapLabel.qml
../app/qmlV2/component/MMPasswordInput.qml
../app/qmlV2/component/MMButtonInput.qml
../app/qmlV2/component/MMToolbarButton.qml
diff --git a/gallery/qml/Main.qml b/gallery/qml/Main.qml
index 1e3cf22c4..738e82116 100644
--- a/gallery/qml/Main.qml
+++ b/gallery/qml/Main.qml
@@ -132,6 +132,10 @@ ApplicationWindow {
title: "Drawers"
source: "DrawerPage.qml"
}
+ ListElement {
+ title: "Map"
+ source: "MapPage.qml"
+ }
ListElement {
title: "Toolbars"
source: "ToolbarPage.qml"
diff --git a/gallery/qml/pages/MapPage.qml b/gallery/qml/pages/MapPage.qml
new file mode 100644
index 000000000..fc25b91c2
--- /dev/null
+++ b/gallery/qml/pages/MapPage.qml
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Basic
+import QtLocation
+import QtPositioning
+
+import "../../app/qmlV2/component"
+import "../../app/qmlV2/Style.js" as Style
+
+Page {
+ id: pane
+
+ Plugin {
+ id: mapPlugin
+ name: "osm"
+ }
+
+ Map {
+ id: map
+
+ anchors.fill: parent
+ plugin: mapPlugin
+ center: QtPositioning.coordinate(48.72, 21.25) // KE
+ zoomLevel: 12
+ property geoCoordinate startCentroid
+
+ PinchHandler {
+ id: pinch
+
+ target: null
+ onActiveChanged: if (active) {
+ map.startCentroid = map.toCoordinate(pinch.centroid.position, false)
+ }
+ onScaleChanged: (delta) => {
+ map.zoomLevel += Math.log2(delta)
+ map.alignCoordinateToPoint(map.startCentroid, pinch.centroid.position)
+ }
+ onRotationChanged: (delta) => {
+ map.bearing -= delta
+ map.alignCoordinateToPoint(map.startCentroid, pinch.centroid.position)
+ }
+ grabPermissions: PointerHandler.TakeOverForbidden
+ }
+
+ WheelHandler {
+ acceptedDevices: Qt.platform.pluginName === "cocoa" || Qt.platform.pluginName === "wayland"
+ ? PointerDevice.Mouse | PointerDevice.TouchPad
+ : PointerDevice.Mouse
+ rotationScale: 1/120
+ property: "zoomLevel"
+ }
+
+ DragHandler {
+ target: null
+ onTranslationChanged: (delta) => map.pan(-delta.x, -delta.y)
+ }
+ }
+
+ Rectangle {
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+ height: 30
+ color: "white"
+
+ Text {
+ anchors.centerIn: parent
+ text: map.center + "\tzoom: " + map.zoomLevel.toFixed(2)
+ }
+ }
+
+ Column {
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: 20
+ anchors.bottomMargin: 50
+ spacing: 20
+
+ MMMapButton {
+ iconSource: Style.arrowLinkRightIcon
+ onClicked: console.log("Map button clicked")
+ }
+
+ MMMapButton {
+ iconSource: Style.searchIcon
+ onClicked: console.log("Map button clicked")
+ }
+ }
+
+ MMMapLabel {
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.leftMargin: 20
+ anchors.bottomMargin: 120
+
+ text: "20.0 m"
+ iconSource: Style.checkmarkIcon
+ }
+
+ MMMapLabel {
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ anchors.leftMargin: 20
+ anchors.bottomMargin: 50
+
+ text: "20.0 m"
+ }
+}