Compare commits
114 Commits
master
...
v4.8-branc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2098529152 | ||
|
|
ddc7e754bc | ||
|
|
a55b3dd2c1 | ||
|
|
d43032f01f | ||
|
|
95326274be | ||
|
|
f72853a597 | ||
|
|
e254820e6c | ||
|
|
ba70bb490f | ||
|
|
a16cca1fcb | ||
|
|
403c920f29 | ||
|
|
c6732e9b26 | ||
|
|
3998cb8245 | ||
|
|
fec354075f | ||
|
|
a85598a0e7 | ||
|
|
6bf980d85e | ||
|
|
c792c00f07 | ||
|
|
f1371adbb8 | ||
|
|
43fb4ef36b | ||
|
|
1f9d7f29c5 | ||
|
|
d6a5fc5386 | ||
|
|
faf34db515 | ||
|
|
f4021bcecd | ||
|
|
101be9e967 | ||
|
|
167b41b6e5 | ||
|
|
5c625d8116 | ||
|
|
450bad9d7b | ||
|
|
ac71705b53 | ||
|
|
072bf67303 | ||
|
|
421e093afd | ||
|
|
7a9203eda2 | ||
|
|
d1b4669304 | ||
|
|
737d8f9c9e | ||
|
|
dbddbfeec3 | ||
|
|
c93f7e4f8c | ||
|
|
9fefd10390 | ||
|
|
8889552b70 | ||
|
|
eb2f811be4 | ||
|
|
72f37f14c6 | ||
|
|
5e192f3c6f | ||
|
|
c0421ab637 | ||
|
|
c7e9825fc6 | ||
|
|
30ea5aa9f6 | ||
|
|
268b453a81 | ||
|
|
a3a1a74d1f | ||
|
|
736941870a | ||
|
|
e685e7e9de | ||
|
|
41de2f66e3 | ||
|
|
a6e0cb79d1 | ||
|
|
2b9da3504b | ||
|
|
e8c1ce7e2c | ||
|
|
cb31d67f61 | ||
|
|
ec8eac185b | ||
|
|
95e6f0c700 | ||
|
|
0e1bd02df6 | ||
|
|
c000123121 | ||
|
|
50eec0231c | ||
|
|
37be26bd8d | ||
|
|
fc66c767fb | ||
|
|
7598e2fce7 | ||
|
|
4b42837327 | ||
|
|
3c5c0185dd | ||
|
|
78ad59b22f | ||
|
|
0bd75c8e9e | ||
|
|
ddac55a3f1 | ||
|
|
5a9a7f005f | ||
|
|
39d5860602 | ||
|
|
6aa51c6232 | ||
|
|
f78f3075c4 | ||
|
|
4aac746bf0 | ||
|
|
f5ef586c72 | ||
|
|
536017f42e | ||
|
|
9b0b5fd489 | ||
|
|
4935f07c9a | ||
|
|
9e83106ff7 | ||
|
|
ee53639306 | ||
|
|
e964bae5b9 | ||
|
|
968b7c1f7c | ||
|
|
a875fd0d44 | ||
|
|
86d3e59d70 | ||
|
|
55a0bed59f | ||
|
|
2153b95bf6 | ||
|
|
071bce0fd1 | ||
|
|
af6da3090a | ||
|
|
8628567e31 | ||
|
|
247513ad08 | ||
|
|
94fa935818 | ||
|
|
1e0ac92dd7 | ||
|
|
5f0ce37559 | ||
|
|
7f4180a777 | ||
|
|
b29a6e4cd2 | ||
|
|
cd75fff054 | ||
|
|
c4aefc0d29 | ||
|
|
a2fb9fde07 | ||
|
|
78d11ed687 | ||
|
|
1219225729 | ||
|
|
64528cd378 | ||
|
|
295c323d51 | ||
|
|
c8c6035d79 | ||
|
|
e46fea155d | ||
|
|
5819076130 | ||
|
|
b0afca5815 | ||
|
|
a5a191e850 | ||
|
|
873a4c8f07 | ||
|
|
3865c1ec0a | ||
|
|
db29fb4e68 | ||
|
|
0f350bef98 | ||
|
|
f7a4327cd4 | ||
|
|
cfc4fca6ad | ||
|
|
fa4dd05dfd | ||
|
|
0d69b420a4 | ||
|
|
18c9db16a5 | ||
|
|
97178896d1 | ||
|
|
ad7f4e8656 | ||
|
|
df1586da22 |
17
.lgtm.yml
Normal file
@ -0,0 +1,17 @@
|
||||
path_classifiers:
|
||||
test:
|
||||
- "tests/*"
|
||||
|
||||
extraction:
|
||||
cpp:
|
||||
configure:
|
||||
command:
|
||||
- export INSTALL_ROOT=/opt/out
|
||||
- export PKG_CONFIG_PATH=$INSTALL_ROOT/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
- bash -x ./scripts/build-libdivecomputer.sh
|
||||
- mkdir _lgtm_build_dir
|
||||
- cd _lgtm_build_dir
|
||||
- cmake -DLIBGIT2_DYNAMIC=ON -DNO_DOCS=ON -DCMAKE_VERBOSE_MAKEFILE=ON ..
|
||||
|
||||
queries:
|
||||
- exclude: "cpp/short-global-name"
|
||||
27
.travis.yml
@ -9,13 +9,26 @@ matrix:
|
||||
|
||||
- env: SUBSURFACE_PLATFORM='mac'
|
||||
os: osx
|
||||
osx_image: xcode8
|
||||
language: c++ ruby
|
||||
osx_image: xcode10.1
|
||||
language: c++
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- xz
|
||||
- hidapi
|
||||
- libusb
|
||||
- libxml2
|
||||
- libxslt
|
||||
- libzip
|
||||
- openssl
|
||||
- pkg-config
|
||||
- libgit2
|
||||
- libssh2
|
||||
update: true
|
||||
|
||||
- env: SUBSURFACE_PLATFORM='windows'
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: c++
|
||||
|
||||
- env: SUBSURFACE_PLATFORM='windows-container'
|
||||
@ -28,7 +41,6 @@ matrix:
|
||||
- env: SUBSURFACE_PLATFORM='linux'
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: c++
|
||||
addons:
|
||||
apt:
|
||||
@ -65,7 +77,6 @@ matrix:
|
||||
- env: SUBSURFACE_PLATFORM='linux2'
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: c++
|
||||
addons:
|
||||
apt:
|
||||
@ -156,6 +167,6 @@ after_success:
|
||||
- source ${TRAVIS_BUILD_DIR}/scripts/${SUBSURFACE_PLATFORM}/after_success.sh
|
||||
|
||||
branches:
|
||||
except:
|
||||
- # Do not build tags that we create when we upload to GitHub Releases
|
||||
- /^(?i:continuous)/
|
||||
only:
|
||||
- master
|
||||
- /^v\d+\.\d+(\.\d+)?(-branch)?$/
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
- Tag: high level what changed (please replace this line with your first CHANGELOG entry)
|
||||
|
||||
---
|
||||
* Always add new entries at the very top of this file above other existing entries and this note.
|
||||
* Use this layout for new entries: `[Area]: [Details about the change] [reference thread / issue]`
|
||||
|
||||
@ -40,7 +40,6 @@ option(NO_PRINTING "disable the printing support" OFF)
|
||||
option(NO_USERMANUAL "don't include a viewer for the user manual" OFF)
|
||||
|
||||
#Options regarding enabling parts of subsurface
|
||||
option(FBSUPPORT "allow posting to Facebook" ON)
|
||||
option(BTSUPPORT "enable support for QtBluetooth (requires Qt5.4 or newer)" ON)
|
||||
option(FTDISUPPORT "enable support for libftdi based serial" OFF)
|
||||
option(USE_WEBENGINE "Use QWebEngine instead of QWebKit" OFF)
|
||||
@ -270,6 +269,11 @@ endif()
|
||||
set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} ${LIBDIVECOMPUTER_LIBRARIES} ${LIBGIT2_LIBRARIES} ${LIBUSB_LIBRARIES})
|
||||
qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc map-widget/qml/map-widget.qrc)
|
||||
|
||||
# hack to build successfully on LGTM
|
||||
if(DEFINED ENV{LGTM_SRC})
|
||||
set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} -lgssapi_krb5 -lhttp_parser)
|
||||
endif()
|
||||
|
||||
# include translations
|
||||
add_subdirectory(translations)
|
||||
add_subdirectory(core)
|
||||
@ -335,15 +339,10 @@ elseif(${SUBSURFACE_TARGET_EXECUTABLE} MATCHES "DesktopExecutable")
|
||||
add_executable(${SUBSURFACE_TARGET} MACOSX_BUNDLE WIN32 ${SUBSURFACE_PKG} ${SUBSURFACE_APP} ${SUBSURFACE_RESOURCES})
|
||||
endif()
|
||||
|
||||
if(FBSUPPORT)
|
||||
set(FACEBOOK_INTEGRATION facebook_integration)
|
||||
add_dependencies(facebook_integration subsurface_generated_ui)
|
||||
endif()
|
||||
target_link_libraries(
|
||||
${SUBSURFACE_TARGET}
|
||||
subsurface_generated_ui
|
||||
subsurface_interface
|
||||
${FACEBOOK_INTEGRATION}
|
||||
subsurface_profile
|
||||
subsurface_statistics
|
||||
subsurface_models_desktop
|
||||
@ -411,14 +410,12 @@ if(ANDROID)
|
||||
if((DEFINED ENV{KEYSTORE}) AND (DEFINED ENV{KEYSTORE_PASSWORD}))
|
||||
add_qt_android_apk(${SUBSURFACE_TARGET}.apk ${SUBSURFACE_TARGET}
|
||||
PACKAGE_SOURCES ${CMAKE_BINARY_DIR}/android-mobile DEPENDS ${ANDROID_NATIVE_LIBSSL} ${ANDROID_NATIVE_LIBCRYPT}
|
||||
BUILDTOOLS_REVISION ${BUILDTOOLS_REVISION}
|
||||
KEYSTORE $ENV{KEYSTORE} Subsurface-mobile KEYSTORE_PASSWORD $ENV{KEYSTORE_PASSWORD}
|
||||
)
|
||||
message(STATUS "KEYSTORE=$ENV{KEYSTORE} KEYSTORE_PASSWORD=$ENV{KEYSTORE_PASSWORD}")
|
||||
else()
|
||||
add_qt_android_apk(${SUBSURFACE_TARGET}.apk ${SUBSURFACE_TARGET}
|
||||
PACKAGE_SOURCES ${CMAKE_BINARY_DIR}/android-mobile DEPENDS ${ANDROID_NATIVE_LIBSSL} ${ANDROID_NATIVE_LIBCRYPT}
|
||||
BUILDTOOLS_REVISION ${BUILDTOOLS_REVISION}
|
||||
)
|
||||
message(STATUS "no KEYSTORE")
|
||||
endif()
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 33 KiB |
@ -2719,44 +2719,6 @@ There are two ways to export dive information from Subsurface:
|
||||
|
||||
- xref:S_Export_other[Export dive information to other destinations or formats]
|
||||
|
||||
[[S_Facebook]]
|
||||
=== Exporting dive information to _Facebook_
|
||||
|
||||
Export of dives to _Facebook_ is handled differently from other types of export because
|
||||
a connection to _Facebook_ is required, needing a _Facebook_ userID and password.
|
||||
From the *Main Menu*, select _Share on -> Connect to -> Facebook_ (image *A* below)
|
||||
A _Facebook_ login screen appears (image *B* below). Provide a _Facebook_ userID and password.
|
||||
From the _Subsurface_ window it’s easy to determine whether _Subsurface_ has a valid connection to _Facebook_:
|
||||
from the *Main Menu*, select _Share on_ (image *A*, below). Normally, the _Facebook_ option is greyed out. But
|
||||
if there is a connection to _Facebook_, this option is active (i.e. in black color and can be selected).
|
||||
|
||||
Once logged into to _Facebook_ , a panel is shown with a message:
|
||||
"_To disconnect Subsurface from your Facebook account, use the 'Share on' menu entry_."
|
||||
Close this message panel.
|
||||
|
||||
image::images/facebook1.jpg["Figure: Facebook login",align="center"]
|
||||
|
||||
Having established a login to _Facebook_, transferring a dive profile to a _Facebook_ timeline is easy.
|
||||
In the _Subsurface_ *Dive List* panel, highlight the dive to be transferred.
|
||||
Then, from the *Main Menu*, select _Share on -> Facebook_. A dialogue box
|
||||
is shown, determining the amount of additional information to be transferred
|
||||
with the dive profile (image *A*, below). To transfer a dive profile to _Facebook_, the name of a
|
||||
_Facebook_ album is needed. The checkboxes on the left hand side determine how much
|
||||
additional information is added to the dive profile, shown in the text box
|
||||
on the right hand side of the panel (image *A*, below). Customise the message that will be posted
|
||||
with the dive profile by editing any of the information. After specifying additional information
|
||||
and verifying the text, select the _OK_ button that triggers the transfer to _Facebook_. After the transfer
|
||||
is done, an acknowledgement dialogue appears, indicating it was successful.
|
||||
|
||||
Both the album created and the post to your timeline are marked as
|
||||
private. In order for friends to be able to see the post,
|
||||
log into _Facebook_ using a browser or Facebook app and change its permissions.
|
||||
|
||||
image::images/facebook2.jpg["Figure: Facebook data submission",align="center"]
|
||||
|
||||
If required, then close the _Facebook_ connection by selecting, from the *Main Menu*,
|
||||
_Share on -> Disconnect from -> Facebook_ (image *B* above).
|
||||
|
||||
[[S_Export_other]]
|
||||
=== Export dive information to other destinations or formats
|
||||
For non-_Facebook exports_, the export function can be found by selecting _File -> Export_, which brings up
|
||||
@ -2790,6 +2752,8 @@ A dive log or part of it can be saved in several formats:
|
||||
* _CSV dive profile_, that includes a large amount of detail for each dive, including
|
||||
the depth profile, temperature and pressure information of each dive.
|
||||
|
||||
* _dive profile_, saves the Subsurface dive profile as a .png file
|
||||
|
||||
* _HTML_ format, in which the dive(s) are stored in HTML files, readable
|
||||
with an Internet browser. Most modern web browsers are supported, but JavaScript
|
||||
must be enabled. The HTML export cannot be changed or edited.
|
||||
|
||||
@ -2934,55 +2934,6 @@ Hay dos posibilidades de exportar información de buceo desde _Subsurface_:
|
||||
|
||||
- xref:S_Export_other[Exportar información de buceo a otros destinos o formatos]
|
||||
|
||||
[[S_Facebook]]
|
||||
=== Exportar información de buceo a _Facebook_
|
||||
|
||||
La exportación de inmersiones a _Facebook_ se maneja de forma diferente a otros
|
||||
tipos de exportación porque se requiere una
|
||||
conexión a esta red social y se necesita un usuario de _Facebook_ y su password.
|
||||
Si, desde el menú principal, seleccionamos _Compartir -> Conectar a ->
|
||||
Facebook_ (imagen *A* siguiente), se nos presentará una pantalla de acceso
|
||||
(imagen *B* a continuación). Introducimos nuestro usuario y password de
|
||||
_Facebook_.
|
||||
Desde la ventana de _Subsurface_ es fácil saber si se tiene una conexión válida
|
||||
con _Facebook_. Desde el *Menú principal*, selecciona _Compartir_
|
||||
(ver imagen *A* a continuación). Normalmente la opción _Facebook_ está
|
||||
desactivada, pero, si hay una conexión establecida, la opción está activa y
|
||||
puede ser seleccionada.
|
||||
Tras haber establecido una conexión con _Facebook_, se mostrará un panel con
|
||||
un mensaje: "_Para desconectar Subsurface de tu cuenta de Facebook, utiliza la
|
||||
entrada del menú 'Compartir'_."
|
||||
Cierra este panel.
|
||||
|
||||
image::images/facebook1.jpg["Figure: Facebook login",align="center"]
|
||||
|
||||
Habiendo establecido una conexión a _Facebook_, transferir un perfil al
|
||||
historial es fácil.
|
||||
Selecciona en la *Lista de Inmersiones* de _Subsurface_ el buceo que quieras
|
||||
transferir; entonces, desde el *Menú* selecciona _Compartir -> Facebook_,
|
||||
aparecerá un diálogo en el que se definirá la cantidad de información
|
||||
adicional que se desea compartir en el historial junto con el perfil (ver imagen
|
||||
*A*, a continuación). Se necesita proporcionar el nombre de un álbum de _Facebook_
|
||||
para poder enviar el perfil de inmersión. Las casillas seleccionables de la
|
||||
izquierda nos permiten seleccionar la información que vamos a enviar. Esta
|
||||
información se muestra en la ventana de texto de la derecha (ver imagen *A*
|
||||
a continuación). El mensaje que se va a enviar se puede editar directamente en
|
||||
esta ventana de texto. Tras haber elegido la información y verificado lo que se va
|
||||
a subir, se selecciona el botón _OK_ lo que inicia la transferencia a _Facebook_.
|
||||
Unos momentos después aparecerá un mensaje indicando una transferencia correcta.
|
||||
|
||||
El álbum creado y el post al historial se marcarán como privados. Para que
|
||||
los amigos puedan ver el post habrá que cambiar los permisos desde un acceso
|
||||
normal a _Facebook_ desde un navegador o desde la app de _Facebook_. Aunque
|
||||
esto suponga un paso de más, los desarrolladores entienden que esta es la mejor
|
||||
solución para evitar subidas no deseadas en el historial público.
|
||||
|
||||
image::images/facebook2.jpg["Figure: Facebook data submission",align="center"]
|
||||
|
||||
Si se considera necesario, cierra la conexión a _Facebook_, seleccionando
|
||||
desde el *Menú principal*, _Compartir -> Desconectar de -> Facebook_ (imagen
|
||||
*B* anterior).
|
||||
|
||||
[[S_Export_other]]
|
||||
=== Exportar información de buceo a otros destinos o formatos
|
||||
Para exportar a otros destinos,
|
||||
|
||||
@ -2987,53 +2987,6 @@ Il y a deux façons d'exporter des informations de plongée depuis Subsurface:
|
||||
- xref:S_Export_other[Exporter des informations de plongée vers d'autres
|
||||
destinations ou formats]
|
||||
|
||||
[[S_Facebook]]
|
||||
=== Export des informations de plongée vers _Facebook_
|
||||
|
||||
L'export des plongées vers _Facebook_ est géré différemment des autres types
|
||||
d'export car une connexion vers _Facebook_ est nécessaire, nécessitant un
|
||||
identifiant et un mot de passe. À partir du menu principal, sélectionnez
|
||||
_Partager sur -> Connecter à -> Facebook_ (image *A* ci-dessous). Un écran
|
||||
de connexion s'affiche (image *B* ci dessous). Entrez l'identifiant et le
|
||||
mot de passe _Facebook_. Depuis la fenêtre _Subsurface_, il est facile de
|
||||
vérifier si _Subsurface_ a une connection valide vers _Facebook_ : Depuis le
|
||||
"Menu principal", sélectionnez _Partager sur_ (image *A*
|
||||
ci-dessous). Normalement, l'option _Facebook_ est grisée. Mais si une
|
||||
connection vers _Facebook_ existe, cette option est active (c'est à dire
|
||||
écrit en noir et sélectionnable).
|
||||
|
||||
Once logged into to _Facebook_ , a panel is shown with a message: "_To
|
||||
disconnect Subsurface from your Facebook account, use the 'Share on' menu
|
||||
entry_." Close this message panel.
|
||||
|
||||
image::images/facebook1.jpg["Figure: Facebook login", align="center"]
|
||||
|
||||
Une fois qu'une connexion à _Facebook_ est établie, transférer un profil de
|
||||
plongée vers _Facebook_ est facile. Dans le panneau *Liste des plongées* de
|
||||
_Subsurface_, sélectionnez la plongée à transférer. Ensuite, à partir du
|
||||
*menu principal*, sélectionnez _Partager sur -> Facebook_. Une fenêtre
|
||||
s'affiche, pour déterminer quelles informations seront transférées avec le
|
||||
profil de plongée (image *A* ci-dessous). Pour transférer un profil de
|
||||
plongée vers _Facebook_, le nom d'un album _Facebook_ doit être fourni. Les
|
||||
cases à cocher sur la partie gauche permettent de sélectionner des
|
||||
informations supplémentaires à transférer avec le profil de plongée. Ces
|
||||
informations sont affichées dans le champs de texte sur la partie droite du
|
||||
panneau. (image *A* ci dessous). Personnalisez le message qui sera envoyé
|
||||
avec le profil de plongée en modifiant les informations. Une fois les
|
||||
informations supplémentaires ajoutées et vérifiées, sélectionner le bouton
|
||||
_OK_ qui effectue le transfert vers _Facebook_. Après le transfert, une
|
||||
fenêtre de confirmation apparait ,indiquant le succès du transfert.
|
||||
|
||||
À la fois l'album créé et la publication sur votre ligne temporelle seront
|
||||
marquées comme privés. Pour que vos amis puissent la voir, connectez-vous à
|
||||
_Facebook_ depuis un navigateur ou l'application Facebook et modifiez les
|
||||
permissions.
|
||||
|
||||
image::images/facebook2.jpg["Figure: Facebook data submission", align="center"]
|
||||
|
||||
If required, then close the _Facebook_ connection by selecting, from the
|
||||
*Main Menu*, _Share on -> Disconnect from -> Facebook_ (image *B* above).
|
||||
|
||||
[[S_Export_other]]
|
||||
=== Exporter des informations de plongée vers d'autres destinations ou formats
|
||||
For non-_Facebook exports_, the export function can be found by selecting
|
||||
|
||||
@ -2545,49 +2545,6 @@ Er zijn twee manieren om duik informatie uit _Subsurface_ te exporteren:
|
||||
|
||||
- xref:S_Export_other[Exporteer duikinformatie naar andere bestemmingen of formaten]
|
||||
|
||||
[[S_Facebook]]
|
||||
=== Exporteer duikinformatie naar _Facebook_
|
||||
|
||||
Exporteren naar _Facebook_ werkt op een andere manier dan andere vormen van
|
||||
export, met name omdat er een verbinding met _Facebook_ aanwezig moet zijn die
|
||||
is ingelogd. Selecteer vanuit het hoofdmenu _Deel via -> Facebook_ (zie figuur
|
||||
*A* hieronder). Een inlogscherm voor _Facebook_ verschijnt (zie figuur
|
||||
*B* hieronder), en log in bij _Facebook_.
|
||||
|
||||
Het is eenvoudig te zien in het hoofdmenu of er een verbinding met _Facebook_
|
||||
actief is. In het _Deel via_ menu is de _Facebook knop_ grijs en niet-selecteerbaar
|
||||
als er geen verbinding is (figuur *A* hieronder).
|
||||
|
||||
Eenmaal ingelogd op _Facebook_ wordt er een paneel getoond met het bericht:
|
||||
"Gebruik het 'Deel via' menu om de verbinding van Subsurface met uw Facebook
|
||||
account te sluiten.". Sluit dit paneel.
|
||||
|
||||
image::images/facebook1.jpg["Figuur: Facebook login",align="center"]
|
||||
|
||||
Met de verbinding met _Facebook_ geactiveerd is het overdragen van een duik naar
|
||||
_Facebook_ eenvoudig. Selecteer eerst de duik in de *Duiklijst*. Selecteer dan
|
||||
uit het hoofdmenu _Deel via -> Facebook_. Er verschijnt een dialoog, waarin
|
||||
aangegeven kan worden welke informatie naast het duikprofiel, moet worden
|
||||
overgedragen naar _Facebook_ (zie figuur *A* hieronder).
|
||||
|
||||
Om een duikprofiel naar _Facebook_ te exporteren is de naam van een (foto) album
|
||||
nodig. De keuzevakjes aan de linker zijde bepalen welke data uit het logboek
|
||||
eveneens wordt geëxporteerd. Deze verschijnen in het tekst veld aan de rechter zijde,
|
||||
welke verder handmatig kan worden aangepast. Nadat alles naar wens is ingevuld,
|
||||
kan via de _OK_ knop de feitelijke export worden gedaan. Als de export gereed is
|
||||
volgt een bevestiging.
|
||||
|
||||
Zowel het album als de geëxporteerde profiel (met annotaties) is in _Facebook_ als
|
||||
privé aangemerkt, en de rechten van de geëxporteerde data moeten dus handmatig
|
||||
in _Facebook_ worden gezet zoals gewenst.
|
||||
|
||||
image::images/facebook2.jpg["Figuur: Facebook data submission",align="center"]
|
||||
|
||||
De verbinding met _Facebook_ kan nu worden afgesloten als dat gewenst is. Gebruik
|
||||
hiervoor uit het hoofdmenu _Deel via -> Verbinding verbreken met -> Facebook_ (
|
||||
figuur *B* hierboven).
|
||||
|
||||
|
||||
[[S_Export_other]]
|
||||
=== Exporteer duikinformatie naar andere bestemmingen of formaten
|
||||
Andere dan _Facebook_ exports kunnen gevonden worden door in het hoofdmenu
|
||||
|
||||
@ -2824,44 +2824,6 @@ image::images/Filterpanel.jpg["Рисунок: Панель фильтров",al
|
||||
|
||||
- xref:S_Export_other[Экспорт данных погружения в другие форматы]
|
||||
|
||||
[[S_Facebook]]
|
||||
=== Экспорт информации о погружении в _Facebook_
|
||||
|
||||
Экспорт в _Facebook_ отличается от всех других видов экспорта, поскольку он требует подключения
|
||||
учетной записи, что в свою очередь требует от вас логин и пароль _Facebook_. Для авторизации
|
||||
необходимо в главном меню выбрать _Файл -> Настройки_ и там выбрать вкладку _Facebook_, на которой
|
||||
вам будет представлена форма авторизации (см. рисунок *А* слева внизу). Авторизуйтесь своими логином
|
||||
и паролем, после чего экран должен выглядеть как показано на рисунке *В*. При необходимости вы
|
||||
можете отключить _Subsurface_ от _Facebook_, нажав на соответствующую кнопку.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
image::images/facebook1.jpg["Рисунок: Авторизация Facebook",align="center"]
|
||||
|
||||
После того как соединение с _Facebook_ установлено, публикация профиля погружения в вашей Хронике не
|
||||
составит проблем. Выберите погружение в списке и убедитесь в том, что именно этот дайв должен быть
|
||||
опубликован. Нажмите кнопку с логотипом _Facebook_, расположенную в *Информационной панели* справа
|
||||
от поля _Примечания_ (см. рисунок *А* ниже). По нажатию на эту кнопку вам будет представлено окно, в
|
||||
котором вы можете выбрать какую дополнительную информацию опубликовать вместе с профилем погружения
|
||||
(рисунок *В*). Обязательным является только поле _Альбом_. Кроме указания стандартных параметров
|
||||
погружения, вы можете вручную отредактировать сопроводительный текст. Для отправки профиля
|
||||
погружения в вашу Хронику _Facebook_ нажмите кнопку _ОК_. Спустя короткое время вы должны получить
|
||||
подтверждение, что запись опубликована.
|
||||
|
||||
|
||||
Созданный альбом и запись в хронике по умолчанию будут доступны только вам. Для того, чтобы ваши
|
||||
друзья смогли увидеть эти записи, вам необходимо изменить настройки безопасности приложений,
|
||||
войдя в _Facebook_ с помощью обычного броузера или приложения _Facebook_. Возможно это и является
|
||||
некоторым неудобством, но разработчики придерживаются мнения, что такой дополнительный шаг позволит избежать нежелательных записей в вашей Хронике.
|
||||
|
||||
image::images/facebook2.jpg["Рисунок: Авторизация в Facebook",align="center"]
|
||||
|
||||
Разорвать соединение с _Facebook_ можно из *Настроек* приложения, либо просто закрыв _Subsurface_.
|
||||
|
||||
|
||||
[[S_Export_other]]
|
||||
=== Экспорт данных погружения в другие форматы
|
||||
Функция экспорта доступна через главное меню _Файл -> Экспорт_. Диалог
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
# Subsurface [](https://travis-ci.org/Subsurface-divelog/subsurface)
|
||||
|
||||
This is the README file for Subsurface 4.8.4
|
||||
This is the README file for Subsurface 4.8.6
|
||||
|
||||
Please check the `ReleaseNotes.txt` for details about new features and
|
||||
changes since Subsurface 4.8.3 (and earlier versions).
|
||||
changes since Subsurface 4.8.5 (and earlier versions).
|
||||
|
||||
Subsurface can be found at http://subsurface-divelog.org
|
||||
|
||||
@ -38,10 +38,10 @@ development version) you can either get this via git or the release tar
|
||||
ball. After cloning run the following command:
|
||||
|
||||
```
|
||||
git checkout v4.8.4 (or whatever the last release is)
|
||||
git checkout v4.8.6 (or whatever the last release is)
|
||||
```
|
||||
|
||||
or download a tarball from http://subsurface-divelog.org/downloads/Subsurface-4.8.4.tgz
|
||||
or download a tarball from http://subsurface-divelog.org/downloads/Subsurface-4.8.6.tgz
|
||||
|
||||
Detailed build instructions can be found in the INSTALL file.
|
||||
|
||||
|
||||
@ -2,6 +2,34 @@
|
||||
|
||||
= _Subsurface_ Release Notes
|
||||
|
||||
New in _Subsurface_ 4.8.6
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- Desktop: update snap and appdata meta data
|
||||
- Desktop: make sure cloud storage email addresses are lower case only
|
||||
- Desktop: Fix editing of dive-time [#1975]
|
||||
- Desktop: Add export option for profile picture [#1962]
|
||||
- Export: fix picture thumbnails [#1963]
|
||||
- Desktop: remove support for the "Share on Facebook" feature.
|
||||
Rationale: It is fairly easy to share images on Facebook, thus it was decided
|
||||
that this feature is redundant and should be removed from Subsurface.
|
||||
- Dive computer support:
|
||||
- Add initial support for tag events on Shearwater Teric
|
||||
- Add support for additional Ratio dive computers
|
||||
- several bug fixes for existing dive computers
|
||||
|
||||
New in _Subsurface_ 4.8.5
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- Shearwater import: add suppport for importing Shearwater Cloud logs
|
||||
- Core, Mobile: all controller states other than powered off are valid [#1903]
|
||||
- Core: shift dive time in correct direction [#1893]
|
||||
- Desktop: translate trip date
|
||||
- Dive computer support:
|
||||
- Fix support for Shearwater Teric with firmware v11
|
||||
- Add support for Oceanic Pro Plus X over BLE
|
||||
- Add support for the Cressi Goa and Cartesio
|
||||
- Add support for the Ratio iDive Color series
|
||||
- Add support for the Aqualung i300C
|
||||
|
||||
New in _Subsurface_ 4.8.4
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
- Windows: add experimental support for BTLE dive computers.
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<li>Quantum X</li></ul>
|
||||
</dd>
|
||||
<dt>Aqualung</dt><dd><ul>
|
||||
<li>i100, i200, i300, i450T, i550, i750TC, i770R</li></ul>
|
||||
<li>i100, i200, i300, i300C, i450T, i550, i750TC, i770R</li></ul>
|
||||
</dd>
|
||||
<dt>Atomic Aquatics</dt><dd><ul>
|
||||
<li>Cobalt, Cobalt 2</li></ul>
|
||||
@ -21,7 +21,7 @@
|
||||
<li>Commander I, Commander II, Commander TM, EMC-14, EMC-16, EMC-20H</li></ul>
|
||||
</dd>
|
||||
<dt>Cressi</dt><dd><ul>
|
||||
<li>Drake, Edy, Giotto, Leonardo, Newton</li></ul>
|
||||
<li>Cartesio, Drake, Edy, Giotto, Goa, Leonardo, Newton</li></ul>
|
||||
</dd>
|
||||
<dt>Dive Rite</dt><dd><ul>
|
||||
<li>NiTek Q, NiTek Trio</li></ul>
|
||||
@ -48,7 +48,7 @@
|
||||
<li>Atom 1.0, Atom 2.0, Atom 3.0, Atom 3.1, Datamask, F10, F11, Geo, Geo 2.0, OC1, OCS, OCi, Pro Plus 2, Pro Plus 2.1, Pro Plus 3, Pro Plus X, VT 4.1, VT Pro, VT3, VT4, VTX, Veo 1.0, Veo 180, Veo 2.0, Veo 200, Veo 250, Veo 3.0, Versa Pro</li></ul>
|
||||
</dd>
|
||||
<dt>Ratio</dt><dd><ul>
|
||||
<li>iDive Deep, iDive Easy, iDive Free, iDive Tech+, iX3M Deep, iX3M Easy, iX3M Pro Deep, iX3M Pro Easy, iX3M Pro Tech+, iX3M Reb, iX3M Tech+</li></ul>
|
||||
<li>iDive Color Deep, iDive Color Easy, iDive Color Fancy, iDive Color Free, iDive Color Pro, iDive Color Reb, iDive Color Tech+, iDive Deep, iDive Easy, iDive Fancy, iDive Free, iDive Pro, iDive Reb, iDive Tech+, iX3M Deep, iX3M Easy, iX3M Fancy, iX3M Pro , iX3M Pro Deep, iX3M Pro Easy, iX3M Pro Fancy, iX3M Pro Pro, iX3M Pro Reb, iX3M Pro Tech+, iX3M Reb, iX3M Tech+</li></ul>
|
||||
</dd>
|
||||
<dt>Reefnet</dt><dd><ul>
|
||||
<li>Sensus, Sensus Pro, Sensus Ultra</li></ul>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# This file is automatically generated, please edit scripts/parse-descriptor.pl
|
||||
Aeris: 500 AI, A300, A300 AI, A300CS, Atmos 2, Atmos AI, Atmos AI 2, Compumask, Elite, Elite T3, Epic, F10, F11, Manta, XR-1 NX, XR-2
|
||||
Apeks: Quantum X
|
||||
Aqualung: i100, i200, i300, i450T, i550, i750TC, i770R
|
||||
Aqualung: i100, i200, i300, i300C, i450T, i550, i750TC, i770R
|
||||
Atomic Aquatics: Cobalt, Cobalt 2
|
||||
Beuchat: Mundial 2, Mundial 3, Voyager 2G
|
||||
Citizen: Hyper Aqualand
|
||||
Cochran: Commander I, Commander II, Commander TM, EMC-14, EMC-16, EMC-20H
|
||||
Cressi: Drake, Edy, Giotto, Leonardo, Newton
|
||||
Cressi: Cartesio, Drake, Edy, Giotto, Goa, Leonardo, Newton
|
||||
Dive Rite: NiTek Q, NiTek Trio
|
||||
DiveSystem: Orca, iDive DAN, iDive Deep, iDive Easy, iDive Free, iDive Pro, iDive Reb, iDive Stealth, iDive Tech, iDive X3M
|
||||
Garmin: Descent Mk1
|
||||
@ -15,7 +15,7 @@ Heinrichs Weikamp: Frog, OSTC, OSTC 2, OSTC 2 TR, OSTC 2C, OSTC 2N, OSTC 3, OSTC
|
||||
Hollis: DG02, DG03, TX1
|
||||
Mares: Airlab, Darwin, Darwin Air, Icon HD, Icon HD Net Ready, M1, M2, Matrix, Nemo, Nemo Air, Nemo Apneist, Nemo Excel, Nemo Steel, Nemo Titanium, Nemo Wide, Nemo Wide 2, Puck, Puck 2, Puck Air, Puck Pro, Quad, Quad Air, Smart, Smart Air, Smart Apnea
|
||||
Oceanic: Atom 1.0, Atom 2.0, Atom 3.0, Atom 3.1, Datamask, F10, F11, Geo, Geo 2.0, OC1, OCS, OCi, Pro Plus 2, Pro Plus 2.1, Pro Plus 3, Pro Plus X, VT 4.1, VT Pro, VT3, VT4, VTX, Veo 1.0, Veo 180, Veo 2.0, Veo 200, Veo 250, Veo 3.0, Versa Pro
|
||||
Ratio: iDive Deep, iDive Easy, iDive Free, iDive Tech+, iX3M Deep, iX3M Easy, iX3M Pro Deep, iX3M Pro Easy, iX3M Pro Tech+, iX3M Reb, iX3M Tech+
|
||||
Ratio: iDive Color Deep, iDive Color Easy, iDive Color Fancy, iDive Color Free, iDive Color Pro, iDive Color Reb, iDive Color Tech+, iDive Deep, iDive Easy, iDive Fancy, iDive Free, iDive Pro, iDive Reb, iDive Tech+, iX3M Deep, iX3M Easy, iX3M Fancy, iX3M Pro , iX3M Pro Deep, iX3M Pro Easy, iX3M Pro Fancy, iX3M Pro Pro, iX3M Pro Reb, iX3M Pro Tech+, iX3M Reb, iX3M Tech+
|
||||
Reefnet: Sensus, Sensus Pro, Sensus Ultra
|
||||
Scubapro: Aladin Sport Matrix, Aladin Square, Chromis, G2, G2 Console, Mantis, Mantis 2, Meridian, XTender 5
|
||||
Seabaer: T1, H3, HUDC
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<uses-sdk android:minSdkVersion="16"
|
||||
<uses-sdk android:minSdkVersion="21"
|
||||
android:targetSdkVersion="26" />
|
||||
|
||||
<supports-screens
|
||||
|
||||
64
android-mobile/build.gradle
Normal file
@ -0,0 +1,64 @@
|
||||
/*******************************************************
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
* Subsurface-Mobile own Gradle build spec. Derived from
|
||||
* the one supplied by Qt.
|
||||
*******************************************************/
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://dl.bintray.com/android/android-tools/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://dl.bintray.com/android/android-tools/" }
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
|
||||
android {
|
||||
/*******************************************************
|
||||
* The following variables:
|
||||
* - androidBuildToolsVersion,
|
||||
* - androidCompileSdkVersion
|
||||
* - qt5AndroidDir - holds the path to qt android files
|
||||
* needed to build any Qt application
|
||||
* on Android.
|
||||
*
|
||||
* are defined in gradle.properties file. This file is
|
||||
* updated by QtCreator and androiddeployqt tools.
|
||||
* Changing them manually might break the compilation!
|
||||
*******************************************************/
|
||||
|
||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||
|
||||
buildToolsVersion androidBuildToolsVersion
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
|
||||
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
|
||||
res.srcDirs = [qt5AndroidDir + '/res', 'res']
|
||||
resources.srcDirs = ['src']
|
||||
renderscript.srcDirs = ['src']
|
||||
assets.srcDirs = ['assets']
|
||||
jniLibs.srcDirs = ['libs']
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
BIN
appdata/diveplanner.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
appdata/main.png
|
Before Width: | Height: | Size: 827 KiB After Width: | Height: | Size: 394 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 56 KiB |
@ -21,13 +21,10 @@
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://subsurface-divelog.org/screenshots/main.png</image>
|
||||
<image>https://raw.githubusercontent.com/Subsurface-divelog/subsurface/master/appdata/main.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://subsurface-divelog.org/screenshots/preferences.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://subsurface-divelog.org/screenshots/preferences2.png</image>
|
||||
<image>https://raw.githubusercontent.com/Subsurface-divelog/subsurface/master/appdata/diveplanner.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">https://subsurface-divelog.org</url>
|
||||
|
||||
@ -22,6 +22,7 @@ HINTS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libdivecomputer/include/
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/opt/out/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY( LIBDIVECOMPUTER_LIBRARIES
|
||||
@ -31,8 +32,9 @@ NAMES
|
||||
HINTS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../install-root/lib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../libdivecomputer/src/.libs/
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
/opt/out/lib
|
||||
)
|
||||
|
||||
INCLUDE( FindPackageHandleStandardArgs )
|
||||
|
||||
@ -10,7 +10,7 @@ execute_process(
|
||||
OUTPUT_VARIABLE CANONICAL_VERSION_STRING
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
set(MOBILE_VERSION_STRING "2.1.5")
|
||||
set(MOBILE_VERSION_STRING "2.1.7")
|
||||
|
||||
configure_file(${SRC} ${DST} @ONLY)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
|
||||
@ -63,7 +63,6 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||
git-access.c
|
||||
gpslocation.cpp
|
||||
imagedownloader.cpp
|
||||
isocialnetworkintegration.cpp
|
||||
libdivecomputer.c
|
||||
liquivision.c
|
||||
load-git.c
|
||||
@ -81,7 +80,6 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||
import-csv.c
|
||||
planner.c
|
||||
plannernotes.c
|
||||
pluginmanager.cpp
|
||||
profile.c
|
||||
qthelper.cpp
|
||||
qt-init.cpp
|
||||
@ -108,7 +106,6 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||
settings/qPrefDisplay.cpp
|
||||
settings/qPrefDiveComputer.cpp
|
||||
settings/qPrefDivePlanner.cpp
|
||||
settings/qPrefFacebook.cpp
|
||||
settings/qPrefGeneral.cpp
|
||||
settings/qPrefGeocoding.cpp
|
||||
settings/qPrefLanguage.cpp
|
||||
|
||||
@ -74,6 +74,11 @@ static dc_descriptor_t *getDeviceType(QString btName)
|
||||
product = "i770R";
|
||||
}
|
||||
|
||||
if (btName.contains(QRegularExpression("^ER\\d{6}$"))) {
|
||||
vendor = "Oceanic";
|
||||
product = "Pro Plus X";
|
||||
}
|
||||
|
||||
if (!vendor.isEmpty() && !product.isEmpty())
|
||||
return descriptorLookup.value(vendor + product);
|
||||
|
||||
@ -97,10 +102,11 @@ BTDiscovery::BTDiscovery(QObject*) : m_btValid(false),
|
||||
void BTDiscovery::BTDiscoveryReDiscover()
|
||||
{
|
||||
#if !defined(Q_OS_IOS)
|
||||
qDebug() << "BTDiscoveryReDiscover: localBtDevice.isValid()" << localBtDevice.isValid();
|
||||
if (localBtDevice.isValid() &&
|
||||
localBtDevice.hostMode() == QBluetoothLocalDevice::HostConnectable) {
|
||||
localBtDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff) {
|
||||
btPairedDevices.clear();
|
||||
qDebug() << "localDevice " + localBtDevice.name() + " is valid, starting discovery";
|
||||
qDebug() << "BTDiscoveryReDiscover: localDevice " + localBtDevice.name() + " is powered on, starting discovery";
|
||||
#else
|
||||
// for iOS we can't use the localBtDevice as iOS is BLE only
|
||||
// we need to find some other way to test if Bluetooth is enabled, though
|
||||
@ -142,7 +148,7 @@ BTDiscovery::~BTDiscovery()
|
||||
{
|
||||
m_instance = NULL;
|
||||
#if defined(BT_SUPPORT)
|
||||
free(discoveryAgent);
|
||||
delete discoveryAgent;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -310,6 +316,12 @@ bool BTDiscovery::checkException(const char* method, const QAndroidJniObject *ob
|
||||
|
||||
void BTDiscovery::discoverAddress(QString address)
|
||||
{
|
||||
// if we have a discovery agent, check if we know about the address and if not
|
||||
// make sure we are looking for it
|
||||
// (if we don't have a discoveryAgent then likely BT is off or something else went wrong)
|
||||
if (!discoveryAgent)
|
||||
return;
|
||||
|
||||
// let's make sure there is no device name mixed in with the address
|
||||
QString btAddress;
|
||||
btAddress = extractBluetoothAddress(address);
|
||||
|
||||
@ -450,23 +450,23 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||
// Get starting depth and temp (tank PSI???)
|
||||
switch (config.type) {
|
||||
case TYPE_GEMINI:
|
||||
depth = (float) (log[CMD_START_DEPTH]
|
||||
depth = (double) (log[CMD_START_DEPTH]
|
||||
+ log[CMD_START_DEPTH + 1] * 256) / 4;
|
||||
temp = log[CMD_START_TEMP];
|
||||
psi = log[CMD_START_PSI] + log[CMD_START_PSI + 1] * 256;
|
||||
sgc_rate = (float)(log[CMD_START_SGC]
|
||||
sgc_rate = (double)(log[CMD_START_SGC]
|
||||
+ log[CMD_START_SGC + 1] * 256) / 2;
|
||||
profile_period = log[CMD_PROFILE_PERIOD];
|
||||
break;
|
||||
case TYPE_COMMANDER:
|
||||
depth = (float) (log[CMD_START_DEPTH]
|
||||
depth = (double) (log[CMD_START_DEPTH]
|
||||
+ log[CMD_START_DEPTH + 1] * 256) / 4;
|
||||
temp = log[CMD_START_TEMP];
|
||||
profile_period = log[CMD_PROFILE_PERIOD];
|
||||
break;
|
||||
|
||||
case TYPE_EMC:
|
||||
depth = (float) log [EMC_START_DEPTH] / 256
|
||||
depth = (double) log [EMC_START_DEPTH] / 256
|
||||
+ log[EMC_START_DEPTH + 1];
|
||||
temp = log[EMC_START_TEMP];
|
||||
profile_period = log[EMC_PROFILE_PERIOD];
|
||||
@ -503,7 +503,7 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||
}
|
||||
|
||||
// Depth is in every sample
|
||||
depth_sample = (float)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
|
||||
depth_sample = (double)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
|
||||
depth += depth_sample;
|
||||
|
||||
#ifdef COCHRAN_DEBUG
|
||||
@ -528,13 +528,13 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||
ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1);
|
||||
break;
|
||||
case 2: // PSI change
|
||||
psi -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4;
|
||||
psi -= (double)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4;
|
||||
break;
|
||||
case 1: // SGC rate
|
||||
sgc_rate -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 2;
|
||||
sgc_rate -= (double)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 2;
|
||||
break;
|
||||
case 3: // Temperature
|
||||
temp = (float)s[1] / 2 + 20;
|
||||
temp = (double)s[1] / 2 + 20;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -544,7 +544,7 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||
ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1);
|
||||
break;
|
||||
case 1: // Temperature
|
||||
temp = (float)s[1] / 2 + 20;
|
||||
temp = (double)s[1] / 2 + 20;
|
||||
break;
|
||||
}
|
||||
// Get NDL and deco information
|
||||
|
||||
@ -1442,7 +1442,7 @@ static dc_status_t read_ostc_settings(dc_device_t *device, DeviceDetails *m_devi
|
||||
|
||||
unsigned char data[256] = {};
|
||||
#ifdef DEBUG_OSTC_CF
|
||||
// FIXME: how should we report settings not supported back?
|
||||
// open question: how should we report settings not supported back?
|
||||
unsigned char max_CF = 0;
|
||||
#endif
|
||||
rc = hw_ostc_device_eeprom_read(device, 0, data, sizeof(data));
|
||||
@ -1829,7 +1829,7 @@ static dc_status_t write_ostc_settings(dc_device_t *device, DeviceDetails *m_dev
|
||||
else if (gas5.type == 2)
|
||||
data[33] = 5;
|
||||
else
|
||||
// FIXME: No gas was First?
|
||||
// odd: No gas was First?
|
||||
// Set gas 1 to first
|
||||
data[33] = 1;
|
||||
|
||||
@ -1956,7 +1956,7 @@ static dc_status_t write_ostc_settings(dc_device_t *device, DeviceDetails *m_dev
|
||||
else if (dil5.type == 2)
|
||||
data[115] = 5;
|
||||
else
|
||||
// FIXME: No first diluent?
|
||||
// odd: No first diluent?
|
||||
// Set gas 1 to fist
|
||||
data[115] = 1;
|
||||
|
||||
@ -2178,7 +2178,7 @@ void WriteSettingsThread::run()
|
||||
}
|
||||
break;
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
// FIXME: Is this the best way?
|
||||
// Is this the best way?
|
||||
if (m_deviceDetails->model == "OSTC 4")
|
||||
rc = write_ostc4_settings(m_data->device, m_deviceDetails, DeviceThread::event_cb, this);
|
||||
else
|
||||
|
||||
@ -7,29 +7,15 @@ ConnectionListModel::ConnectionListModel(QObject *parent) :
|
||||
{
|
||||
}
|
||||
|
||||
QHash <int, QByteArray> ConnectionListModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[AddressRole] = "address";
|
||||
return roles;
|
||||
}
|
||||
|
||||
QVariant ConnectionListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() < 0 || index.row() >= m_addresses.count())
|
||||
return QVariant();
|
||||
if (role != AddressRole)
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
return m_addresses[index.row()];
|
||||
}
|
||||
|
||||
QString ConnectionListModel::address(int idx) const
|
||||
{
|
||||
if (idx < 0 || idx >> m_addresses.count())
|
||||
return QString();
|
||||
return m_addresses[idx];
|
||||
}
|
||||
|
||||
int ConnectionListModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_addresses.count();
|
||||
|
||||
@ -6,13 +6,8 @@
|
||||
class ConnectionListModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum CLMRole {
|
||||
AddressRole = Qt::UserRole + 1
|
||||
};
|
||||
ConnectionListModel(QObject *parent = 0);
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
QVariant data(const QModelIndex &index, int role = AddressRole) const;
|
||||
QString address(int idx) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
void addAddress(const QString address);
|
||||
void removeAllAddresses();
|
||||
|
||||
@ -15,12 +15,6 @@
|
||||
#include "device.h"
|
||||
#include "file.h"
|
||||
|
||||
unsigned char lector_bytes[2], lector_word[4], tmp_1byte, *byte;
|
||||
unsigned int tmp_2bytes;
|
||||
char is_nitrox, is_O2, is_SCR;
|
||||
unsigned long tmp_4bytes;
|
||||
long maxbuf;
|
||||
|
||||
static unsigned int two_bytes_to_int(unsigned char x, unsigned char y)
|
||||
{
|
||||
return (x << 8) + y;
|
||||
@ -31,12 +25,12 @@ static unsigned long four_bytes_to_long(unsigned char x, unsigned char y, unsign
|
||||
return ((long)x << 24) + ((long)y << 16) + ((long)z << 8) + (long)t;
|
||||
}
|
||||
|
||||
static unsigned char *byte_to_bits(unsigned char byte)
|
||||
static unsigned char *byte_to_bits(unsigned char byte_value)
|
||||
{
|
||||
unsigned char i, *bits = (unsigned char *)malloc(8);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
bits[i] = byte & (1 << i);
|
||||
bits[i] = byte_value & (1 << i);
|
||||
return bits;
|
||||
}
|
||||
|
||||
@ -146,7 +140,7 @@ static dc_status_t dt_libdc_buffer(unsigned char *ptr, int prf_length, int dc_mo
|
||||
* Parses a mem buffer extracting its data and filling a subsurface's dive structure.
|
||||
* Returns a pointer to last position in buffer, or NULL on failure.
|
||||
*/
|
||||
unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive)
|
||||
static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, long maxbuf)
|
||||
{
|
||||
int rc, profile_length, libdc_model;
|
||||
char *tmp_notes_str = NULL;
|
||||
@ -156,13 +150,13 @@ unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive)
|
||||
*compl_buffer,
|
||||
*membuf = runner;
|
||||
char buffer[1024];
|
||||
unsigned char tmp_1byte, *byte;
|
||||
unsigned int tmp_2bytes;
|
||||
unsigned long tmp_4bytes;
|
||||
struct dive_site *ds;
|
||||
device_data_t *devdata = calloc(1, sizeof(device_data_t));
|
||||
char is_nitrox = 0, is_O2 = 0, is_SCR = 0;
|
||||
|
||||
/*
|
||||
* Reset global variables for new dive
|
||||
*/
|
||||
is_nitrox = is_O2 = is_SCR = 0;
|
||||
device_data_t *devdata = calloc(1, sizeof(device_data_t));
|
||||
|
||||
/*
|
||||
* Parse byte to byte till next dive entry
|
||||
@ -581,7 +575,7 @@ int datatrak_import(struct memblock *mem, struct dive_table *table)
|
||||
unsigned char *runner;
|
||||
int i = 0, numdives = 0, rc = 0;
|
||||
|
||||
maxbuf = (long) mem->buffer + mem->size;
|
||||
long maxbuf = (long) mem->buffer + mem->size;
|
||||
|
||||
// Verify fileheader, get number of dives in datatrak divelog, zero on error
|
||||
numdives = read_file_header((unsigned char *)mem->buffer);
|
||||
@ -597,7 +591,7 @@ int datatrak_import(struct memblock *mem, struct dive_table *table)
|
||||
while ((i < numdives) && ((long) runner < maxbuf)) {
|
||||
struct dive *ptdive = alloc_dive();
|
||||
|
||||
runner = dt_dive_parser(runner, ptdive);
|
||||
runner = dt_dive_parser(runner, ptdive, maxbuf);
|
||||
if (runner == NULL) {
|
||||
report_error(translate("gettextFromC", "Error: no dive"));
|
||||
free(ptdive);
|
||||
|
||||
@ -292,7 +292,7 @@ double tissue_tolerance_calc(struct deco_state *ds, const struct dive *dive, dou
|
||||
if (plot_depth) {
|
||||
++sum1;
|
||||
sumx += plot_depth;
|
||||
sumxx += plot_depth * plot_depth;
|
||||
sumxx += (long)plot_depth * plot_depth;
|
||||
double n2_gradient, he_gradient, total_gradient;
|
||||
n2_gradient = update_gradient(ds, depth_to_bar(plot_depth, &displayed_dive), ds->bottom_n2_gradient[ds->ci_pointing_to_guiding_tissue]);
|
||||
he_gradient = update_gradient(ds, depth_to_bar(plot_depth, &displayed_dive), ds->bottom_he_gradient[ds->ci_pointing_to_guiding_tissue]);
|
||||
|
||||
@ -1577,7 +1577,7 @@ static void simplify_dc_pressures(struct divecomputer *dc)
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME! sensor -> cylinder mapping? */
|
||||
/* Do we need a sensor -> cylinder mapping? */
|
||||
static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p)
|
||||
{
|
||||
if (idx >= 0 && idx < MAX_CYLINDERS) {
|
||||
@ -2366,7 +2366,7 @@ static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, unsign
|
||||
if (different_manual_pressures(cyl, target))
|
||||
continue;
|
||||
|
||||
/* FIXME! Should we check sizes too? */
|
||||
/* open question: Should we check sizes too? */
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
|
||||
@ -500,6 +500,7 @@ extern void set_filename(const char *filename);
|
||||
extern int parse_dm4_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table);
|
||||
extern int parse_dm5_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table);
|
||||
extern int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table);
|
||||
extern int parse_shearwater_cloud_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table);
|
||||
extern int parse_cobalt_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table);
|
||||
extern int parse_divinglog_buffer(sqlite3 *handle, const char *url, const char *buf, int size, struct dive_table *table);
|
||||
extern int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *table);
|
||||
|
||||
@ -297,12 +297,8 @@ QStringList DCDeviceData::getProductListFromVendor(const QString &vendor)
|
||||
|
||||
int DCDeviceData::getMatchingAddress(const QString &vendor, const QString &product)
|
||||
{
|
||||
for (int i = 0; i < connectionListModel.rowCount(); i++) {
|
||||
QString address = connectionListModel.address(i);
|
||||
if (address.contains(product))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
Q_UNUSED(vendor)
|
||||
return connectionListModel.indexOf(product);
|
||||
}
|
||||
|
||||
DCDeviceData *DownloadThread::data()
|
||||
|
||||
@ -132,6 +132,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||
char dm4_test[] = "select count(*) from sqlite_master where type='table' and name='Dive' and sql like '%ProfileBlob%'";
|
||||
char dm5_test[] = "select count(*) from sqlite_master where type='table' and name='Dive' and sql like '%SampleBlob%'";
|
||||
char shearwater_test[] = "select count(*) from sqlite_master where type='table' and name='system' and sql like '%dbVersion%'";
|
||||
char shearwater_cloud_test[] = "select count(*) from sqlite_master where type='table' and name='SyncV3MetadataDiveLog' and sql like '%CreatedDevice%'";
|
||||
char cobalt_test[] = "select count(*) from sqlite_master where type='table' and name='TrackPoints' and sql like '%DepthPressure%'";
|
||||
char divinglog_test[] = "select count(*) from sqlite_master where type='table' and name='DBInfo' and sql like '%PrgName%'";
|
||||
int retval;
|
||||
@ -167,6 +168,14 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Testing if DB schema resembles Shearwater cloud database format */
|
||||
retval = sqlite3_exec(handle, shearwater_cloud_test, &db_test_func, 0, NULL);
|
||||
if (!retval) {
|
||||
retval = parse_shearwater_cloud_buffer(handle, filename, mem->buffer, mem->size, table);
|
||||
sqlite3_close(handle);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Testing if DB schema resembles Atomic Cobalt database format */
|
||||
retval = sqlite3_exec(handle, cobalt_test, &db_test_func, 0, NULL);
|
||||
if (!retval) {
|
||||
|
||||
@ -836,7 +836,7 @@ static struct git_repository *get_remote_repo(const char *localdir, const char *
|
||||
if (is_subsurface_cloud)
|
||||
(void)cleanup_local_cache(remote, branch);
|
||||
else
|
||||
report_error("local git cache at '%s' is corrupt");
|
||||
report_error("local git cache at '%s' is corrupt", localdir);
|
||||
return NULL;
|
||||
}
|
||||
return update_local_repo(localdir, remote, branch, rt);
|
||||
|
||||
@ -84,9 +84,9 @@ static bool hasVideoFileExtension(const QString &filename)
|
||||
// If the input-flag "tryDownload" is set to false, no download attempt is made. This is to
|
||||
// prevent infinite loops, where failed image downloads would be repeated ad infinitum.
|
||||
// Returns: fetched image, type
|
||||
Thumbnailer::Thumbnail Thumbnailer::fetchImage(const QString &filename, const QString &originalFilename, bool tryDownload)
|
||||
Thumbnailer::Thumbnail Thumbnailer::fetchImage(const QString &urlfilename, const QString &originalFilename, bool tryDownload)
|
||||
{
|
||||
QUrl url = QUrl::fromUserInput(filename);
|
||||
QUrl url = QUrl::fromUserInput(urlfilename);
|
||||
if (url.isLocalFile()) {
|
||||
// We try to determine the type first by peeking into the file.
|
||||
QString filename = url.toLocalFile();
|
||||
@ -456,8 +456,23 @@ void Thumbnailer::imageDownloadFailed(QString filename)
|
||||
workingOn.remove(filename);
|
||||
}
|
||||
|
||||
QImage Thumbnailer::fetchThumbnail(const QString &filename)
|
||||
QImage Thumbnailer::fetchThumbnail(const QString &filename, bool synchronous)
|
||||
{
|
||||
if (synchronous) {
|
||||
// In synchronous mode, first try the thumbnail cache.
|
||||
Thumbnail thumbnail = getThumbnailFromCache(filename);
|
||||
if (!thumbnail.img.isNull())
|
||||
return thumbnail.img;
|
||||
|
||||
// If that didn't work, try to thumbnail the image.
|
||||
thumbnail = getHashedImage(filename, false);
|
||||
if (thumbnail.type == MEDIATYPE_STILL_LOADING || thumbnail.img.isNull())
|
||||
return failImage; // No support for delayed thumbnails (web).
|
||||
|
||||
int size = maxThumbnailSize();
|
||||
return thumbnail.img.scaled(size, size, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
QMutexLocker l(&lock);
|
||||
|
||||
// We are not currently fetching this thumbnail - add it to the list.
|
||||
|
||||
@ -31,9 +31,13 @@ public:
|
||||
static Thumbnailer *instance();
|
||||
|
||||
// Schedule a thumbnail for fetching or calculation.
|
||||
// Returns a placeholder thumbnail. The actual thumbnail will be sent
|
||||
// via a signal later.
|
||||
QImage fetchThumbnail(const QString &filename);
|
||||
// If synchronous is false, returns a placeholder thumbnail.
|
||||
// The actual thumbnail will be sent via a signal later.
|
||||
// If synchronous is true, try to fetch the actual thumbnail.
|
||||
// In this mode only precalculated thumbnails or thumbnails
|
||||
// from pictures are returned. Video extraction and remote
|
||||
// images are not supported.
|
||||
QImage fetchThumbnail(const QString &filename, bool synchronous);
|
||||
|
||||
// Schedule multiple thumbnails for forced recalculation
|
||||
void calculateThumbnails(const QVector<QString> &filenames);
|
||||
|
||||
@ -73,7 +73,7 @@ static int shearwater_changes(void *param, int columns, char **data, char **colu
|
||||
i = state->cur_cylinder_index;
|
||||
}
|
||||
|
||||
add_gas_switch_event(state->cur_dive, get_dc(state), atoi(data[0]), i);
|
||||
add_gas_switch_event(state->cur_dive, get_dc(state), state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]), i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ static int shearwater_profile_sample(void *param, int columns, char **data, char
|
||||
|
||||
sample_start(state);
|
||||
if (data[0])
|
||||
state->cur_sample->time.seconds = atoi(data[0]);
|
||||
state->cur_sample->time.seconds = state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]);
|
||||
if (data[1])
|
||||
state->cur_sample->depth.mm = state->metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0));
|
||||
if (data[2])
|
||||
@ -137,7 +137,7 @@ static int shearwater_ai_profile_sample(void *param, int columns, char **data, c
|
||||
|
||||
sample_start(state);
|
||||
if (data[0])
|
||||
state->cur_sample->time.seconds = atoi(data[0]);
|
||||
state->cur_sample->time.seconds = state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]);
|
||||
if (data[1])
|
||||
state->cur_sample->depth.mm = state->metric ? lrint(strtod_flags(data[1], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[1], NULL, 0));
|
||||
if (data[2])
|
||||
@ -202,11 +202,11 @@ static int shearwater_dive(void *param, int columns, char **data, char **column)
|
||||
struct parser_state *state = (struct parser_state *)param;
|
||||
sqlite3 *handle = state->sql_handle;
|
||||
char *err = NULL;
|
||||
char get_profile_template[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,firstStopDepth,firstStopTime from dive_log_records where diveLogId=%d";
|
||||
char get_profile_template_ai[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,aiSensor0_PressurePSI,aiSensor1_PressurePSI,firstStopDepth,firstStopTime from dive_log_records where diveLogId = %d";
|
||||
char get_cylinder_template[] = "select fractionO2,fractionHe from dive_log_records where diveLogId = %d group by fractionO2,fractionHe";
|
||||
char get_changes_template[] = "select a.currentTime,a.fractionO2,a.fractionHe from dive_log_records as a,dive_log_records as b where (a.id - 1) = b.id and (a.fractionO2 != b.fractionO2 or a.fractionHe != b.fractionHe) and a.diveLogId=b.divelogId and a.diveLogId = %d";
|
||||
char get_mode_template[] = "select distinct currentCircuitSetting from dive_log_records where diveLogId = %d";
|
||||
char get_profile_template[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,firstStopDepth,firstStopTime from dive_log_records where diveLogId=%ld";
|
||||
char get_profile_template_ai[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,aiSensor0_PressurePSI,aiSensor1_PressurePSI,firstStopDepth,firstStopTime from dive_log_records where diveLogId = %ld";
|
||||
char get_cylinder_template[] = "select fractionO2,fractionHe from dive_log_records where diveLogId = %ld group by fractionO2,fractionHe";
|
||||
char get_changes_template[] = "select a.currentTime,a.fractionO2,a.fractionHe from dive_log_records as a,dive_log_records as b where (a.id - 1) = b.id and (a.fractionO2 != b.fractionO2 or a.fractionHe != b.fractionHe) and a.diveLogId=b.divelogId and a.diveLogId = %ld";
|
||||
char get_mode_template[] = "select distinct currentCircuitSetting from dive_log_records where diveLogId = %ld";
|
||||
char get_buffer[1024];
|
||||
|
||||
dive_start(state);
|
||||
@ -214,7 +214,131 @@ static int shearwater_dive(void *param, int columns, char **data, char **column)
|
||||
|
||||
state->cur_dive->when = (time_t)(atol(data[1]));
|
||||
|
||||
int dive_id = atoi(data[11]);
|
||||
long int dive_id = atol(data[11]);
|
||||
|
||||
if (data[2])
|
||||
add_dive_site(data[2], state->cur_dive, state);
|
||||
if (data[3])
|
||||
utf8_string(data[3], &state->cur_dive->buddy);
|
||||
if (data[4])
|
||||
utf8_string(data[4], &state->cur_dive->notes);
|
||||
|
||||
state->metric = atoi(data[5]) == 1 ? 0 : 1;
|
||||
|
||||
/* TODO: verify that metric calculation is correct */
|
||||
if (data[6])
|
||||
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(strtod_flags(data[6], NULL, 0) * 1000) : feet_to_mm(strtod_flags(data[6], NULL, 0));
|
||||
|
||||
if (data[7])
|
||||
state->cur_dive->dc.duration.seconds = atoi(data[7]) * 60;
|
||||
|
||||
if (data[8])
|
||||
state->cur_dive->dc.surface_pressure.mbar = atoi(data[8]);
|
||||
/*
|
||||
* TODO: the deviceid hash should be calculated here.
|
||||
*/
|
||||
settings_start(state);
|
||||
dc_settings_start(state);
|
||||
if (data[9])
|
||||
utf8_string(data[9], &state->cur_settings.dc.serial_nr);
|
||||
if (data[10]) {
|
||||
switch (atoi(data[10])) {
|
||||
case 2:
|
||||
state->cur_settings.dc.model = strdup("Shearwater Petrel/Perdix");
|
||||
break;
|
||||
case 4:
|
||||
state->cur_settings.dc.model = strdup("Shearwater Predator");
|
||||
break;
|
||||
default:
|
||||
state->cur_settings.dc.model = strdup("Shearwater import");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
state->cur_settings.dc.deviceid = atoi(data[9]);
|
||||
|
||||
dc_settings_end(state);
|
||||
settings_end(state);
|
||||
|
||||
if (data[10]) {
|
||||
switch (atoi(data[10])) {
|
||||
case 2:
|
||||
state->cur_dive->dc.model = strdup("Shearwater Petrel/Perdix");
|
||||
break;
|
||||
case 4:
|
||||
state->cur_dive->dc.model = strdup("Shearwater Predator");
|
||||
break;
|
||||
default:
|
||||
state->cur_dive->dc.model = strdup("Shearwater import");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[11]) {
|
||||
snprintf(get_buffer, sizeof(get_buffer) - 1, get_mode_template, dive_id);
|
||||
retval = sqlite3_exec(handle, get_buffer, &shearwater_mode, state, &err);
|
||||
if (retval != SQLITE_OK) {
|
||||
fprintf(stderr, "%s", "Database query shearwater_mode failed.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, dive_id);
|
||||
retval = sqlite3_exec(handle, get_buffer, &shearwater_cylinders, state, &err);
|
||||
if (retval != SQLITE_OK) {
|
||||
fprintf(stderr, "%s", "Database query shearwater_cylinders failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(get_buffer, sizeof(get_buffer) - 1, get_changes_template, dive_id);
|
||||
retval = sqlite3_exec(handle, get_buffer, &shearwater_changes, state, &err);
|
||||
if (retval != SQLITE_OK) {
|
||||
fprintf(stderr, "%s", "Database query shearwater_changes failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template_ai, dive_id);
|
||||
retval = sqlite3_exec(handle, get_buffer, &shearwater_ai_profile_sample, state, &err);
|
||||
if (retval != SQLITE_OK) {
|
||||
snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template, dive_id);
|
||||
retval = sqlite3_exec(handle, get_buffer, &shearwater_profile_sample, state, &err);
|
||||
if (retval != SQLITE_OK) {
|
||||
fprintf(stderr, "%s", "Database query shearwater_profile_sample failed.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
dive_end(state);
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int shearwater_cloud_dive(void *param, int columns, char **data, char **column)
|
||||
{
|
||||
UNUSED(columns);
|
||||
UNUSED(column);
|
||||
|
||||
int retval = 0;
|
||||
struct parser_state *state = (struct parser_state *)param;
|
||||
sqlite3 *handle = state->sql_handle;
|
||||
char *err = NULL;
|
||||
char get_profile_template[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,firstStopDepth,firstStopTime from dive_log_records where diveLogId=%ld";
|
||||
char get_profile_template_ai[] = "select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,aiSensor0_PressurePSI,aiSensor1_PressurePSI,firstStopDepth,firstStopTime from dive_log_records where diveLogId = %ld";
|
||||
char get_cylinder_template[] = "select fractionO2 / 100,fractionHe / 100 from dive_log_records where diveLogId = %ld group by fractionO2,fractionHe";
|
||||
char get_changes_template[] = "select a.currentTime,a.fractionO2 / 100,a.fractionHe /100 from dive_log_records as a,dive_log_records as b where (a.id - 1) = b.id and (a.fractionO2 != b.fractionO2 or a.fractionHe != b.fractionHe) and a.diveLogId=b.divelogId and a.diveLogId = %ld";
|
||||
char get_mode_template[] = "select distinct currentCircuitSetting from dive_log_records where diveLogId = %ld";
|
||||
char get_buffer[1024];
|
||||
|
||||
dive_start(state);
|
||||
state->cur_dive->number = atoi(data[0]);
|
||||
|
||||
state->cur_dive->when = (time_t)(atol(data[1]));
|
||||
|
||||
long int dive_id = atol(data[11]);
|
||||
if (data[12])
|
||||
state->sample_rate = atoi(data[12]);
|
||||
else
|
||||
state->sample_rate = 0;
|
||||
|
||||
if (data[2])
|
||||
add_dive_site(data[2], state->cur_dive, state);
|
||||
@ -327,6 +451,9 @@ int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char *buffer
|
||||
state.target_table = table;
|
||||
state.sql_handle = handle;
|
||||
|
||||
// So far have not seen any sample rate in Shearwater Desktop
|
||||
state.sample_rate = 0;
|
||||
|
||||
char get_dives[] = "select l.number,timestamp,location||' / '||site,buddy,notes,imperialUnits,maxDepth,maxTime,startSurfacePressure,computerSerial,computerModel,i.diveId FROM dive_info AS i JOIN dive_logs AS l ON i.diveId=l.diveId";
|
||||
|
||||
retval = sqlite3_exec(handle, get_dives, &shearwater_dive, &state, &err);
|
||||
@ -340,3 +467,29 @@ int parse_shearwater_buffer(sqlite3 *handle, const char *url, const char *buffer
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_shearwater_cloud_buffer(sqlite3 *handle, const char *url, const char *buffer, int size,
|
||||
struct dive_table *table)
|
||||
{
|
||||
UNUSED(buffer);
|
||||
UNUSED(size);
|
||||
|
||||
int retval;
|
||||
char *err = NULL;
|
||||
struct parser_state state;
|
||||
|
||||
init_parser_state(&state);
|
||||
state.target_table = table;
|
||||
state.sql_handle = handle;
|
||||
|
||||
char get_dives[] = "select l.number,strftime('%s', DiveDate),location||' / '||site,buddy,notes,imperialUnits,maxDepth,maxTime,startSurfacePressure,computerSerial,computerModel,d.diveId,l.sampleRateMs FROM dive_details AS d JOIN dive_logs AS l ON d.diveId=l.diveId";
|
||||
|
||||
retval = sqlite3_exec(handle, get_dives, &shearwater_cloud_dive, &state, &err);
|
||||
free_parser_state(&state);
|
||||
|
||||
if (retval != SQLITE_OK) {
|
||||
fprintf(stderr, "Database query failed '%s'.\n", url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "isocialnetworkintegration.h"
|
||||
|
||||
//Hack for moc.
|
||||
ISocialNetworkIntegration::ISocialNetworkIntegration(QObject* parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef ISOCIALNETWORKINTEGRATION_H
|
||||
#define ISOCIALNETWORKINTEGRATION_H
|
||||
|
||||
#include <QtPlugin>
|
||||
|
||||
/* This Interface represents a Plugin for Social Network integration,
|
||||
* with it you may be able to create plugins for facebook, instagram,
|
||||
* twitpic, google plus and any other thing you may imagine.
|
||||
*
|
||||
* We bundle facebook integration as an example.
|
||||
*/
|
||||
|
||||
class ISocialNetworkIntegration : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ISocialNetworkIntegration(QObject* parent = 0);
|
||||
|
||||
/*!
|
||||
* @name socialNetworkName
|
||||
* @brief The name of this social network
|
||||
* @return The name of this social network
|
||||
*
|
||||
* The name of this social network will be used to populate the Menu to toggle states
|
||||
* between connected/disconnected, and also submit stuff to it.
|
||||
*/
|
||||
virtual QString socialNetworkName() const = 0;
|
||||
|
||||
/*!
|
||||
* @name socialNetworkIcon
|
||||
* @brief The icon of this social network
|
||||
* @return The icon of this social network
|
||||
*
|
||||
* The icon of this social network will be used to populate the menu, and can also be
|
||||
* used on a toolbar if requested.
|
||||
*/
|
||||
virtual QString socialNetworkIcon() const = 0;
|
||||
|
||||
/*!
|
||||
* @name isConnected
|
||||
* @brief returns true if connected to this social network, false otherwise
|
||||
* @return true if connected to this social network, false otherwise
|
||||
*/
|
||||
virtual bool isConnected() = 0;
|
||||
|
||||
/*!
|
||||
* @name requestLogin
|
||||
* @brief try to login on this social network.
|
||||
*
|
||||
* Try to login on this social network. All widget implementation that
|
||||
* manages login should be done inside this function.
|
||||
*/
|
||||
virtual void requestLogin() = 0;
|
||||
|
||||
/*!
|
||||
* @name requestLogoff
|
||||
* @brief tries to logoff from this social network
|
||||
*
|
||||
* Try to logoff from this social network.
|
||||
*/
|
||||
virtual void requestLogoff() = 0;
|
||||
|
||||
/*!
|
||||
* @name uploadCurrentDive
|
||||
* @brief send the current dive info to the Social Network
|
||||
*
|
||||
* Should format all the options and pixmaps from the current dive
|
||||
* to update to the social network. All widget stuff related to sendint
|
||||
* dive information should be executed inside this function.
|
||||
*/
|
||||
virtual void requestUpload() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1069,14 +1069,17 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
|
||||
break;
|
||||
case DC_EVENT_DEVINFO:
|
||||
if (dc_descriptor_get_model(devdata->descriptor) != devinfo->model) {
|
||||
fprintf(stderr, "EVENT_DEVINFO gave us the correct detected product (model %d instead of %d)\n",
|
||||
devinfo->model, dc_descriptor_get_model(devdata->descriptor));
|
||||
dc_descriptor_t *better_descriptor = get_descriptor(dc_descriptor_get_type(devdata->descriptor), devinfo->model);
|
||||
if (better_descriptor != NULL) {
|
||||
fprintf(stderr, "EVENT_DEVINFO gave us a different detected product (model %d instead of %d), which we are using now.\n",
|
||||
devinfo->model, dc_descriptor_get_model(devdata->descriptor));
|
||||
devdata->descriptor = better_descriptor;
|
||||
devdata->product = dc_descriptor_get_product(better_descriptor);
|
||||
devdata->vendor = dc_descriptor_get_vendor(better_descriptor);
|
||||
devdata->model = str_printf("%s %s", devdata->vendor, devdata->product);
|
||||
} else {
|
||||
fprintf(stderr, "EVENT_DEVINFO gave us a different detected product (model %d instead of %d), but that one is unknown.\n",
|
||||
devinfo->model, dc_descriptor_get_model(devdata->descriptor));
|
||||
}
|
||||
}
|
||||
dev_info(devdata, translate("gettextFromC", "model=%s firmware=%u serial=%u"),
|
||||
|
||||
@ -2139,19 +2139,19 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *tabl
|
||||
|
||||
/* Recording the starting battery status to extra data */
|
||||
if (battery_start.volt1) {
|
||||
size_t size = snprintf(NULL, 0, "%dmV (%d%%)", battery_start.volt1, battery_start.percent1) + 1;
|
||||
size_t stringsize = snprintf(NULL, 0, "%dmV (%d%%)", battery_start.volt1, battery_start.percent1) + 1;
|
||||
char *ptr = malloc(size);
|
||||
|
||||
if (ptr) {
|
||||
snprintf(ptr, size, "%dmV (%d%%)", battery_start.volt1, battery_start.percent1);
|
||||
snprintf(ptr, stringsize, "%dmV (%d%%)", battery_start.volt1, battery_start.percent1);
|
||||
add_extra_data(state.cur_dc, "Battery 1 (start)", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
size = snprintf(NULL, 0, "%dmV (%d%%)", battery_start.volt2, battery_start.percent2) + 1;
|
||||
ptr = malloc(size);
|
||||
stringsize = snprintf(NULL, 0, "%dmV (%d%%)", battery_start.volt2, battery_start.percent2) + 1;
|
||||
ptr = malloc(stringsize);
|
||||
if (ptr) {
|
||||
snprintf(ptr, size, "%dmV (%d%%)", battery_start.volt2, battery_start.percent2);
|
||||
snprintf(ptr, stringsize, "%dmV (%d%%)", battery_start.volt2, battery_start.percent2);
|
||||
add_extra_data(state.cur_dc, "Battery 2 (start)", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
@ -2159,19 +2159,19 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *tabl
|
||||
|
||||
/* Recording the ending battery status to extra data */
|
||||
if (battery_end.volt1) {
|
||||
size_t size = snprintf(NULL, 0, "%dmV (%d%%)", battery_end.volt1, battery_end.percent1) + 1;
|
||||
char *ptr = malloc(size);
|
||||
size_t stringsize = snprintf(NULL, 0, "%dmV (%d%%)", battery_end.volt1, battery_end.percent1) + 1;
|
||||
char *ptr = malloc(stringsize);
|
||||
|
||||
if (ptr) {
|
||||
snprintf(ptr, size, "%dmV (%d%%)", battery_end.volt1, battery_end.percent1);
|
||||
snprintf(ptr, stringsize, "%dmV (%d%%)", battery_end.volt1, battery_end.percent1);
|
||||
add_extra_data(state.cur_dc, "Battery 1 (end)", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
size = snprintf(NULL, 0, "%dmV (%d%%)", battery_end.volt2, battery_end.percent2) + 1;
|
||||
ptr = malloc(size);
|
||||
stringsize = snprintf(NULL, 0, "%dmV (%d%%)", battery_end.volt2, battery_end.percent2) + 1;
|
||||
ptr = malloc(stringsize);
|
||||
if (ptr) {
|
||||
snprintf(ptr, size, "%dmV (%d%%)", battery_end.volt2, battery_end.percent2);
|
||||
snprintf(ptr, stringsize, "%dmV (%d%%)", battery_end.volt2, battery_end.percent2);
|
||||
add_extra_data(state.cur_dc, "Battery 2 (end)", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ void init_parser_state(struct parser_state *state)
|
||||
memset(state, 0, sizeof(*state));
|
||||
state->metric = true;
|
||||
state->cur_event.deleted = 1;
|
||||
state->sample_rate = 0;
|
||||
}
|
||||
|
||||
void free_parser_state(struct parser_state *state)
|
||||
|
||||
@ -55,6 +55,7 @@ struct parser_state {
|
||||
int cur_cylinder_index, cur_ws_index;
|
||||
int lastcylinderindex, next_o2_sensor;
|
||||
int o2pressure_sensor;
|
||||
int sample_rate;
|
||||
struct extra_data cur_extra_data;
|
||||
struct units xml_parsing_units;
|
||||
struct dive_table *target_table; /* non-owning */
|
||||
|
||||
@ -715,7 +715,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
||||
bottom_time = clock = previous_point_time = dive->dc.sample[dive->dc.samples - 1].time.seconds;
|
||||
|
||||
current_cylinder = get_cylinderid_at_time(dive, &dive->dc, sample->time);
|
||||
// FIXME: This needs a function to find the divemode at the end of the dive like in
|
||||
// Find the divemode at the end of the dive
|
||||
const struct event *ev = NULL;
|
||||
divemode = UNDEF_COMP_TYPE;
|
||||
divemode = get_current_divemode(&dive->dc, bottom_time, &ev, &divemode);
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "pluginmanager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QPluginLoader>
|
||||
#include <QDebug>
|
||||
|
||||
static QList<ISocialNetworkIntegration*> _socialNetworks;
|
||||
|
||||
// no point in including dive.h for this
|
||||
extern int verbose;
|
||||
|
||||
PluginManager& PluginManager::instance()
|
||||
{
|
||||
static PluginManager self;
|
||||
return self;
|
||||
}
|
||||
|
||||
PluginManager::PluginManager()
|
||||
{
|
||||
}
|
||||
|
||||
void PluginManager::loadPlugins()
|
||||
{
|
||||
QDir pluginsDir(qApp->applicationDirPath());
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
|
||||
pluginsDir.cdUp();
|
||||
#elif defined(Q_OS_MAC)
|
||||
if (pluginsDir.dirName() == "MacOS") {
|
||||
pluginsDir.cdUp();
|
||||
pluginsDir.cdUp();
|
||||
pluginsDir.cdUp();
|
||||
}
|
||||
#endif
|
||||
pluginsDir.cd("plugins");
|
||||
|
||||
if (verbose)
|
||||
qDebug() << "Plugins Directory: " << pluginsDir;
|
||||
|
||||
foreach (const QString& fileName, pluginsDir.entryList(QDir::Files)) {
|
||||
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
|
||||
QObject *plugin = loader.instance();
|
||||
if(!plugin)
|
||||
continue;
|
||||
|
||||
if (ISocialNetworkIntegration *social = qobject_cast<ISocialNetworkIntegration*>(plugin)) {
|
||||
qDebug() << "Adding the plugin: " << social->socialNetworkName();
|
||||
_socialNetworks.push_back(social);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef PLUGINMANAGER_H
|
||||
#define PLUGINMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "isocialnetworkintegration.h"
|
||||
|
||||
class PluginManager {
|
||||
public:
|
||||
static PluginManager& instance();
|
||||
void loadPlugins();
|
||||
private:
|
||||
PluginManager();
|
||||
PluginManager(const PluginManager&);
|
||||
PluginManager& operator=(const PluginManager&);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -22,12 +22,6 @@ typedef struct
|
||||
double phe_threshold;
|
||||
} partial_pressure_graphs_t;
|
||||
|
||||
typedef struct {
|
||||
const char *access_token;
|
||||
const char *user_id;
|
||||
const char *album_id;
|
||||
} facebook_prefs_t;
|
||||
|
||||
typedef struct {
|
||||
enum taxonomy_category category[3];
|
||||
} geocoding_prefs_t;
|
||||
@ -111,9 +105,6 @@ struct preferences {
|
||||
double mobile_scale;
|
||||
bool show_developer;
|
||||
|
||||
// ********** Facebook **********
|
||||
facebook_prefs_t facebook;
|
||||
|
||||
// ********** General **********
|
||||
bool auto_recalculate_thumbnails;
|
||||
bool extract_video_thumbnails;
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
#define MAX_PROFILE_DECO 7200
|
||||
|
||||
extern int ascent_velocity(int depth, int avg_depth, int bottom_time);
|
||||
|
||||
struct dive *current_dive = NULL;
|
||||
unsigned int dc_number = 0;
|
||||
@ -914,13 +915,10 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
|
||||
/* calculate DECO STOP / TTS / NDL */
|
||||
static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, struct plot_data *entry, struct gasmix gasmix, double surface_pressure,enum divemode_t divemode)
|
||||
{
|
||||
/* FIXME: This should be configurable */
|
||||
/* should this be configurable? */
|
||||
/* ascent speed up to first deco stop */
|
||||
const int ascent_s_per_step = 1;
|
||||
const int ascent_mm_per_step = 200; /* 12 m/min */
|
||||
/* ascent speed between deco stops */
|
||||
const int ascent_s_per_deco_step = 1;
|
||||
const int ascent_mm_per_deco_step = 16; /* 1 m/min */
|
||||
/* how long time steps in deco calculations? */
|
||||
const int time_stepsize = 60;
|
||||
const int deco_stepsize = 3000;
|
||||
@ -957,7 +955,7 @@ static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, st
|
||||
entry->in_deco_calc = true;
|
||||
|
||||
/* Add segments for movement to stopdepth */
|
||||
for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_step, entry->tts_calc += ascent_s_per_step) {
|
||||
for (; ascent_depth > next_stop; ascent_depth -= ascent_s_per_step * ascent_velocity(ascent_depth, entry->running_sum / entry->sec, 0), entry->tts_calc += ascent_s_per_step) {
|
||||
add_segment(ds, depth_to_bar(ascent_depth, dive),
|
||||
gasmix, ascent_s_per_step, entry->o2pressure.mbar, divemode, prefs.decosac);
|
||||
next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive)),
|
||||
@ -984,7 +982,7 @@ static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, st
|
||||
|
||||
if (deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth,dive)), surface_pressure, dive, 1) <= next_stop) {
|
||||
/* move to the next stop and add the travel between stops */
|
||||
for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_deco_step, entry->tts_calc += ascent_s_per_deco_step)
|
||||
for (; ascent_depth > next_stop; ascent_depth -= ascent_s_per_deco_step * ascent_velocity(ascent_depth, entry->running_sum / entry->sec, 0), entry->tts_calc += ascent_s_per_deco_step)
|
||||
add_segment(ds, depth_to_bar(ascent_depth, dive),
|
||||
gasmix, ascent_s_per_deco_step, entry->o2pressure.mbar, divemode, prefs.decosac);
|
||||
ascent_depth = next_stop;
|
||||
|
||||
@ -52,15 +52,18 @@ extern "C" {
|
||||
|
||||
void BLEObject::serviceStateChanged(QLowEnergyService::ServiceState newState)
|
||||
{
|
||||
qDebug() << "serviceStateChanged";
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << "serviceStateChanged";
|
||||
auto service = qobject_cast<QLowEnergyService*>(sender());
|
||||
if (service)
|
||||
qDebug() << service->serviceUuid() << newState;
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << service->serviceUuid() << newState;
|
||||
}
|
||||
|
||||
void BLEObject::characteristcStateChanged(const QLowEnergyCharacteristic &c, const QByteArray &value)
|
||||
{
|
||||
qDebug() << QTime::currentTime() << "packet RECV" << value.toHex();
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << QTime::currentTime() << "packet RECV" << value.toHex();
|
||||
if (IS_HW(device)) {
|
||||
if (c.uuid() == hwAllCharacteristics[HW_OSTC_BLE_DATA_TX]) {
|
||||
hw_credit--;
|
||||
@ -84,14 +87,15 @@ void BLEObject::characteristicWritten(const QLowEnergyCharacteristic &c, const Q
|
||||
isCharacteristicWritten = true;
|
||||
}
|
||||
} else {
|
||||
if (debugCounter < DEBUG_THRESHOLD)
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << "BLEObject::characteristicWritten";
|
||||
}
|
||||
}
|
||||
|
||||
void BLEObject::writeCompleted(const QLowEnergyDescriptor&, const QByteArray&)
|
||||
{
|
||||
qDebug() << "BLE write completed";
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << "BLE write completed";
|
||||
desc_written++;
|
||||
}
|
||||
|
||||
@ -178,7 +182,8 @@ dc_status_t BLEObject::write(const void *data, size_t size, size_t *actual)
|
||||
continue;
|
||||
|
||||
QByteArray bytes((const char *)data, (int) size);
|
||||
qDebug() << QTime::currentTime() << "packet SEND" << bytes.toHex();
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << QTime::currentTime() << "packet SEND" << bytes.toHex();
|
||||
|
||||
QLowEnergyService::WriteMode mode;
|
||||
mode = (c.properties() & QLowEnergyCharacteristic::WriteNoResponse) ?
|
||||
@ -202,7 +207,8 @@ dc_status_t BLEObject::read(void *data, size_t size, size_t *actual)
|
||||
if (list.isEmpty())
|
||||
return DC_STATUS_IO;
|
||||
|
||||
qDebug() << QTime::currentTime() << "packet WAIT";
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << QTime::currentTime() << "packet WAIT";
|
||||
|
||||
WAITFOR(!receivedPackets.isEmpty(), timeout);
|
||||
if (receivedPackets.isEmpty())
|
||||
@ -225,7 +231,8 @@ dc_status_t BLEObject::read(void *data, size_t size, size_t *actual)
|
||||
if (actual)
|
||||
*actual += packet.size();
|
||||
|
||||
qDebug() << QTime::currentTime() << "packet READ" << packet.toHex();
|
||||
if (verbose > 2 || debugCounter < DEBUG_THRESHOLD)
|
||||
qDebug() << QTime::currentTime() << "packet READ" << packet.toHex();
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -972,16 +972,12 @@ QString get_trip_date_string(timestamp_t when, int nr, bool getday)
|
||||
utc_mkdate(when, &tm);
|
||||
QDateTime localTime = QDateTime::fromMSecsSinceEpoch(1000*when,Qt::UTC);
|
||||
localTime.setTimeSpec(Qt::UTC);
|
||||
QString ret ;
|
||||
|
||||
QString suffix = " " + gettextFromC::tr("(%n dive(s))", "", nr);
|
||||
if (getday) {
|
||||
ret = localTime.date().toString(prefs.date_format) + suffix;
|
||||
} else {
|
||||
ret = localTime.date().toString("MMM yyyy") + suffix;
|
||||
}
|
||||
return ret;
|
||||
|
||||
if (getday)
|
||||
return loc.toString(localTime, prefs.date_format) + suffix;
|
||||
else
|
||||
return loc.toString(localTime, "MMM yyyy") + suffix;
|
||||
}
|
||||
|
||||
static QMutex hashOfMutex;
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <QtBluetooth/QBluetoothAddress>
|
||||
#include <QtBluetooth/QBluetoothSocket>
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
@ -114,34 +115,6 @@ static dc_status_t qt_serial_open(qt_serial_t **io, dc_context_t*, const char* d
|
||||
timer.setSingleShot(true);
|
||||
loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
// First try to connect on RFCOMM channel 1. This is the default channel for most devices
|
||||
QBluetoothAddress remoteDeviceAddress(devaddr);
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, 1, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
timer.start(msec);
|
||||
loop.exec();
|
||||
|
||||
if (serial_port->socket->state() == QBluetoothSocket::ConnectingState) {
|
||||
// It seems that the connection on channel 1 took more than expected. Wait another 15 seconds
|
||||
qDebug() << "The connection on RFCOMM channel number 1 took more than expected. Wait another 15 seconds.";
|
||||
timer.start(3 * msec);
|
||||
loop.exec();
|
||||
} else if (serial_port->socket->state() == QBluetoothSocket::UnconnectedState) {
|
||||
// Try to connect on channel number 5. Maybe this is a Shearwater Petrel2 device.
|
||||
qDebug() << "Connection on channel 1 failed. Trying on channel number 5.";
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, 5, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
timer.start(msec);
|
||||
loop.exec();
|
||||
|
||||
if (serial_port->socket->state() == QBluetoothSocket::ConnectingState) {
|
||||
// It seems that the connection on channel 5 took more than expected. Wait another 15 seconds
|
||||
qDebug() << "The connection on RFCOMM channel number 5 took more than expected. Wait another 15 seconds.";
|
||||
timer.start(3 * msec);
|
||||
loop.exec();
|
||||
}
|
||||
}
|
||||
#elif defined(Q_OS_ANDROID) || (QT_VERSION >= 0x050500 && defined(Q_OS_MAC))
|
||||
// Try to connect to the device using the uuid of the Serial Port Profile service
|
||||
QBluetoothAddress remoteDeviceAddress(devaddr);
|
||||
#if defined(Q_OS_ANDROID)
|
||||
QBluetoothUuid uuid = QBluetoothUuid(QUuid("{00001101-0000-1000-8000-00805f9b34fb}"));
|
||||
@ -149,7 +122,10 @@ static dc_status_t qt_serial_open(qt_serial_t **io, dc_context_t*, const char* d
|
||||
serial_port->socket->setPreferredSecurityFlags(QBluetooth::NoSecurity);
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, uuid, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
#else
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, 1, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
QBluetoothLocalDevice dev;
|
||||
QBluetoothUuid uuid = QBluetoothUuid(QUuid("{00001101-0000-1000-8000-00805f9b34fb}"));
|
||||
qDebug() << "Linux Bluez connecting to Uuid" << uuid;
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, uuid, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
#endif
|
||||
timer.start(msec);
|
||||
loop.exec();
|
||||
@ -161,7 +137,7 @@ static dc_status_t qt_serial_open(qt_serial_t **io, dc_context_t*, const char* d
|
||||
timer.start(4 * msec);
|
||||
loop.exec();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (serial_port->socket->state() != QBluetoothSocket::ConnectedState) {
|
||||
|
||||
// Get the latest error and try to match it with one from libdivecomputer
|
||||
|
||||
@ -1040,7 +1040,7 @@ static int get_authorship(git_repository *repo, git_signature **authorp)
|
||||
/* try to fetch the user info from the OS, otherwise use default values. */
|
||||
struct user_info user = { .name = NULL, .email = NULL };
|
||||
subsurface_user_info(&user);
|
||||
if (!user.name)
|
||||
if (!user.name || !*user.name)
|
||||
user.name = strdup("Subsurface");
|
||||
if (!user.email)
|
||||
user.email = strdup("subsurface-app-account@subsurface-divelog.org");
|
||||
|
||||
@ -156,7 +156,7 @@ static int serial_ftdi_open_device (struct ftdi_context *ftdi_ctx)
|
||||
0xF680, // Suunto
|
||||
0x87D0, // Cressi (Leonardo)
|
||||
};
|
||||
int num_accepted_pids = 6;
|
||||
int num_accepted_pids = sizeof(accepted_pids) / sizeof(accepted_pids[0]);
|
||||
int i, pid, ret;
|
||||
for (i = 0; i < num_accepted_pids; i++) {
|
||||
pid = accepted_pids[i];
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include "qPrefDisplay.h"
|
||||
#include "qPrefDiveComputer.h"
|
||||
#include "qPrefDivePlanner.h"
|
||||
#include "qPrefFacebook.h"
|
||||
#include "qPrefGeneral.h"
|
||||
#include "qPrefGeocoding.h"
|
||||
#include "qPrefLanguage.h"
|
||||
@ -51,7 +50,6 @@ void qPref::loadSync(bool doSync)
|
||||
qPrefDisplay::loadSync(doSync);
|
||||
qPrefDiveComputer::loadSync(doSync);
|
||||
qPrefDivePlanner::loadSync(doSync);
|
||||
qPrefFacebook::loadSync(doSync);
|
||||
qPrefGeneral::loadSync(doSync);
|
||||
qPrefGeocoding::loadSync(doSync);
|
||||
qPrefLanguage::loadSync(doSync);
|
||||
@ -76,7 +74,6 @@ void qPref::registerQML(QQmlEngine *engine)
|
||||
ct->setContextProperty("PrefDisplay", qPrefDisplay::instance());
|
||||
ct->setContextProperty("PrefDiveComputer", qPrefDiveComputer::instance());
|
||||
ct->setContextProperty("PrefDivePlanner", qPrefDivePlanner::instance());
|
||||
ct->setContextProperty("PrefFacebook", qPrefFacebook::instance());
|
||||
ct->setContextProperty("PrefGeneral", qPrefGeneral::instance());
|
||||
ct->setContextProperty("PrefGeocoding", qPrefGeocoding::instance());
|
||||
ct->setContextProperty("PrefLanguage", qPrefLanguage::instance());
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "qPrefFacebook.h"
|
||||
#include "qPrefPrivate.h"
|
||||
|
||||
static const QString group = QStringLiteral("WebApps/Facebook");
|
||||
|
||||
qPrefFacebook::qPrefFacebook(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
qPrefFacebook*qPrefFacebook::instance()
|
||||
{
|
||||
static qPrefFacebook *self = new qPrefFacebook;
|
||||
return self;
|
||||
}
|
||||
|
||||
void qPrefFacebook::loadSync(bool doSync)
|
||||
{
|
||||
// Empty, because FB probs are not loaded/synced to disk
|
||||
}
|
||||
|
||||
void qPrefFacebook::set_access_token(const QString &value)
|
||||
{
|
||||
if (value != prefs.facebook.access_token) {
|
||||
qPrefPrivate::copy_txt(&prefs.facebook.access_token, value);
|
||||
emit instance()->access_tokenChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
void qPrefFacebook::set_album_id(const QString &value)
|
||||
{
|
||||
if (value != prefs.facebook.album_id) {
|
||||
qPrefPrivate::copy_txt(&prefs.facebook.album_id, value);
|
||||
emit instance()->album_idChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
void qPrefFacebook::set_user_id(const QString &value)
|
||||
{
|
||||
if (value != prefs.facebook.user_id) {
|
||||
qPrefPrivate::copy_txt(&prefs.facebook.user_id, value);
|
||||
emit instance()->user_idChanged(value);
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef QPREFSFACEBOOK_H
|
||||
#define QPREFSFACEBOOK_H
|
||||
#include "core/pref.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
|
||||
class qPrefFacebook : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString access_token READ access_token WRITE set_access_token NOTIFY access_tokenChanged);
|
||||
Q_PROPERTY(QString album_id READ album_id WRITE set_album_id NOTIFY album_idChanged);
|
||||
Q_PROPERTY(QString user_id READ user_id WRITE set_user_id NOTIFY user_idChanged);
|
||||
|
||||
public:
|
||||
qPrefFacebook(QObject *parent = NULL);
|
||||
static qPrefFacebook *instance();
|
||||
|
||||
// Load/Sync local settings (disk) and struct preference
|
||||
static void loadSync(bool doSync);
|
||||
static void load() {loadSync(false); }
|
||||
static void sync() {loadSync(true); }
|
||||
|
||||
public:
|
||||
static QString access_token() { return prefs.facebook.access_token; }
|
||||
static QString album_id() { return prefs.facebook.album_id; }
|
||||
static QString user_id() { return prefs.facebook.user_id; }
|
||||
|
||||
public slots:
|
||||
static void set_access_token(const QString& value);
|
||||
static void set_album_id(const QString& value);
|
||||
static void set_user_id(const QString& value);
|
||||
|
||||
signals:
|
||||
void access_tokenChanged(const QString& value);
|
||||
void album_idChanged(const QString& value);
|
||||
void user_idChanged(const QString& value);
|
||||
|
||||
private:
|
||||
static void disk_access_token(bool doSync);
|
||||
static void disk_album_id(bool doSync);
|
||||
static void disk_user_id(bool doSync);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -76,11 +76,6 @@ struct preferences default_prefs = {
|
||||
.pscr_ratio = 100,
|
||||
.show_pictures_in_profile = true,
|
||||
.tankbar = false,
|
||||
.facebook = {
|
||||
.user_id = NULL,
|
||||
.album_id = NULL,
|
||||
.access_token = NULL
|
||||
},
|
||||
.defaultsetpoint = 1100,
|
||||
.geocoding = {
|
||||
.category = { 0 }
|
||||
@ -311,9 +306,6 @@ void copy_prefs(struct preferences *src, struct preferences *dest)
|
||||
dest->cloud_storage_password = copy_string(src->cloud_storage_password);
|
||||
dest->cloud_storage_email = copy_string(src->cloud_storage_email);
|
||||
dest->cloud_storage_email_encoded = copy_string(src->cloud_storage_email_encoded);
|
||||
dest->facebook.access_token = copy_string(src->facebook.access_token);
|
||||
dest->facebook.user_id = copy_string(src->facebook.user_id);
|
||||
dest->facebook.album_id = copy_string(src->facebook.album_id);
|
||||
dest->ffmpeg_executable = copy_string(src->ffmpeg_executable);
|
||||
}
|
||||
|
||||
|
||||
12
core/unix.c
@ -38,8 +38,18 @@ void subsurface_user_info(struct user_info *user)
|
||||
const char *username = getenv("USER");
|
||||
|
||||
if (pwd) {
|
||||
if (!empty_string(pwd->pw_gecos))
|
||||
if (!empty_string(pwd->pw_gecos)) {
|
||||
user->name = strdup(pwd->pw_gecos);
|
||||
// We only want the name, not the office or phone number
|
||||
char *c = user->name;
|
||||
while (*c) {
|
||||
if (*c == ',') {
|
||||
*c = '\0';
|
||||
break;
|
||||
}
|
||||
++c;
|
||||
}
|
||||
}
|
||||
if (!username)
|
||||
username = pwd->pw_name;
|
||||
}
|
||||
|
||||
@ -50,16 +50,20 @@ static char *utf16_to_utf8_fl(const wchar_t *utf16, char *file, int line)
|
||||
assert(file != NULL);
|
||||
assert(line);
|
||||
/* estimate buffer size */
|
||||
const int sz = wcslen(utf16) + 1;
|
||||
const int sz = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL);
|
||||
if (!sz) {
|
||||
fprintf(stderr, "%s:%d: cannot estimate buffer size\n", file, line);
|
||||
return NULL;
|
||||
}
|
||||
char *utf8 = (char *)malloc(sz);
|
||||
if (!utf8) {
|
||||
fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz);
|
||||
fprintf(stderr, "%s:%d: cannot allocate buffer of size: %d\n", file, line, sz);
|
||||
return NULL;
|
||||
}
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, utf16, -1, utf8, sz, NULL, NULL)) {
|
||||
return utf8;
|
||||
}
|
||||
fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string.");
|
||||
fprintf(stderr, "%s:%d: cannot convert string\n", file, line);
|
||||
free((void *)utf8);
|
||||
return NULL;
|
||||
}
|
||||
@ -78,12 +82,12 @@ static wchar_t *utf8_to_utf16_fl(const char *utf8, char *file, int line)
|
||||
const int sz = strlen(utf8) + 1;
|
||||
wchar_t *utf16 = (wchar_t *)malloc(sizeof(wchar_t) * sz);
|
||||
if (!utf16) {
|
||||
fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz);
|
||||
fprintf(stderr, "%s:%d: cannot allocate buffer of size: %d\n", file, line, sz);
|
||||
return NULL;
|
||||
}
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, sz))
|
||||
return utf16;
|
||||
fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string.");
|
||||
fprintf(stderr, "%s:%d: cannot convert string\n", file, line);
|
||||
free((void *)utf16);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ static timestamp_t extract_timestamp_from_attributes(const xmlNode *node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static timestamp_t extract_timestamp(const xmlNode *node)
|
||||
static timestamp_t extract_timestamp(const xmlNode *firstnode)
|
||||
{
|
||||
// We use a private stack, so that we can return in one go without
|
||||
// having to unwind the call-stack. We only recurse to a fixed depth,
|
||||
@ -80,7 +80,7 @@ static timestamp_t extract_timestamp(const xmlNode *node)
|
||||
// This can be increased on demand.
|
||||
static const int max_recursion_depth = 16;
|
||||
const xmlNode *stack[max_recursion_depth];
|
||||
stack[0] = node;
|
||||
stack[0] = firstnode;
|
||||
int stack_depth = 1;
|
||||
|
||||
while (stack_depth > 0) {
|
||||
|
||||
@ -7,20 +7,12 @@ if(BTSUPPORT)
|
||||
set(BT_SRC_FILES btdeviceselectiondialog.cpp)
|
||||
endif()
|
||||
|
||||
if (FBSUPPORT)
|
||||
add_definitions(-DFBSUPPORT)
|
||||
endif()
|
||||
|
||||
|
||||
include_directories(.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
add_subdirectory(preferences)
|
||||
if(NOT DISABLE_PLUGINS)
|
||||
add_subdirectory(plugins)
|
||||
endif()
|
||||
|
||||
set (SUBSURFACE_UI
|
||||
about.ui
|
||||
|
||||
@ -21,7 +21,7 @@ SubsurfaceAbout::SubsurfaceAbout(QWidget *parent, Qt::WindowFlags f) : QDialog(p
|
||||
"Subsurface %1 </span><br><br>"
|
||||
"Multi-platform divelog software<br>"
|
||||
"<span style='font-size: 8pt'>"
|
||||
"Linus Torvalds, Dirk Hohndel, Tomaz Canabrava, and others, 2011-2018"
|
||||
"Linus Torvalds, Dirk Hohndel, Tomaz Canabrava, and others, 2011-2019"
|
||||
"</span>").arg(versionString));
|
||||
|
||||
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);
|
||||
|
||||
@ -600,7 +600,7 @@ ShiftTime::ShiftTime(const QVector<dive *> &changedDives, int amount)
|
||||
void ShiftTime::redoit()
|
||||
{
|
||||
for (dive *d: diveList)
|
||||
d->when -= timeChanged;
|
||||
d->when += timeChanged;
|
||||
|
||||
// Changing times may have unsorted the dive table
|
||||
sort_table(&dive_table);
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Which components would you like to copy</string>
|
||||
<string>Which components would you like to copy?</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
@ -67,34 +67,6 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="divesite">
|
||||
<property name="text">
|
||||
<string>Dive site</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="suit">
|
||||
<property name="text">
|
||||
<string>Suit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="visibility">
|
||||
<property name="text">
|
||||
<string>Visibility</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="notes">
|
||||
<property name="text">
|
||||
<string>Notes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="tags">
|
||||
<property name="text">
|
||||
@ -109,6 +81,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="divesite">
|
||||
<property name="text">
|
||||
<string>Dive site</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="visibility">
|
||||
<property name="text">
|
||||
<string>Visibility</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="cylinders">
|
||||
<property name="text">
|
||||
@ -116,6 +102,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="buddy">
|
||||
<property name="text">
|
||||
<string>Buddy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="notes">
|
||||
<property name="text">
|
||||
<string>Notes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="divemaster">
|
||||
<property name="text">
|
||||
@ -123,10 +123,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="buddy">
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="suit">
|
||||
<property name="text">
|
||||
<string>Buddy</string>
|
||||
<string>Suit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -140,6 +140,19 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>You can paste these to another dive or as text to another application.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
|
||||
@ -94,6 +94,8 @@ void DiveLogExportDialog::showExplanation()
|
||||
ui->description->setText(tr("Write depths of images to file."));
|
||||
} else if (ui->exportTeX->isChecked()) {
|
||||
ui->description->setText(tr("Write dive as TeX macros to file."));
|
||||
} else if (ui->exportProfile->isChecked()) {
|
||||
ui->description->setText(tr("Write the profile image as PNG file."));
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,6 +169,10 @@ void DiveLogExportDialog::on_buttonBox_accepted()
|
||||
filename = QFileDialog::getSaveFileName(this, tr("Export to TeX file"), lastDir, tr("TeX files") + " (*.tex)");
|
||||
if (!filename.isNull() && !filename.isEmpty())
|
||||
export_TeX(qPrintable(filename), ui->exportSelected->isChecked());
|
||||
} else if (ui->exportProfile->isChecked()) {
|
||||
filename = QFileDialog::getSaveFileName(this, tr("Save profile image"), lastDir);
|
||||
if (!filename.isNull() && !filename.isEmpty())
|
||||
exportProfile(qPrintable(filename), ui->exportSelected->isChecked());
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@ -227,6 +233,36 @@ void DiveLogExportDialog::export_depths(const char *filename, const bool selecte
|
||||
free_buffer(&buf);
|
||||
}
|
||||
|
||||
void DiveLogExportDialog::exportProfile(QString filename, const bool selected_only)
|
||||
{
|
||||
struct dive *dive;
|
||||
int i;
|
||||
int count = 0;
|
||||
if (!filename.endsWith(".png", Qt::CaseInsensitive))
|
||||
filename = filename.append(".png");
|
||||
QFileInfo fi(filename);
|
||||
|
||||
for_each_dive (i, dive) {
|
||||
if (selected_only && !dive->selected)
|
||||
continue;
|
||||
if (count)
|
||||
saveProfile(dive, fi.path() + QDir::separator() + fi.completeBaseName().append(QString("-%1.").arg(count)) + fi.suffix());
|
||||
else
|
||||
saveProfile(dive, filename);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
void DiveLogExportDialog::saveProfile(const struct dive *dive, const QString filename)
|
||||
{
|
||||
ProfileWidget2 *profile = MainWindow::instance()->graphics;
|
||||
profile->plotDive(dive, true, false, true);
|
||||
profile->setToolTipVisibile(false);
|
||||
QPixmap pix = profile->grab();
|
||||
profile->setToolTipVisibile(true);
|
||||
pix.save(filename);
|
||||
}
|
||||
|
||||
void DiveLogExportDialog::export_TeX(const char *filename, const bool selected_only)
|
||||
{
|
||||
FILE *f;
|
||||
@ -275,14 +311,7 @@ void DiveLogExportDialog::export_TeX(const char *filename, const bool selected_o
|
||||
if (selected_only && !dive->selected)
|
||||
continue;
|
||||
|
||||
ProfileWidget2 *profile = MainWindow::instance()->graphics;
|
||||
profile->plotDive(dive, true);
|
||||
profile->setToolTipVisibile(false);
|
||||
QPixmap pix = QPixmap::grabWidget(profile);
|
||||
profile->setToolTipVisibile(true);
|
||||
pix.save(texdir.filePath(QString("profile%1.png").arg(dive->number)));
|
||||
|
||||
|
||||
saveProfile(dive, texdir.filePath(QString("profile%1.png").arg(dive->number)));
|
||||
struct tm tm;
|
||||
utc_mkdate(dive->when, &tm);
|
||||
|
||||
|
||||
@ -34,6 +34,8 @@ private:
|
||||
void exportHtmlInit(const QString &filename);
|
||||
void export_depths(const char *filename, const bool selected_only);
|
||||
void export_TeX(const char *filename, const bool selected_only);
|
||||
void exportProfile(QString filename, const bool selected_only);
|
||||
void saveProfile(const struct dive *dive, const QString filename);
|
||||
};
|
||||
|
||||
#endif // DIVELOGEXPORTDIALOG_H
|
||||
|
||||
@ -181,6 +181,16 @@
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="exportProfile">
|
||||
<property name="text">
|
||||
<string>Dive profile</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">exportGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="exportWorldMap">
|
||||
<property name="text">
|
||||
|
||||
@ -22,7 +22,6 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent, Qt::WindowFlags f) :
|
||||
previousLast(0),
|
||||
timer(new QTimer(this)),
|
||||
dumpWarningShown(false),
|
||||
ostcFirmwareCheck(0),
|
||||
#if defined (BT_SUPPORT)
|
||||
btd(nullptr),
|
||||
#endif
|
||||
@ -72,10 +71,6 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent, Qt::WindowFlags f) :
|
||||
connect(&thread, SIGNAL(finished()),
|
||||
this, SLOT(onDownloadThreadFinished()), Qt::QueuedConnection);
|
||||
|
||||
//TODO: Don't call mainwindow.
|
||||
MainWindow *w = MainWindow::instance();
|
||||
connect(&thread, SIGNAL(finished()), w, SLOT(refreshDisplay()));
|
||||
|
||||
if (!qPrefDiveComputer::vendor().isEmpty()) {
|
||||
ui.vendor->setCurrentIndex(ui.vendor->findText(qPrefDiveComputer::vendor()));
|
||||
productModel.setStringList(productList[qPrefDiveComputer::vendor()]);
|
||||
@ -412,7 +407,7 @@ void DownloadFromDCWidget::on_downloadCancelRetryButton_clicked()
|
||||
if ((product == "OSTC 3" || product == "OSTC 3+" || product == "OSTC cR" ||
|
||||
product == "OSTC Sport" || product == "OSTC 4" || product == "OSTC Plus") &&
|
||||
!data->saveDump()) {
|
||||
ostcFirmwareCheck = new OstcFirmwareCheck(product);
|
||||
ostcFirmwareCheck.reset(new OstcFirmwareCheck(product));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QAbstractTableModel>
|
||||
#include <memory>
|
||||
|
||||
#include "core/libdivecomputer.h"
|
||||
#include "desktop-widgets/configuredivecomputerdialog.h"
|
||||
@ -79,7 +80,7 @@ private:
|
||||
void fill_device_list(unsigned int transport);
|
||||
QTimer *timer;
|
||||
bool dumpWarningShown;
|
||||
OstcFirmwareCheck *ostcFirmwareCheck;
|
||||
std::unique_ptr<OstcFirmwareCheck> ostcFirmwareCheck;
|
||||
DiveImportedModel *diveImportedModel;
|
||||
#if defined(BT_SUPPORT)
|
||||
BtDeviceSelectionDialog *btDeviceSelectionDialog;
|
||||
|
||||
@ -93,7 +93,7 @@ struct Dir {
|
||||
double progressFrom, progressTo;
|
||||
};
|
||||
|
||||
QVector<FindMovedImagesDialog::Match> FindMovedImagesDialog::learnImages(const QString &dir, int maxRecursions, QVector<QString> imagePathsIn)
|
||||
QVector<FindMovedImagesDialog::Match> FindMovedImagesDialog::learnImages(const QString &rootdir, int maxRecursions, QVector<QString> imagePathsIn)
|
||||
{
|
||||
QMap<QString, ImageMatch> matches;
|
||||
|
||||
@ -112,7 +112,7 @@ QVector<FindMovedImagesDialog::Match> FindMovedImagesDialog::learnImages(const Q
|
||||
|
||||
QVector<QVector<Dir>> stack; // Use a stack to recurse into directories
|
||||
stack.reserve(maxRecursions + 1);
|
||||
stack.append({ { dir, 0.0, 1.0 } });
|
||||
stack.append({ { rootdir, 0.0, 1.0 } });
|
||||
while (!stack.isEmpty()) {
|
||||
if (stack.last().isEmpty()) {
|
||||
stack.removeLast();
|
||||
|
||||
@ -22,10 +22,8 @@
|
||||
#include "core/divesitehelpers.h"
|
||||
#include "core/gettextfromc.h"
|
||||
#include "core/git-access.h"
|
||||
#include "core/isocialnetworkintegration.h"
|
||||
#include "core/import-csv.h"
|
||||
#include "core/planner.h"
|
||||
#include "core/pluginmanager.h"
|
||||
#include "core/qthelper.h"
|
||||
#include "core/subsurface-string.h"
|
||||
#include "core/version.h"
|
||||
@ -75,11 +73,6 @@
|
||||
#include "usermanual.h"
|
||||
#endif
|
||||
|
||||
#if defined(FBSUPPORT)
|
||||
#include "plugins/facebook/facebook_integration.h"
|
||||
#include "plugins/facebook/facebookconnectwidget.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
QProgressDialog *progressDialog = nullptr;
|
||||
bool progressDialogCanceled = false;
|
||||
@ -381,63 +374,6 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::setupSocialNetworkMenu()
|
||||
{
|
||||
#ifdef FBSUPPORT
|
||||
connections = new QMenu(tr("Connect to"));
|
||||
FacebookPlugin *facebookPlugin = new FacebookPlugin();
|
||||
QAction *toggle_connection = new QAction(this);
|
||||
QObject *obj = facebookPlugin;
|
||||
toggle_connection->setText(facebookPlugin->socialNetworkName());
|
||||
toggle_connection->setIcon(QIcon(facebookPlugin->socialNetworkIcon()));
|
||||
toggle_connection->setData(QVariant::fromValue(obj));
|
||||
connect(toggle_connection, SIGNAL(triggered()), this, SLOT(socialNetworkRequestConnect()));
|
||||
FacebookManager *fb = FacebookManager::instance();
|
||||
connect(fb, &FacebookManager::justLoggedIn, this, &MainWindow::facebookLoggedIn);
|
||||
connect(fb, &FacebookManager::justLoggedOut, this, &MainWindow::facebookLoggedOut);
|
||||
connect(fb, &FacebookManager::sendMessage, [this](const QString& msg) {
|
||||
statusBar()->showMessage(msg, 10000); // show message for 10 secs on the statusbar.
|
||||
});
|
||||
share_on_fb = new QAction(this);
|
||||
share_on_fb->setText(facebookPlugin->socialNetworkName());
|
||||
share_on_fb->setIcon(QIcon(facebookPlugin->socialNetworkIcon()));
|
||||
share_on_fb->setData(QVariant::fromValue(obj));
|
||||
share_on_fb->setEnabled(false);
|
||||
ui.menuShare_on->addAction(share_on_fb);
|
||||
connections->addAction(toggle_connection);
|
||||
connect(share_on_fb, SIGNAL(triggered()), this, SLOT(socialNetworkRequestUpload()));
|
||||
ui.menuShare_on->addSeparator();
|
||||
ui.menuShare_on->addMenu(connections);
|
||||
ui.menubar->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::facebookLoggedIn()
|
||||
{
|
||||
connections->setTitle(tr("Disconnect from"));
|
||||
share_on_fb->setEnabled(true);
|
||||
}
|
||||
|
||||
void MainWindow::facebookLoggedOut()
|
||||
{
|
||||
connections->setTitle(tr("Connect to"));
|
||||
share_on_fb->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::socialNetworkRequestConnect()
|
||||
{
|
||||
qDebug() << "Requesting connect on the social network";
|
||||
QAction *action = qobject_cast<QAction*>(sender());
|
||||
ISocialNetworkIntegration *plugin = qobject_cast<ISocialNetworkIntegration*>(action->data().value<QObject*>());
|
||||
if (plugin->isConnected())
|
||||
plugin->requestLogoff();
|
||||
else
|
||||
plugin->requestLogin();
|
||||
}
|
||||
|
||||
void MainWindow::socialNetworkRequestUpload()
|
||||
{
|
||||
QAction *action = qobject_cast<QAction*>(sender());
|
||||
ISocialNetworkIntegration *plugin = action->data().value<ISocialNetworkIntegration*>();
|
||||
plugin->requestUpload();
|
||||
}
|
||||
|
||||
void MainWindow::setStateProperties(const QByteArray& state, const PropertyList& tl, const PropertyList& tr, const PropertyList& bl, const PropertyList& br)
|
||||
|
||||
@ -174,11 +174,6 @@ slots:
|
||||
// should only be enabled when the profile's visible.
|
||||
void disableShortcuts(bool disablePaste = true);
|
||||
void enableShortcuts();
|
||||
|
||||
void socialNetworkRequestConnect();
|
||||
void socialNetworkRequestUpload();
|
||||
void facebookLoggedIn();
|
||||
void facebookLoggedOut();
|
||||
void updateVariations(QString);
|
||||
|
||||
|
||||
|
||||
@ -131,18 +131,11 @@
|
||||
<string>&Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuShare_on">
|
||||
<property name="title">
|
||||
<string>Share on</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menu_Edit"/>
|
||||
<addaction name="menuImport"/>
|
||||
<addaction name="menuLog"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuShare_on"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<action name="actionNew">
|
||||
@ -694,11 +687,6 @@
|
||||
<string>Dive Site &Edit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFacebook">
|
||||
<property name="text">
|
||||
<string>Facebook</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCloudOnline">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
@ -1 +0,0 @@
|
||||
add_subdirectory(facebook)
|
||||
@ -1,22 +0,0 @@
|
||||
if (ANDROID)
|
||||
set(FACEBOOK_INTEGRATION "")
|
||||
elseif (${FBSUPPORT})
|
||||
add_definitions(-DFBSUPPORT)
|
||||
set(FACEBOOK_INTEGRATION facebook_integration)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(FACEBOOK_PLUGIN_UI
|
||||
facebookconnectwidget.ui
|
||||
socialnetworksdialog.ui
|
||||
)
|
||||
|
||||
set(FACEBOOK_PLUGIN_SRCS
|
||||
facebook_integration.cpp
|
||||
facebookconnectwidget.cpp
|
||||
)
|
||||
|
||||
qt5_wrap_ui(FACEBOOK_PLUGIN_UI_SRCS ${FACEBOOK_PLUGIN_UI})
|
||||
add_library(facebook_integration STATIC ${FACEBOOK_PLUGIN_SRCS} ${FACEBOOK_PLUGIN_UI_SRCS})
|
||||
target_link_libraries(facebook_integration ${QT_LIBRARIES})
|
||||
add_dependencies(facebook_integration subsurface_corelib)
|
||||
endif()
|
||||
@ -1,43 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "facebook_integration.h"
|
||||
#include "facebookconnectwidget.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
FacebookPlugin::FacebookPlugin(QObject*) :
|
||||
fbConnectWidget(new FacebookConnectWidget())
|
||||
{
|
||||
}
|
||||
|
||||
bool FacebookPlugin::isConnected()
|
||||
{
|
||||
FacebookManager *instance = FacebookManager::instance();
|
||||
return instance->loggedIn();
|
||||
}
|
||||
|
||||
void FacebookPlugin::requestLogin()
|
||||
{
|
||||
fbConnectWidget->exec();
|
||||
}
|
||||
|
||||
void FacebookPlugin::requestLogoff()
|
||||
{
|
||||
FacebookManager::instance()->logout();
|
||||
}
|
||||
|
||||
QString FacebookPlugin::socialNetworkIcon() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString FacebookPlugin::socialNetworkName() const
|
||||
{
|
||||
return tr("Facebook");
|
||||
}
|
||||
|
||||
void FacebookPlugin::requestUpload()
|
||||
{
|
||||
FacebookManager *instance = FacebookManager::instance();
|
||||
if (instance->loggedIn())
|
||||
instance->sendDiveInit();
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef FACEBOOK_INTEGRATION_H
|
||||
#define FACEBOOK_INTEGRATION_H
|
||||
|
||||
#include "core/isocialnetworkintegration.h"
|
||||
#include <QString>
|
||||
|
||||
class FacebookConnectWidget;
|
||||
class SocialNetworkDialog;
|
||||
class FacebookManager;
|
||||
|
||||
class FacebookPlugin : public ISocialNetworkIntegration {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FacebookPlugin(QObject* parent = 0);
|
||||
bool isConnected() override;
|
||||
void requestLogin() override;
|
||||
void requestLogoff() override;
|
||||
QString socialNetworkIcon() const override;
|
||||
QString socialNetworkName() const override;
|
||||
void requestUpload() override;
|
||||
private:
|
||||
FacebookConnectWidget *fbConnectWidget;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,421 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "facebookconnectwidget.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkCookieJar>
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <QHttpMultiPart>
|
||||
#include <QFile>
|
||||
#include <QBuffer>
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
#include <QLoggingCategory>
|
||||
#ifdef USE_WEBENGINE
|
||||
#include <QWebEngineView>
|
||||
#else
|
||||
#include <QWebView>
|
||||
#endif
|
||||
#include "mainwindow.h"
|
||||
#include "profile-widget/profilewidget2.h"
|
||||
|
||||
#include "core/pref.h"
|
||||
#include "core/qthelper.h"
|
||||
#include "core/settings/qPrefFacebook.h"
|
||||
|
||||
#include "ui_socialnetworksdialog.h"
|
||||
#include "ui_facebookconnectwidget.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFacebook, "subsurface.facebook")
|
||||
|
||||
FacebookManager *FacebookManager::instance()
|
||||
{
|
||||
static FacebookManager *self = new FacebookManager();
|
||||
return self;
|
||||
}
|
||||
|
||||
FacebookManager::FacebookManager(QObject *parent) :
|
||||
QObject(parent),
|
||||
manager(new QNetworkAccessManager(this))
|
||||
{
|
||||
// log only in verbose mode
|
||||
QLoggingCategory::setFilterRules(QStringLiteral("subsurface.facebook=%1").arg(verbose ? "true" : "false"));
|
||||
connect(this, &FacebookManager::albumIdReceived, this, &FacebookManager::sendDiveToAlbum);
|
||||
}
|
||||
|
||||
static QString graphApi = QStringLiteral("https://graph.facebook.com/v2.10/");
|
||||
|
||||
QUrl FacebookManager::albumListUrl()
|
||||
{
|
||||
return QUrl("https://graph.facebook.com/me/albums?access_token=" + QString(prefs.facebook.access_token));
|
||||
}
|
||||
|
||||
QUrl FacebookManager::connectUrl() {
|
||||
return QUrl("https://www.facebook.com/dialog/oauth?"
|
||||
"client_id=427722490709000"
|
||||
"&redirect_uri=http://www.facebook.com/connect/login_success.html"
|
||||
"&response_type=token,granted_scopes"
|
||||
"&display=popup"
|
||||
"&scope=publish_actions,user_photos"
|
||||
);
|
||||
}
|
||||
|
||||
bool FacebookManager::loggedIn() {
|
||||
return prefs.facebook.access_token != NULL;
|
||||
}
|
||||
|
||||
void FacebookManager::tryLogin(const QUrl& loginResponse)
|
||||
{
|
||||
qCDebug(lcFacebook) << "Current url call" << loginResponse;
|
||||
QString result = loginResponse.toString();
|
||||
if (!result.contains("access_token")) {
|
||||
qCDebug(lcFacebook) << "Response without access token!";
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.contains("denied_scopes=publish_actions") || result.contains("denied_scopes=user_photos")) {
|
||||
qCDebug(lcFacebook) << "user did not allow us access" << result;
|
||||
return;
|
||||
}
|
||||
|
||||
int from = result.indexOf("access_token=") + strlen("access_token=");
|
||||
int to = result.indexOf("&expires_in");
|
||||
QString securityToken = result.mid(from, to-from);
|
||||
|
||||
qPrefFacebook::set_access_token(securityToken);
|
||||
qCDebug(lcFacebook) << "Got securityToken" << securityToken;
|
||||
requestUserId();
|
||||
}
|
||||
|
||||
void FacebookManager::logout()
|
||||
{
|
||||
qPrefFacebook::set_access_token(QString());
|
||||
qPrefFacebook::set_user_id(QString());
|
||||
qPrefFacebook::set_album_id(QString());
|
||||
emit justLoggedOut(true);
|
||||
}
|
||||
|
||||
void FacebookManager::requestAlbumId()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Starting to request the album id" << albumListUrl();
|
||||
QNetworkReply *reply = manager->get(QNetworkRequest(albumListUrl()));
|
||||
connect(reply, &QNetworkReply::finished, this, &FacebookManager::albumListReceived);
|
||||
}
|
||||
|
||||
void FacebookManager::albumListReceived()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Reply for the album id";
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
QJsonDocument albumsDoc = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonArray albumObj = albumsDoc.object().value("data").toArray();
|
||||
|
||||
reply->deleteLater();
|
||||
foreach(const QJsonValue &v, albumObj){
|
||||
QJsonObject obj = v.toObject();
|
||||
if (obj.value("name").toString() == fbInfo.albumName) {
|
||||
qPrefFacebook::set_album_id(obj.value("id").toString());
|
||||
qCDebug(lcFacebook) << "Album" << fbInfo.albumName << "already exists, using id" << obj.value("id").toString();
|
||||
emit albumIdReceived(qPrefFacebook::album_id());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No album with the name we requested, create a new one.
|
||||
createFacebookAlbum();
|
||||
}
|
||||
|
||||
void FacebookManager::createFacebookAlbum()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Album with name" << fbInfo.albumName << "doesn't exists, creating it.";
|
||||
QUrlQuery params;
|
||||
params.addQueryItem("name", fbInfo.albumName );
|
||||
params.addQueryItem("description", "Subsurface Album");
|
||||
params.addQueryItem("privacy", "{'value': 'SELF'}");
|
||||
|
||||
QNetworkRequest request(albumListUrl());
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
|
||||
|
||||
QNetworkReply *reply = manager->post(request, params.query().toUtf8());
|
||||
connect(reply, &QNetworkReply::finished, this, &FacebookManager::facebookAlbumCreated);
|
||||
}
|
||||
|
||||
void FacebookManager::facebookAlbumCreated()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
QJsonDocument albumsDoc = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject album = albumsDoc.object();
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
if (album.contains("id")) {
|
||||
qCDebug(lcFacebook) << "Album" << fbInfo.albumName << "created successfully with id" << album.value("id").toString();
|
||||
qPrefFacebook::set_album_id(album.value("id").toString());
|
||||
emit albumIdReceived(qPrefFacebook::album_id());
|
||||
return;
|
||||
} else {
|
||||
qCDebug(lcFacebook) << "It was not possible to create the album with name" << fbInfo.albumName;
|
||||
qCDebug(lcFacebook).noquote() << "Reply was: " << QString(albumsDoc.toJson(QJsonDocument::Indented));
|
||||
// FIXME: we are lacking 'user_photos' facebook permission to create an album,
|
||||
// but we are able to upload the image to Facebook (album will be named 'Subsurface Photos')
|
||||
qCDebug(lcFacebook) << "But we are still able to upload data. Album name will be 'Subsurface Photos'";
|
||||
emit albumIdReceived(qPrefFacebook::album_id());
|
||||
}
|
||||
}
|
||||
|
||||
void FacebookManager::requestUserId()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Requesting user id";
|
||||
QUrl userIdRequest("https://graph.facebook.com/me?fields=id&access_token=" + QString(prefs.facebook.access_token));
|
||||
QNetworkReply *reply = manager->get(QNetworkRequest(userIdRequest));
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, &FacebookManager::userIdReceived);
|
||||
}
|
||||
|
||||
void FacebookManager::userIdReceived()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject obj = jsonDoc.object();
|
||||
if (obj.keys().contains("id")) {
|
||||
qCDebug(lcFacebook) << "User id requested successfully:" << obj.value("id").toString();
|
||||
qPrefFacebook::set_user_id(obj.value("id").toString());
|
||||
emit sendMessage(tr("Facebook logged in successfully"));
|
||||
emit justLoggedIn(true);
|
||||
} else {
|
||||
emit sendMessage(tr("Error, unknown user id, cannot login."));
|
||||
qCDebug(lcFacebook) << "Error, unknown user id, cannot login.";
|
||||
}
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
QPixmap FacebookManager::grabProfilePixmap()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Grabbing Dive Profile pixmap";
|
||||
ProfileWidget2 *profile = MainWindow::instance()->graphics;
|
||||
|
||||
QSize size = fbInfo.profileSize == FacebookInfo::SMALL ? QSize(800,600) :
|
||||
fbInfo.profileSize == FacebookInfo::MEDIUM ? QSize(1024,760) :
|
||||
fbInfo.profileSize == FacebookInfo::BIG ? QSize(1280,1024) : QSize();
|
||||
|
||||
auto currSize = profile->size();
|
||||
profile->resize(size);
|
||||
profile->setToolTipVisibile(false);
|
||||
QPixmap pix = profile->grab();
|
||||
profile->setToolTipVisibile(true);
|
||||
profile->resize(currSize);
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
|
||||
/* to be changed to export the currently selected dive as shown on the profile.
|
||||
* Much much easier, and its also good to people do not select all the dives
|
||||
* and send erroniously *all* of them to facebook. */
|
||||
void FacebookManager::sendDiveInit()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Starting to upload the dive to facebook";
|
||||
|
||||
SocialNetworkDialog dialog(qApp->activeWindow());
|
||||
if (dialog.exec() != QDialog::Accepted) {
|
||||
qCDebug(lcFacebook) << "User cancelled.";
|
||||
return;
|
||||
}
|
||||
|
||||
fbInfo.bodyText = dialog.text();
|
||||
fbInfo.profileSize = dialog.profileSize();
|
||||
fbInfo.profileData = grabProfilePixmap();
|
||||
fbInfo.albumName = dialog.album();
|
||||
fbInfo.albumId = QString(); // request Album Id wil handle that.
|
||||
|
||||
// will emit albumIdReceived, that's connected to sendDiveToAlbum
|
||||
requestAlbumId();
|
||||
}
|
||||
|
||||
void FacebookManager::sendDiveToAlbum(const QString& albumId)
|
||||
{
|
||||
qCDebug(lcFacebook) << "Starting to upload the dive to album" << fbInfo.albumName << "id" << albumId;
|
||||
QUrl url(graphApi + albumId + "/photos?" +
|
||||
"&access_token=" + QString(prefs.facebook.access_token) +
|
||||
"&source=image" +
|
||||
"&message=" + fbInfo.bodyText.replace(""", "%22"));
|
||||
|
||||
QNetworkRequest request(url);
|
||||
|
||||
QString bound="margin";
|
||||
|
||||
//according to rfc 1867 we need to put this string here:
|
||||
QByteArray data(QString("--" + bound + "\r\n").toUtf8());
|
||||
data.append("Content-Disposition: form-data; name=\"action\"\r\n\r\n");
|
||||
data.append(graphApi + "\r\n");
|
||||
data.append("--" + bound + "\r\n"); //according to rfc 1867
|
||||
|
||||
//name of the input is "uploaded" in my form, next one is a file name.
|
||||
data.append("Content-Disposition: form-data; name=\"uploaded\"; filename=\"" + QString::number(qrand()) + ".png\"\r\n");
|
||||
data.append("Content-Type: image/jpeg\r\n\r\n"); //data type
|
||||
|
||||
QByteArray bytes;
|
||||
QBuffer buffer(&bytes);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
fbInfo.profileData.save(&buffer, "PNG");
|
||||
|
||||
data.append(bytes); //let's read the file
|
||||
data.append("\r\n");
|
||||
data.append("--" + bound + "--\r\n"); //closing boundary according to rfc 1867
|
||||
|
||||
request.setRawHeader(QByteArray("Content-Type"),QString("multipart/form-data; boundary=" + bound).toUtf8());
|
||||
request.setRawHeader(QByteArray("Content-Length"), QString::number(data.length()).toUtf8());
|
||||
QNetworkReply *reply = manager->post(request,data);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, &FacebookManager::uploadFinished);
|
||||
}
|
||||
|
||||
void FacebookManager::uploadFinished()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Upload finish";
|
||||
auto reply = qobject_cast<QNetworkReply*>(sender());
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(response);
|
||||
QJsonObject obj = jsonDoc.object();
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
if (obj.keys().contains("id")){
|
||||
emit sendMessage(tr("Dive uploaded successfully to Facebook"));
|
||||
} else {
|
||||
emit sendMessage(tr("Dive upload failed. Please see debug output and send to Subsurface mailing list"));
|
||||
qCDebug(lcFacebook) << "Dive upload failed" << response;
|
||||
}
|
||||
|
||||
emit sendDiveFinished();
|
||||
}
|
||||
|
||||
void FacebookConnectWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
if (FacebookManager::instance()->loggedIn()) {
|
||||
facebookLoggedIn();
|
||||
} else {
|
||||
facebookDisconnect();
|
||||
}
|
||||
return QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
FacebookConnectWidget::FacebookConnectWidget(QWidget *parent) : QDialog(parent), ui(new Ui::FacebookConnectWidget) {
|
||||
ui->setupUi(this);
|
||||
FacebookManager *fb = FacebookManager::instance();
|
||||
#ifdef USE_WEBENGINE
|
||||
facebookWebView = new QWebEngineView(this);
|
||||
#else
|
||||
facebookWebView = new QWebView(this);
|
||||
#endif
|
||||
ui->fbWebviewContainer->layout()->addWidget(facebookWebView);
|
||||
#ifdef USE_WEBENGINE
|
||||
connect(facebookWebView, &QWebEngineView::urlChanged, fb, &FacebookManager::tryLogin);
|
||||
#else
|
||||
connect(facebookWebView, &QWebView::urlChanged, fb, &FacebookManager::tryLogin);
|
||||
#endif
|
||||
connect(fb, &FacebookManager::justLoggedIn, this, &FacebookConnectWidget::facebookLoggedIn);
|
||||
connect(fb, &FacebookManager::justLoggedOut, this, &FacebookConnectWidget::facebookDisconnect);
|
||||
}
|
||||
|
||||
void FacebookConnectWidget::facebookLoggedIn()
|
||||
{
|
||||
ui->fbWebviewContainer->hide();
|
||||
ui->fbWebviewContainer->setEnabled(false);
|
||||
ui->FBLabel->setText(tr("To disconnect Subsurface from your Facebook account, use the 'Share on' menu entry."));
|
||||
close();
|
||||
}
|
||||
|
||||
void FacebookConnectWidget::facebookDisconnect()
|
||||
{
|
||||
qCDebug(lcFacebook) << "Disconnecting from facebook";
|
||||
// remove the connect/disconnect button
|
||||
// and instead add the login view
|
||||
ui->fbWebviewContainer->show();
|
||||
ui->fbWebviewContainer->setEnabled(true);
|
||||
ui->FBLabel->setText(tr("To connect to Facebook, please log in. This enables Subsurface to publish dives to your timeline"));
|
||||
if (facebookWebView) {
|
||||
#ifdef USE_WEBENGINE
|
||||
//FIX ME
|
||||
#else
|
||||
facebookWebView->page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
|
||||
#endif
|
||||
facebookWebView->setUrl(FacebookManager::instance()->connectUrl());
|
||||
}
|
||||
}
|
||||
|
||||
SocialNetworkDialog::SocialNetworkDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui( new Ui::SocialnetworksDialog())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
connect(ui->date, &QCheckBox::clicked, this, &SocialNetworkDialog::selectionChanged);
|
||||
connect(ui->duration, &QCheckBox::clicked, this, &SocialNetworkDialog::selectionChanged);
|
||||
connect(ui->Buddy, &QCheckBox::clicked, this, &SocialNetworkDialog::selectionChanged);
|
||||
connect(ui->Divemaster, &QCheckBox::clicked, this, &SocialNetworkDialog::selectionChanged);
|
||||
connect(ui->Location, &QCheckBox::clicked, this, &SocialNetworkDialog::selectionChanged);
|
||||
connect(ui->Notes, &QCheckBox::clicked, this, &SocialNetworkDialog::selectionChanged);
|
||||
connect(ui->album, &QLineEdit::textChanged, this, &SocialNetworkDialog::albumChanged);
|
||||
}
|
||||
|
||||
FacebookInfo::Size SocialNetworkDialog::profileSize() const
|
||||
{
|
||||
QString currText = ui->profileSize->currentText();
|
||||
return currText.startsWith(tr("Small")) ? FacebookInfo::SMALL :
|
||||
currText.startsWith(tr("Medium")) ? FacebookInfo::MEDIUM :
|
||||
/* currText.startsWith(tr("Big")) ? */ FacebookInfo::BIG;
|
||||
}
|
||||
|
||||
|
||||
void SocialNetworkDialog::albumChanged()
|
||||
{
|
||||
QAbstractButton *button = ui->buttonBox->button(QDialogButtonBox::Ok);
|
||||
button->setEnabled(!ui->album->text().isEmpty());
|
||||
}
|
||||
|
||||
void SocialNetworkDialog::selectionChanged()
|
||||
{
|
||||
struct dive *d = current_dive;
|
||||
QString fullText;
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
if (ui->date->isChecked()) {
|
||||
fullText += tr("Dive date: %1 \n").arg(get_short_dive_date_string(d->when));
|
||||
}
|
||||
if (ui->duration->isChecked()) {
|
||||
fullText += tr("Duration: %1 \n").arg(get_dive_duration_string(d->duration.seconds,
|
||||
tr("h", "abbreviation for hours"),
|
||||
tr("min", "abbreviation for minutes")));
|
||||
}
|
||||
if (ui->Location->isChecked()) {
|
||||
fullText += tr("Dive location: %1 \n").arg(get_dive_location(d));
|
||||
}
|
||||
if (ui->Buddy->isChecked()) {
|
||||
fullText += tr("Buddy: %1 \n").arg(d->buddy);
|
||||
}
|
||||
if (ui->Divemaster->isChecked()) {
|
||||
fullText += tr("Divemaster: %1 \n").arg(d->divemaster);
|
||||
}
|
||||
if (ui->Notes->isChecked()) {
|
||||
fullText += tr("\n%1").arg(d->notes);
|
||||
}
|
||||
ui->text->setPlainText(fullText);
|
||||
}
|
||||
|
||||
QString SocialNetworkDialog::text() const {
|
||||
return ui->text->toPlainText().toHtmlEscaped();
|
||||
}
|
||||
|
||||
QString SocialNetworkDialog::album() const {
|
||||
return ui->album->text().toHtmlEscaped();
|
||||
}
|
||||
|
||||
|
||||
@ -1,99 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#ifndef FACEBOOKCONNECTWIDGET_H
|
||||
#define FACEBOOKCONNECTWIDGET_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QUrl>
|
||||
#ifdef USE_WEBENGINE
|
||||
class QWebEngineView;
|
||||
#else
|
||||
class QWebView;
|
||||
#endif
|
||||
class QNetworkReply;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
namespace Ui {
|
||||
class FacebookConnectWidget;
|
||||
class SocialnetworksDialog;
|
||||
}
|
||||
|
||||
struct FacebookInfo {
|
||||
enum Size {SMALL, MEDIUM, BIG};
|
||||
|
||||
QString bodyText;
|
||||
QString albumId;
|
||||
QString albumName;
|
||||
Size profileSize;
|
||||
QPixmap profileData;
|
||||
};
|
||||
|
||||
class FacebookManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static FacebookManager *instance();
|
||||
void requestAlbumId();
|
||||
void requestUserId();
|
||||
QUrl connectUrl();
|
||||
QUrl albumListUrl();
|
||||
bool loggedIn();
|
||||
QPixmap grabProfilePixmap();
|
||||
|
||||
signals:
|
||||
void justLoggedIn(bool triggererd);
|
||||
void justLoggedOut(bool triggered);
|
||||
void albumIdReceived(const QString& albumId);
|
||||
void sendDiveFinished();
|
||||
void sendMessage(const QString& message);
|
||||
|
||||
public slots:
|
||||
void tryLogin(const QUrl& loginResponse);
|
||||
void logout();
|
||||
void sendDiveInit();
|
||||
void sendDiveToAlbum(const QString& album);
|
||||
|
||||
void uploadFinished();
|
||||
void albumListReceived();
|
||||
void userIdReceived();
|
||||
void createFacebookAlbum();
|
||||
void facebookAlbumCreated();
|
||||
private:
|
||||
explicit FacebookManager(QObject *parent = 0);
|
||||
FacebookInfo fbInfo;
|
||||
QNetworkAccessManager *manager;
|
||||
};
|
||||
|
||||
|
||||
class FacebookConnectWidget : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FacebookConnectWidget(QWidget* parent = 0);
|
||||
void facebookLoggedIn();
|
||||
void facebookDisconnect();
|
||||
void showEvent(QShowEvent *event);
|
||||
private:
|
||||
Ui::FacebookConnectWidget *ui;
|
||||
#ifdef USE_WEBENGINE
|
||||
QWebEngineView *facebookWebView;
|
||||
#else
|
||||
QWebView *facebookWebView;
|
||||
#endif
|
||||
};
|
||||
|
||||
class SocialNetworkDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
SocialNetworkDialog(QWidget *parent = 0);
|
||||
QString text() const;
|
||||
QString album() const;
|
||||
FacebookInfo::Size profileSize() const;
|
||||
|
||||
public slots:
|
||||
void selectionChanged();
|
||||
void albumChanged();
|
||||
private:
|
||||
Ui::SocialnetworksDialog *ui;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -1,104 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FacebookConnectWidget</class>
|
||||
<widget class="QDialog" name="FacebookConnectWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>835</width>
|
||||
<height>698</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normalon>:subsurface-icon</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="mainHorizontalLayout">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="facebook_page">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="fbLayout" stretch="0">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="FBLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect to Facebook text placeholder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="fbWebviewContainer" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@ -1,189 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SocialnetworksDialog</class>
|
||||
<widget class="QDialog" name="SocialnetworksDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>591</width>
|
||||
<height>619</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0">
|
||||
<property name="margin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item row="7" column="0">
|
||||
<widget class="QComboBox" name="profileSize">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Small</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Medium</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Big</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>The text to the right will be posted as the description with your dive profile graph to Facebook. The album name is required (the profile graph will be posted to that album).</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Album</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLineEdit" name="album">
|
||||
<property name="toolTip">
|
||||
<string>The profile picture will be posted in this album (required)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Include</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="date">
|
||||
<property name="text">
|
||||
<string>Date and time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QCheckBox" name="duration">
|
||||
<property name="text">
|
||||
<string>Duration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QCheckBox" name="Location">
|
||||
<property name="text">
|
||||
<string>Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QCheckBox" name="Divemaster">
|
||||
<property name="text">
|
||||
<string>Divemaster</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<widget class="QCheckBox" name="Buddy">
|
||||
<property name="text">
|
||||
<string>Buddy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<widget class="QCheckBox" name="Notes">
|
||||
<property name="text">
|
||||
<string>Notes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Facebook post preview</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" rowspan="11">
|
||||
<widget class="QPlainTextEdit" name="text"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Image Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>SocialnetworksDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SocialnetworksDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@ -53,7 +53,7 @@ void PreferencesNetwork::syncSettings()
|
||||
proxy->set_proxy_user(ui->proxyUsername->text());
|
||||
proxy->set_proxy_pass(ui->proxyPassword->text());
|
||||
|
||||
QString email = ui->cloud_storage_email->text();
|
||||
QString email = ui->cloud_storage_email->text().toLower();
|
||||
QString password = ui->cloud_storage_password->text();
|
||||
QString newpassword = ui->cloud_storage_new_passwd->text();
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ PreferencesDialog::PreferencesDialog()
|
||||
//s.endGroup();
|
||||
|
||||
setWindowIcon(QIcon(":subsurface-icon"));
|
||||
setWindowTitle(tr("Preferences"));
|
||||
pagesList = new QListWidget();
|
||||
pagesStack = new QStackedWidget();
|
||||
buttonBox = new QDialogButtonBox(
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include <QAction>
|
||||
#include <QDesktopServices>
|
||||
#include <QToolTip>
|
||||
#include <QClipboard>
|
||||
|
||||
#include "core/file.h"
|
||||
#include "desktop-widgets/mainwindow.h"
|
||||
@ -490,6 +491,50 @@ void DiveComponentSelection::buttonClicked(QAbstractButton *button)
|
||||
COMPONENT_FROM_UI(cylinders);
|
||||
COMPONENT_FROM_UI(weights);
|
||||
selective_copy_dive(&displayed_dive, targetDive, *what, true);
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
QTextStream text;
|
||||
QString cliptext;
|
||||
text.setString(&cliptext);
|
||||
if (what->divesite)
|
||||
text << tr("Dive site: ") << displayed_dive.dive_site->name << "\n";
|
||||
if (what->divemaster)
|
||||
text << tr("Dive master: ") << displayed_dive.divemaster << "\n";
|
||||
if (what->buddy)
|
||||
text << tr("Buddy: ") << displayed_dive.buddy << "\n";
|
||||
if (what->rating)
|
||||
text << tr("Rating: ") + QString("*").repeated(displayed_dive.rating) << "\n";
|
||||
if (what->visibility)
|
||||
text << tr("Visibility: ") + QString("*").repeated(displayed_dive.visibility) << "\n";
|
||||
if (what->notes)
|
||||
text << tr("Notes:\n") << displayed_dive.notes << "\n";
|
||||
if (what->suit)
|
||||
text << tr("Suit: ") << displayed_dive.suit << "\n";
|
||||
if (what-> tags) {
|
||||
text << tr("Tags: ");
|
||||
tag_entry *entry = displayed_dive.tag_list;
|
||||
while (entry) {
|
||||
text << entry->tag->name << " ";
|
||||
entry = entry->next;
|
||||
}
|
||||
text << "\n";
|
||||
}
|
||||
if (what->cylinders) {
|
||||
int cyl;
|
||||
text << tr("Cylinders:\n");
|
||||
for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
|
||||
if (is_cylinder_used(&displayed_dive, cyl))
|
||||
text << displayed_dive.cylinder[cyl].type.description << " " << gasname(displayed_dive.cylinder[cyl].gasmix) << "\n";
|
||||
}
|
||||
}
|
||||
if (what->weights) {
|
||||
int w;
|
||||
text << tr("Weights:\n");
|
||||
for (w = 0; w < MAX_WEIGHTSYSTEMS; w++) {
|
||||
if (displayed_dive.weightsystem[w].weight.grams)
|
||||
text << displayed_dive.weightsystem[w].description << displayed_dive.weightsystem[w].weight.grams / 1000 << "kg\n";
|
||||
}
|
||||
}
|
||||
clipboard->setText(cliptext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -484,6 +484,10 @@ void DivelogsDeWebServices::prepareDivesForUpload(bool selected)
|
||||
{
|
||||
/* generate a random filename and create/open that file with zip_open */
|
||||
QString filename = QDir::tempPath() + "/import-" + QString::number(qrand() % 99999999) + ".dld";
|
||||
if (!amount_selected) {
|
||||
report_error(tr("no dives were selected").toUtf8());
|
||||
return;
|
||||
}
|
||||
if (prepare_dives_for_divelogs(filename, selected)) {
|
||||
QFile f(filename);
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
@ -531,7 +535,7 @@ DivelogsDeWebServices::DivelogsDeWebServices(QWidget *parent, Qt::WindowFlags f)
|
||||
multipart(NULL),
|
||||
uploadMode(false)
|
||||
{
|
||||
//FIXME: DivelogDE user and pass should be on the prefs struct or something?
|
||||
// should DivelogDE user and pass be stored in the prefs struct or something?
|
||||
QSettings s;
|
||||
ui.userID->setText(s.value("divelogde_user").toString());
|
||||
ui.password->setText(s.value("divelogde_pass").toString());
|
||||
|
||||
@ -903,11 +903,9 @@ void MainTab::acceptChanges()
|
||||
}
|
||||
}
|
||||
|
||||
if (displayed_dive.when != cd->when) {
|
||||
timestamp_t offset = cd->when - displayed_dive.when;
|
||||
if (offset)
|
||||
Command::shiftTime(selectedDives, (int)offset);
|
||||
}
|
||||
timestamp_t offset = displayed_dive.when - cd->when;
|
||||
if (offset)
|
||||
Command::shiftTime(selectedDives, (int)offset);
|
||||
}
|
||||
if (editMode != TRIP && current_dive->divetrip) {
|
||||
current_dive->divetrip->when = current_dive->when;
|
||||
|
||||
@ -43,7 +43,7 @@ void UpdateManager::checkForUpdates(bool automatic)
|
||||
isAutomaticCheck = automatic;
|
||||
QString version = subsurface_canonical_version();
|
||||
QString uuidString = getUUID();
|
||||
QString url = QString("http://subsurface-divelog.org/updatecheck.html?os=%1&version=%2&uuid=%3").arg(os, version, uuidString);
|
||||
QString url = QString("http://updatecheck.subsurface-divelog.org/updatecheck.html?os=%1&version=%2&uuid=%3").arg(os, version, uuidString);
|
||||
QNetworkRequest request;
|
||||
request.setUrl(url);
|
||||
request.setRawHeader("Accept", "text/xml");
|
||||
|
||||
|
Before Width: | Height: | Size: 150 KiB |
@ -1 +1 @@
|
||||
Subproject commit abde311d3a6ea97c7a586e4cc879e07d4ce0fd4f
|
||||
Subproject commit e4698c484461426a4cf4ef3fc1bdbb304b676f06
|
||||
@ -46,7 +46,7 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
text: qsTr("Version: %1\n\n© Subsurface developer team\n2011-2018").arg(manager.getVersion())
|
||||
text: qsTr("Version: %1\n\n© Subsurface developer team\n2011-2019").arg(manager.getVersion())
|
||||
level: 5
|
||||
font.pointSize: subsurfaceTheme.smallPointSize + 1
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
@ -167,18 +167,6 @@ Kirigami.Page {
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
onCurrentTextChanged: {
|
||||
// pattern that matches BT addresses
|
||||
var btAddr = /[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]:[0-9A-Fa-f][0-9A-Fa-f]/ ;
|
||||
|
||||
// On iOS we store UUID instead of device address.
|
||||
if (Qt.platform.os === 'ios')
|
||||
btAddr = /\{?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}/;
|
||||
|
||||
if (btAddr.test(currentText))
|
||||
manager.DC_bluetoothMode = true
|
||||
else
|
||||
manager.DC_bluetoothMode = false
|
||||
manager.DC_devName = currentText
|
||||
dc1.enabled = dc2.enabled = dc3.enabled = dc4.enabled = true
|
||||
for (var i = 1; i < 5; i++) {
|
||||
if (comboProduct.currentIndex === -1 && currentText === "FTDI"){
|
||||
@ -198,7 +186,6 @@ Kirigami.Page {
|
||||
}
|
||||
}
|
||||
download.text = qsTr("Download")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -277,10 +264,28 @@ Kirigami.Page {
|
||||
comboConnection.currentIndex != -1
|
||||
onClicked: {
|
||||
text = qsTr("Retry")
|
||||
// strip any BT Name from the address
|
||||
var devName = manager.DC_devName
|
||||
if (devName != qsTr("USB device"))
|
||||
manager.DC_devName = devName.replace(/^(.*) /, "")
|
||||
|
||||
var connectionString = comboConnection.currentText
|
||||
// separate BT address and BT name (if applicable)
|
||||
// pattern that matches BT addresses
|
||||
var btAddr = "(LE:)?([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}";
|
||||
|
||||
// On iOS we store UUID instead of device address.
|
||||
if (Qt.platform.os === 'ios')
|
||||
btAddr = "(LE:)?\{?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}";
|
||||
|
||||
var pattern = new RegExp(btAddr);
|
||||
var devAddress = "";
|
||||
devAddress = pattern.exec(connectionString);
|
||||
if (devAddress !== null) {
|
||||
manager.DC_bluetoothMode = true;
|
||||
manager.DC_devName = devAddress[0]; // exec returns an array with the matched text in element 0
|
||||
manager.retrieveBluetoothName();
|
||||
manager.appendTextToLog("setting btName to " + manager.DC_devBluetoothName);
|
||||
} else {
|
||||
manager.DC_bluetoothMode = false;
|
||||
manager.DC_devName = connectionString;
|
||||
}
|
||||
manager.appendTextToLog("DCDownloadThread started for " + manager.DC_vendor + " " + manager.DC_product + " on "+ manager.DC_devName)
|
||||
progressBar.visible = true
|
||||
downloadThread.start()
|
||||
@ -392,7 +397,7 @@ Kirigami.Page {
|
||||
comboVendor.currentIndex = manager.getDetectedVendorIndex()
|
||||
comboProduct.currentIndex = manager.getDetectedProductIndex(comboVendor.currentText)
|
||||
comboConnection.currentIndex = manager.getMatchingAddress(comboVendor.currentText, comboProduct.currentText)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -876,11 +876,9 @@ bool QMLManager::checkLocation(DiveObjectHelper *myDive, struct dive *d, QString
|
||||
qDebug() << "checkLocation" << location << "gps" << gps << "dive had" << myDive->location() << "gps" << myDive->gas();
|
||||
if (myDive->location() != location) {
|
||||
diveChanged = true;
|
||||
if (!ds)
|
||||
ds = get_dive_site_by_name(qPrintable(location));
|
||||
if (!ds && !location.isEmpty()) {
|
||||
ds = get_dive_site_by_name(qPrintable(location));
|
||||
if (!ds && !location.isEmpty())
|
||||
ds = create_dive_site(qPrintable(location), d->when);
|
||||
}
|
||||
d->dive_site = ds;
|
||||
}
|
||||
// now make sure that the GPS coordinates match - if the user changed the name but not
|
||||
@ -1637,6 +1635,17 @@ void QMLManager::setStatusbarColor(QColor)
|
||||
|
||||
#endif
|
||||
|
||||
void QMLManager::retrieveBluetoothName()
|
||||
{
|
||||
QString name = DC_devName();
|
||||
QList<BTDiscovery::btVendorProduct> btDCs = BTDiscovery::instance()->getBtDcs();
|
||||
foreach (BTDiscovery::btVendorProduct btDC, btDCs) {
|
||||
qDebug() << "compare" <<name << btDC.btpdi.address;
|
||||
if (name.contains(btDC.btpdi.address))
|
||||
DC_setDevBluetoothName(btDC.btpdi.name);
|
||||
}
|
||||
}
|
||||
|
||||
QString QMLManager::DC_vendor() const
|
||||
{
|
||||
return m_device_data->vendor();
|
||||
|
||||
@ -62,6 +62,8 @@ public:
|
||||
QString DC_devName() const;
|
||||
void DC_setDevName(const QString& devName);
|
||||
|
||||
Q_INVOKABLE void retrieveBluetoothName();
|
||||
|
||||
QString DC_devBluetoothName() const;
|
||||
void DC_setDevBluetoothName(const QString& devBluetoothName);
|
||||
|
||||
|
||||
@ -17,26 +17,33 @@ exec 1> >(tee ./build.log) 2>&1
|
||||
|
||||
USE_X=$(case $- in *x*) echo "-x" ;; esac)
|
||||
|
||||
# these are the current versions for Qt, Android SDK & NDK:
|
||||
source subsurface/packaging/android/variables.sh
|
||||
# deal with the command line arguments
|
||||
while [[ $# -gt 0 ]] ; do
|
||||
arg="$1"
|
||||
case $arg in
|
||||
-prep-only)
|
||||
# only download the dependencies, don't build
|
||||
PREP_ONLY="1"
|
||||
;;
|
||||
release|Release)
|
||||
# simply pass through to build.sh
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command line argument $arg"
|
||||
echo "Usage: $0 [-prep-only]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# avoid timeouts on Travis when downloads take a long time
|
||||
SLOW_PROG=""
|
||||
if [ -n "${TRAVIS:-}" ]; then
|
||||
source subsurface/scripts/travis-wait.sh
|
||||
set -x # make debugging Travis easier
|
||||
SLOW_PROG="travis_wait"
|
||||
# since we are running on Travis, let's just get our minimal Qt install
|
||||
mkdir -p Qt/"${LATEST_QT}"
|
||||
$SLOW_PROG wget -q https://storage.googleapis.com/travis-cache/Qt-"${LATEST_QT}"-android.tar.xz
|
||||
tar -xJ -C Qt/"${LATEST_QT}" -f Qt-"${LATEST_QT}"-android.tar.xz
|
||||
fi
|
||||
# these are the current versions for Qt, Android SDK & NDK:
|
||||
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
|
||||
source "$SCRIPTDIR"/variables.sh
|
||||
|
||||
PLATFORM=$(uname)
|
||||
|
||||
pushd $(dirname "$0")/../../
|
||||
export SUBSURFACE_SOURCE=$PWD
|
||||
popd
|
||||
export SUBSURFACE_SOURCE="$SCRIPTDIR"/../..
|
||||
|
||||
if [ "$PLATFORM" = Linux ] ; then
|
||||
QT_BINARIES=qt-opensource-linux-x64-${LATEST_QT}.run
|
||||
@ -68,25 +75,28 @@ fi
|
||||
# first we need to get the Android SDK and NDK
|
||||
if [ ! -d "$ANDROID_NDK" ] ; then
|
||||
if [ ! -f "$NDK_BINARIES" ] ; then
|
||||
$SLOW_PROG wget -q https://dl.google.com/android/repository/"$NDK_BINARIES"
|
||||
wget -q https://dl.google.com/android/repository/"$NDK_BINARIES"
|
||||
fi
|
||||
unzip -q "$NDK_BINARIES"
|
||||
fi
|
||||
|
||||
if [ ! -d "$ANDROID_SDK"/build-tools/"${ANDROID_BUILDTOOLS_REVISION}" ] ; then
|
||||
if [ ! -d "$ANDROID_SDK"/build-tools/"${ANDROID_BUILDTOOLS_REVISION}" ] ||
|
||||
[ ! -d "$ANDROID_SDK"/platforms/android-"${ANDROID_PLATFORMS}" ] ||
|
||||
[ ! -d "$ANDROID_SDK"/platforms/android-"${ANDROID_PLATFORM}" ] ; then
|
||||
if [ ! -d "$ANDROID_SDK" ] ; then
|
||||
if [ ! -f "$SDK_TOOLS" ] ; then
|
||||
$SLOW_PROG wget -q https://dl.google.com/android/repository/"$SDK_TOOLS"
|
||||
wget -q https://dl.google.com/android/repository/"$SDK_TOOLS"
|
||||
fi
|
||||
mkdir "$ANDROID_SDK"
|
||||
pushd "$ANDROID_SDK"
|
||||
unzip -q ../"$SDK_TOOLS"
|
||||
yes | tools/bin/sdkmanager --licenses > /dev/null 2>&1 || echo "d56f5187479451eabf01fb78af6dfcb131a6481e" > licenses/android-sdk-license
|
||||
cat licenses/android-sdk-license
|
||||
yes | tools/bin/sdkmanager tools platform-tools 'platforms;'"${ANDROID_PLATFORM}" 'platforms;'"${ANDROID_PLATFORMS}" 'build-tools;'"${ANDROID_BUILDTOOLS_REVISION}" > /dev/null
|
||||
echo ""
|
||||
else
|
||||
pushd "$ANDROID_SDK"
|
||||
tools/bin/sdkmanager tools platform-tools 'platforms;'"${ANDROID_PLATFORMS}" 'build-tools;'"${ANDROID_BUILDTOOLS_REVISION}"
|
||||
yes | tools/bin/sdkmanager tools platform-tools 'platforms;'"${ANDROID_PLATFORM}" 'platforms;'"${ANDROID_PLATFORMS}" 'build-tools;'"${ANDROID_BUILDTOOLS_REVISION}" > /dev/null
|
||||
fi
|
||||
popd
|
||||
fi
|
||||
@ -101,15 +111,19 @@ if [ ! -d Qt/"${LATEST_QT}"/android_armv7 ] ; then
|
||||
echo "Qt installation found, backing it up to Qt_OLD."
|
||||
fi
|
||||
if [ ! -f "${QT_BINARIES}" ] ; then
|
||||
$SLOW_PROG wget -q "${QT_DOWNLOAD_URL}"
|
||||
wget -q "${QT_DOWNLOAD_URL}"
|
||||
fi
|
||||
chmod +x ./"${QT_BINARIES}"
|
||||
./"${QT_BINARIES}" --platform minimal --script "$SUBSURFACE_SOURCE"/qt-installer-noninteractive.qs --no-force-installations
|
||||
./"${QT_BINARIES}" --platform minimal --script "$SCRIPTDIR"/qt-installer-noninteractive.qs --no-force-installations
|
||||
fi
|
||||
|
||||
# patch the cmake / Qt5.7.1 incompatibility mentioned above
|
||||
sed -i 's/set_property(TARGET Qt5::Core PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)/# set_property(TARGET Qt5::Core PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)/' Qt/"${LATEST_QT}"/android_armv7/lib/cmake/Qt5Core/Qt5CoreConfigExtras.cmake
|
||||
|
||||
if [ ! -z ${PREP_ONLY+x} ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -d subsurface/libdivecomputer/src ] ; then
|
||||
pushd subsurface
|
||||
git submodule init
|
||||
@ -117,12 +131,12 @@ if [ ! -d subsurface/libdivecomputer/src ] ; then
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ ! -f subsurface/libdivecomputer/configure ] ; then
|
||||
pushd subsurface/libdivecomputer
|
||||
autoreconf --install
|
||||
autoreconf --install
|
||||
popd
|
||||
fi
|
||||
# always reconfigure here
|
||||
rm -f subsurface/libdivecomputer/configure
|
||||
pushd subsurface/libdivecomputer
|
||||
autoreconf --install --force
|
||||
autoreconf --install --force
|
||||
popd
|
||||
|
||||
# and now we need a monotonic build number...
|
||||
if [ ! -f ./buildnr.dat ] ; then
|
||||
@ -140,8 +154,10 @@ rm -df ./subsurface-mobile-build-arm/AndroidManifest.xml
|
||||
|
||||
if [ "$USE_X" ] ; then
|
||||
bash "$USE_X" "$SUBSURFACE_SOURCE"/packaging/android/build.sh -buildnr "$BUILDNR" arm "$@"
|
||||
bash "$USE_X" "$SUBSURFACE_SOURCE"/packaging/android/build.sh -buildnr "$BUILDNR" arm64 "$@"
|
||||
else
|
||||
bash "$SUBSURFACE_SOURCE"/packaging/android/build.sh -buildnr "$BUILDNR" arm "$@"
|
||||
bash "$SUBSURFACE_SOURCE"/packaging/android/build.sh -buildnr "$BUILDNR" arm64 "$@"
|
||||
fi
|
||||
|
||||
ls -l ./subsurface-mobile-build-arm/build/outputs/apk/*.apk
|
||||
|
||||
@ -63,7 +63,7 @@ while [ "$#" -gt 0 ] ; do
|
||||
SUBSURFACE_DESKTOP=ON
|
||||
shift
|
||||
;;
|
||||
arm|x86)
|
||||
arm|arm64|x86)
|
||||
ARCH=$1
|
||||
shift
|
||||
;;
|
||||
@ -117,10 +117,17 @@ if [ "$ARCH" = "arm" ] ; then
|
||||
QT_ARCH=armv7
|
||||
BUILDCHAIN=arm-linux-androideabi
|
||||
OPENSSL_MACHINE=armv7
|
||||
ANDROID_ABI=armeabi-v7a
|
||||
elif [ "$ARCH" = "arm64" ] ; then # requires Qt 5.12
|
||||
QT_ARCH=arm64_v8a
|
||||
BUILDCHAIN=aarch64-linux-android
|
||||
ANDROID_ABI=arm64-v8a
|
||||
OPENSSL_MACHINE=aarch64
|
||||
elif [ "$ARCH" = "x86" ] ; then
|
||||
QT_ARCH=$ARCH
|
||||
BUILDCHAIN=i686-linux-android
|
||||
OPENSSL_MACHINE=i686
|
||||
ANDROID_ABI=x86
|
||||
fi
|
||||
|
||||
# Verify Qt install and adjust for single-arch Qt install layout
|
||||
@ -136,21 +143,20 @@ else
|
||||
fi
|
||||
|
||||
if [ ! -e ndk-"$ARCH" ] ; then
|
||||
"$ANDROID_NDK_ROOT/build/tools/make_standalone_toolchain.py" --arch="$ARCH" --install-dir=ndk-"$ARCH" --api=16
|
||||
"$ANDROID_NDK_ROOT/build/tools/make_standalone_toolchain.py" --arch="$ARCH" --install-dir=ndk-"$ARCH" --api=$ANDROID_PLATFORM_LEVEL
|
||||
fi
|
||||
export BUILDROOT=$PWD
|
||||
export PATH=${BUILDROOT}/ndk-$ARCH/bin:$PATH
|
||||
export PREFIX=${BUILDROOT}/ndk-$ARCH/sysroot/usr
|
||||
export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig
|
||||
export CC=${BUILDROOT}/ndk-$ARCH/bin/${BUILDCHAIN}-gcc
|
||||
export CXX=${BUILDROOT}/ndk-$ARCH/bin/${BUILDCHAIN}-g++
|
||||
export CC=${BUILDROOT}/ndk-$ARCH/bin/clang
|
||||
export CXX=${BUILDROOT}/ndk-$ARCH/bin/clang++
|
||||
# autoconf seems to get lost without this
|
||||
export SYSROOT=${BUILDROOT}/ndk-$ARCH/sysroot
|
||||
export CFLAGS=--sysroot=${SYSROOT}
|
||||
export CPPFLAGS=--sysroot=${SYSROOT}
|
||||
export CXXFLAGS=--sysroot=${SYSROOT}
|
||||
# Junk needed for qt-android-cmake
|
||||
export ANDROID_STANDALONE_TOOLCHAIN=${BUILDROOT}/ndk-$ARCH
|
||||
export CFLAGS="--sysroot=${SYSROOT} -fPIC"
|
||||
export CPPFLAGS="--sysroot=${SYSROOT} -fPIC"
|
||||
export CXXFLAGS="--sysroot=${SYSROOT} -fPIC"
|
||||
|
||||
if [ "$PLATFORM" = "Darwin" ] ; then
|
||||
JAVA_HOME=$(/usr/libexec/java_home)
|
||||
export JAVA_HOME
|
||||
@ -159,7 +165,8 @@ else
|
||||
fi
|
||||
|
||||
# find qmake
|
||||
QMAKE=$QT5_ANDROID/android_armv7/bin/qmake
|
||||
QMAKE=$QT5_ANDROID/android_$QT_ARCH/bin/qmake
|
||||
echo $QMAKE
|
||||
$QMAKE -query
|
||||
|
||||
# if we are just doing a quick rebuild, don't bother with any of the dependencies
|
||||
@ -170,7 +177,7 @@ if [ "$QUICK" = "" ] ; then
|
||||
# build google maps plugin
|
||||
"${SUBSURFACE_SOURCE}"/scripts/get-dep-lib.sh singleAndroid . googlemaps
|
||||
# find qmake
|
||||
QMAKE=$QT5_ANDROID/android_armv7/bin/qmake
|
||||
QMAKE=$QT5_ANDROID/android_$QT_ARCH/bin/qmake
|
||||
$QMAKE -query
|
||||
QT_PLUGINS_PATH=$($QMAKE -query QT_INSTALL_PLUGINS)
|
||||
GOOGLEMAPS_BIN=libqtgeoservices_googlemaps.so
|
||||
@ -228,8 +235,33 @@ if [ "$QUICK" = "" ] ; then
|
||||
make install
|
||||
popd
|
||||
fi
|
||||
|
||||
|
||||
"${SUBSURFACE_SOURCE}"/scripts/get-dep-lib.sh singleAndroid . libzip
|
||||
"${SUBSURFACE_SOURCE}"/scripts/get-dep-lib.sh singleAndroid . openssl
|
||||
if [ ! -e "$PKG_CONFIG_LIBDIR/libssl.pc" ] ; then
|
||||
mkdir -p openssl-build-"$ARCH"
|
||||
cp -r openssl/* openssl-build-"$ARCH"
|
||||
pushd openssl-build-"$ARCH"
|
||||
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
|
||||
perl -pi -e 's/-mandroid//g' Configure
|
||||
# Use env to make all these temporary, so they don't pollute later builds.
|
||||
env SYSTEM=android \
|
||||
CROSS_COMPILE=${BUILDCHAIN}- \
|
||||
MACHINE=$OPENSSL_MACHINE \
|
||||
HOSTCC=clang \
|
||||
CC=clang \
|
||||
ANDROID_DEV="$PREFIX" \
|
||||
bash -x ./config shared no-ssl2 no-ssl3 no-comp no-hw no-engine no-asm --openssldir="$PREFIX"
|
||||
# sed -i.bak -e 's/soname=\$\$SHLIB\$\$SHLIB_SOVER\$\$SHLIB_SUFFIX/soname=\$\$SHLIB/g' Makefile.shared
|
||||
make depend
|
||||
make
|
||||
# now fix the reference to libcrypto.so.1.0.0 to be just to libcrypto.so
|
||||
perl -pi -e 's/libcrypto.so.1.0.0/libcrypto.so\x00\x00\x00\x00\x00\x00/' libssl.so.1.0.0
|
||||
make install_sw
|
||||
popd
|
||||
fi
|
||||
|
||||
"${SUBSURFACE_SOURCE}"/scripts/get-dep-lib.sh singleAndroid . libzip
|
||||
if [ ! -e "$PKG_CONFIG_LIBDIR/libzip.pc" ] ; then
|
||||
# libzip expects a predefined macro that isn't there for our compiler
|
||||
pushd libzip
|
||||
@ -244,6 +276,7 @@ if [ "$QUICK" = "" ] ; then
|
||||
-DCMAKE_C_COMPILER="$CC" \
|
||||
-DCMAKE_LINKER="$CC" \
|
||||
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
|
||||
-DCMAKE_INSTALL_LIBDIR="lib" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
../libzip/
|
||||
make
|
||||
@ -251,30 +284,6 @@ if [ "$QUICK" = "" ] ; then
|
||||
popd
|
||||
fi
|
||||
|
||||
"${SUBSURFACE_SOURCE}"/scripts/get-dep-lib.sh singleAndroid . openssl
|
||||
if [ ! -e openssl-build-"$ARCH" ] ; then
|
||||
mv openssl openssl-build-"$ARCH"
|
||||
fi
|
||||
if [ ! -e "$PKG_CONFIG_LIBDIR/libssl.pc" ] ; then
|
||||
pushd openssl-build-"$ARCH"
|
||||
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
|
||||
# Use env to make all these temporary, so they don't pollute later builds.
|
||||
env SYSTEM=android \
|
||||
CROSS_COMPILE=${BUILDCHAIN}- \
|
||||
MACHINE=$OPENSSL_MACHINE \
|
||||
HOSTCC=gcc \
|
||||
CC=gcc \
|
||||
ANDROID_DEV="$PREFIX" \
|
||||
bash -x ./config shared no-ssl2 no-ssl3 no-comp no-hw no-engine --openssldir="$PREFIX"
|
||||
# sed -i.bak -e 's/soname=\$\$SHLIB\$\$SHLIB_SOVER\$\$SHLIB_SUFFIX/soname=\$\$SHLIB/g' Makefile.shared
|
||||
make depend
|
||||
make
|
||||
# now fix the reference to libcrypto.so.1.0.0 to be just to libcrypto.so
|
||||
perl -pi -e 's/libcrypto.so.1.0.0/libcrypto.so\x00\x00\x00\x00\x00\x00/' libssl.so.1.0.0
|
||||
make install_sw
|
||||
popd
|
||||
fi
|
||||
|
||||
"${SUBSURFACE_SOURCE}"/scripts/get-dep-lib.sh singleAndroid . libgit2
|
||||
if [ ! -e "$PKG_CONFIG_LIBDIR/libgit2.pc" ] ; then
|
||||
# We don't want to find the HTTP_Parser package of the build host by mistake
|
||||
@ -395,28 +404,27 @@ fi
|
||||
|
||||
PKGCONF=$(which pkg-config)
|
||||
cmake $MOBILE_CMAKE \
|
||||
-DPKG_CONFIG_EXECUTABLE="$PKGCONF" \
|
||||
-DCMAKE_SYSTEM_NAME="Android" \
|
||||
-DANDROID_ABI=$ANDROID_ABI \
|
||||
-DANDROID_PLATFORM="$ANDROID_PLATFORM" \
|
||||
-DQT_ANDROID_SDK_ROOT="$ANDROID_SDK_ROOT" \
|
||||
-DQT_ANDROID_NDK_ROOT="$ANDROID_NDK_ROOT" \
|
||||
-DANDROID_TOOLCHAIN="gcc" \
|
||||
-DANDROID_PLATFORM="android-16" \
|
||||
-DPKG_CONFIG_EXECUTABLE="$PKGCONF" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_ROOT"/build/cmake/android.toolchain.cmake \
|
||||
-DQT_ANDROID_CMAKE="$BUILDROOT"/qt-android-cmake/AddQtAndroidApk.cmake \
|
||||
-DANDROID_STL="gnustl_shared" \
|
||||
-DANDROID_STL="c++_shared" \
|
||||
-DFORCE_LIBSSH=OFF \
|
||||
-DLIBDC_FROM_PKGCONFIG=ON \
|
||||
-DLIBGIT2_FROM_PKGCONFIG=ON \
|
||||
-DNO_PRINTING=ON \
|
||||
-DNO_USERMANUAL=ON \
|
||||
-DNO_DOCS=ON \
|
||||
-DFBSUPPORT=OFF \
|
||||
-DCMAKE_PREFIX_PATH:UNINITIALIZED="$QT5_ANDROID_CMAKE" \
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DMAKE_TESTS=OFF \
|
||||
-DFTDISUPPORT=${FTDI} \
|
||||
-DANDROID_NATIVE_LIBSSL="$BUILDROOT/ndk-$ARCH/sysroot/usr/lib/libssl.so" \
|
||||
-DANDROID_NATIVE_LIBCRYPT="$BUILDROOT/ndk-$ARCH/sysroot/usr/lib/libcrypto.so" \
|
||||
-DBUILDTOOLS_REVISION="$ANDROID_BUILDTOOLS_REVISION" \
|
||||
-DCMAKE_MAKE_PROGRAM="make" \
|
||||
"$SUBSURFACE_SOURCE"
|
||||
|
||||
|
||||
@ -32,7 +32,8 @@ Controller.prototype.ComponentSelectionPageCallback = function() {
|
||||
var widget = gui.currentPageWidget();
|
||||
|
||||
widget.deselectAll();
|
||||
widget.selectComponent('qt.qt5.5111.android_armv7');
|
||||
widget.selectComponent('qt.qt5.5120.android_armv7');
|
||||
widget.selectComponent('qt.qt5.5120.android_arm64_v8a');
|
||||
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
@ -1,11 +1,13 @@
|
||||
#!/bin/bash
|
||||
# When changing Qt version remember to update the
|
||||
# qt-installer-noninteractive file as well.
|
||||
QT_VERSION=5.11
|
||||
LATEST_QT=5.11.1
|
||||
NDK_VERSION=r14b
|
||||
SDK_VERSION=3859397
|
||||
ANDROID_BUILDTOOLS_REVISION=25.0.3
|
||||
QT_VERSION=5.12
|
||||
LATEST_QT=5.12.0
|
||||
NDK_VERSION=r18b
|
||||
SDK_VERSION=4333796
|
||||
ANDROID_BUILDTOOLS_REVISION=28.0.2
|
||||
ANDROID_PLATFORM_LEVEL=21
|
||||
ANDROID_PLATFORM=android-21
|
||||
ANDROID_PLATFORMS=android-27
|
||||
ANDROID_NDK=android-ndk-${NDK_VERSION}
|
||||
ANDROID_SDK=android-sdk-linux
|
||||
|
||||