diff --git a/resources/qml/ScrollHelper.qml b/resources/qml/ScrollHelper.qml
new file mode 100644
index 0000000000000000000000000000000000000000..3a8868f563de5443bae2d03e26736cfebe8d5ed6
--- /dev/null
+++ b/resources/qml/ScrollHelper.qml
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (C) 2016 Michael Bohlender, <michael.bohlender@kdemail.net>
+ *  Copyright (C) 2017 Christian Mollekopf, <mollekopf@kolabsystems.com>
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+/*
+* Shamelessly stolen from:
+* https://cgit.kde.org/kube.git/tree/framework/qml/ScrollHelper.qml
+*
+* The MouseArea + interactive: false + maximumFlickVelocity are required
+* to fix scrolling for desktop systems where we don't want flicking behaviour.
+*
+* See also:
+* ScrollView.qml in qtquickcontrols
+* qquickwheelarea.cpp in qtquickcontrols
+*/
+MouseArea {
+    id: root
+    propagateComposedEvents: true
+
+    property Flickable flickable
+    property alias enabled: root.enabled
+
+    //Place the mouse area under the flickable
+    z: -1
+    onFlickableChanged: {
+        if (enabled) {
+            flickable.maximumFlickVelocity = 100000
+            flickable.boundsBehavior = Flickable.StopAtBounds
+            root.parent = flickable
+        }
+    }
+
+    acceptedButtons: Qt.NoButton
+
+    function calculateNewPosition(flickableItem, wheel) {
+        //Nothing to scroll
+        if (flickableItem.contentHeight < flickableItem.height) {
+            return flickableItem.contentY;
+        }
+        //Ignore 0 events (happens at least with Christians trackpad)
+        if (wheel.pixelDelta.y == 0 && wheel.angleDelta.y == 0) {
+            return flickableItem.contentY;
+        }
+        //pixelDelta seems to be the same as angleDelta/8
+        var pixelDelta = 0
+        //The pixelDelta is a smaller number if both are provided, so pixelDelta can be 0 while angleDelta is still something. So we check the angleDelta
+        if (wheel.angleDelta.y) {
+            var wheelScrollLines = 3 //Default value of QApplication wheelScrollLines property
+            var pixelPerLine = 20 //Default value in Qt, originally comes from QTextEdit
+            var ticks = (wheel.angleDelta.y / 8) / 15.0 //Divide by 8 gives us pixels typically come in 15pixel steps.
+            pixelDelta =  ticks * pixelPerLine * wheelScrollLines
+        } else {
+            pixelDelta = wheel.pixelDelta.y
+        }
+
+        if (!pixelDelta) {
+            return flickableItem.contentY;
+        }
+
+        var minYExtent = flickableItem.originY + flickableItem.topMargin;
+        var maxYExtent = (flickableItem.contentHeight + flickableItem.bottomMargin + flickableItem.originY) - flickableItem.height;
+
+        if (typeof(flickableItem.headerItem) !== "undefined" && flickableItem.headerItem) {
+            minYExtent += flickableItem.headerItem.height
+        }
+
+        //Avoid overscrolling
+        return Math.max(minYExtent, Math.min(maxYExtent, flickableItem.contentY - pixelDelta));
+    }
+
+    onWheel: {
+        var newPos = calculateNewPosition(flickable, wheel);
+        // console.warn("Delta: ", wheel.pixelDelta.y);
+        // console.warn("Old position: ", flickable.contentY);
+        // console.warn("New position: ", newPos);
+
+        // Show the scrollbars
+        flickable.flick(0, 0);
+        flickable.contentY = newPos;
+        cancelFlickStateTimer.start()
+    }
+
+
+    Timer {
+        id: cancelFlickStateTimer
+        //How long the scrollbar will remain visible
+        interval: 500
+        // Hide the scrollbars
+        onTriggered: flickable.cancelFlick();
+    }
+}
diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml
index 09865d16763826689087fe9d836f0f7b9d0a5d12..c42cd6e9fc8b927e4d8ad6a84dd347d1bf79cfe5 100644
--- a/resources/qml/TimelineView.qml
+++ b/resources/qml/TimelineView.qml
@@ -115,21 +115,11 @@ Page {
 			model: timelineManager.timeline
 
 			boundsBehavior: Flickable.StopAtBounds
-			pixelAligned: true
-
-			MouseArea {
-				anchors.fill: parent
-				acceptedButtons: Qt.NoButton
-				propagateComposedEvents: true
-				z: -1
-				onWheel: {
-					if (wheel.angleDelta != 0) {
-						chat.contentY = chat.contentY - wheel.angleDelta.y
-						wheel.accepted = true
-						chat.returnToBounds()
-					}
-				}
-			}
+
+            ScrollHelper {
+                flickable: parent
+                anchors.fill: parent
+            }
 
 			Shortcut {
 				sequence: StandardKey.MoveToPreviousPage
@@ -218,9 +208,10 @@ Page {
 						text: chat.model.formatDateSeparator(modelData.timestamp)
 						color: colors.brightText
 
-						height: contentHeight * 1.2
-						width: contentWidth * 1.2
-						horizontalAlignment: Text.AlignHCenter
+                        height: fontMetrics.height * 1.4
+                        width: contentWidth * 1.2
+
+                        horizontalAlignment: Text.AlignHCenter
 						background: Rectangle {
 							radius: parent.height / 2
 							color: colors.dark
@@ -228,7 +219,7 @@ Page {
 					}
 					Row {
 						height: userName.height
-						spacing: 4
+                        spacing: 4
 						Avatar {
 							width: avatarSize
 							height: avatarSize
@@ -335,4 +326,8 @@ Page {
 			}
 		}
 	}
+
+    FontMetrics {
+        id: fontMetrics
+    }
 }
diff --git a/resources/qml/delegates/Pill.qml b/resources/qml/delegates/Pill.qml
index 27985b586c287ff600cd7026d81e0f3e9e25e777..c4260c33e1d6eca6fe2226c2bd6722a51c473f13 100644
--- a/resources/qml/delegates/Pill.qml
+++ b/resources/qml/delegates/Pill.qml
@@ -5,8 +5,9 @@ Label {
 	color: colors.brightText
 	horizontalAlignment: Text.AlignHCenter
 
-	height: contentHeight * 1.2
-	width: contentWidth * 1.2
+    height: fontMetrics.height * 1.4
+    width: contentWidth * 1.2
+
 	background: Rectangle {
 		radius: parent.height / 2
 		color: colors.dark
diff --git a/resources/res.qrc b/resources/res.qrc
index c94f0f1909d6ff63e674b786267f25025a2a3aef..c6daaa80198b5aff493193a90ded74c9fc9336fd 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -118,6 +118,7 @@
         <file>qml/StatusIndicator.qml</file>
         <file>qml/EncryptionIndicator.qml</file>
         <file>qml/TimelineRow.qml</file>
+        <file>qml/ScrollHelper.qml</file>
         <file>qml/delegates/MessageDelegate.qml</file>
         <file>qml/delegates/TextMessage.qml</file>
         <file>qml/delegates/NoticeMessage.qml</file>