Skip to content

Commit 51b20f6

Browse files
authored
Merge pull request GH-1318 from dg0yt
Replace Android system Toast
2 parents 3e775f3 + 6ffa3bc commit 51b20f6

File tree

9 files changed

+349
-72
lines changed

9 files changed

+349
-72
lines changed

code-check-wrapper.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ PATTERN=" \
7979
/symbol.cpp \
8080
symbol_rule_set.cpp \
8181
symbol_t.cpp \
82+
symbol_tooltip.cpp \
8283
tag_select_widget.cpp \
8384
template_image.cpp \
8485
template_list_widget.cpp \
8586
template_tool \
8687
text_brwoser_dialog \
88+
toast.cpp \
8789
track_t.cpp \
8890
/track.cpp \
8991
undo_manager.cpp \

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ set(Mapper_Common_SRCS
156156
gui/widgets/template_list_widget.cpp
157157
gui/widgets/text_alignment_widget.cpp
158158
gui/widgets/text_browser.cpp
159+
gui/widgets/toast.cpp
159160

160161
sensors/compass.cpp
161162
sensors/gps_display.cpp

src/android/java/org/openorienteering/mapper/MapperActivity.java

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,12 @@
3939
import android.net.Uri;
4040
import android.os.Build;
4141
import android.os.Bundle;
42-
import android.os.CountDownTimer;
4342
import android.os.Looper;
4443
import android.os.PowerManager;
4544
import android.os.SystemClock;
4645
import android.provider.Settings;
4746
import android.view.Gravity;
4847
import android.view.Surface;
49-
import android.widget.Toast;
5048

5149

5250
/**
@@ -60,8 +58,6 @@ public class MapperActivity extends org.qtproject.qt5.android.bindings.QtActivit
6058
private String no_string;
6159
private String gps_disabled_string;
6260

63-
private static Toast toast;
64-
private static CountDownTimer toast_reset;
6561
private static boolean service_started = false;
6662
private static boolean optimization_request_done = false;
6763

@@ -180,52 +176,6 @@ public static void setTranslatableStrings(String yes_string, String no_string, S
180176
instance.gps_disabled_string = gps_disabled_string;
181177
}
182178

183-
public static void showToast(final String message, final int duration)
184-
{
185-
instance.runOnUiThread(new Runnable() {
186-
public void run() {
187-
if (toast_reset != null)
188-
toast_reset.cancel();
189-
190-
if (toast == null)
191-
{
192-
toast = Toast.makeText(instance, "", Toast.LENGTH_SHORT);
193-
toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 4);
194-
}
195-
196-
toast.setText(message);
197-
toast.show();
198-
199-
if (duration <= 0)
200-
return;
201-
202-
toast_reset = new CountDownTimer(duration, 500) {
203-
public void onTick(long millisUntilFinished)
204-
{
205-
toast.show();
206-
}
207-
208-
public void onFinish() {
209-
toast.cancel();
210-
}
211-
};
212-
toast_reset.start();
213-
}
214-
} );
215-
}
216-
217-
public static void hideToast()
218-
{
219-
instance.runOnUiThread(new Runnable() {
220-
public void run() {
221-
if (toast_reset != null)
222-
toast_reset.cancel();
223-
if (toast != null)
224-
toast.cancel();
225-
}
226-
} );
227-
}
228-
229179
/** Locks the current display orientation.
230180
* While a native "locked" mode comes in API level 18,
231181
* this method tries to determine and lock the current orientation

src/gui/main_window.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
#if defined(Q_OS_ANDROID)
3939
# include <QtAndroid>
40-
# include <QAndroidJniObject>
4140
# include <QDesktopWidget>
4241
# include <QTimer>
4342
# include <QUrl>
@@ -60,6 +59,7 @@
6059
#include "gui/util_gui.h"
6160
#include "gui/map/map_editor.h"
6261
#include "gui/map/new_map_dialog.h"
62+
#include "gui/widgets/toast.h"
6363
#include "undo/undo_manager.h"
6464
#include "util/util.h"
6565
#include "util/backports.h" // IWYU pragma: keep
@@ -99,7 +99,10 @@ MainWindow::MainWindow(bool as_main_window, QWidget* parent, Qt::WindowFlags fla
9999
statusBar()->addWidget(status_label, 1);
100100
statusBar()->setSizeGripEnabled(as_main_window);
101101
if (mobileMode())
102+
{
102103
statusBar()->hide();
104+
toast = new Toast(this);
105+
}
103106

104107
central_widget = new QStackedWidget(this);
105108
QMainWindow::setCentralWidget(central_widget);
@@ -513,28 +516,18 @@ void MainWindow::setStatusBarText(const QString& text)
513516

514517
void MainWindow::showStatusBarMessage(const QString& text, int timeout)
515518
{
516-
#if defined(Q_OS_ANDROID)
517-
QAndroidJniObject java_string = QAndroidJniObject::fromString(text);
518-
QAndroidJniObject::callStaticMethod<void>(
519-
"org/openorienteering/mapper/MapperActivity",
520-
"showToast",
521-
"(Ljava/lang/String;I)V",
522-
java_string.object<jstring>(), timeout);
523-
#else
524-
statusBar()->showMessage(text, timeout);
525-
#endif
519+
if (toast)
520+
toast->showText(text, timeout);
521+
else
522+
statusBar()->showMessage(text, timeout);
526523
}
527524

528525
void MainWindow::clearStatusBarMessage()
529526
{
530-
#if defined(Q_OS_ANDROID)
531-
QAndroidJniObject::callStaticMethod<void>(
532-
"org/openorienteering/mapper/MapperActivity",
533-
"hideToast",
534-
"()V");
535-
#else
536-
statusBar()->clearMessage();
537-
#endif
527+
if (toast)
528+
toast->hide();
529+
else
530+
statusBar()->clearMessage();
538531
}
539532

540533
void MainWindow::setShortcutsBlocked(bool blocked)
@@ -562,8 +555,18 @@ bool MainWindow::closeFile()
562555

563556
bool MainWindow::event(QEvent* event)
564557
{
565-
if (event->type() == QEvent::ShortcutOverride && shortcutsBlocked())
566-
event->accept();
558+
switch (event->type())
559+
{
560+
case QEvent::ShortcutOverride:
561+
if (shortcutsBlocked())
562+
event->accept();
563+
break;
564+
565+
case QEvent::Resize:
566+
if (toast)
567+
toast->adjustPosition(frameGeometry());
568+
break;
569+
}
567570

568571
return QMainWindow::event(event);
569572
}

src/gui/main_window.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace OpenOrienteering {
4747

4848
class MainWindowController;
4949
class MapperServiceProxy;
50+
class Toast;
5051

5152

5253
/**
@@ -512,6 +513,7 @@ protected slots:
512513
QAction* settings_act;
513514
QAction* close_act;
514515
QLabel* status_label;
516+
Toast* toast = nullptr;
515517

516518
std::unique_ptr<MapperServiceProxy> service_proxy;
517519

src/gui/widgets/symbol_tooltip.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <QApplication>
2727
#include <QCursor>
2828
#include <QDesktopWidget>
29-
#include <QFlags>
3029
#include <QHideEvent>
3130
#include <QLabel>
3231
#include <QLatin1Char>

src/gui/widgets/symbol_tooltip.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class QPaintEvent;
3434
class QShortcut;
3535
class QShowEvent;
3636
// IWYU pragma: no_forward_declare QWidget
37+
// IWYU pragma: no_include <QString>
3738

3839
namespace OpenOrienteering {
3940

src/gui/widgets/toast.cpp

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* Copyright 2012, 2013 Thomas Schöps
3+
* Copyright 2017, 2019 Kai Pastor
4+
*
5+
* This file is part of OpenOrienteering.
6+
*
7+
* OpenOrienteering is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* OpenOrienteering is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
22+
#include "toast.h"
23+
24+
#include <algorithm>
25+
26+
#include <Qt>
27+
#include <QtGlobal>
28+
#include <QColor>
29+
#include <QHideEvent>
30+
#include <QLabel>
31+
#include <QPainter>
32+
#include <QPalette>
33+
#include <QRect>
34+
#include <QRgb>
35+
#include <QString>
36+
#include <QStyle>
37+
#include <QStyleOption>
38+
#include <QTimerEvent>
39+
#include <QVBoxLayout>
40+
41+
42+
namespace OpenOrienteering {
43+
44+
namespace {
45+
46+
constexpr auto min_timeout = 500; // ms
47+
constexpr auto max_timeout = 5000; // ms
48+
49+
} // namespace
50+
51+
52+
Toast::Toast(QWidget* parent)
53+
: QWidget{ parent }
54+
{
55+
setAttribute(Qt::WA_TranslucentBackground);
56+
if (!parent)
57+
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
58+
59+
QPalette text_palette;
60+
auto foreground = Qt::white;
61+
auto background = Qt::black;
62+
if (qGray(text_palette.color(QPalette::Window).rgb()) < 128)
63+
std::swap(foreground, background);
64+
text_palette.setColor(QPalette::WindowText, foreground);
65+
text_palette.setColor(QPalette::Window, background);
66+
setPalette(text_palette);
67+
68+
label = new QLabel();
69+
label->setAttribute(Qt::WA_TranslucentBackground);
70+
label->setWordWrap(true);
71+
connect(label, &QLabel::linkActivated, this, &Toast::linkActivated);
72+
73+
auto* layout = new QVBoxLayout();
74+
layout->addWidget(label);
75+
setLayout(layout);
76+
77+
setVisible(false);
78+
}
79+
80+
81+
void Toast::showText(const QString& text, int timeout)
82+
{
83+
label->setText(text);
84+
adjustSize();
85+
if (!isWindow())
86+
adjustPosition(window()->frameGeometry());
87+
show();
88+
raise();
89+
startTimer(timeout);
90+
}
91+
92+
QString Toast::text() const
93+
{
94+
return label->text();
95+
}
96+
97+
98+
void Toast::adjustPosition(const QRect& region)
99+
{
100+
QStyleOption style_option;
101+
auto const margin = style()->pixelMetric(QStyle::PM_LayoutBottomMargin, &style_option);
102+
auto const x = region.left() + (region.width() - width()) / 2;
103+
auto const y = region.bottom() - height() - margin;
104+
move(x, y);
105+
}
106+
107+
108+
void Toast::startTimer(int timeout)
109+
{
110+
if (Q_UNLIKELY(timeout < min_timeout))
111+
{
112+
qWarning("Minimum toast timeout is %d, got: %d", min_timeout, timeout);
113+
timeout = min_timeout;
114+
}
115+
else if (Q_UNLIKELY(timeout > max_timeout))
116+
{
117+
qWarning("Maximum toast timeout is %d, got: %d", max_timeout, timeout);
118+
timeout = max_timeout;
119+
}
120+
121+
timer_id = QObject::startTimer(timeout, Qt::PreciseTimer);
122+
123+
if (Q_UNLIKELY(timer_id == 0))
124+
{
125+
// There is no way to hide the toast, except for doing it right now.
126+
qWarning("Toast suppressed: %s\n"
127+
"Reason: Failed to start a timer for hiding the toast.",
128+
qPrintable(text()));
129+
hide();
130+
}
131+
}
132+
133+
void Toast::stopTimer()
134+
{
135+
if (timer_id != 0)
136+
{
137+
killTimer(timer_id);
138+
timer_id = 0;
139+
}
140+
}
141+
142+
143+
void Toast::timerEvent(QTimerEvent* event)
144+
{
145+
if (event->timerId() == timer_id)
146+
{
147+
stopTimer();
148+
hide();
149+
}
150+
}
151+
152+
153+
void Toast::hideEvent(QHideEvent* event)
154+
{
155+
if (!event->spontaneous())
156+
{
157+
stopTimer();
158+
}
159+
QWidget::hideEvent(event);
160+
}
161+
162+
163+
void Toast::paintEvent(QPaintEvent* /*event*/)
164+
{
165+
QPainter painter(this);
166+
painter.setRenderHint(QPainter::Antialiasing);
167+
painter.setPen(Qt::NoPen);
168+
auto color = QColor(palette().color(QPalette::Window));
169+
painter.setBrush(color);
170+
painter.setOpacity(0.7);
171+
QStyleOption style_option;
172+
auto const radius = style()->pixelMetric(QStyle::PM_LayoutLeftMargin, &style_option)
173+
+ style()->pixelMetric(QStyle::PM_LayoutTopMargin, &style_option);
174+
painter.drawRoundRect(0, 0, width(), height(), radius);
175+
}
176+
177+
178+
} // namespace OpenOrienteering

0 commit comments

Comments
 (0)