Porównaj commity

...

60 Commity
0.1 ... master

Autor SHA1 Wiadomość Data
Mateusz Lubecki 4641945295 better colours in night mode 2023-10-03 11:32:57 +02:00
Mateusz Lubecki f8dbcff362 compileSdkVersion increased to 31 2023-02-07 16:57:04 +01:00
Mateusz Lubecki 4f192e9a15 application icon 2022-07-15 20:13:29 +02:00
Mateusz Lubecki b6123ec677 version 2022-06-24 21:28:34 +02:00
Rafal Woloszyn 4c3b17fbfe
feat: Search view in all station activity (#4)
* feat: Search view in all station activity

* Fix searchbar width and animation
2022-06-24 21:08:58 +02:00
Mateusz Lubecki a2dd3149e9 version number increased in gradle config 2022-05-11 17:26:53 +02:00
SP8EBC ea23e7b5fb
Do not wait for network I/O to complete during activity creation (#3)
* downloading available params and summary refactored to separate thread

* downloading available parameters only when they are required instead of all at once during startup

* magic numbers extracted to separate static and final ints

* displaying loading prompt in values row on favourites list

* application renamed
2022-05-11 17:04:21 +02:00
Mateusz Lubecki 57fe1bfbfd speed up FavouritesStationSummaryUpdater in case of empty favs list 2022-05-08 17:26:47 +02:00
Mateusz Lubecki 5a211da64e credits added 2022-05-08 17:02:48 +02:00
Rafal Woloszyn 34d43825f9
Add JobIntentService for getting list of all stations + add refresh l… (#2)
* Add JobIntentService for getting list of all stations + add refresh listners

* Fix favourites list while all stations is still refreshing

* Add PL translation string

* Remove all files from commit.

* null reference access check in AvailableParametersDao, required to solve crash on very slow connection

Co-authored-by: rwoloszyn <rafal.woloszyn@iqvia.com>
2022-05-08 16:42:45 +02:00
Mateusz Lubecki 6bcdf9fdbb more fixing of handling http errors during updating favourites list 2022-05-03 19:56:00 +02:00
Mateusz Lubecki 1c7c805d58 Merge branch 'master' of github.com:SP8EBC/MeteoSystem 2022-05-03 17:39:29 +02:00
Mateusz Lubecki 89b08a3d11 bugfix in FavouritesStationDetailsOnListUpdater which sometimes crashed the application on ontry to favs list 2022-05-03 17:38:36 +02:00
SP8EBC 898e85d3bc
Update README.md 2022-01-09 22:19:48 +01:00
SP8EBC 1294a51f64
Update README.md 2022-01-09 22:17:33 +01:00
SP8EBC 1ab918a996
Update README.md 2022-01-07 09:38:30 +01:00
Mateusz Lubecki c15939a415 increased versionCode in gradle configuration 2022-01-07 09:22:18 +01:00
Mateusz Lubecki ed675f0233 changes to ux according to google play review 2022-01-07 09:20:48 +01:00
Mateusz Lubecki a40fb19282 gradle script with version pushed to the google play 2022-01-06 22:34:23 +01:00
Mateusz Lubecki 4b967b6857 more logging and updated screenshots 2022-01-06 22:06:53 +01:00
Mateusz Lubecki a08f06618b exporting logs to user storage 2022-01-06 21:09:33 +01:00
Mateusz Lubecki 63f4d64a4b ux improvements, changed colours, buttons etc 2022-01-06 19:52:59 +01:00
Mateusz Lubecki 0b18117b9c updating station summary for favourites separated from updating text view within activity 2022-01-06 12:36:18 +01:00
Mateusz Lubecki 660390391a favourites update handler moved to main 2022-01-05 21:28:47 +01:00
Mateusz Lubecki 31135df0c9 favourites and all station moved to main application class 2022-01-04 00:13:56 +01:00
Mateusz Lubecki 5e984ce264 Merge branch 'master' of github.com:SP8EBC/MeteoSystem 2021-12-10 15:02:25 +01:00
Mateusz Lubecki ef5277c4ff first public beta version 2021-12-10 15:01:53 +01:00
SP8EBC 375267bea4
Update README.md 2021-12-10 11:22:35 +01:00
Mateusz Lubecki a26da27200 application renamed 2021-12-10 11:21:06 +01:00
Mateusz Lubecki 1a93c9aab2 excel export 2021-12-09 22:05:00 +01:00
Mateusz Lubecki 8c24b0fe7e slight tweaks on wind rose 2021-12-09 21:38:54 +01:00
Mateusz Lubecki 37fdbc6a58 changing minimal decimation period and few ux tweaks 2021-12-09 20:50:19 +01:00
Mateusz Lubecki 797352c30e translation to CZE, UKR, RUS with an option to swith between them from settings. saving settings across application restart, few minor tweaks in layouts 2021-12-09 00:14:34 +01:00
Mateusz Lubecki 6e57412b1f showing NOT_AVALIABLE parameters in red 2021-12-08 13:36:01 +01:00
Mateusz Lubecki 6566b24b15 shortened delay after values on favourites list are updated, chenges with plots 2021-12-08 01:00:23 +01:00
Mateusz Lubecki a05a11988a consumers adjusted to new API design 2021-11-29 11:32:10 +01:00
Mateusz Lubecki a4dd0b9972 various ux tweaks 2021-11-27 00:20:53 +01:00
Mateusz Lubecki 6423966f9f changed the way background image is downloaded 2021-11-26 10:13:46 +01:00
Mateusz Lubecki 93aab76863 corrected formatting in WindRose activity and Trend 2021-11-26 00:27:13 +01:00
Mateusz Lubecki 8628529de0 updated to newest target API and some updates within gradle dependiences 2021-11-25 22:58:57 +01:00
Mateusz Lubecki f19b196aac displaying windspeed either in m/s and knots 2021-11-25 21:56:02 +01:00
Mateusz Lubecki bbd4657946 updating favourites list in background 2021-11-25 21:13:27 +01:00
Mateusz Lubecki 22d340efbd sorting favourites list 2021-11-11 13:13:55 +01:00
Mateusz Lubecki 022016d605 displaying current values into favourites list 2021-11-10 23:04:05 +01:00
Mateusz Lubecki 78093e489c excel export 2021-11-01 20:31:30 +01:00
Mateusz Lubecki 42256bf457 XLS export almost done 2021-10-24 11:28:48 +02:00
Mateusz Lubecki 7577673df6 exporting data to file 2021-10-23 20:53:59 +02:00
Mateusz Lubecki f903a5e636 directory chooser 2021-10-17 18:17:21 +02:00
Mateusz Lubecki aa992cb23a file chooser 2021-10-16 22:41:14 +02:00
Mateusz Lubecki 1907b88bbd data exoirt 2021-10-14 22:00:47 +02:00
Mateusz Lubecki 32ada27816 data export sketch 2021-10-13 21:00:10 +02:00
Mateusz Lubecki 2f1652a9fb saving restoring favourites list 2021-08-12 22:42:41 +02:00
Mateusz Lubecki e460611820 prototyping event bus 2021-08-12 07:07:44 +02:00
Mateusz Lubecki 8629960d88 removed some problems with API incompatiblity 2021-08-11 20:15:21 +02:00
Mateusz Lubecki 26067db9a2 Merge branch 'master' of https://github.com/SP8EBC/Pogoda.cc 2021-08-11 19:20:26 +02:00
Mateusz Lubecki c073b91d44 parceable stations list 2021-08-11 19:20:03 +02:00
SP8EBC 94259bb4e5
Merge pull request #1 from SP8EBC/translations-lv
Add LV translations
2021-02-15 15:10:43 +01:00
Andris Stikans b4b183c480 Add LV translations 2021-02-11 22:04:41 +02:00
Mateusz Lubecki e4793debe4 new resources 2021-02-11 19:28:38 +01:00
Mateusz Lubecki 03de2eda38 new strings in resources 2021-02-07 23:47:13 +01:00
219 zmienionych plików z 8690 dodań i 1918 usunięć

140
.gitignore vendored
Wyświetl plik

@ -13,3 +13,143 @@
.externalNativeBuild
.cxx
local.properties
# Built application files
*.apk
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle
.gradle/
build/
# Signing files
.signing/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio
/*/build/
/*/local.properties
/*/out
/*/*/build
/*/*/production
captures/
.navigation/
*.ipr
*~
*.swp
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Android Patch
gen-external-apklibs
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# NDK
obj/
# IntelliJ IDEA
*.iml
*.iws
/out/
# User-specific configurations
.idea/caches/
.idea/libraries/
.idea/shelf/
.idea/workspace.xml
.idea/tasks.xml
.idea/.name
.idea/compiler.xml
.idea/copyright/profiles_settings.xml
.idea/encodings.xml
.idea/misc.xml
.idea/modules.xml
.idea/scopes/scope_settings.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
.idea/datasources.xml
.idea/dataSources.ids
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
.idea/assetWizardSettings.xml
.idea/gradle.xml
.idea/jarRepositories.xml
.idea/navEditor.xml
# OS-specific files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Legacy Eclipse project files
.classpath
.project
.cproject
.settings/
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.ear
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
hs_err_pid*
## Plugin-specific files:
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Mongo Explorer plugin
.idea/mongoSettings.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### AndroidStudio Patch ###
!/gradle/wrapper/gradle-wrapper.jar

Wyświetl plik

@ -1 +0,0 @@
Pogoda.cc

Wyświetl plik

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
<bytecodeTargetLevel target="11" />
</component>
</project>

Wyświetl plik

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_4_XL_API_28.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-10-01T07:46:55.840082Z" />
</component>
</project>

Wyświetl plik

@ -4,7 +4,7 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="PLATFORM" />
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />
@ -15,7 +15,6 @@
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>

Wyświetl plik

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AndroidLintUnknownNullness" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

Wyświetl plik

@ -1,9 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="../../../../../layout/custom_preview.xml" value="0.2171875" />
<entry key="app/src/main/res/drawable/button_border.xml" value="0.38125" />
<entry key="app/src/main/res/layout/activity_all_stations.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_all_stations_linear_layout.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_export_data.xml" value="0.25" />
<entry key="app/src/main/res/layout/activity_favourites.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_favourites_empty.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_favourites_linear_layout.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_favourites_linear_layout_data.xml" value="0.5" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.5451010886469674" />
<entry key="app/src/main/res/layout/activity_settings.xml" value="0.67" />
<entry key="app/src/main/res/layout/activity_station_details.xml" value="0.33" />
<entry key="app/src/main/res/layout/activity_station_details_plots.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_station_details_summary.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/layout/activity_station_details_wind_rose.xml" value="0.5" />
<entry key="app/src/main/res/layout/activity_trend.xml" value="0.3645833333333333" />
<entry key="app/src/main/res/layout/fragment_pressure.xml" value="0.3645833333333333" />
<entry key="app/src/main/res/layout/fragment_temperature.xml" value="0.3645833333333333" />
<entry key="app/src/main/res/layout/fragment_wind.xml" value="0.3645833333333333" />
<entry key="app/src/main/res/layout/spinner_item.xml" value="0.28306159420289856" />
<entry key="app/src/main/res/menu/main_activity_menu.xml" value="0.3651041666666667" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_icon.xml" value="0.3335" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.3651041666666667" />
</ProjectState>
</option>
</component>
</project>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 188 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 196 KiB

Wyświetl plik

@ -1 +1,25 @@
# Pogoda.cc
# MeteoSystem
An Android application which displays meteo information from few APRS weather stations. Now mostly from Beskids mountins in Poland, but let's hope that it will widespread a little bit firther ;) The app was initialy called Pogoda.cc but then it was renamed to something more suitable for international use.
Google Play link to this software: https://play.google.com/store/apps/details?id=cc.pogoda.mobile.meteosystem
A list of currently avaliable weather stations (with APRS callsign in brackets) are below, with english or german site name after the comma. As for now all of them are located in southern Poland, mostly in Beskids Mountains but also in Low Beskids (located in SW Poland) and Oppelner Schlesien land.
- Skrzyczne (SR9NSK), Rauhkogel
- Jaworzyna Skrzyczneńska (SR9NSK-5)
- Kozia Góra (SR9WXS), Ziegenbock
- Magurka Wilkowicka (SR9WXM)
- Bezmiechowa Górna (SR8WXB)
- Góra Chełm (SR9WXG)
- Dukla, Wzgórze 534 (SR8WXD)
- Polska Nowa Wieś (SR6WXP), Polnisch Neudorf
- Leskowiec (SR9WXL)
- Markowe Szczawiny (SR9WXM)
- Jezioro Żywieckie (SR9WXZ)
- Międzybrodzie Żywieckie
This application is a part of bigger weather station system. The rest of it is formed by:
1. API: https://github.com/SP8EBC/meteo_backend
2. Receiving data from stations via APRS and storing in DB: https://github.com/SP8EBC/aprs2rrd-se
3. Firmware for APRS weather station controller and it's design: https://github.com/SP8EBC/ParaTNC

156
app/.gitignore vendored
Wyświetl plik

@ -1 +1,155 @@
/build
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# Built application files
*.apk
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle
.gradle/
build/
# Signing files
.signing/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio
/*/build/
/*/local.properties
/*/out
/*/*/build
/*/*/production
captures/
.navigation/
*.ipr
*~
*.swp
# Keystore files
*.jks
*.keystore
# Google Services (e.g. APIs or Firebase)
# google-services.json
# Android Patch
gen-external-apklibs
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# NDK
obj/
# IntelliJ IDEA
*.iml
*.iws
/out/
# User-specific configurations
.idea/caches/
.idea/libraries/
.idea/shelf/
.idea/workspace.xml
.idea/tasks.xml
.idea/.name
.idea/compiler.xml
.idea/copyright/profiles_settings.xml
.idea/encodings.xml
.idea/misc.xml
.idea/modules.xml
.idea/scopes/scope_settings.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
.idea/datasources.xml
.idea/dataSources.ids
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
.idea/assetWizardSettings.xml
.idea/gradle.xml
.idea/jarRepositories.xml
.idea/navEditor.xml
# OS-specific files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Legacy Eclipse project files
.classpath
.project
.cproject
.settings/
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.ear
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
hs_err_pid*
## Plugin-specific files:
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Mongo Explorer plugin
.idea/mongoSettings.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### AndroidStudio Patch ###
!/gradle/wrapper/gradle-wrapper.jar

Wyświetl plik

@ -3,17 +3,17 @@ plugins {
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
compileSdkVersion 33
buildToolsVersion "30.0.3"
apply plugin: "androidx.navigation.safeargs"
defaultConfig {
applicationId "cc.pogoda.mobile.pogodacc"
applicationId "cc.pogoda.mobile.meteosystem"
minSdkVersion 24
targetSdkVersion 26
versionCode 1
versionName "1.0"
targetSdkVersion 33
versionCode 19
versionName "0.19"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -36,23 +36,29 @@ repositories {
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'org.tinylog:tinylog-api:2.1.0'
runtimeOnly 'org.tinylog:tinylog-impl:2.1.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.navigation:navigation-fragment:2.3.2'
implementation 'androidx.navigation:navigation-ui:2.3.2'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
implementation 'com.squareup.okhttp3:okhttp:3.9.1'
implementation 'androidx.navigation:navigation-fragment:2.3.5'
implementation 'androidx.navigation:navigation-ui:2.3.5'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.2'
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'
implementation 'org.greenrobot:eventbus:3.0.0'
implementation 'org.apache.poi:poi:3.12'
// implementation 'org.apache.poi:poi-ooxml:3.12'
implementation 'com.fasterxml:aalto-xml:1.0.0'
}

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc;
package cc.pogoda.mobile.meteosystem;
import android.content.Context;

Wyświetl plik

@ -1,31 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.pogoda.mobile.pogodacc">
xmlns:tools="http://schemas.android.com/tools"
package="cc.pogoda.mobile.meteosystem">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission
android:name="android.permission.MANAGE_DOCUMENTS"
tools:ignore="ProtectedPermissions" />
<application
android:name=".Main"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:icon="@drawable/sun_rays_cloud"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_icon_foreground"
android:supportsRtl="true"
android:theme="@style/Theme.Pogodacc">
android:theme="@style/Theme.Meteosystem">
<service
android:name=".service.GetAllStationsService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<activity
android:name=".activity.SettingsActivity"
android:exported="true" />
<activity
android:name=".activity.ExportDataActivity"
android:exported="true" />
<activity
android:name=".activity.TrendActivity"
android:label="@string/title_activity_trend"></activity>
<activity android:name=".activity.StationDetailsWindRoseActivity" />
<activity android:name=".activity.StationDetailsPlotsWind" />
<activity android:name=".activity.StationDetailsPlotsDirection" />
<activity android:name=".activity.StationDetailsPlotsTemperature" />
<activity android:name=".activity.StationDetailsSummaryActivity" />
<activity android:name=".activity.StationDetailsActivity" />
<activity android:name=".activity.AllStationsActivity" />
<activity android:name=".activity.FavouritesActivity"/>
<activity android:name=".activity.MainActivity">
android:exported="true"
android:label="@string/title_activity_trend" />
<activity
android:name=".activity.StationDetailsWindRoseActivity"
android:exported="true" />
<activity
android:name=".activity.StationDetailsPlotsWind"
android:exported="true" />
<activity
android:name=".activity.StationDetailsPlotsDirection"
android:exported="true" />
<activity
android:name=".activity.StationDetailsPlotsTemperature"
android:exported="true" />
<activity
android:name=".activity.StationDetailsPlotsHumidity"
android:exported="true" />
<activity
android:name=".activity.StationDetailsSummaryActivity"
android:exported="true" />
<activity
android:name=".activity.StationDetailsActivity"
android:exported="true" />
<activity
android:name=".activity.AllStationsActivity"
android:launchMode="singleTop"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity
android:name=".activity.FavouritesActivity"
android:exported="true" />
<activity
android:name=".activity.MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 39 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 39 KiB

Wyświetl plik

@ -0,0 +1,317 @@
package cc.pogoda.mobile.meteosystem;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.jakewharton.threetenabp.AndroidThreeTen;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.tinylog.Logger;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import cc.pogoda.mobile.meteosystem.activity.updater.thread.FavouritesStationSummaryUpdaterThread;
import cc.pogoda.mobile.meteosystem.file.ConfigurationFile;
import cc.pogoda.mobile.meteosystem.file.FavouritiesFile;
import cc.pogoda.mobile.meteosystem.file.FileNames;
import cc.pogoda.mobile.meteosystem.service.GetAllStationsService;
import cc.pogoda.mobile.meteosystem.type.AllStationsReceivedEvent;
import cc.pogoda.mobile.meteosystem.type.AvailableParameters;
import cc.pogoda.mobile.meteosystem.type.ThemeColours;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.WeatherStationListEvent;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
public class Main extends Application {
private static String TAG = Main.class.getSimpleName();
private File directory;
private File directoryForLogs;
private Context ctx;
private ConfigurationFile confFile;
public FileNames getFileNames() {
return fileNames;
}
private FileNames fileNames;
private FavouritiesFile favouritiesFile;
public List<WeatherStation> getListOfAllStations() {
return listOfAllStations;
}
private List<WeatherStation> listOfAllStations;
public List<WeatherStation> getFavs() {
return favs;
}
private List<WeatherStation> favs;
/**
* This download summary for all stations stored on favourites list and stores results
* in 'HashMap<String, Summary> stationSystemNameToSummary'
*/
private FavouritesStationSummaryUpdaterThread favsSummaryUpdater = null;
/**
* This map stores summary for all favourites station
*/
private HashMap<String, Summary> hashmapFavStationSystemNameToSummary = null;
/**
* This hash map stores available parameters for all stations defined in the system
*/
private HashMap<String, AvailableParameters> hashmapAllStationSystemNameToAvailParameters = null;
public ThemeColours getThemeColours() {
return themeColours;
}
/**
* Used everywhere, where a colour of any element is set programatically (not globally from the theme)
*/
private ThemeColours themeColours;
public File getDirectory() {
return directory;
}
public File getDirectoryForLogs() {
return directoryForLogs;
}
public ConfigurationFile getConfFile() {
return confFile;
}
public HashMap<String, Summary> getHashmapFavStationSystemNameToSummary() {
return hashmapFavStationSystemNameToSummary;
}
public HashMap<String, AvailableParameters> getHashmapAllStationSystemNameToAvailParameters() {
return hashmapAllStationSystemNameToAvailParameters;
}
@Override
public void onCreate() {
super.onCreate();
ctx = this.getApplicationContext();
confFile = new ConfigurationFile(ctx);
directory = getApplicationContext().getDir("files", Context.MODE_PRIVATE);
directoryForLogs = new File(directory.getAbsolutePath() + "/logs/");
System.setProperty("tinylog.directory", directoryForLogs.getAbsolutePath());
Logger.info("Application starting...");
// StrictMode.VmPolicy.Builder b = new StrictMode.VmPolicy.Builder();
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// StrictMode.VmPolicy policy = b.detectAll().detectNonSdkApiUsage().penaltyListener((Runnable r) -> r.run(), (Violation v) -> {
// v.printStackTrace();
// Logger.warn("[StrictMode.VmPolicy][penaltyListener][Violation][v.getLocalizedMessage() = " + v.getLocalizedMessage() + "]");
// }).build();
// StrictMode.setVmPolicy(policy);
// }
AndroidThreeTen.init(this);
EventBus.getDefault().register(this);
ConfigurationFile confFile = new ConfigurationFile(ctx);
confFile.restoreFromFile();
hashmapFavStationSystemNameToSummary = new HashMap<>();
hashmapAllStationSystemNameToAvailParameters = new HashMap<>();
fileNames = new FileNames(ctx);
favouritiesFile = new FavouritiesFile(fileNames);
themeColours = new ThemeColours();
// Download all stations from API in background via JobIntentService. Results are send
//back with Broadcast receiver.
startGetAllStationsService();
// recreate list of favorites
recreateListOfFavs();
favsSummaryUpdater = new FavouritesStationSummaryUpdaterThread(hashmapFavStationSystemNameToSummary, hashmapAllStationSystemNameToAvailParameters);
favsSummaryUpdater.start(50);
// if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
// Logger.debug("[Main][onCreate][AppConfiguration.locale = " + AppConfiguration.locale + "]");
// Locale locale = new Locale(AppConfiguration.locale);
// Locale.setDefault(locale);
// Resources resources = this.getResources();
// Configuration config = resources.getConfiguration();
// config.setLocale(locale);
// Logger.debug("[Main][onCreate][locale = " + locale.toLanguageTag() + "]");
// resources.updateConfiguration(config, resources.getDisplayMetrics());
// }
}
@Override
public void onTerminate() {
super.onTerminate();
EventBus.getDefault().unregister(this);
}
private void recreateListOfFavs() {
if(listOfAllStations == null) {
Logger.info("[listOfAllStations=null]");
return;
}
// check if this is a first call after application start
if (favs == null) {
favs = favouritiesFile.loadFavourites();
}
// if favs is still null it means that favourites file doesn't even exists
// so and user hasn't added any station to it yet
if (favs == null) {
favs = new ArrayList<>();
}
else {
// update values for the fav list with listOfAllStations
//for (WeatherStation f : favs) {
for (int i = 0; i < favs.size(); i++) {
//
WeatherStation fromFavs = favs.get(i);
// find an index of updated station
int idx = listOfAllStations.indexOf(fromFavs);
// get the station
WeatherStation fromAllStations = listOfAllStations.get(idx);
// update all parameters
fromFavs.setAvailableParameters(fromAllStations.getAvailableParameters());
fromFavs.setMoreInfo(fromAllStations.getMoreInfo());
fromFavs.setImageAlign(fromAllStations.getImageAlign());
fromFavs.setImageUrl(fromAllStations.getImageUrl());
fromFavs.setSponsorUrl(fromAllStations.getSponsorUrl());
fromFavs.setMoreInfo(fromAllStations.getMoreInfo());
fromFavs.setLon(fromAllStations.getLon());
fromFavs.setLat(fromAllStations.getLat());
fromFavs.setDisplayedName(fromAllStations.getDisplayedName());
fromFavs.setDisplayedLocation(fromAllStations.getDisplayedLocation());
fromFavs.setTimezone(fromAllStations.getTimezone());
fromFavs.setCallsignSsid(fromAllStations.getCallsignSsid());
fromFavs.setStationNameTextColor(fromAllStations.getStationNameTextColor());
// there is no need to delete and put object on the list once again
// as a list does not make a copy of the object. It (ArrayList) keeps
// only a reference to an object
hashmapFavStationSystemNameToSummary.put(fromAllStations.getSystemName(), null);
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void weatherStationListHandler(WeatherStationListEvent serviceEvent) {
Logger.info("[serviceEvent = " + serviceEvent + "]");
switch (serviceEvent.getEventReason()) {
case ADD:
// check of list consist this station
if (favs.contains(serviceEvent.getStation())) {
return;
}
// add favourites to list
favs.add(serviceEvent.getStation());
try {
// save the list into JSON file
favouritiesFile.persistFavourities(favs);
} catch (IOException e) {
e.printStackTrace();
}
break;
case DELETE:
favs.remove(serviceEvent.getStation());
try {
// save the list into JSON file
favouritiesFile.persistFavourities(favs);
} catch (IOException e) {
e.printStackTrace();
}
break;
}
// recreate parceable object and pass it everywhere
recreateListOfFavs();
favsSummaryUpdater.updateImmediately();
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void allStationsEventHandler(@NonNull AllStationsReceivedEvent event) {
Logger.info("[event = " + event.toString() +"]");
this.listOfAllStations = event.getStations();
recreateListOfFavs();
}
public boolean listOfAllStationsReady() {
return listOfAllStations != null && listOfAllStations.size() > 0;
}
public boolean listOfFavsReady() {
/* && favs.size() > 0*/
return favs != null;
}
public boolean checkIsOnFavsList(String _system_name) {
boolean out = false;
for (WeatherStation wx : favs) {
if (wx.getSystemName().equals(_system_name)) {
out = true;
break;
}
}
return out;
}
public void startGetAllStationsService () {
Intent mIntent = new Intent(this, GetAllStationsService.class);
GetAllStationsService.enqueueWork(this, mIntent);
}
}

Wyświetl plik

@ -0,0 +1,152 @@
package cc.pogoda.mobile.meteosystem.activity;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.widget.SearchView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import cc.pogoda.mobile.meteosystem.Main;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.adapter.WeatherStationRecyclerViewAdapter;
import cc.pogoda.mobile.meteosystem.type.AllStationsReceivedEvent;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
import cc.pogoda.mobile.meteosystem.type.StartStationsRefreshEvent;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class AllStationsActivity extends AppCompatActivity {
private List<WeatherStation> allStationsList;
private SwipeRefreshLayout refreshLayout;
private WeatherStationRecyclerViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_all_stations);
refreshLayout = findViewById(R.id.refreshAllStationsView);
refreshLayout.setOnRefreshListener(
() -> ((Main) getApplication()).startGetAllStationsService()
);
RecyclerView recyclerViewAllStations = findViewById(R.id.recyclerViewAllStations);
adapter = new WeatherStationRecyclerViewAdapter(
new LinkedList<>(), this, ParceableFavsCallReason.Reason.ALL_STATIONS);
recyclerViewAllStations.setAdapter(adapter);
recyclerViewAllStations.setLayoutManager(new LinearLayoutManager(this));
handleIntent(getIntent());
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
filterStationList(query);
}
}
private void filterStationList(String searchQuery) {
if (allStationsList == null || allStationsList.isEmpty())
return;
if(searchQuery.isEmpty())
adapter.update(allStationsList);
List<WeatherStation> newList = allStationsList.stream()
.filter(station -> station.getDisplayedName()
.toLowerCase(Locale.ROOT).contains(searchQuery.toLowerCase(Locale.ROOT)))
.collect(Collectors.toList());
adapter.update(newList);
}
@Override
protected void onResume() {
super.onResume();
EventBus.getDefault().register(this);
updateStationList(((Main) getApplication()).getListOfAllStations());
}
@Override
protected void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_all_stations, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
@Override
public boolean onQueryTextSubmit(String s) {
return false;
}
@Override
public boolean onQueryTextChange(String s) {
filterStationList(s);
return false;
}
});
searchView.setOnCloseListener(() -> {
adapter.update(allStationsList);
return false;
});
return true;
}
private void updateStationList(List<WeatherStation> stations) {
if (stations != null) {
refreshLayout.setRefreshing(false);
allStationsList = stations;
adapter.update(stations);
} else {
EventBus.getDefault().post(new StartStationsRefreshEvent());
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void allStationsEventHandler(@NonNull AllStationsReceivedEvent event) {
updateStationList(event.getStations());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void startStationsRefreshEventHandler(@NonNull StartStationsRefreshEvent event) {
refreshLayout.setRefreshing(true);
Toast.makeText(this, R.string.refreshing_station_list, Toast.LENGTH_SHORT).show();
}
}

Wyświetl plik

@ -0,0 +1,302 @@
package cc.pogoda.mobile.meteosystem.activity;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
import java.io.FileNotFoundException;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.dao.StationDataDao;
import cc.pogoda.mobile.meteosystem.file.CsvExport;
import cc.pogoda.mobile.meteosystem.file.ExcelExport;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
import cc.pogoda.mobile.meteosystem.type.ParceableStationsList;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
public class ExportDataActivity extends AppCompatActivity {
private Spinner formatSpinner;
private Button selectStationButton;
private Button startExportButton, outputFileButton;
private Spinner outputFormat;
ExportDataActivity act;
TextView stationNameToExport;
EditText exportLn;
DatePicker datePicker;
WeatherStation stationToExport = null;
Uri exportUri = null;
public WeatherStation getStationToExport() {
return stationToExport;
}
public void openDirectory(String fn, int outputFormat) {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
if (outputFormat == 1) {
intent.setType("text/csv");
intent.putExtra(Intent.EXTRA_TITLE, fn + ".csv");
}
if (outputFormat == 2) {
intent.setType("application/vnd.ms-excel");
intent.putExtra(Intent.EXTRA_TITLE, fn + ".xls");
}
startActivityForResult(intent, 123);
}
public int getExportLnInHours() {
int out = 0;
Editable text = exportLn.getText();
try {
Integer ln = Integer.valueOf(text.toString());
if (ln > 199) {
out = 199;
}
else {
out = ln;
}
}
catch (NumberFormatException ee) {
out = -1;
}
return out;
}
public long getStartTimestamp() {
long out = 0;
int year = datePicker.getYear();
int month = datePicker.getMonth();
int day = datePicker.getDayOfMonth();
ZonedDateTime dateTime = ZonedDateTime.of(year, month, day, 0, 0, 0, 0, ZoneId.systemDefault());
ZonedDateTime utc = dateTime.withZoneSameInstant(ZoneId.of("UTC"));
out = utc.toEpochSecond();
return out;
}
public int getOutputFormat() {
String selected = outputFormat.getSelectedItem().toString();
switch (selected) {
case "CSV" : return 1;
case "MS Excel XLS": return 2;
}
return -1;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == 123 && resultCode == RESULT_OK) {
Uri uri = data.getData();
grantUriPermission(getPackageName(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
exportUri = uri;
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_export_data);
EventBus.getDefault().register(this);
act = this;
formatSpinner = findViewById(R.id.spinnerOutputFormat);
selectStationButton = findViewById(R.id.buttonSelectStationExport);
stationNameToExport = findViewById(R.id.textViewStationToExport);
startExportButton = findViewById(R.id.buttonExportStart);
exportLn = findViewById(R.id.editTextNumberExport);
datePicker = findViewById(R.id.datePickerExportStartDate);
outputFormat = findViewById(R.id.spinnerOutputFormat);
outputFileButton = findViewById(R.id.buttonExportTarget);
outputFileButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String fn;
if (stationToExport != null) {
fn = stationToExport.getSystemName() + "_" + datePicker.getDayOfMonth() + "-" + String.format("%02d", datePicker.getMonth()) + "-" + datePicker.getYear() +"_" + act.getExportLnInHours() + "hrs";
}
else {
fn = "export";
}
openDirectory(fn, act.getOutputFormat());
}
});
selectStationButton.setOnClickListener(new View.OnClickListener() {
Intent intent;
@Override
public void onClick(View view) {
intent = new Intent(act, FavouritesActivity.class);
ParceableFavsCallReason callReason = new ParceableFavsCallReason(ParceableFavsCallReason.Reason.EXPORT_SELECT);
intent.putExtra("callReason", callReason);
act.startActivity(intent);
}
});
startExportButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
StationDataDao stationDataDao;
WeatherStation toExport = act.getStationToExport();
if (toExport != null && exportUri != null) {
long timestampStart = act.getStartTimestamp();
long timestampStop = timestampStart + act.getExportLnInHours() * 3600;
stationDataDao = new StationDataDao();
ListOfStationData stationData = stationDataDao.getLastStationData(toExport.getSystemName(), timestampStart, timestampStop);
int format = act.getOutputFormat();
if (format == 2) {
try {
if (ExcelExport.exportToExcel(stationData, toExport, act.getApplicationContext(), getContentResolver().openOutputStream(exportUri))) {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.success);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
else {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.failure);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
else if (format == 1) {
try {
if (CsvExport.exportToCsv(stationData, toExport, act.getApplicationContext(), getContentResolver().openOutputStream(exportUri))) {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.success);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
else if (toExport == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.select_station_export);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
else {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.select_output_file);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
}
});
ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.export_formats, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
formatSpinner.setAdapter(adapter);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void stationToExportEvent(WeatherStation wx) {
stationNameToExport.setText(wx.getDisplayedName());
stationToExport = wx;
}
}

Wyświetl plik

@ -0,0 +1,172 @@
package cc.pogoda.mobile.meteosystem.activity;
import android.app.PendingIntent;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import cc.pogoda.mobile.meteosystem.Main;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.adapter.WeatherStationRecyclerViewAdapter;
import cc.pogoda.mobile.meteosystem.type.AllStationsReceivedEvent;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
import cc.pogoda.mobile.meteosystem.type.StartStationsRefreshEvent;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class FavouritesActivity extends AppCompatActivity {
RecyclerView recyclerViewFavourites;
private SwipeRefreshLayout refreshLayout;
List<WeatherStation> favourites = new LinkedList<>();
List<WeatherStation> sortedFavourites;
boolean sorting = false;
WeatherStationRecyclerViewAdapter adapter = null;
ParceableFavsCallReason callReason;
private static class WxStationComparator implements Comparator<WeatherStation> {
@Override
public int compare(WeatherStation station, WeatherStation t1) {
return (station.getDisplayedName().compareTo(t1.getDisplayedName()));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_favourites, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
//return super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.fav_sort_alph_oder:
sorting = true;
if (recyclerViewFavourites != null) {
adapter = new WeatherStationRecyclerViewAdapter(sortedFavourites, this, callReason.getReason());
adapter.createAndStartUpdater();
recyclerViewFavourites.setAdapter(adapter);
}
break;
case R.id.fav_sort_add_order:
sorting = false;
if (recyclerViewFavourites != null) {
adapter = new WeatherStationRecyclerViewAdapter(favourites, this, callReason.getReason());
adapter.createAndStartUpdater();
recyclerViewFavourites.setAdapter(adapter);
}
break;
}
return true;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_favourites);
recyclerViewFavourites = findViewById(R.id.recyclerViewFavourites);
refreshLayout = findViewById(R.id.refreshViewFavourites);
refreshLayout.setOnRefreshListener(
() -> ((Main) getApplication()).startGetAllStationsService()
);
callReason = getIntent().getParcelableExtra("callReason");
adapter = new WeatherStationRecyclerViewAdapter(favourites,
this, callReason.getReason());
recyclerViewFavourites.setAdapter(adapter);
recyclerViewFavourites.setLayoutManager(new LinearLayoutManager(this));
}
@Override
protected void onResume() {
Logger.debug("[onResume]");
super.onResume();
EventBus.getDefault().register(this);
updateStationList();
}
@Override
protected void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
@Override
protected void onDestroy() {
adapter.stopUpdater();
super.onDestroy();
}
private void updateStationList() {
List favList = ((Main) getApplication()).getFavs();
if(favList != null) {
favourites.clear();
favourites.addAll(favList);
refreshLayout.setRefreshing(false);
sortedFavourites = new ArrayList<>(favourites);
sortedFavourites.sort(new WxStationComparator());
adapter.notifyDataSetChanged();
if (!favList.isEmpty()) {
adapter.createAndStartUpdater();
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void allStationsEventHandler(@NonNull AllStationsReceivedEvent event) {
Logger.info("[event = " + event.toString() +"]");
updateStationList();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void startStationsRefreshEventHandler(@NonNull StartStationsRefreshEvent event) {
refreshLayout.setRefreshing(true);
Toast.makeText(this, R.string.refreshing_station_list, Toast.LENGTH_SHORT).show();
}
}

Wyświetl plik

@ -0,0 +1,219 @@
package cc.pogoda.mobile.meteosystem.activity;
// https://www.softicons.com/web-icons/vector-stylish-weather-icons-by-bartosz-kaszubowski/sun-rays-cloud-icon#google_vignette
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.color.MaterialColors;
import org.greenrobot.eventbus.EventBus;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.tinylog.Logger;
import java.io.FileNotFoundException;
import java.util.Locale;
import cc.pogoda.mobile.meteosystem.Main;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.MainActImageButtonAllStationsClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.MainActImageButtonExportClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.MainActImageButtonFavouritesClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.MainActImageButtonSettingsClickEvent;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.file.CopyLog;
import cc.pogoda.mobile.meteosystem.type.ThemeColours;
public class MainActivity extends AppCompatActivity {
private Main main;
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
Logger.info("[onDestroy]");
}
/**
* Called when a user goes back to the main screen
*/
@Override
protected void onResume() {
super.onResume();
Logger.info("[onResume]");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Logger.info("[onCreate]");
main = (Main) getApplication();
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default")) {
Logger.debug("[AppConfiguration.locale = "
+ AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
Logger.debug("[locale = " + locale.toLanguageTag() + "]");
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
setContentView(R.layout.activity_main);
ImageButton imageButtonAllStations = findViewById(R.id.imageButtonAllStations);
imageButtonAllStations.setOnClickListener(
new MainActImageButtonAllStationsClickEvent(this));
ImageButton imageButtonFavourites = findViewById(R.id.imageButtonFavourites);
imageButtonFavourites.setOnClickListener(
new MainActImageButtonFavouritesClickEvent(this));
ImageButton exportButton = findViewById(R.id.imageButtonExport);
exportButton.setOnClickListener(new MainActImageButtonExportClickEvent(this));
ImageButton settingsButton = findViewById(R.id.imageButtonSettings);
settingsButton.setOnClickListener(
new MainActImageButtonSettingsClickEvent(this, main.getConfFile()));
ThemeColours colours = ((Main) getApplication()).getThemeColours();
TypedValue typedValue = new TypedValue();
Resources.Theme theme = getTheme();
//MaterialColors.getColor(, R.attr.colorOnPrimary);
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
TypedArray arr = obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorPrimary});
colours.colorPrimary = arr.getColor(0, -1);
arr.recycle();
theme.resolveAttribute(R.attr.colorPrimaryVariant, typedValue, true);
arr = obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorPrimaryVariant});
colours.colorPrimaryVariant = arr.getColor(0, -1);
arr.recycle();
theme.resolveAttribute(R.attr.colorOnPrimary, typedValue, true);
arr = obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorOnPrimary});
colours.colorOnPrimary = arr.getColor(0, -1);
arr.recycle();
theme.resolveAttribute(R.attr.colorSecondary, typedValue, true);
arr = obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorSecondary});
colours.colorSecondary = arr.getColor(0, -1);
arr.recycle();
theme.resolveAttribute(R.attr.colorSecondaryVariant, typedValue, true);
arr = obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorSecondaryVariant});
colours.colorSecondaryVariant = arr.getColor(0, -1);
arr.recycle();
theme.resolveAttribute(R.attr.colorOnSecondary, typedValue, true);
arr = obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorOnSecondary});
colours.colorOnSecondary = arr.getColor(0, -1);
arr.recycle();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == 123 && resultCode == RESULT_OK) {
Uri uri = data.getData();
Logger.debug("[requestCode = 123][uri.getPath() = "
+ uri.getPath() + "]");
grantUriPermission(getPackageName(), uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
try {
CopyLog.forDay(main.getFileNames(), LocalDateTime.now(),
getContentResolver().openOutputStream(uri));
} catch (FileNotFoundException e) {
Logger.error("[FileNotFoundException][e = " + e.toString() +"]");
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_activity_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
//return super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_item_translation_authors: {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("ENG: Mateusz Lubecki\r\n" +
"CZE: Sylwiusz Pachel\r\n" +
"GER: Jakub Fiałek\r\n" +
"LAT: Andris Stikāns\r\n" +
"UKR, RUS: Влад Поливач \r\n" +
"(Wład Polywacz)\r\n\r\nProgram Icon: Bartosz Kaszubowski");
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
break;
}
case (R.id.menu_item_log_export): {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TITLE, "meteosystem_" +
LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + ".log");
startActivityForResult(intent, 123);
break;
}
}
return true;
}
public boolean listOfAllStationsReady() {
return main.listOfAllStationsReady() && main != null;
}
public boolean listOfAllFavsReady() {
return main.listOfFavsReady() && main != null;
}
}

Wyświetl plik

@ -0,0 +1,174 @@
package cc.pogoda.mobile.meteosystem.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import org.tinylog.Logger;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.file.ConfigurationFile;
public class SettingsActivity extends AppCompatActivity {
Switch windspdUnitSwitch;
TextView windspdUnitDisplayTv;
ConfigurationFile confFile;
Spinner language;
EditText enditTextMinutesPeriod;
AppCompatActivity act;
private static String languageNameFromShort(String shortName) {
Logger.info("[shortName = " + shortName +"]");
switch (shortName) {
case "en-rUS": return "English";
case "pl": return "Polski";
case "cs": return "Čeština";
case "uk": return "Українська мова";
case "ru": return "Русский";
case "lv": return "Latviešu";
case "de": return "Deutsch";
default: return "AUTO";
}
}
private void updateWindspdUnitTv(boolean b) {
if (windspdUnitDisplayTv != null) {
if (b) {
windspdUnitDisplayTv.setText(R.string.knots_long);
}
else {
windspdUnitDisplayTv.setText(R.string.meters_per_second);
}
confFile.storeToFile();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Logger.info("[onCreate]");
confFile = new ConfigurationFile(getBaseContext());
act = this;
windspdUnitDisplayTv = (TextView) findViewById(R.id.textViewSettingsWindspeedUnitDisp);
updateWindspdUnitTv(AppConfiguration.replaceMsWithKnots);
windspdUnitSwitch = (Switch) findViewById(R.id.switchKnots);
if (windspdUnitSwitch != null) {
windspdUnitSwitch.setChecked(AppConfiguration.replaceMsWithKnots);
windspdUnitSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
AppConfiguration.replaceMsWithKnots = b;
updateWindspdUnitTv(b);
}
});
}
enditTextMinutesPeriod = (EditText) findViewById(R.id.editTextNumberSettingsMinTimeRes);
enditTextMinutesPeriod.setText(Integer.toString(AppConfiguration.decimationPeriod));
if (enditTextMinutesPeriod != null) {
enditTextMinutesPeriod.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (i2 > 0) {
try {
int newValue = Integer.valueOf(String.valueOf(charSequence), 10);
if (newValue > 60) {
newValue = 60;
enditTextMinutesPeriod.setText(Integer.toString(newValue));
}
AppConfiguration.decimationPeriod = newValue;
confFile.storeToFile();
}
catch (NumberFormatException e) {
AppConfiguration.decimationPeriod = 0;
}
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
language = (Spinner) findViewById(R.id.spinnerSettingsLanguage);
if (language != null) {
ArrayAdapter spinnerLanguageAdapter = ArrayAdapter.createFromResource(getBaseContext(), R.array.languages, R.layout.spinner_item);
int currentLanguagePosition = spinnerLanguageAdapter.getPosition(SettingsActivity.languageNameFromShort(AppConfiguration.locale));
language.setAdapter(spinnerLanguageAdapter);
// if an item has been found (if no -1 is returned by 'getPosition'
if (currentLanguagePosition >= 0) {
language.setSelection(currentLanguagePosition);
}
language.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
String languageSelected = adapterView.getItemAtPosition(i).toString();
Logger.debug("[AdapterView.OnItemSelectedListener()][languageSelected = " + languageSelected +"]");
switch (languageSelected) {
case "English": AppConfiguration.locale = "en-rUS"; break;
case "Polski": AppConfiguration.locale = "pl"; break;
case "Čeština": AppConfiguration.locale = "cs"; break;
case "Українська мова": AppConfiguration.locale = "uk"; break;
case "Русский": AppConfiguration.locale = "ru"; break;
case "Latviešu": AppConfiguration.locale = "lv"; break;
case "Deutsch": AppConfiguration.locale = "de"; break;
default: AppConfiguration.locale = "default";
}
confFile.storeToFile();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
}
}

Wyświetl plik

@ -1,38 +1,44 @@
package cc.pogoda.mobile.pogodacc.activity;
package cc.pogoda.mobile.meteosystem.activity;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.text.HtmlCompat;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.icu.text.LocaleDisplayNames;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.RadioGroup;
import android.widget.TextView;
import java.io.InputStream;
import org.greenrobot.eventbus.EventBus;
import org.tinylog.Logger;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActTemperaturePlotButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActTrendButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActWindDirectionPlotsButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActWindSpeedPlotsButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActSummaryButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActWindRoseButtonClickEvent;
import cc.pogoda.mobile.pogodacc.config.AppConfiguration;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import java.util.Locale;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActHumidityPlotButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActTemperaturePlotButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActTrendButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActWindDirectionPlotsButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActWindSpeedPlotsButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActSummaryButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.handler.StationDetailsActWindRoseButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.updater.StationBackgroundImageUpdater;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.type.AvailableParameters;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.WeatherStationListEvent;
import cc.pogoda.mobile.meteosystem.web.StationBackgroundDownloader;
public class StationDetailsActivity extends AppCompatActivity {
@ -48,11 +54,14 @@ public class StationDetailsActivity extends AppCompatActivity {
ImageButton windSpeedPlotsButton = null;
ImageButton windDirectionPlotsButton = null;
ImageButton temperatureButton = null;
ImageButton humidityButton = null;
ImageButton windRoseButton = null;
ImageButton trendButton = null;
ImageView topBackground = null;
AppCompatActivity act;
/**
* Click event on Station Summary Button
*/
@ -67,6 +76,8 @@ public class StationDetailsActivity extends AppCompatActivity {
StationDetailsActTemperaturePlotButtonClickEvent temperaturePlotButtonClickEvent = null;
StationDetailsActHumidityPlotButtonClickEvent humidityPlotButtonClickEvent = null;
StationDetailsActTrendButtonClickEvent trendButtonClickEvent = null;
/**
@ -84,34 +95,7 @@ public class StationDetailsActivity extends AppCompatActivity {
*/
int selectedLn = 0;
/**
* This class downloads the background JPG image from the internet and
*/
private class DownloadImage implements Runnable {
ImageView iv;
String image_url;
Bitmap bitmap;
public DownloadImage(ImageView background, String url) {
iv = background;
image_url = url;
}
@Override
public void run() {
try {
InputStream in = new java.net.URL(image_url).openStream();
bitmap = BitmapFactory.decodeStream(in);
iv.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Handler handler;
public StationDetailsActivity() {
stationName = null;
@ -130,9 +114,9 @@ public class StationDetailsActivity extends AppCompatActivity {
switch (item.getItemId()) {
case R.id.menuItemStationDetailsAddFavourites:
if (station != null) {
boolean result = false;
boolean result = true;
result = AppConfiguration.favourites.addFav(station);
EventBus.getDefault().post(new WeatherStationListEvent(station, WeatherStationListEvent.EventReason.ADD));
if (result) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@ -147,9 +131,10 @@ public class StationDetailsActivity extends AppCompatActivity {
break;
case R.id.menuItemStationDetailsDeleteFavourites:
if (station != null) {
boolean result = false;
boolean result = true;
result = AppConfiguration.favourites.removeFav(station);
//result = AppConfiguration.favourites.removeFav(station);
EventBus.getDefault().post(new WeatherStationListEvent(station, WeatherStationListEvent.EventReason.DELETE));
if (result) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@ -179,9 +164,24 @@ public class StationDetailsActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
act = this;
station = (WeatherStation) getIntent().getSerializableExtra("station");
Logger.info("[station.getSystemName() = " + station.getSystemName() +"]");
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
setContentView(R.layout.activity_station_details);
station = (WeatherStation) getIntent().getSerializableExtra("station");
AvailableParameters parameters = station.getAvailableParameters();
stationName = findViewById(R.id.textViewStationName);
stationLocation = findViewById(R.id.textViewLocalization);
@ -213,6 +213,7 @@ public class StationDetailsActivity extends AppCompatActivity {
windSpeedPlotsClickEvent = new StationDetailsActWindSpeedPlotsButtonClickEvent(station, this);
windDirectionPlotsClickEvent = new StationDetailsActWindDirectionPlotsButtonClickEvent(station, this);
temperaturePlotButtonClickEvent = new StationDetailsActTemperaturePlotButtonClickEvent(station, this);
humidityPlotButtonClickEvent = new StationDetailsActHumidityPlotButtonClickEvent(station, this);
windRoseClickEvent = new StationDetailsActWindRoseButtonClickEvent(station, this);
trendButtonClickEvent = new StationDetailsActTrendButtonClickEvent(station, this);
@ -220,10 +221,43 @@ public class StationDetailsActivity extends AppCompatActivity {
summaryButton.setOnClickListener(summaryClickEvent);
windSpeedPlotsButton = findViewById(R.id.imageButtonPlotsWindSpeed);
windSpeedPlotsButton.setOnClickListener(windSpeedPlotsClickEvent);
if (parameters.windSpeed) {
windSpeedPlotsButton.setOnClickListener(windSpeedPlotsClickEvent);
}
else {
windSpeedPlotsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.station_doesnt_measure);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
});
}
windDirectionPlotsButton = findViewById(R.id.imageButtonPlotsWindDirection);
windDirectionPlotsButton.setOnClickListener(windDirectionPlotsClickEvent);
if (parameters.windSpeed) {
windDirectionPlotsButton.setOnClickListener(windDirectionPlotsClickEvent);
}
else {
windDirectionPlotsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.station_doesnt_measure);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
});
}
windRoseButton = findViewById(R.id.imageButtonWindRose);
windRoseButton.setOnClickListener(windRoseClickEvent);
@ -231,6 +265,25 @@ public class StationDetailsActivity extends AppCompatActivity {
temperatureButton = findViewById(R.id.imageButtonPlotsTemperature);
temperatureButton.setOnClickListener(temperaturePlotButtonClickEvent);
humidityButton = findViewById(R.id.imageButtonPlotsHumidity);
if (parameters.humidity) {
humidityButton.setOnClickListener(humidityPlotButtonClickEvent);
}
else {
humidityButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(act);
builder.setMessage(R.string.station_doesnt_measure);
builder.setPositiveButton(R.string.ok, (DialogInterface var1, int var2) -> {
var1.dismiss();
});
builder.create();
builder.show();
}
});
}
trendButton = findViewById(R.id.imageButtonTrend);
trendButton.setOnClickListener(trendButtonClickEvent);
@ -262,50 +315,82 @@ public class StationDetailsActivity extends AppCompatActivity {
}
stationName.setText(station.getDisplayedName());
if (station.getDisplayedName().length() > 18) {
stationName.setText(station.getDisplayedName());
stationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30.0f);
}
else {
stationName.setText(station.getDisplayedName());
stationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 36.0f);
}
stationLocation.setText(station.getDisplayedLocation());
station_lat = station.getLat();
station_lon = station.getLon();
stationSponsorUrl.setText(station.getSponsorUrl());
stationSponsorUrl.setAutoLinkMask(0);
stationSponsorUrl.setMovementMethod(LinkMovementMethod.getInstance());
String anchorText;
if (station.getSponsorUrl().length() > 32) {
anchorText = getString(R.string.www_link);
} else {
anchorText = station.getSponsorUrl();
}
stationSponsorUrl.setMovementMethod(LinkMovementMethod.getInstance());
stationSponsorUrl.setText(
HtmlCompat.fromHtml(
"<a href=\"" + station.getSponsorUrl() + "\">" + anchorText + "</a>\n", HtmlCompat.FROM_HTML_MODE_LEGACY
)
);
// if (station.getSponsorUrl().length() > 32) {
// stationSponsorUrl.setClickable(true);
// stationSponsorUrl.setMovementMethod(LinkMovementMethod.getInstance());
// stationSponsorUrl.setText(Html.fromHtml("<a href=\"" + station.getSponsorUrl() +"\">" + getString(R.string.www_link) + "</a>\n", HtmlCompat.FROM_HTML_MODE_LEGACY));
// }
// else {
// stationSponsorUrl.setText(station.getSponsorUrl());
// }
stationMoreInfo.setText(station.getMoreInfo());
DownloadImage downloadImage = new DownloadImage(topBackground, station.getImageUrl());
Thread t = new Thread(downloadImage);
StationBackgroundDownloader downloader = new StationBackgroundDownloader(station);
Thread t = new Thread(downloader);
t.start();
//runOnUiThread(downloadImage);
handler = new Handler();
handler.postDelayed(new StationBackgroundImageUpdater(topBackground, stationName, station, downloader, handler), 100);
if (station_lat > 0.0f && station_lon > 0.0f) {
// europe
sb.append(station_lon);
sb.append(" N / ");
sb.append(station_lat);
sb.append(" N / ");
sb.append(station_lon);
sb.append(" E");
stationLatLon.setText(sb.toString());
} else if (station_lat < 0.0f && station_lon > 0.0f) {
// usa
sb.append(station_lon);
sb.append(station_lat);
sb.append(" N / ");
sb.append(-station_lat);
sb.append(-station_lon);
sb.append(" W");
stationLatLon.setText(sb.toString());
} else if (station_lat < 0.0f && station_lon < 0.0f) {
// brazil
sb.append(-station_lon);
sb.append(" S / ");
sb.append(-station_lat);
sb.append(" S / ");
sb.append(-station_lon);
sb.append(" W");
stationLatLon.setText(sb.toString());
} else if (station_lat > 0.0f && station_lat > 0.0f) {
// australia
sb.append(-station_lon);
sb.append(-station_lat);
sb.append(" S / ");
sb.append(station_lat);
sb.append(station_lon);
sb.append(" E");
stationLatLon.setText(sb.toString());

Wyświetl plik

@ -1,5 +1,7 @@
package cc.pogoda.mobile.pogodacc.activity;
package cc.pogoda.mobile.meteosystem.activity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
@ -21,18 +23,21 @@ import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Locale;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.pogodacc.dao.LastStationDataDao;
import cc.pogoda.mobile.pogodacc.dao.StationDataDao;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.type.web.StationData;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.dao.LastStationDataDao;
import cc.pogoda.mobile.meteosystem.dao.StationDataDao;
import cc.pogoda.mobile.meteosystem.type.StationDetailsPlot;
import cc.pogoda.mobile.meteosystem.type.StationSummaryActElements;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.StationData;
public class StationDetailsPlotsDirection extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
@ -70,8 +75,10 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
// and then shift to the user timezone for convinient display
ZonedDateTime localDateTime = utcDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault());
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm");
/* format only the time to keep X axis clean */
return DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(localDateTime);
return fmt.format(localDateTime);
//return dt;
}
@ -123,10 +130,22 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
// get data length for this plot
dataLn = (int)getIntent().getExtras().get("data_ln");
setContentView(R.layout.activity_station_details_plots);
station = (WeatherStation) getIntent().getSerializableExtra("station");
Logger.info("[station.getSystemName() = " + station.getSystemName() +"][dataLn = " + dataLn +"]");
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
setContentView(R.layout.activity_station_details_plots);
// download data from web service
this.downloadDataFromWebservice();
@ -161,10 +180,13 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawAxisLine(false);
xAxis.setDrawGridLines(true);
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setTextColor(R.color.design_default_color_primary_dark);
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setGranularity(100f); // one hour
xAxis.setLabelRotationAngle(45.0f);
xAxis.setValueFormatter(new StationDetailsPlotsDirection.ValueFormatter());
xAxis.setTextSize(123.0f);
xAxis.setCenterAxisLabels(true);
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
@ -173,9 +195,10 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
leftAxis.setDrawGridLines(true);
leftAxis.setGranularityEnabled(true);
leftAxis.setAxisMinimum(0.0f);
leftAxis.setAxisMaximum(360.0f);
leftAxis.setAxisMaximum(400.0f);
leftAxis.setYOffset(0.0f);
leftAxis.setTextColor(Color.rgb(255, 192, 56));
leftAxis.setTextColor(R.color.design_default_color_primary_dark);
leftAxis.setTextSize(123.0f);
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
@ -210,7 +233,7 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
if (this.textViewSpeed != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewSpeed.setText(getString(R.string.wind_direction_short) + String.format(": %d", (int)direction));
this.textViewSpeed.setText(getString(R.string.wind_direction_short) + String.format(": %d - ", (int)direction) + StationSummaryActElements.convertDegreesToDir((int) direction));
}
else {
return;
@ -319,6 +342,8 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
// utc timestamp
long utcTimestamp = utcTime.toEpochSecond();
Logger.debug("[station.getSystemName() = " + station.getSystemName() +"]");
if (this.dataLn < 0 || this.dataLn > 2) {
// last 2000 points of data, regardless the timescale
data = lastStationDataDao.getLastStationData(station.getSystemName());
@ -339,6 +364,9 @@ public class StationDetailsPlotsDirection extends AppCompatActivity implements S
valuesWindDirection = new ArrayList<>();
if (data != null) {
Logger.debug("[data.list_of_station_data.length = " + data.list_of_station_data.length +"]");
for (StationData d : data.list_of_station_data) {
valuesWindDirection.add(new Entry(d.epoch * 1000, d.winddir));
}

Wyświetl plik

@ -0,0 +1,362 @@
package cc.pogoda.mobile.meteosystem.activity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Locale;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.dao.LastStationDataDao;
import cc.pogoda.mobile.meteosystem.dao.StationDataDao;
import cc.pogoda.mobile.meteosystem.type.StationDetailsPlot;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.StationData;
public class StationDetailsPlotsHumidity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
private LineChart chart = null;
private SeekBar seekBarX = null;
private TextView textViewTimestamp = null;
private TextView textViewHumidity = null;
private int dataLn = -2;
private WeatherStation station;
private final LastStationDataDao lastStationDataDao;
private final StationDataDao stationDataDao;
private PlotClickEvent plotClickEvent;
private ArrayList<Entry> valuesHumidity;
private static final int twelve_hours = 3600 * 12;
private static final int twenty_four_hours = 3600 * 24;
private static final int three_days = 3600 * 24 * 3;
private static class ValueFormatter extends com.github.mikephil.charting.formatter.ValueFormatter {
@Override
public String getFormattedValue(float value) {
long millis = (long) value;
// the web service and the plot always stores the entries as UTC. So first convert epoch timestamp to the LocalDateTime
LocalDateTime utcDateTime = LocalDateTime.ofEpochSecond(millis / 1000, 0, ZoneOffset.UTC);
// and then shift to the user timezone for convinient display
ZonedDateTime localDateTime = utcDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault());
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm");
/* format only the time to keep X axis clean */
return fmt.format(localDateTime);
}
}
public StationDetailsPlotsHumidity() {
lastStationDataDao = new LastStationDataDao();
stationDataDao = new StationDataDao();
plotClickEvent = new PlotClickEvent(this);
}
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// first and last index to display on plot
int first_index, last_index = 0;
// display only 20% of the set at once
int window_size = (int) (valuesHumidity.size() * 0.2f);
last_index = (int) ((seekBarX.getProgress() / 100.0f) * valuesHumidity.size());
first_index = last_index - window_size;
if (first_index < 0) {
first_index = 0;
last_index = window_size;
}
this.setData(first_index, last_index, false);
// redraw
chart.invalidate();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void updateLabels(String date, Entry entry) {
int humidity = 0;
// get a timestamp from the entry
long timestamp = (long) entry.getX();
// look for the windspeed coresponding to that timestamp
for (Entry e : valuesHumidity) {
// if this is what we are looking for
if (e.getX() == entry.getX()) {
humidity = (int) e.getY();
}
}
if (this.textViewHumidity != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewHumidity.setText(getText(R.string.humidity) + String.format(": %d%%", humidity));
}
else {
return;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get data length for this plot
dataLn = (int)getIntent().getExtras().get("data_ln");
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
setContentView(R.layout.activity_station_details_plots);
station = (WeatherStation) getIntent().getSerializableExtra("station");
// download data from web service
this.downloadDataFromWebservice();
Typeface tfLight = Typeface.MONOSPACE;
setTitle(R.string.humidity_plot);
textViewTimestamp = findViewById(R.id.textViewPlotsWindTimestamp);
textViewHumidity = findViewById(R.id.textViewPlotsWindMean);
seekBarX = findViewById(R.id.seekBarPlotsWind);
chart = findViewById(R.id.chartPlotsWind);
// enable scaling and dragging
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
chart.setDrawGridBackground(false);
chart.setHighlightPerDragEnabled(true);
// set an alternative background color
chart.setBackgroundColor(Color.WHITE);
chart.setViewPortOffsets(0f, 0f, 0f, 0f);
// add data
seekBarX.setProgress(100);
seekBarX.setOnSeekBarChangeListener(this);
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);
xAxis.setTypeface(tfLight);
xAxis.setTextSize(10f);
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawAxisLine(false);
xAxis.setDrawGridLines(true);
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setValueFormatter(new StationDetailsPlotsHumidity.ValueFormatter());
xAxis.setLabelRotationAngle(45.0f);
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
leftAxis.setTypeface(tfLight);
leftAxis.setTextColor(ColorTemplate.getHoloBlue());
leftAxis.setDrawGridLines(true);
leftAxis.setGranularityEnabled(true);
leftAxis.setAxisMinimum(0.0f);
leftAxis.setAxisMaximum(100.0f);
leftAxis.setYOffset(0.0f);
leftAxis.setTextColor(R.color.design_default_color_primary_dark);
leftAxis.setTextSize(123.0f);
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
int lastDataIndex = valuesHumidity.size() - 1;
// display only the last data (20% of newest data)
this.setData((long) (0.8 * (lastDataIndex)), lastDataIndex, false);
// set bar to maximum value
seekBarX.setProgress(100);
}
/**
* Downloads the data from the web service and stores it as entries ready to be displayed on the
* plot. Web Service gives the data with the epoch timestamp in second resolution, but the plot
* shows the data in millisecond resolution
*/
private void downloadDataFromWebservice() {
ListOfStationData data = null;
// utc time
ZonedDateTime utcTime = ZonedDateTime.now().withZoneSameInstant(ZoneId.of("UTC"));
// utc timestamp
long utcTimestamp = utcTime.toEpochSecond();
if (this.dataLn < 0 || this.dataLn > 2) {
// last 2000 points of data, regardless the timescale
data = lastStationDataDao.getLastStationData(station.getSystemName());
}
else if (dataLn == 0) {
// 12 hours
data = stationDataDao.getLastStationData(station.getSystemName(), utcTimestamp - twelve_hours, utcTimestamp);
}
else if (dataLn == 1) {
// 24 hours
data = stationDataDao.getLastStationData(station.getSystemName(), utcTimestamp - twenty_four_hours, utcTimestamp);
}
else if (dataLn == 2) {
// 3 days
data = stationDataDao.getLastStationData(station.getSystemName(), utcTimestamp - three_days, utcTimestamp);
}
valuesHumidity = new ArrayList<>();
if (data != null) {
for (StationData d : data.list_of_station_data) {
valuesHumidity.add(new Entry(d.epoch * 1000, d.humidity));
}
}
}
/**
*
* @param from
* @param to
* @param index_or_timestamp if set to false 'to' and 'from' are treated as an index, if they are set
* to true this method will use it as epoch timestamps (in seconds)
*/
public void setData(long from, long to, boolean index_or_timestamp) {
// if only some part of input set needs to be displayed use this intermediate buffer
ArrayList<Entry> narrowed_set, narrowed_set_gusts;
// data set to be displayed on the plot
LineDataSet set_humidity;
if (valuesHumidity.size() > 0) {
if (from != 0 || to != 0) {
// if 'from' and 'to' are the index values
if (!index_or_timestamp) {
// make a sublist
narrowed_set = new ArrayList<>(valuesHumidity.subList((int)from, (int)to));
}
else {
// get first and last entry from the set
Entry first = valuesHumidity.get(0);
Entry last = valuesHumidity.get(valuesHumidity.size() - 1 );
// check if 'from' and 'to' timestamp epoch covers any data from the input set
if ( (long)first.getX() > (to * 1000) ||
(long)last.getX() < (from * 1000)) {
// if there is no data to display exit from an function
return;
}
else {
narrowed_set = new ArrayList<>();
narrowed_set_gusts = new ArrayList<>();
// if not copy matching elements to narrowed set
valuesHumidity.forEach((Entry e) -> {
if (e.getX() > (from * 1000) &&
e.getX() < (to * 1000)) {
narrowed_set.add(e);
}
});
}
}
// and generate the set from it
set_humidity = new LineDataSet(narrowed_set, "Humidity");
}
else {
// use 'values_wind_speed' directly as a whole
set_humidity = new LineDataSet(valuesHumidity, "Humidity");
}
// create a dataset and give it a type
set_humidity.setAxisDependency(YAxis.AxisDependency.LEFT);
set_humidity.setColor(ColorTemplate.getHoloBlue());
set_humidity.setValueTextColor(ColorTemplate.getHoloBlue());
set_humidity.setLineWidth(3.5f);
set_humidity.setDrawCircles(true);
set_humidity.setDrawValues(true);
set_humidity.setFillAlpha(65);
set_humidity.setFillColor(ColorTemplate.getHoloBlue());
set_humidity.setHighLightColor(Color.rgb(244, 117, 117));
set_humidity.setDrawCircleHole(false);
// create a data object with the data sets
LineData line_data = new LineData();
line_data.addDataSet(set_humidity);
line_data.setValueTextColor(Color.WHITE);
line_data.setValueTextSize(9f);
// set data
chart.setData(line_data);
chart.setDoubleTapToZoomEnabled(false);
chart.setOnChartValueSelectedListener(plotClickEvent);
}
}
}

Wyświetl plik

@ -1,5 +1,7 @@
package cc.pogoda.mobile.pogodacc.activity;
package cc.pogoda.mobile.meteosystem.activity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
@ -21,18 +23,20 @@ import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Locale;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.pogodacc.dao.LastStationDataDao;
import cc.pogoda.mobile.pogodacc.dao.StationDataDao;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.type.web.StationData;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.dao.LastStationDataDao;
import cc.pogoda.mobile.meteosystem.dao.StationDataDao;
import cc.pogoda.mobile.meteosystem.type.StationDetailsPlot;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.StationData;
public class StationDetailsPlotsTemperature extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
@ -69,10 +73,10 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
// and then shift to the user timezone for convinient display
ZonedDateTime localDateTime = utcDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault());
// format only the time to keep X axis clean
String dt = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(localDateTime);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm");
return dt;
/* format only the time to keep X axis clean */
return fmt.format(localDateTime);
}
}
@ -92,6 +96,8 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
// utc timestamp
long utcTimestamp = utcTime.toEpochSecond();
Logger.debug("[station.getSystemName() = " + station.getSystemName() +"]");
if (this.dataLn < 0 || this.dataLn > 2) {
// last 2000 points of data, regardless the timescale
data = lastStationDataDao.getLastStationData(station.getSystemName());
@ -110,6 +116,9 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
}
if (data instanceof ListOfStationData) {
Logger.debug("[data.list_of_station_data.length = " + data.list_of_station_data.length +"]");
for (StationData d : data.list_of_station_data) {
valuesTemperature.add(new Entry(d.epoch * 1000, d.temperature));
}
@ -137,7 +146,7 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
// use wind speed label (on the left) to display the temperature
if (this.textViewSpeed != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewSpeed.setText(getString(R.string.temperature) + String.format(": %.1f°C", temperature));
this.textViewSpeed.setText(getString(R.string.temperature) + String.format(": %.1f°C", temperature).replace(',', '.'));
}
else {
return;
@ -242,14 +251,26 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// this activity layout is common for all plots
setContentView(R.layout.activity_station_details_plots);
// get data length for this plot
dataLn = (int)getIntent().getExtras().get("data_ln");
station = (WeatherStation) getIntent().getSerializableExtra("station");
Logger.info("[StationDetailsPlotsTemperature][onCreate][station.getSystemName() = " + station.getSystemName() +"][dataLn = " + dataLn +"]");
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[StationDetailsPlotsHumidity][onCreate][AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
// this activity layout is common for all plots
setContentView(R.layout.activity_station_details_plots);
// exit from the function if station object hasn't been added to the intent
if (station == null) {
return;
@ -289,10 +310,13 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawAxisLine(false);
xAxis.setDrawGridLines(true);
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setTextColor(R.color.design_default_color_primary_dark);
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setValueFormatter(new StationDetailsPlotsTemperature.ValueFormatter());
xAxis.setTextSize(123.0f);
xAxis.setCenterAxisLabels(true);
xAxis.setLabelRotationAngle(45.0f);
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
@ -303,7 +327,8 @@ public class StationDetailsPlotsTemperature extends AppCompatActivity implements
leftAxis.setAxisMinimum(-30.0f);
leftAxis.setAxisMaximum(40.0f);
leftAxis.setYOffset(0.0f);
leftAxis.setTextColor(Color.rgb(255, 192, 56));
leftAxis.setTextColor(R.color.design_default_color_primary_dark);
leftAxis.setTextSize(123.0f);
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);

Wyświetl plik

@ -1,7 +1,9 @@
package cc.pogoda.mobile.pogodacc.activity;
package cc.pogoda.mobile.meteosystem.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
@ -22,19 +24,20 @@ import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import org.tinylog.Logger;
import java.util.ArrayList;
import java.util.Locale;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.pogodacc.config.AppConfiguration;
import cc.pogoda.mobile.pogodacc.dao.LastStationDataDao;
import cc.pogoda.mobile.pogodacc.dao.StationDataDao;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.type.web.StationData;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.dao.LastStationDataDao;
import cc.pogoda.mobile.meteosystem.dao.StationDataDao;
import cc.pogoda.mobile.meteosystem.type.StationDetailsPlot;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.StationData;
public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
@ -76,10 +79,10 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
// and then shift to the user timezone for convinient display
ZonedDateTime localDateTime = utcDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault());
// format only the time to keep X axis clean
String dt = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(localDateTime);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm");
return dt;
/* format only the time to keep X axis clean */
return fmt.format(localDateTime);
}
}
@ -96,13 +99,26 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
int lastDataIndex = 0;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station_details_plots);
// get data length for this plot
dataLn = (int)getIntent().getExtras().get("data_ln");
station = (WeatherStation) getIntent().getSerializableExtra("station");
Logger.info("[station.getSystemName() = " + station.getSystemName() +"][dataLn = " + dataLn +"]");
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
setContentView(R.layout.activity_station_details_plots);
// download data from web service
this.downloadDataFromWebservice();
@ -137,10 +153,14 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawAxisLine(false);
xAxis.setDrawGridLines(true);
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setTextColor(R.color.design_default_color_primary_dark);
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setValueFormatter(new ValueFormatter());
xAxis.setLabelRotationAngle(45.0f);
xAxis.setTextSize(123.0f);
xAxis.setCenterAxisLabels(true);
xAxis.setLabelRotationAngle(45.0f);
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
@ -151,7 +171,8 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
leftAxis.setAxisMinimum(0.0f);
leftAxis.setAxisMaximum(this.findMaxValueForPlotScale());
leftAxis.setYOffset(0.0f);
leftAxis.setTextColor(Color.rgb(255, 192, 56));
leftAxis.setTextColor(R.color.design_default_color_primary_dark);
leftAxis.setTextSize(123.0f);
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
@ -197,6 +218,8 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
// utc timestamp
long utcTimestamp = utcTime.toEpochSecond();
Logger.debug("[station.getSystemName() = " + station.getSystemName() +"]");
if (this.dataLn < 0 || this.dataLn > 2) {
// last 2000 points of data, regardless the timescale
data = lastStationDataDao.getLastStationData(station.getSystemName());
@ -218,6 +241,9 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
valuesWindGusts = new ArrayList<>();
if (data instanceof ListOfStationData) {
Logger.debug("[data.list_of_station_data.length = " + data.list_of_station_data.length +"]");
for (StationData d : data.list_of_station_data) {
valuesWindSpeed.add(new Entry(d.epoch * 1000, d.windspeed));
valuesWindGusts.add(new Entry(d.epoch * 1000, d.windgusts));
@ -263,8 +289,8 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
if (this.textViewGusts != null && this.textViewSpeed != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewSpeed.setText(getString(R.string.mean_value_short) + String.format(": %.1f%s", mean, unit));
this.textViewGusts.setText(getString(R.string.wind_gust_short) + String.format(": %.1f%s", gusts, unit));
this.textViewSpeed.setText(getString(R.string.mean_value_short) + String.format(": %.1f%s", mean, unit).replace(',', '.'));
this.textViewGusts.setText(getString(R.string.wind_gust_short) + String.format(": %.1f%s", gusts, unit).replace(',', '.'));
}
else {
return;

Wyświetl plik

@ -0,0 +1,163 @@
package cc.pogoda.mobile.meteosystem.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.util.TypedValue;
import org.tinylog.Logger;
import java.util.Locale;
import cc.pogoda.mobile.meteosystem.Main;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.updater.StationDetailsValuesOnActivityFromFavsUpdater;
import cc.pogoda.mobile.meteosystem.activity.updater.StationDetailsValuesOnActivityUpdater;
import cc.pogoda.mobile.meteosystem.activity.updater.thread.StationSummaryUpdaterThread;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.dao.SummaryDao;
import cc.pogoda.mobile.meteosystem.type.StationSummaryActElements;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
public class StationDetailsSummaryActivity extends AppCompatActivity {
StationSummaryActElements elems = null;
WeatherStation station = null;
StationSummaryUpdaterThread updaterThread = null;
StationDetailsValuesOnActivityUpdater valuesOnActUpdater = null;
StationDetailsValuesOnActivityFromFavsUpdater valuesFromFavsSummaryUpdater = null;
Handler handler = null;
Main main = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
main = (Main)getApplication();
elems = new StationSummaryActElements();
int color = main.getThemeColours().colorOnSecondary;
Summary summary = null;
SummaryDao summary_dao = new SummaryDao();
super.onCreate(savedInstanceState);
station = (WeatherStation) getIntent().getSerializableExtra("station");
Logger.info("[station.getSystemName() = " + station.getSystemName() +"]");
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
setContentView(R.layout.activity_station_details_summary);
elems.title = findViewById(R.id.textViewStationDetailsSummaryTitle);
elems.title.setText(station.getDisplayedName());
if (station.getDisplayedName().length() < 18) {
elems.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 38);
}
else {
elems.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30);
}
elems.wind_dir_val = findViewById(R.id.textViewWinddirValue);
elems.wind_gusts_val = findViewById(R.id.textViewWindGustsValue);
elems.wind_speed_val = findViewById(R.id.textViewWindSpeedValue);
elems.temperature_val = findViewById(R.id.textViewTemperatureValue);
elems.qnh_val = findViewById(R.id.textViewQnhVaue);
elems.humidity_val = findViewById(R.id.textViewHumidityValue);
elems.message = findViewById(R.id.textViewSummaryMessage);
elems.goodColor = color;
elems.badColor = Color.RED;
// create a handler to update station data in background
handler = new Handler();
// check if this station is on favourites list
boolean onFavs = main.checkIsOnFavsList(station.getSystemName());
if (onFavs) {
valuesFromFavsSummaryUpdater = new StationDetailsValuesOnActivityFromFavsUpdater(elems, handler, station, main.getHashmapFavStationSystemNameToSummary());
if (handler != null && valuesFromFavsSummaryUpdater != null) {
handler.post(valuesFromFavsSummaryUpdater);
}
}
else {
updaterThread = new StationSummaryUpdaterThread(station.getSystemName());
// create a copy of updater class for this station
valuesOnActUpdater = new StationDetailsValuesOnActivityUpdater(elems, handler, updaterThread, station);
if (handler != null && valuesOnActUpdater != null) {
updaterThread.start(50);
handler.postDelayed(valuesOnActUpdater, 500);
}
}
}
@Override
protected void onPause() {
super.onPause();
if (updaterThread != null) {
updaterThread.stop();
}
}
@Override
protected void onResume() {
super.onResume();
if (updaterThread != null) {
updaterThread.start(50);
}
}
@Override
protected void onStop() {
if (handler != null && valuesOnActUpdater != null) {
handler.removeCallbacks(valuesOnActUpdater);
}
if (updaterThread != null) {
updaterThread.stop();
}
super.onStop();
}
@Override
protected void onDestroy() {
if (updaterThread != null) {
updaterThread.stop();
}
super.onDestroy();
}
}

Wyświetl plik

@ -0,0 +1,142 @@
package cc.pogoda.mobile.meteosystem.activity;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import org.tinylog.Logger;
import cc.pogoda.mobile.meteosystem.Main;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.updater.StationDetailsValuesOnActivityFromFavsUpdater;
import cc.pogoda.mobile.meteosystem.activity.updater.StationDetailsValuesOnActivityUpdater;
import cc.pogoda.mobile.meteosystem.activity.updater.thread.StationSummaryUpdaterThread;
import cc.pogoda.mobile.meteosystem.dao.SummaryDao;
import cc.pogoda.mobile.meteosystem.type.StationWindRoseActElements;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
public class StationDetailsWindRoseActivity extends AppCompatActivity {
WeatherStation station;
Summary summary;
StationSummaryUpdaterThread updaterThread = null;
StationDetailsValuesOnActivityUpdater onActivityUpdater = null;
StationDetailsValuesOnActivityFromFavsUpdater fromSummaryUpdater = null;
Handler handler = null;
StationWindRoseActElements elements;
Main main = null;
public StationDetailsWindRoseActivity() {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station_details_wind_rose);
station = (WeatherStation) getIntent().getSerializableExtra("station");
Logger.info("[station.getSystemName() = " + station.getSystemName() +"]");
main = (Main)getApplication();
// find all elements in the xml layout file and set the references in a holding object
elements = new StationWindRoseActElements();
elements.windArrow = findViewById(R.id.imageViewWindRoseArrow);
elements.windSpeed = findViewById(R.id.textViewWindRoseWindSpeedValue);
elements.windGusts = findViewById(R.id.textViewWindRoseWindGustsValue);
elements.windDirection = findViewById(R.id.textViewWindRoseWindDirectionValue);
elements.temperature = findViewById(R.id.textViewWindRoseTemperaturaValue);
elements.maxGust = findViewById(R.id.textViewWindRoseMaxHourGust);
elements.minAverage = findViewById(R.id.textViewWindRoseMinHourSpeed);
elements.pressure = findViewById(R.id.textViewWindRosePressure);
elements.goodColor = ((Main) getApplication()).getThemeColours().colorOnSecondary;
elements.badColor = Color.RED;
elements.setActivity(this);
// create the handler which will update the screen in background
handler = new Handler();
SummaryDao summary_dao = new SummaryDao();
handler = new Handler();
// check if this station is on favourites list
boolean onFavs = main.checkIsOnFavsList(station.getSystemName());
if (onFavs) {
fromSummaryUpdater = new StationDetailsValuesOnActivityFromFavsUpdater(elements, handler, station, main.getHashmapFavStationSystemNameToSummary());
if (handler != null && fromSummaryUpdater != null) {
handler.post(fromSummaryUpdater);
}
}
else {
updaterThread = new StationSummaryUpdaterThread(station.getSystemName());
onActivityUpdater = new StationDetailsValuesOnActivityUpdater(elements, handler, updaterThread, station);
if (handler != null && onActivityUpdater != null) {
updaterThread.start(50);
// start the handler to update the wind rose activity in background
handler.postDelayed(onActivityUpdater, 500);
}
}
}
@Override
protected void onPause() {
super.onPause();
if (updaterThread != null) {
updaterThread.stop();
}
}
@Override
protected void onResume() {
super.onResume();
if (updaterThread != null && updaterThread.isEnabled() == false) {
updaterThread.start(50);
}
}
@Override
protected void onStop() {
// remove and stop background callback
if (handler != null && onActivityUpdater != null) {
handler.removeCallbacks(onActivityUpdater);
}
if (updaterThread != null) {
updaterThread.stop();
}
super.onStop();
}
@Override
protected void onDestroy() {
if (updaterThread != null) {
updaterThread.stop();
}
super.onDestroy();
}
}

Wyświetl plik

@ -1,5 +1,7 @@
package cc.pogoda.mobile.pogodacc.activity;
package cc.pogoda.mobile.meteosystem.activity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import com.google.android.material.bottomnavigation.BottomNavigationView;
@ -8,18 +10,19 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavArgument;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.NavGraph;
import androidx.navigation.Navigation;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.trend.pressure.PressureTrendFragment;
import cc.pogoda.mobile.pogodacc.activity.trend.pressure.PressureTrendFragmentArgs;
import cc.pogoda.mobile.pogodacc.activity.trend.pressure.PressureTrendFragmentDirections;
import cc.pogoda.mobile.pogodacc.activity.trend.temperature.TemperatureTrendFragmentDirections;
import cc.pogoda.mobile.pogodacc.activity.trend.wind.WindTrendFragmentDirections;
import org.tinylog.Logger;
import java.util.Locale;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.trend.pressure.PressureTrendFragmentDirections;
import cc.pogoda.mobile.meteosystem.activity.trend.temperature.TemperatureTrendFragmentDirections;
import cc.pogoda.mobile.meteosystem.activity.trend.wind.WindTrendFragmentDirections;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
public class TrendActivity extends AppCompatActivity {
@ -33,15 +36,24 @@ public class TrendActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String stationName = (String)getIntent().getExtras().get("station");
setContentView(R.layout.activity_trend);
NavArgument.Builder builder = new NavArgument.Builder();
if (AppConfiguration.locale != null && !AppConfiguration.locale.equals("default") ) {
Logger.debug("[AppConfiguration.locale = " + AppConfiguration.locale + "]");
Locale locale = new Locale(AppConfiguration.locale);
Locale.setDefault(locale);
Resources resources = this.getResources();
Configuration config = resources.getConfiguration();
config.setLocale(locale);
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
this.station = stationName;
Bundle bundle = new Bundle();
bundle.putString("station", stationName);
this.station = stationName;
setContentView(R.layout.activity_trend);
NavArgument.Builder builder = new NavArgument.Builder();
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
@ -55,20 +67,8 @@ public class TrendActivity extends AppCompatActivity {
NavDirections wind = WindTrendFragmentDirections.actionNavigationWindToNavigationTemperature(stationName);
NavDirections pressure = PressureTrendFragmentDirections.actionNavigationPressureToNavigationWind(stationName);
//NavHostFragment.create(R.navigation.mobile_navigation, bundle);
// NavGraph navGraph = navController.getNavInflater().inflate(R.navigation.mobile_navigation);
// builder.setDefaultValue(stationName);
// navGraph.addArgument("station", builder.build());
// navController.setGraph(navGraph, bundle);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
//navController.navigate(temperature);
//
// NavArgument.Builder builder = new NavArgument.Builder();
// builder.setDefaultValue(stationName);
// navGraph.addArgument("station", builder.build());
// navController.setGraph(navGraph);
}

Wyświetl plik

@ -0,0 +1,52 @@
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import org.greenrobot.eventbus.EventBus;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsActivity;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class AllStationsActRecyclerViewButtonClickEvent implements View.OnClickListener {
WeatherStation station;
AppCompatActivity p;
Intent intent;
ParceableFavsCallReason.Reason reason;
public AllStationsActRecyclerViewButtonClickEvent(WeatherStation wx, AppCompatActivity parent, ParceableFavsCallReason.Reason r) {
station = wx;
p = parent;
reason = r;
}
@Override
public void onClick(View v) {
if (reason == null || reason == ParceableFavsCallReason.Reason.FAVOURITES || reason == ParceableFavsCallReason.Reason.ALL_STATIONS) {
intent = new Intent(p, StationDetailsActivity.class);
intent.putExtra("station", station);
p.startActivity(intent);
return;
}
else if (reason == ParceableFavsCallReason.Reason.EXPORT_SELECT) {
EventBus.getDefault().post(station);
p.setResult(Activity.RESULT_OK);
p.finish();
return;
}
}
}

Wyświetl plik

@ -1,34 +1,26 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.AllStationsActivity;
import cc.pogoda.mobile.meteosystem.activity.AllStationsActivity;
import cc.pogoda.mobile.meteosystem.activity.MainActivity;
import cc.pogoda.mobile.meteosystem.type.ParceableStationsList;
public class MainActImageButtonAllStationsClickEvent implements View.OnClickListener {
AppCompatActivity parent;
MainActivity parent;
Intent intent;
public MainActImageButtonAllStationsClickEvent(AppCompatActivity parent) {
public MainActImageButtonAllStationsClickEvent(MainActivity parent) {
this.parent = parent;
intent = new Intent(this.parent, AllStationsActivity.class);
}
@Override
public void onClick(View v) {
launchActivity();
return;
}
private void launchActivity() {
parent.startActivity(intent);
}
}

Wyświetl plik

@ -0,0 +1,32 @@
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import org.tinylog.Logger;
import cc.pogoda.mobile.meteosystem.activity.ExportDataActivity;
import cc.pogoda.mobile.meteosystem.type.ParceableStationsList;
public class MainActImageButtonExportClickEvent implements View.OnClickListener{
AppCompatActivity parent;
Intent intent;
public MainActImageButtonExportClickEvent(AppCompatActivity p) {
parent = p;
intent = new Intent(this.parent, ExportDataActivity.class);
}
@Override
public void onClick(View view) {
Logger.info("[onClick]");
parent.startActivity(intent);
}
}

Wyświetl plik

@ -0,0 +1,32 @@
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.meteosystem.activity.FavouritesActivity;
import cc.pogoda.mobile.meteosystem.activity.MainActivity;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
import cc.pogoda.mobile.meteosystem.type.ParceableStationsList;
public class MainActImageButtonFavouritesClickEvent implements View.OnClickListener{
MainActivity parent;
Intent intent;
public MainActImageButtonFavouritesClickEvent(MainActivity parent) {
this.parent = parent;
intent = new Intent(this.parent, FavouritesActivity.class);
ParceableFavsCallReason callReason = new ParceableFavsCallReason(ParceableFavsCallReason.Reason.FAVOURITES);
intent.putExtra("callReason", callReason);
}
@Override
public void onClick(View view) {
parent.startActivity(intent);
}
}

Wyświetl plik

@ -0,0 +1,28 @@
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.meteosystem.activity.SettingsActivity;
import cc.pogoda.mobile.meteosystem.file.ConfigurationFile;
public class MainActImageButtonSettingsClickEvent implements View.OnClickListener {
AppCompatActivity parent;
Intent intent;
public MainActImageButtonSettingsClickEvent(AppCompatActivity _parent, ConfigurationFile _configuration_file) {
parent = _parent;
intent = new Intent(parent, SettingsActivity.class);
}
@Override
public void onClick(View view) {
parent.startActivity(intent);
}
}

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
@ -13,7 +13,7 @@ import org.threeten.bp.format.FormatStyle;
import java.util.Date;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.meteosystem.type.StationDetailsPlot;
public class PlotClickEvent implements OnChartValueSelectedListener {

Wyświetl plik

@ -0,0 +1,32 @@
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsPlotsHumidity;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActHumidityPlotButtonClickEvent implements View.OnClickListener {
WeatherStation station;
AppCompatActivity p;
Intent intent;
@Override
public void onClick(View view) {
intent = new Intent(p, StationDetailsPlotsHumidity.class);
intent.putExtra("station", station);
intent.putExtra("data_ln", (int)p.getIntent().getExtras().get("data_ln"));
p.startActivity(intent);
}
public StationDetailsActHumidityPlotButtonClickEvent(WeatherStation wx, AppCompatActivity parent) {
station = wx;
p = parent;
}
}

Wyświetl plik

@ -1,13 +1,12 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsSummaryActivity;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsSummaryActivity;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActSummaryButtonClickEvent implements View.OnClickListener {

Wyświetl plik

@ -1,12 +1,12 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsTemperature;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsPlotsTemperature;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActTemperaturePlotButtonClickEvent implements View.OnClickListener {

Wyświetl plik

@ -1,12 +1,12 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.TrendActivity;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.activity.TrendActivity;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActTrendButtonClickEvent implements View.OnClickListener {

Wyświetl plik

@ -1,13 +1,12 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsDirection;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsTemperature;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsPlotsDirection;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActWindDirectionPlotsButtonClickEvent implements View.OnClickListener {

Wyświetl plik

@ -1,12 +1,12 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsWindRoseActivity;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsWindRoseActivity;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActWindRoseButtonClickEvent implements View.OnClickListener {

Wyświetl plik

@ -1,12 +1,12 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
package cc.pogoda.mobile.meteosystem.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsWind;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.activity.StationDetailsPlotsWind;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationDetailsActWindSpeedPlotsButtonClickEvent implements View.OnClickListener {

Wyświetl plik

@ -1,21 +1,20 @@
package cc.pogoda.mobile.pogodacc.activity.trend.pressure;
package cc.pogoda.mobile.meteosystem.activity.trend.pressure;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.TrendActivity;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.TrendActivity;
public class PressureTrendFragment extends Fragment {
@ -53,7 +52,15 @@ public class PressureTrendFragment extends Fragment {
eightHours = root.findViewById(R.id.textViewPressureTrendEightHoursVal);
pressureTrendViewModel.getStationName().observe(getViewLifecycleOwner(), s -> {
if (s.length() < 18) {
stationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 38);
}
else {
stationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 28);
}
stationName.setText(s);
});
pressureTrendViewModel.getLastMeasuremenetTime().observe(getViewLifecycleOwner(), s -> {

Wyświetl plik

@ -1,18 +1,16 @@
package cc.pogoda.mobile.pogodacc.activity.trend.pressure;
package cc.pogoda.mobile.meteosystem.activity.trend.pressure;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import cc.pogoda.mobile.pogodacc.dao.TrendDao;
import cc.pogoda.mobile.pogodacc.type.web.Trend;
import cc.pogoda.mobile.meteosystem.dao.TrendDao;
import cc.pogoda.mobile.meteosystem.type.web.Trend;
public class PressureTrendViewModel extends ViewModel {
@ -51,11 +49,11 @@ public class PressureTrendViewModel extends ViewModel {
stationName.postValue(trend.displayed_name);
if (!trend.current_qnh_qf.equals("NOT_AVALIABLE") && !trend.current_qnh_qf.equals("NO_DATA")) {
currentValue.postValue(String.format("%.1f hPa", trend.pressure_trend.current_value));
twoHoursValue.postValue(String.format("%.1f hPa", trend.pressure_trend.two_hours_value));
fourHoursValue.postValue(String.format("%.1f hPa", trend.pressure_trend.four_hours_value));
sixHoursValue.postValue(String.format("%.1f hPa", trend.pressure_trend.six_hours_value));
eightHoursValue.postValue(String.format("%.1f hPa", trend.pressure_trend.eight_hours_value));
currentValue.postValue(String.format("%shPa", trend.pressure_trend.getCurrentVal(true, true)));
twoHoursValue.postValue(String.format("%shPa", trend.pressure_trend.getTwoHoursVal(true, true)));
fourHoursValue.postValue(String.format("%shPa", trend.pressure_trend.getFourHoursVal(true, true)));
sixHoursValue.postValue(String.format("%shPa", trend.pressure_trend.getSixHoursVal(true, true)));
eightHoursValue.postValue(String.format("%shPa", trend.pressure_trend.getEightHoursVal(true, true)));
}
else {
currentValue.postValue("-- hPa");

Wyświetl plik

@ -1,23 +1,20 @@
package cc.pogoda.mobile.pogodacc.activity.trend.temperature;
package cc.pogoda.mobile.meteosystem.activity.trend.temperature;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import org.w3c.dom.Text;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.TrendActivity;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.TrendActivity;
public class TemperatureTrendFragment extends Fragment {
@ -72,6 +69,14 @@ public class TemperatureTrendFragment extends Fragment {
textViewTemperatureTrendEightHoursHVal = root.findViewById(R.id.textViewTemperatureTrendEightHoursHVal);
temperatureTrendViewModel.getDisplayedStationName().observe(getViewLifecycleOwner(), s -> {
if (s.length() < 18) {
textViewTemperatureTrendStationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 38);
}
else {
textViewTemperatureTrendStationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 28);
}
textViewTemperatureTrendStationName.setText(s);
});

Wyświetl plik

@ -1,6 +1,5 @@
package cc.pogoda.mobile.pogodacc.activity.trend.temperature;
package cc.pogoda.mobile.meteosystem.activity.trend.temperature;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
@ -9,8 +8,8 @@ import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import cc.pogoda.mobile.pogodacc.dao.TrendDao;
import cc.pogoda.mobile.pogodacc.type.web.Trend;
import cc.pogoda.mobile.meteosystem.dao.TrendDao;
import cc.pogoda.mobile.meteosystem.type.web.Trend;
public class TemperatureTrendViewModel extends ViewModel {
@ -118,11 +117,11 @@ public class TemperatureTrendViewModel extends ViewModel {
if (!trend.current_humidity_qf.equals("NOT_AVALIABLE") && !trend.current_humidity_qf.equals("NO_DATA")) {
currentHumidityValue.postValue(String.format("%.1f %%", trend.humidity_trend.current_value));
twoHoursHumidityValue.postValue(String.format("%.1f %%", trend.humidity_trend.two_hours_value));
fourHoursHumidityValue.postValue(String.format("%.1f %%", trend.humidity_trend.four_hours_value));
sixHoursHumidityValue.postValue(String.format("%.1f %%", trend.humidity_trend.six_hours_value));
eightHoursHumidityValue.postValue(String.format("%.1f %%", trend.humidity_trend.eight_hours_value));
currentHumidityValue.postValue(String.format("%s%%", trend.humidity_trend.getCurrentVal(true, true)));
twoHoursHumidityValue.postValue(String.format("%s%%", trend.humidity_trend.getTwoHoursVal(true, true)));
fourHoursHumidityValue.postValue(String.format("%s%%", trend.humidity_trend.getFourHoursVal(true, true)));
sixHoursHumidityValue.postValue(String.format("%s%%", trend.humidity_trend.getSixHoursVal(true, true)));
eightHoursHumidityValue.postValue(String.format("%s%%", trend.humidity_trend.getEightHoursVal(true, true)));
}
else {
@ -136,11 +135,11 @@ public class TemperatureTrendViewModel extends ViewModel {
}
if (!trend.current_temperature_qf.equals("NOT_AVALIABLE") && !trend.current_temperature_qf.equals("NO_DATA")) {
currentTemperatureValue.postValue(String.format("%.1f °C", trend.temperature_trend.current_value));
twoHoursTemperatureValue.postValue(String.format("%.1f °C", trend.temperature_trend.two_hours_value));
fourHoursTemperatureValue.postValue(String.format("%.1f °C", trend.temperature_trend.four_hours_value));
sixHoursTemperatureValue.postValue(String.format("%.1f °C", trend.temperature_trend.six_hours_value));
eightHoursTemperatureValue.postValue(String.format("%.1f °C", trend.temperature_trend.eight_hours_value));
currentTemperatureValue.postValue(String.format("%s°C", trend.temperature_trend.getCurrentVal(true, false)));
twoHoursTemperatureValue.postValue(String.format("%s°C", trend.temperature_trend.getTwoHoursVal(true, false)));
fourHoursTemperatureValue.postValue(String.format("%s°C", trend.temperature_trend.getFourHoursVal(true, false)));
sixHoursTemperatureValue.postValue(String.format("%s°C", trend.temperature_trend.getSixHoursVal(true, false)));
eightHoursTemperatureValue.postValue(String.format("%s°C", trend.temperature_trend.getEightHoursVal(true, false)));
}
else {
currentTemperatureValue.postValue("-- °C");

Wyświetl plik

@ -1,8 +1,9 @@
package cc.pogoda.mobile.pogodacc.activity.trend.wind;
package cc.pogoda.mobile.meteosystem.activity.trend.wind;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -12,8 +13,8 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.TrendActivity;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.TrendActivity;
public class WindTrendFragment extends Fragment {
@ -64,6 +65,13 @@ public class WindTrendFragment extends Fragment {
textViewWindTrendEightHoursGustsVal = root.findViewById(R.id.textViewTemperatureTrendEightHoursHVal);
windTrendViewModel.getDisplayedStationName().observe(getViewLifecycleOwner(), s -> {
if (s.length() < 18) {
textViewWindTrendStationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 38);
}
else {
textViewWindTrendStationName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 28);
}
textViewWindTrendStationName.setText(s);
});

Wyświetl plik

@ -0,0 +1,194 @@
package cc.pogoda.mobile.meteosystem.activity.trend.wind;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import cc.pogoda.mobile.meteosystem.dao.TrendDao;
import cc.pogoda.mobile.meteosystem.type.web.Trend;
public class WindTrendViewModel extends ViewModel {
public void setStation(String station) {
this.station = station;
}
private String station = "";
private TrendDao trendDao;
private MutableLiveData<String> displayedStationName;
private MutableLiveData<String> lastMeasuremenetTime;
private MutableLiveData<String> currentMeanValue;
private MutableLiveData<String> twoHoursMeanValue;
private MutableLiveData<String> fourHoursMeanValue;
private MutableLiveData<String> sixHoursMeanValue;
private MutableLiveData<String> eightHoursMeanValue;
private MutableLiveData<String> currentGustValue;
private MutableLiveData<String> twoHoursGustValue;
private MutableLiveData<String> fourHoursGustValue;
private MutableLiveData<String> sixHoursGustValue;
private MutableLiveData<String> eightHoursGustValue;
public MutableLiveData<String> getDisplayedStationName() {
return displayedStationName;
}
public MutableLiveData<String> getLastMeasuremenetTime() {
return lastMeasuremenetTime;
}
public MutableLiveData<String> getCurrentMeanValue() {
return currentMeanValue;
}
public MutableLiveData<String> getTwoHoursMeanValue() {
return twoHoursMeanValue;
}
public MutableLiveData<String> getFourHoursMeanValue() {
return fourHoursMeanValue;
}
public MutableLiveData<String> getSixHoursMeanValue() {
return sixHoursMeanValue;
}
public MutableLiveData<String> getEightHoursMeanValue() {
return eightHoursMeanValue;
}
public MutableLiveData<String> getCurrentGustValue() {
return currentGustValue;
}
public MutableLiveData<String> getTwoHoursGustValue() {
return twoHoursGustValue;
}
public MutableLiveData<String> getFourHoursGustValue() {
return fourHoursGustValue;
}
public MutableLiveData<String> getSixHoursGustValue() {
return sixHoursGustValue;
}
public MutableLiveData<String> getEightHoursGustValue() {
return eightHoursGustValue;
}
public WindTrendViewModel() {
trendDao = new TrendDao();
displayedStationName = new MutableLiveData<String>();
lastMeasuremenetTime = new MutableLiveData<String>();
currentMeanValue = new MutableLiveData<String>();
twoHoursMeanValue = new MutableLiveData<String>();
fourHoursMeanValue = new MutableLiveData<String>();
sixHoursMeanValue = new MutableLiveData<String>();
eightHoursMeanValue = new MutableLiveData<String>();
currentGustValue = new MutableLiveData<String>();
twoHoursGustValue = new MutableLiveData<String>();
fourHoursGustValue = new MutableLiveData<String>();
sixHoursGustValue = new MutableLiveData<String>();
eightHoursGustValue = new MutableLiveData<String>();
}
public boolean updateData() {
if (station != null && station.length() > 0) {
Trend trend = trendDao.getStationTrend(station);
if (trend != null) {
// format the time and date according to current locale
String dt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT).format(LocalDateTime.ofEpochSecond(trend.last_timestamp, 0, ZoneOffset.UTC).atOffset(ZoneOffset.UTC).atZoneSameInstant(ZoneOffset.systemDefault()));
lastMeasuremenetTime.postValue(dt);
displayedStationName.postValue(trend.displayed_name);
if (!trend.current_wind_qf.equals("NOT_AVALIABLE") && !trend.current_wind_qf.equals("NO_DATA")) {
currentMeanValue.postValue(String.format("%sm/s", trend.average_wind_speed_trend.getCurrentVal(true, false)));
twoHoursMeanValue.postValue(String.format("%sm/s", trend.average_wind_speed_trend.getTwoHoursVal(true, false)));
fourHoursMeanValue.postValue(String.format("%sm/s", trend.average_wind_speed_trend.getFourHoursVal(true, false)));
sixHoursMeanValue.postValue(String.format("%sm/s", trend.average_wind_speed_trend.getSixHoursVal(true, false)));
eightHoursMeanValue.postValue(String.format("%sm/s", trend.average_wind_speed_trend.getEightHoursVal(true, false)));
currentGustValue.postValue(String.format("%sm/s", trend.maximum_wind_speed_trend.getCurrentVal(true, false)));
twoHoursGustValue.postValue(String.format("%sm/s", trend.maximum_wind_speed_trend.getTwoHoursVal(true, false)));
fourHoursGustValue.postValue(String.format("%sm/s", trend.maximum_wind_speed_trend.getFourHoursVal(true, false)));
sixHoursGustValue.postValue(String.format("%sm/s", trend.maximum_wind_speed_trend.getSixHoursVal(true, false)));
eightHoursGustValue.postValue(String.format("%sm/s", trend.maximum_wind_speed_trend.getEightHoursVal(true, false)));
// if (AppConfiguration.replaceMsWithKnots) {
// // if knots
// currentMeanValue.postValue(String.format("%.0f kts", trend.average_wind_speed_trend.current_value));
// twoHoursMeanValue.postValue(String.format("%.0f kts", trend.average_wind_speed_trend.two_hours_value));
// fourHoursMeanValue.postValue(String.format("%.0f kts", trend.average_wind_speed_trend.four_hours_value));
// sixHoursMeanValue.postValue(String.format("%.0f kts", trend.average_wind_speed_trend.six_hours_value));
// eightHoursMeanValue.postValue(String.format("%.0f kts", trend.average_wind_speed_trend.eight_hours_value));
//
// currentGustValue.postValue(String.format("%.0f kts", trend.maximum_wind_speed_trend.current_value));
// twoHoursGustValue.postValue(String.format("%.0f kts", trend.maximum_wind_speed_trend.two_hours_value));
// fourHoursGustValue.postValue(String.format("%.0f kts", trend.maximum_wind_speed_trend.four_hours_value));
// sixHoursGustValue.postValue(String.format("%.0f kts", trend.maximum_wind_speed_trend.six_hours_value));
// eightHoursGustValue.postValue(String.format("%.0f kts", trend.maximum_wind_speed_trend.eight_hours_value));
// } else {
// // if meters per second
// currentMeanValue.postValue(String.format("%.1f m/s", trend.average_wind_speed_trend.current_value));
// twoHoursMeanValue.postValue(String.format("%.1f m/s", trend.average_wind_speed_trend.two_hours_value));
// fourHoursMeanValue.postValue(String.format("%.1f m/s", trend.average_wind_speed_trend.four_hours_value));
// sixHoursMeanValue.postValue(String.format("%.1f m/s", trend.average_wind_speed_trend.six_hours_value));
// eightHoursMeanValue.postValue(String.format("%.1f m/s", trend.average_wind_speed_trend.eight_hours_value));
//
// currentGustValue.postValue(String.format("%.1f m/s", trend.maximum_wind_speed_trend.current_value));
// twoHoursGustValue.postValue(String.format("%.1f m/s", trend.maximum_wind_speed_trend.two_hours_value));
// fourHoursGustValue.postValue(String.format("%.1f m/s", trend.maximum_wind_speed_trend.four_hours_value));
// sixHoursGustValue.postValue(String.format("%.1f m/s", trend.maximum_wind_speed_trend.six_hours_value));
// eightHoursGustValue.postValue(String.format("%.1f m/s", trend.maximum_wind_speed_trend.eight_hours_value));
// }
} else {
currentMeanValue.postValue("--");
twoHoursMeanValue.postValue("--");
fourHoursMeanValue.postValue("--");
sixHoursMeanValue.postValue("--");
eightHoursMeanValue.postValue("--");
currentGustValue.postValue("--");
twoHoursGustValue.postValue("--");
fourHoursGustValue.postValue("--");
sixHoursGustValue.postValue("--");
eightHoursGustValue.postValue("--");
}
return true;
} else {
currentMeanValue.postValue("--");
twoHoursMeanValue.postValue("--");
fourHoursMeanValue.postValue("--");
sixHoursMeanValue.postValue("--");
eightHoursMeanValue.postValue("--");
currentGustValue.postValue("--");
twoHoursGustValue.postValue("--");
fourHoursGustValue.postValue("--");
sixHoursGustValue.postValue("--");
eightHoursGustValue.postValue("--");
return false;
}
}
return false;
}
}

Wyświetl plik

@ -0,0 +1,161 @@
package cc.pogoda.mobile.meteosystem.activity.updater;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.DETAILS_ON_FAVS_LIST_DEFAULT_UPDATE;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.DETAILS_ON_FAVS_LIST_REUPDATE;
import android.annotation.SuppressLint;
import android.graphics.Color;
import android.os.Handler;
import android.widget.TextView;
import org.tinylog.Logger;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import cc.pogoda.mobile.meteosystem.activity.updater.thread.FavouritesStationSummaryUpdaterThread;
import cc.pogoda.mobile.meteosystem.dao.AvailableParametersDao;
import cc.pogoda.mobile.meteosystem.type.AvailableParameters;
import cc.pogoda.mobile.meteosystem.type.ThemeColours;
import cc.pogoda.mobile.meteosystem.type.web.AvailableParametersWeb;
import cc.pogoda.mobile.meteosystem.type.web.QualityFactor;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
/**
* This class is used to update entries (TextView) on Favourites list using HashMap
* which is updated by {@link FavouritesStationSummaryUpdaterThread}
*/
public class FavouritesStationDetailsOnListUpdater implements Runnable {
/**
* Handler is used by Android to put a Runnable into MessageQueue handler by the Looper. This
* runnable can be scheduled to be serviced at certain point of time
*/
private Handler handler;
/**
* A collection which holds
*/
private HashMap<String, TextView> stationsToUpdate;
/**
*
*/
//private AvailableParametersDao availableParametersDao = null;
private HashMap<String, AvailableParameters> availParams;
/**
* This map comes from 'Main' class and it is shared with @link{{@link FavouritesStationSummaryUpdaterThread}}
*/
HashMap<String, Summary> stationNameSummary = null;
/**
* Not sure if this is really required but just to be sure that updater won't be started
* after the activity had been torn down.
*/
private boolean enabled;
/**
* Used everywhere, where a colour of any element is set programatically (not globally from the theme)
*/
private ThemeColours themeColours;
public FavouritesStationDetailsOnListUpdater(Handler _handler, HashMap<String, Summary> _station_system_name_to_summary, HashMap<String, AvailableParameters> _avail_params, ThemeColours _themeColours) {
handler = _handler;
stationsToUpdate = new HashMap<>();
availParams = _avail_params;
stationNameSummary = _station_system_name_to_summary;
themeColours = _themeColours;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void addNewStation(String _station_system_name, TextView _tv) {
stationsToUpdate.put(_station_system_name, _tv);
}
@SuppressLint("ResourceAsColor")
@Override
public void run() {
int nextExecutionDelay = DETAILS_ON_FAVS_LIST_DEFAULT_UPDATE;
if (stationNameSummary != null && enabled && stationsToUpdate != null && stationsToUpdate.size() > 0) {
// get a set of all elements stored in the map
Set<Map.Entry<String, TextView>> entries = stationsToUpdate.entrySet();
// create something iterable from the set. the set itself doesn't guarantee the same order than
// objects were put in, but in this case it isn't a problem.
Vector<Map.Entry<String, TextView>> vectorOfEntries = new Vector<>(entries);
for (Map.Entry<String, TextView> e : vectorOfEntries) {
// extract data from pair
String stationSystemName = e.getKey();
TextView toUpdate = e.getValue();
// query web service for station data
Summary summary = stationNameSummary.get(stationSystemName);
// query for available parameters
AvailableParameters params = availParams.get(stationSystemName);
// if data has been collected
if (summary != null && params != null) {
Logger.debug("[stationSystemName = " + stationSystemName +"][summary.last_timestamp = " + summary.last_timestamp +"]");
String str;
// check if this station transmits wind information
if (params.windSpeed) {
// check if station transmits humidity
if (params.humidity) {
str = String.format("%s %d%% %s %s max %s", summary.getTemperatureStr(false, true), summary.humidity, summary.getWindDirStr(), summary.getWindspeedStr(false), summary.getWindgustsStr(false));
}
else {
str = String.format("%s %s %s max %s", summary.getTemperatureStr(false, true), summary.getWindDirStr(), summary.getWindspeedStr(false), summary.getWindgustsStr(false));
}
}
else {
if (params.humidity) {
str = String.format("%s %d%%", summary.getTemperatureStr(false, true), summary.humidity);
}
else {
str = String.format("%s", summary.getTemperatureStr(false, true));
}
}
// update text view on the favourites list
toUpdate.setText(str);
if ( (params.humidity && summary.humidity_qf_native.equals(QualityFactor.NOT_AVALIABLE)) ||
(summary.temperature_qf_native.equals(QualityFactor.NOT_AVALIABLE)) ||
(params.windSpeed && summary.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)))
{
toUpdate.setTextColor(Color.RED);
}
else {
toUpdate.setTextColor(themeColours.colorPrimary);
}
}
else {
Logger.error("[stationSystemName = " + stationSystemName + "][summary object is null!! Maybe the API responds exceptionally slow?]");
nextExecutionDelay = DETAILS_ON_FAVS_LIST_REUPDATE;
}
}
handler.postDelayed(this, nextExecutionDelay);
}
}
}

Wyświetl plik

@ -0,0 +1,44 @@
package cc.pogoda.mobile.meteosystem.activity.updater;
import android.graphics.Bitmap;
import android.os.Handler;
import android.widget.ImageView;
import android.widget.TextView;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.web.StationBackgroundDownloader;
public class StationBackgroundImageUpdater implements Runnable{
ImageView iv;
TextView station_name;
WeatherStation station;
StationBackgroundDownloader downloader;
Handler handler;
public StationBackgroundImageUpdater(ImageView _background, TextView _station_name, WeatherStation _station, StationBackgroundDownloader _downloader, Handler _handler) {
iv = _background;
station = _station;
station_name = _station_name;
downloader = _downloader;
handler = _handler;
}
@Override
public void run() {
Bitmap bitmap = downloader.getBitmap();
if (bitmap != null) {
station_name.setTextColor(station.getStationNameTextColor());
station_name.setText(station.getDisplayedName());
iv.setImageBitmap(bitmap);
}
else {
handler.postDelayed(this, 200);
}
}
}

Wyświetl plik

@ -0,0 +1,56 @@
package cc.pogoda.mobile.meteosystem.activity.updater;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.NORMAL_UPDATE_VALUES_ON_ACTIVITY;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL;
import android.os.Handler;
import org.tinylog.Logger;
import java.util.HashMap;
import cc.pogoda.mobile.meteosystem.activity.updater.thread.FavouritesStationSummaryUpdaterThread;
import cc.pogoda.mobile.meteosystem.type.StationActivityElements;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
/**
* This class uses external HashMap updated by @link{{@link FavouritesStationSummaryUpdaterThread}}
*/
public class StationDetailsValuesOnActivityFromFavsUpdater implements Runnable {
HashMap<String, Summary> mapWithSummary;
StationActivityElements elementsToUpdate;
Handler handler;
WeatherStation stationToUpdate;
public StationDetailsValuesOnActivityFromFavsUpdater(StationActivityElements elems, Handler h, WeatherStation station, HashMap<String, Summary> _map_with_summary_data) {
stationToUpdate = station;
handler = h;
elementsToUpdate = elems;
mapWithSummary = _map_with_summary_data;
}
@Override
public void run() {
if (mapWithSummary != null && elementsToUpdate != null) {
Logger.info("[stationToUpdate.getSystemName() = " + stationToUpdate.getSystemName() +"]");
Summary summary = mapWithSummary.get(stationToUpdate.getSystemName());
if (summary != null) {
elementsToUpdate.updateFromSummary(summary, stationToUpdate.getAvailableParameters());
handler.postDelayed(this, NORMAL_UPDATE_VALUES_ON_ACTIVITY);
}
else {
handler.postDelayed(this, REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL);
}
}
}
}

Wyświetl plik

@ -0,0 +1,75 @@
package cc.pogoda.mobile.meteosystem.activity.updater;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.NORMAL_UPDATE_VALUES_ON_ACTIVITY;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL;
import android.os.Handler;
import org.tinylog.Logger;
import cc.pogoda.mobile.meteosystem.activity.updater.thread.StationSummaryUpdaterThread;
import cc.pogoda.mobile.meteosystem.dao.SummaryDao;
import cc.pogoda.mobile.meteosystem.type.StationActivityElements;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
/**
* Class used to update the content of StationDetailsSummaryActivity and
* StationDetailsWindRoseActivity
*/
public class StationDetailsValuesOnActivityUpdater implements Runnable {
StationActivityElements elements = null;
Handler handler = null;
SummaryDao dao = null;
StationSummaryUpdaterThread updater_thread;
Summary station_summary = null;
String station_name;
WeatherStation station;
public StationDetailsValuesOnActivityUpdater(StationActivityElements elems, Handler h, StationSummaryUpdaterThread updaterThread, WeatherStation station) {
elements = elems;
handler = h;
updater_thread = updaterThread;
this.station_name = station.getSystemName();
this.station = station;
dao = new SummaryDao();
}
@Override
public void run() {
if (elements == null || updater_thread == null) {
Logger.error("[something is null even if it shouldn't!!!!]");
return;
}
else {
// get the current data from the Web Service
station_summary = updater_thread.getSummary();
Logger.debug("[station_name = " + station_name +"]");
if (station_summary != null) {
// null check is done inside this call
elements.updateFromSummary(station_summary, station.getAvailableParameters());
handler.postDelayed(this, NORMAL_UPDATE_VALUES_ON_ACTIVITY);
}
else {
// 'station_summary' might be null if internet connection is poor and background
// thread wasn't able to download a summary on time
handler.postDelayed(this, REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL);
}
}
}
}

Wyświetl plik

@ -0,0 +1,143 @@
package cc.pogoda.mobile.meteosystem.activity.updater.thread;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL;
import android.os.Handler;
import android.telephony.SubscriptionManager;
import org.tinylog.Logger;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import cc.pogoda.mobile.meteosystem.dao.AvailableParametersDao;
import cc.pogoda.mobile.meteosystem.dao.SummaryDao;
import cc.pogoda.mobile.meteosystem.type.AvailableParameters;
import cc.pogoda.mobile.meteosystem.type.web.AvailableParametersWeb;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
/**
* This class is a runnable executed from background Thread by ScheduledExecuter
* which periodically download current Summary for all stations stored on favourites list
*/
public class FavouritesStationSummaryUpdaterThread implements Runnable {
private HashMap<String, Summary> map;
private HashMap<String, AvailableParameters> availableParametersHashMap;
private SummaryDao summaryDao;
private AvailableParametersDao availableParametersDao;
private ScheduledExecutorService executor;
private ScheduledFuture scheduledTask;
private boolean enabled = false;
/**
* Set to true when a update is forced in case of a removal or adding new entry to the map
*/
private boolean forceUpdate = false;
public FavouritesStationSummaryUpdaterThread(HashMap<String, Summary> _out_map, HashMap<String, AvailableParameters> _avail_params_map) {
map = _out_map;
availableParametersHashMap = _avail_params_map;
summaryDao = new SummaryDao();
availableParametersDao = new AvailableParametersDao();
executor = Executors.newScheduledThreadPool(5);
}
@Override
public void run() {
// check if map was set so something
if (map != null && map.size() > 0) {
Logger.info("[map.size() = " + map.size() +"]");
// get a set of all stations from favourites
Set<Map.Entry<String, Summary>> _set_of_stations_names = map.entrySet();
// get an iterator to the set
Iterator<Map.Entry<String, Summary>> it = _set_of_stations_names.iterator();
while (it.hasNext()) {
// get currently processed entry
Map.Entry<String, Summary> entry = it.next();
// get station name
String station_name = entry.getKey();
Summary summary = summaryDao.getStationSummary(station_name);
// check if summary was returned (as it will not in case on HTTP 500 or something else)
if (summary != null) {
Logger.info("[station_name = " + station_name + "][summary.last_timestamp = " + summary.last_timestamp + "]");
// put the summary back into the map
map.put(station_name, summary);
}
AvailableParameters parameters = AvailableParameters.fromWebData(availableParametersDao.getAvaliableParamsByStationName(station_name));
if (parameters != null) {
availableParametersHashMap.put(station_name, parameters);
}
}
}
else {
// no station to update may be caused by two reasons
// 1. there is no weather station to update
// 2. API responds very slow or there is a problem with internet connection
Logger.info("[no station to update]");
stop();
start(REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL);
}
if (forceUpdate) {
forceUpdate = false;
start(66000);
}
}
public void updateImmediately() {
forceUpdate = true;
stop();
Thread t = new Thread(this);
t.start();
}
public void start(int _initial_delay) {
Logger.debug("[_initial_delay = " + _initial_delay +"]");
if (enabled) {
stop();
}
scheduledTask = executor.scheduleAtFixedRate(this, _initial_delay, 123000, TimeUnit.MILLISECONDS);
enabled = true;
}
public void stop() {
if (enabled) {
scheduledTask.cancel(true);
enabled = false;
}
}
}

Wyświetl plik

@ -0,0 +1,89 @@
package cc.pogoda.mobile.meteosystem.activity.updater.thread;
import static cc.pogoda.mobile.meteosystem.config.ConstAppConfiguration.REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL;
import androidx.annotation.NonNull;
import org.tinylog.Logger;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import cc.pogoda.mobile.meteosystem.dao.SummaryDao;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
/**
* This class is simmilar to {@link FavouritesStationSummaryUpdaterThread}, but it
* downloads summary data for any defined weather station
*/
public class StationSummaryUpdaterThread implements Runnable {
public boolean isEnabled() {
return enabled;
}
boolean enabled = false;
@NonNull
String systemName;
ScheduledExecutorService executorService;
ScheduledFuture scheduledTask;
Summary summary = null;
public Summary getSummary() {
return summary;
}
public StationSummaryUpdaterThread(@NonNull String stationSystemName) {
systemName = stationSystemName;
executorService = Executors.newScheduledThreadPool(3);
}
@Override
public void run() {
if (systemName != null) {
Logger.info("[StationSummaryUpdaterThread][run][systemName = " + systemName +"]");
SummaryDao summaryDao = new SummaryDao();
summary = summaryDao.getStationSummary(systemName);
if (summary == null) {
// no ssummary data may be caused by two reasons
// 1. there is no weather station to update
// 2. API responds very slow or there is a problem with internet connection
Logger.info("[no station to update]");
stop();
start(REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL);
}
}
}
public void start(int _initial_delay) {
Logger.info("[_initial_delay = " + _initial_delay +"]");
if (enabled) {
stop();
}
scheduledTask = executorService.scheduleAtFixedRate(this, _initial_delay, 60000, TimeUnit.MILLISECONDS);
enabled = true;
}
public void stop() {
if (enabled) {
Logger.info("[systemName = " + systemName +"]");
scheduledTask.cancel(true);
enabled = false;
}
}
}

Wyświetl plik

@ -0,0 +1,36 @@
package cc.pogoda.mobile.meteosystem.activity.view;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
public class AllStationsActRecyclerViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public Button button;
public TextView textViewData;
public AllStationsActRecyclerViewHolder(@NonNull View itemView, ParceableFavsCallReason.Reason callReason) {
super(itemView);
if (callReason.equals(ParceableFavsCallReason.Reason.EXPORT_SELECT) || callReason.equals(ParceableFavsCallReason.Reason.ALL_STATIONS)) {
textView = itemView.findViewById(R.id.station_name);
button = itemView.findViewById(R.id.station_button);
textViewData = null;
}
else {
textView = itemView.findViewById(R.id.station_name_fav);
button = itemView.findViewById(R.id.station_button_fav);
textViewData = itemView.findViewById(R.id.station_data_fav);
}
}
}

Wyświetl plik

@ -0,0 +1,192 @@
package cc.pogoda.mobile.meteosystem.adapter;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import cc.pogoda.mobile.meteosystem.Main;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.activity.handler.AllStationsActRecyclerViewButtonClickEvent;
import cc.pogoda.mobile.meteosystem.activity.updater.FavouritesStationDetailsOnListUpdater;
import cc.pogoda.mobile.meteosystem.activity.view.AllStationsActRecyclerViewHolder;
import cc.pogoda.mobile.meteosystem.type.ParceableFavsCallReason;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class WeatherStationRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final private List<WeatherStation> stations;
AppCompatActivity activity;
ParceableFavsCallReason.Reason reason;
/**
* This updater takes data stored in the hashmap and then updates TextViews on View Holders on
* Favourites list
*/
private FavouritesStationDetailsOnListUpdater favsUpdater = null;
Handler handler = null;
/**
* This instance of 'Main' singleton class is used to obtain HashMap<String, Summary> stationSystemNameToSummary
*/
Main main;
private static final int VIEW_TYPE_EMPTY_LIST = 0;
private static final int VIEW_TYPE_OBJECT = 1;
public WeatherStationRecyclerViewAdapter(
List<WeatherStation> stations,
AppCompatActivity parentActivity,
ParceableFavsCallReason.Reason callReason) {
this.stations = stations;
this.activity = parentActivity;
this.reason = callReason;
this.main = (Main) parentActivity.getApplication();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View view;
switch (viewType){
case VIEW_TYPE_OBJECT:
// check the call reason
if (reason.equals(ParceableFavsCallReason.Reason.FAVOURITES)) {
// inflate custom layout
view = inflater.inflate(R.layout.activity_favourites_linear_layout_data,
parent, false);
}
else {
// Inflate the custom layout without current data
view = inflater.inflate(R.layout.activity_all_stations_linear_layout,
parent, false);
}
return new AllStationsActRecyclerViewHolder(view, reason);
case VIEW_TYPE_EMPTY_LIST:
default:
if (reason.equals(ParceableFavsCallReason.Reason.FAVOURITES)) {
view = inflater.inflate(R.layout.activity_favourites_empty, parent,
false);
} else {
view = inflater.inflate(R.layout.activity_all_stations_empty, parent,
false);
}
return new EmptyViewHolder(view);
}
}
@Override
public int getItemViewType(int position) {
if (stations.isEmpty()) {
return VIEW_TYPE_EMPTY_LIST;
} else {
return VIEW_TYPE_OBJECT;
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
if(viewHolder instanceof AllStationsActRecyclerViewHolder) {
AllStationsActRecyclerViewHolder holder =
(AllStationsActRecyclerViewHolder) viewHolder;
// this TextView shows the station name
TextView textView = holder.textView;
// this TextView shows station data if this is favourites list
TextView textViewData = holder.textViewData;
// button to go to the StationDetailsActivity
Button button = holder.button;
// get the station object from a list of either all stations or favourites
WeatherStation station = stations.get(position);
if (station != null) {
textView.setText(station.getDisplayedName());
button.setText(R.string.select_station);
if (station.getDisplayedName().length() > 22) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20.0f);
} else {
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 22.0f);
}
button.setOnClickListener(new AllStationsActRecyclerViewButtonClickEvent(station, activity, reason));
}
// this if distinguish between All Stations and Favorites view
if (textViewData != null && favsUpdater != null) {
favsUpdater.addNewStation(station.getSystemName(), textViewData);
}
}
}
public void update(@NonNull List<WeatherStation> updatedStations) {
stations.clear();
stations.addAll(updatedStations);
notifyDataSetChanged();
}
@Override
public int getItemCount() {
// In case of empty station list at least 1 should be returned to properly select view type
// and render empty list info.
return stations.isEmpty() ? 1 : stations.size();
}
public void createAndStartUpdater() {
// check if there is previous instance of updater
if (favsUpdater != null && favsUpdater.isEnabled()) {
stopUpdater();
}
handler = new Handler(Looper.getMainLooper());
favsUpdater = new FavouritesStationDetailsOnListUpdater(
handler,
main.getHashmapFavStationSystemNameToSummary(),
main.getHashmapAllStationSystemNameToAvailParameters(),
main.getThemeColours());
handler.postDelayed(favsUpdater, 100);
favsUpdater.setEnabled(true);
}
public void stopUpdater() {
if (reason.equals(ParceableFavsCallReason.Reason.FAVOURITES)
&& handler != null && favsUpdater != null) {
handler.removeCallbacks(favsUpdater);
favsUpdater.setEnabled(false);
}
}
private class EmptyViewHolder extends RecyclerView.ViewHolder{
public EmptyViewHolder(@NonNull View itemView) {
super(itemView);
}
}
}

Wyświetl plik

@ -0,0 +1,10 @@
package cc.pogoda.mobile.meteosystem.config;
public class AppConfiguration {
public static boolean replaceMsWithKnots = false;
public static String locale = "default";
public static int decimationPeriod = 0;
}

Wyświetl plik

@ -0,0 +1,17 @@
package cc.pogoda.mobile.meteosystem.config;
public class ConstAppConfiguration {
public static final int REUPDATE_VALUES_ON_ACTIVITY_ON_FAIL = 1000;
public static final int NORMAL_UPDATE_VALUES_ON_ACTIVITY = 60000;
/**
* This is an interval how often labels on Favourites List (with station
* summary) are updated.
*/
public static final int DETAILS_ON_FAVS_LIST_REUPDATE = 500;
public static final int DETAILS_ON_FAVS_LIST_DEFAULT_UPDATE = 45000;
}

Wyświetl plik

@ -0,0 +1,6 @@
package cc.pogoda.mobile.meteosystem.config;
public class WebIoConfig {
public static final int TIMEOUT_SECOND = 20;
}

Wyświetl plik

@ -1,14 +1,18 @@
package cc.pogoda.mobile.pogodacc.dao;
package cc.pogoda.mobile.meteosystem.dao;
import static cc.pogoda.mobile.meteosystem.config.WebIoConfig.TIMEOUT_SECOND;
import org.tinylog.Logger;
import java.util.LinkedList;
import java.util.List;
import cc.pogoda.mobile.pogodacc.type.AvailableParameters;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfAllStations;
import cc.pogoda.mobile.pogodacc.type.web.StationDefinition;
import cc.pogoda.mobile.pogodacc.web.RestClientConfig;
import cc.pogoda.mobile.pogodacc.web.StationListConsumer;
import cc.pogoda.mobile.meteosystem.type.AvailableParameters;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfAllStations;
import cc.pogoda.mobile.meteosystem.type.web.StationDefinition;
import cc.pogoda.mobile.meteosystem.web.RestClientConfig;
import cc.pogoda.mobile.meteosystem.web.StationListConsumer;
import retrofit2.Response;
public class AllStationsDao {
@ -30,6 +34,7 @@ public class AllStationsDao {
try {
resp = consumer.getAllStations().execute();
} catch (Exception e) {
Logger.error("[Exception][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
}
@ -66,6 +71,9 @@ public class AllStationsDao {
elem.setStationNameTextColor(def.stationNameTextColour);
elem.setImageAlign(def.backgroundJpgAlign);
elem.setMoreInfo(def.moreInfo);
elem.setTimezone(def.timezone);
elem.setCallsignSsid(def.callsign, def.ssid);
AvailableParameters availableParameters = AvailableParameters.fromStation(def);
elem.setAvailableParameters(availableParameters);

Wyświetl plik

@ -0,0 +1,77 @@
package cc.pogoda.mobile.meteosystem.dao;
import static cc.pogoda.mobile.meteosystem.config.WebIoConfig.TIMEOUT_SECOND;
import org.tinylog.Logger;
import java.io.IOException;
import cc.pogoda.mobile.meteosystem.type.web.AvailableParametersWeb;
import cc.pogoda.mobile.meteosystem.web.AvailableParametersConsumer;
import cc.pogoda.mobile.meteosystem.web.RestClientConfig;
import retrofit2.Response;
public class AvailableParametersDao {
RestClientConfig restClient;
Response<AvailableParametersWeb> response = null;
String stationName;
class Worker implements Runnable {
@Override
public void run() {
restClient = new RestClientConfig();
AvailableParametersConsumer consumer = restClient.getWeatherStationClient().create(AvailableParametersConsumer.class);
try {
response = consumer.getParametersForStation(stationName).execute();
} catch (IOException e) {
Logger.error("[IOException][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
} catch (RuntimeException e) {
Logger.error("[RuntimeException][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
catch (Exception e) {
Logger.error("[Exception][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
if (response == null) {
Logger.error("[worker is done, response is null]");
}
else {
Logger.info("[worker is done][response.code() = " + response.code() +"]");
}
}
}
public AvailableParametersWeb getAvaliableParamsByStationName(String name) {
AvailableParametersWeb out = null;
stationName = name;
Thread t = new Thread(new Worker());
t.start();
try {
t.join();
if (response != null) {
out = response.body();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return out;
}
}

Wyświetl plik

@ -1,9 +1,12 @@
package cc.pogoda.mobile.pogodacc.dao;
package cc.pogoda.mobile.meteosystem.dao;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.web.LastStationDataConsumer;
import cc.pogoda.mobile.pogodacc.web.RestClientConfig;
import cc.pogoda.mobile.pogodacc.web.StationListConsumer;
import static cc.pogoda.mobile.meteosystem.config.WebIoConfig.TIMEOUT_SECOND;
import org.tinylog.Logger;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.web.LastStationDataConsumer;
import cc.pogoda.mobile.meteosystem.web.RestClientConfig;
import retrofit2.Response;
public class LastStationDataDao {
@ -24,6 +27,8 @@ public class LastStationDataDao {
try {
response = consumer.getLastDataForStation(station, true, true).execute();
} catch (Exception e) {
Logger.error("[Exception][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
}

Wyświetl plik

@ -1,9 +1,10 @@
package cc.pogoda.mobile.pogodacc.dao;
package cc.pogoda.mobile.meteosystem.dao;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.web.LastStationDataConsumer;
import cc.pogoda.mobile.pogodacc.web.RestClientConfig;
import cc.pogoda.mobile.pogodacc.web.StationDataConsumer;
import org.tinylog.Logger;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.web.RestClientConfig;
import cc.pogoda.mobile.meteosystem.web.StationDataConsumer;
import retrofit2.Response;
public class StationDataDao {
@ -27,6 +28,8 @@ public class StationDataDao {
try {
response = consumer.getDataForStation(station, from, to).execute();
} catch (Exception e) {
Logger.error("[Exception][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
}
@ -49,7 +52,9 @@ public class StationDataDao {
thread.start();
thread.join();
out = response.body();
if (response != null) {
out = response.body();
}
}
catch (InterruptedException ex) {

Wyświetl plik

@ -1,11 +1,15 @@
package cc.pogoda.mobile.pogodacc.dao;
package cc.pogoda.mobile.meteosystem.dao;
import static cc.pogoda.mobile.meteosystem.config.WebIoConfig.TIMEOUT_SECOND;
import org.tinylog.Logger;
import java.io.IOException;
import cc.pogoda.mobile.pogodacc.type.web.QualityFactor;
import cc.pogoda.mobile.pogodacc.type.web.Summary;
import cc.pogoda.mobile.pogodacc.web.RestClientConfig;
import cc.pogoda.mobile.pogodacc.web.SummaryConsumer;
import cc.pogoda.mobile.meteosystem.type.web.QualityFactor;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
import cc.pogoda.mobile.meteosystem.web.RestClientConfig;
import cc.pogoda.mobile.meteosystem.web.SummaryConsumer;
import retrofit2.Response;
/**
@ -30,9 +34,29 @@ public class SummaryDao {
SummaryConsumer consumer = restClient.getWeatherStationClient().create(SummaryConsumer.class);
try {
Logger.info("[station = " + station +"]");
response = consumer.getSummaryForStation(station).execute();
} catch (IOException e) {
Logger.error("[station = " + station + "][IOException][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
} catch (RuntimeException e) {
Logger.error("[station = " + station + "][RuntimeException][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
catch (Exception e) {
Logger.error("[station = " + station + "][Exception][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
if (response == null) {
Logger.error("[station = " + station + "][worker is done, response is null]");
}
else {
Logger.info("[station = " + station + "][worker is done][response.code() = " + response.code() +"]");
}
}
}
@ -63,9 +87,17 @@ public class SummaryDao {
out.humidity_qf_native = QualityFactor.valueOf(out.humidity_qf);
out.qnh_qf_native = QualityFactor.valueOf(out.qnh_qf);
}
else {
Logger.error("[station = " + station +"][response.code() = " + response.code() +"][response body is nulll, probably HTTP error" +
"]");
}
}
else {
Logger.error("[station = " + station +"][response is null!!]");
}
} catch (InterruptedException e) {
e.printStackTrace();
Logger.error("[station = " + station +"][InterruptedException]");
}
return out;

Wyświetl plik

@ -1,14 +1,17 @@
package cc.pogoda.mobile.pogodacc.dao;
package cc.pogoda.mobile.meteosystem.dao;
import static cc.pogoda.mobile.meteosystem.config.WebIoConfig.TIMEOUT_SECOND;
import org.tinylog.Logger;
import java.io.IOException;
import cc.pogoda.mobile.pogodacc.type.web.Trend;
import cc.pogoda.mobile.pogodacc.web.RestClientConfig;
import cc.pogoda.mobile.pogodacc.web.TrendConsumer;
import cc.pogoda.mobile.meteosystem.type.web.Trend;
import cc.pogoda.mobile.meteosystem.web.RestClientConfig;
import cc.pogoda.mobile.meteosystem.web.TrendConsumer;
import retrofit2.Response;
public class TrendDao {
RestClientConfig restClient;
Response<Trend> trend;
@ -16,6 +19,8 @@ public class TrendDao {
class Worker implements Runnable {
RestClientConfig restClient;
@Override
public void run() {
@ -27,7 +32,9 @@ public class TrendDao {
trend = trendConsumer.getTrendForStation(station).execute();
}
catch (IOException e) {
Logger.error("[TrendDao][Worker][Exception][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
}
}
}
@ -43,10 +50,15 @@ public class TrendDao {
try {
thread.join();
out = trend.body();
if (trend != null) {
out = trend.body();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
catch (NullPointerException e) {
e.printStackTrace();
}
return out;
}

Wyświetl plik

@ -1,9 +1,9 @@
package cc.pogoda.mobile.pogodacc.dao.mock;
package cc.pogoda.mobile.meteosystem.dao.mock;
import java.util.LinkedList;
import java.util.List;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class AllStationsDaoMock {

Wyświetl plik

@ -0,0 +1,92 @@
package cc.pogoda.mobile.meteosystem.file;
import android.content.Context;
import org.json.JSONException;
import org.json.JSONObject;
import org.tinylog.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
public class ConfigurationFile {
FileNames fileNames;
public ConfigurationFile(Context context) {
fileNames = new FileNames(context);
}
public void restoreFromFile() {
File file = fileNames.getAppConfigurationFile();
// create an input stream to load file content
FileInputStream fns = null;
try {
fns = new FileInputStream(file);
InputStreamReader streamReader = new InputStreamReader(fns);
// create a place fo JSON content
char buffer[] = new char[(int) file.length()];
// read the content of file
streamReader.read(buffer);
streamReader.close();
JSONObject mainObject = new JSONObject(String.valueOf(buffer));
AppConfiguration.replaceMsWithKnots = mainObject.getBoolean("replaceMsWithKnots");
AppConfiguration.locale = mainObject.getString("locale");
AppConfiguration.decimationPeriod = mainObject.getInt("decimationPeriodMinutes");
} catch (IOException | JSONException e) {
e.printStackTrace();
Logger.error("[e = " + e.getLocalizedMessage() +"]");
AppConfiguration.locale = "default";
AppConfiguration.replaceMsWithKnots = false;
AppConfiguration.decimationPeriod = 0;
}
}
public void storeToFile() {
String jsonData = "";
try {
FileOutputStream outputStream = new FileOutputStream(fileNames.getAppConfigurationFile());
JSONObject masterObject = new JSONObject();
masterObject.put("replaceMsWithKnots", AppConfiguration.replaceMsWithKnots);
masterObject.put("locale", AppConfiguration.locale);
masterObject.put("decimationPeriodMinutes", AppConfiguration.decimationPeriod);
jsonData = masterObject.toString();
// write JSON content to file on disk
outputStream.write(jsonData.getBytes());
// synchronize and close stream
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}

Wyświetl plik

@ -0,0 +1,83 @@
package cc.pogoda.mobile.meteosystem.file;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.tinylog.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class CopyLog {
public static class CopyLogRunner implements Runnable {
InputStreamReader streamReader;
OutputStreamWriter streamWriter;
int logFileLn;
public CopyLogRunner(InputStreamReader _stream_reader, OutputStreamWriter _stream_writer, int _log_file_ln) {
streamReader = _stream_reader;
streamWriter = _stream_writer;
logFileLn = _log_file_ln;
}
@Override
public void run() {
try {
char buffer[] = new char[logFileLn];
streamReader.read(buffer);
streamWriter.write(buffer);
streamReader.close();
streamWriter.flush();
streamWriter.close();
Logger.info("[log file copied succesfully]");
}
catch (IOException e) {
Logger.error("[IOException e = " + e.getLocalizedMessage() +"]");
}
}
}
public static void forDay(FileNames _file_names, LocalDateTime _date, OutputStream _out) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
File baseDir = _file_names.getDirectory();
File logfile = new File(baseDir.getAbsolutePath() + "/logs/log_" + _date.format(formatter) + ".txt");
Logger.debug("[logfile.getAbsolutePath() = " + logfile.getAbsolutePath() +"][logfile.length() = " + logfile.length() +"]");
try {
// create an input stream to load log file
FileInputStream fns = new FileInputStream(logfile);
InputStreamReader streamReader = new InputStreamReader(fns);
// create output stream writer to copy log file into
OutputStreamWriter writer = new OutputStreamWriter(_out);
CopyLogRunner runner = new CopyLogRunner(streamReader, writer, (int)logfile.length());
Thread t = new Thread(runner);
t.start();
}
catch (IOException e) {
Logger.error("[IOException e = " + e.getLocalizedMessage() +"]");
}
// log_{date:yyyy-MM-dd}.txt
}
}

Wyświetl plik

@ -0,0 +1,48 @@
package cc.pogoda.mobile.meteosystem.file;
import android.content.Context;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.StationData;
public class CsvExport {
public static boolean exportToCsv(ListOfStationData data, WeatherStation station, Context context, OutputStream out) {
OutputStreamWriter writer = new OutputStreamWriter(out);
try {
writer.write("epoch,temperature,pressure,humidity,winddirection,windspeed,windgusts\r\n");
for (StationData d : data.list_of_station_data) {
writer.write( String.valueOf(d.epoch) + "," +
String.valueOf(d.temperature) + "," +
String.valueOf(d.pressure) + "," +
String.valueOf(d.humidity) + "," +
String.valueOf(d.winddir) + "," +
String.valueOf(d.windspeed) + "," +
String.valueOf(d.windgusts) + "\r\n");
}
writer.flush();
writer.close();
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
}

Wyświetl plik

@ -0,0 +1,248 @@
package cc.pogoda.mobile.meteosystem.file;
import android.content.Context;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.threeten.bp.Instant;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.StationData;
public class ExcelExport {
private static final SimpleDateFormat SDF = new SimpleDateFormat("dd-M-yyyy HH:mm:ss");
private static double round (double in) {
double out = 0;
long temp = (long)(in * 10);
out = temp / 10.0d;
return out;
}
public static boolean exportToExcel(ListOfStationData data, WeatherStation station, Context context, OutputStream out) {
if (out == null) {
return false;
}
if (data == null || data.list_of_station_data.length == 0) {
return false;
}
int rowNumber = 0;
long previousEpoch = 0;
Cell cell;
ZonedDateTime first = ZonedDateTime.ofInstant(Instant.ofEpochSecond(data.list_of_station_data[0].epoch), ZoneId.of(station.getTimezone()));
String generalTimezone = first.format(DateTimeFormatter.ofPattern("zzzz"));
Workbook workbook = new HSSFWorkbook();
CellStyle left = workbook.createCellStyle();
left.setAlignment(CellStyle.ALIGN_LEFT);
Sheet sheet = workbook.createSheet(station.getSystemName());
{
Row stationame = sheet.createRow(rowNumber++);
Cell name = stationame.createCell(0);
name.setCellValue("Station name:");
name = stationame.createCell(1);
name.setCellValue(station.getDisplayedName());
Row localization = sheet.createRow(rowNumber++);
Cell loc = localization.createCell(0);
loc.setCellValue("Location:");
loc = localization.createCell(1);
loc.setCellValue(station.getDisplayedLocation());
Row coordinates = sheet.createRow(rowNumber++);
Cell coord = coordinates.createCell(0);
coord.setCellValue("Coordinates:");
coord = coordinates.createCell(1);
coord.setCellValue("Lat " + station.getLat() + " , Lon " + station.getLon());
Row timezone = sheet.createRow(rowNumber++);
Cell tz = timezone.createCell(0);
tz.setCellValue("All date and time as in:");
tz = timezone.createCell(1);
tz.setCellValue(station.getTimezone());
Row generaltz = sheet.createRow(rowNumber++);
Cell gtz = generaltz.createCell(0);
gtz.setCellValue("Timezone in this export:");
gtz = generaltz.createCell(1);
gtz.setCellValue(generalTimezone);
Row offset = sheet.createRow(rowNumber++);
Cell off = offset.createCell(0);
off.setCellValue("Time offset for the timezone:");
off = offset.createCell(1);
off.setCellValue(first.getOffset().toString());
Row aprscall = sheet.createRow(rowNumber++);
Cell call = aprscall.createCell(0);
call.setCellValue("APRS Callsign:");
call = aprscall.createCell(1);
call.setCellValue(station.getCallsignSsid());
}
rowNumber++;
rowNumber++;
Row info = sheet.createRow(rowNumber++);
cell = info.createCell(0);
cell.setCellValue("Windspeed is exported both in m/s and knots. One knot equals one nautical mile per hour");
if (AppConfiguration.decimationPeriod > 0) {
rowNumber++;
Row decim = sheet.createRow(rowNumber++);
cell = decim.createCell(0);
cell.setCellValue("Decimation has been applied to the station data and some measurements have been dropped during an export. Minimal time difference between consecutive records is set to " + AppConfiguration.decimationPeriod + " minutes");
}
rowNumber++;
rowNumber++;
Row header = sheet.createRow(rowNumber++);
cell = header.createCell(0);
cell.setCellValue("UNIX Epoch Timestamp");
cell.setCellStyle(left);
cell = header.createCell(1);
cell.setCellValue("Date / Time [DD-MM-YYYY 24HH:MM]");
cell.setCellStyle(left);
cell = header.createCell(2);
cell.setCellValue("Temperature [C]");
cell.setCellStyle(left);
cell = header.createCell(3);
cell.setCellValue("QNH pressure [hPa]");
cell.setCellStyle(left);
cell = header.createCell(4);
cell.setCellValue("Humidity [%]");
cell.setCellStyle(left);
cell = header.createCell(5);
cell.setCellValue("Wind Direction");
cell.setCellStyle(left);
cell = header.createCell(6);
cell.setCellValue("Wind Average Speed [m/s]");
cell.setCellStyle(left);
cell = header.createCell(7);
cell.setCellValue("Wind Gusts [m/s]");
cell.setCellStyle(left);
cell = header.createCell(8);
cell.setCellValue("Wind Average Speed [knots]");
cell.setCellStyle(left);
cell = header.createCell(9);
cell.setCellValue("Wind Gusts [knots]");
cell.setCellStyle(left);
// put data into output file
for (StationData d : data.list_of_station_data) {
if (d.epoch - previousEpoch < AppConfiguration.decimationPeriod * 60) {
continue;
}
previousEpoch = d.epoch;
Row r = sheet.createRow(rowNumber++);
Cell epoch = r.createCell(0);
epoch.setCellValue(d.epoch);
epoch.setCellStyle(left);
ZonedDateTime zoneddatetime = ZonedDateTime.ofInstant(Instant.ofEpochSecond(d.epoch), ZoneId.of(station.getTimezone()));
Cell datetime = r.createCell(1);
datetime.setCellValue(zoneddatetime.format(DateTimeFormatter.ofPattern("dd-M-yyyy HH:mm:ss")));
datetime.setCellStyle(left);
Cell temperature = r.createCell(2);
temperature.setCellValue(round(d.temperature));
temperature.setCellStyle(left);
Cell pressure = r.createCell(3);
pressure.setCellValue(d.pressure);
pressure.setCellStyle(left);
Cell humidity = r.createCell(4);
humidity.setCellValue(d.humidity);
humidity.setCellStyle(left);
Cell winddir = r.createCell(5);
winddir.setCellValue(d.winddir);
winddir.setCellStyle(left);
Cell windspeed = r.createCell(6);
windspeed.setCellValue(round(d.windspeed));
windspeed.setCellStyle(left);
Cell windgust = r.createCell(7);
windgust.setCellValue(round(d.windgusts));
windgust.setCellStyle(left);
Cell windspeed_kts = r.createCell(8);
windspeed_kts.setCellValue(round(d.windspeed * 0.514));
windspeed_kts.setCellStyle(left);
Cell windgust_kts = r.createCell(9);
windgust_kts.setCellValue(round(d.windgusts * 0.514));
windgust_kts.setCellStyle(left);
}
sheet.setColumnWidth(0, 6600);
sheet.setColumnWidth(1, 5900);
sheet.setColumnWidth(2, 3900);
sheet.setColumnWidth(3, 4600);
sheet.setColumnWidth(4, 2900);
sheet.setColumnWidth(5, 3200);
sheet.setColumnWidth(6, 5000);
sheet.setColumnWidth(7, 4400);
sheet.setColumnWidth(8, 4900);
sheet.setColumnWidth(9, 4400);
try {
workbook.write(out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
}

Wyświetl plik

@ -0,0 +1,134 @@
package cc.pogoda.mobile.meteosystem.file;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.tinylog.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class FavouritiesFile {
FileNames fileNames;
public FavouritiesFile(FileNames fns) {
fileNames = fns;
}
public List<WeatherStation> loadFavourites() {
List<WeatherStation> out = new LinkedList<>();
File file = fileNames.getFavJsonFile();
Logger.info("[file = " + file + "]");
try {
// create an input stream to load file content
FileInputStream fns = new FileInputStream(file);
InputStreamReader streamReader = new InputStreamReader(fns);
// create a place fo JSON content
char buffer[] = new char[(int) file.length()];
try {
// read the content of file
streamReader.read(buffer);
streamReader.close();
// parse JSON to array
JSONArray root = new JSONArray(new String(buffer));
if (root != null) {
for (int i = 0 ; i < root.length(); i++) {
// create new weather station data object
WeatherStation station = new WeatherStation();
// get onlu 'systemName' as the rest will be copied from current 'allStationsList'
station.setSystemName(root.getJSONObject(i).getString("systemName"));
out.add(station);
Logger.debug("[i = " + i +"][station.getSystemName() = " + station.getSystemName() + "]");
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
}
} catch (FileNotFoundException e) {
return null;
}
return out;
}
public void persistFavourities(List<WeatherStation> favourites) throws IOException {
// do nothing in case that no statations have been added to favourites yet
if (favourites == null || favourites.size() == 0)
return;
String jsonData = "";
// main array for all stations
JSONArray mainArray = new JSONArray();
Logger.info("[favourites.size() = " + favourites.size() + "]");
for (WeatherStation wx : favourites) {
JSONObject obj = new JSONObject();
try {
obj.put("systemName", wx.getSystemName());
obj.put("displayedName", wx.getDisplayedName());
obj.put("displayedLocation", wx.getDisplayedLocation());
obj.put("sponsorUrl", wx.getSponsorUrl());
obj.put("imageUrl", wx.getImageUrl());
obj.put("imageAlign", wx.getImageAlign());
obj.put("lat", wx.getLat());
obj.put("lon", wx.getLon());
mainArray.put(obj);
Logger.debug("[wx.getSystemName() = " + wx.getSystemName() + "]");
} catch (JSONException e) {
e.printStackTrace();
}
}
jsonData = mainArray.toString();
if (jsonData != null && jsonData.length() > 0) {
File output = fileNames.getFavJsonFile();
// checks if file exists and delete it if yes
if (output.exists()) {
output.delete();
output.createNewFile();
}
FileOutputStream outputStream = new FileOutputStream(output);
// write JSON content to file on disk
outputStream.write(jsonData.getBytes());
// synchronize and close stream
outputStream.flush();
outputStream.close();
}
}
}

Wyświetl plik

@ -0,0 +1,36 @@
package cc.pogoda.mobile.meteosystem.file;
import android.content.Context;
import java.io.File;
public class FileNames {
public static final String DIRECTORY = "files";
public static final String FAVS = "favourites.json";
public static final String CONF = "app_configuration.json";
private Context ctx;
public FileNames(Context context) {
ctx = context;
}
public File getDirectory() {
return ctx.getDir(DIRECTORY, Context.MODE_PRIVATE);
}
public File getFavJsonFile() {
File dir = this.getDirectory();
return new File(dir.getAbsolutePath() + "/" + FAVS);
}
public File getAppConfigurationFile() {
File dir = this.getDirectory();
return new File(dir.getAbsolutePath() + "/" + CONF);
}
}

Wyświetl plik

@ -0,0 +1,42 @@
package cc.pogoda.mobile.meteosystem.service;
import android.content.Context;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import org.greenrobot.eventbus.EventBus;
import org.tinylog.Logger;
import java.util.HashMap;
import java.util.List;
import cc.pogoda.mobile.meteosystem.dao.AllStationsDao;
import cc.pogoda.mobile.meteosystem.dao.AvailableParametersDao;
import cc.pogoda.mobile.meteosystem.type.AllStationsReceivedEvent;
import cc.pogoda.mobile.meteosystem.type.AvailableParameters;
import cc.pogoda.mobile.meteosystem.type.StartStationsRefreshEvent;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class GetAllStationsService extends JobIntentService {
private static final int JOB_ID = 1;
public static void enqueueWork(@NonNull Context context, @NonNull Intent intent) {
enqueueWork(context, GetAllStationsService.class, JOB_ID, intent);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
EventBus.getDefault().post(new StartStationsRefreshEvent());
// download all stations
List<WeatherStation> allStations = new AllStationsDao().getAllStations();
if (allStations != null){
EventBus.getDefault().post(new AllStationsReceivedEvent(allStations));
Logger.debug("onHandleWork done. allStations size:" + allStations.size());
}
}
}

Wyświetl plik

@ -0,0 +1,25 @@
package cc.pogoda.mobile.meteosystem.type;
import androidx.annotation.NonNull;
import java.util.HashMap;
import java.util.List;
public class AllStationsReceivedEvent {
List<WeatherStation> stations;
public AllStationsReceivedEvent(@NonNull List<WeatherStation> stations) {
this.stations = stations;
}
@NonNull
public List<WeatherStation> getStations(){
return this.stations;
}
@NonNull
@Override
public String toString() {
return "[AllStationsReceivedEvent][stations.size() = " + stations.size() +"]";
}
}

Wyświetl plik

@ -1,8 +1,9 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import java.io.Serializable;
import cc.pogoda.mobile.pogodacc.type.web.StationDefinition;
import cc.pogoda.mobile.meteosystem.type.web.AvailableParametersWeb;
import cc.pogoda.mobile.meteosystem.type.web.StationDefinition;
public class AvailableParameters implements Serializable {
@ -33,6 +34,20 @@ public class AvailableParameters implements Serializable {
rain = false;
}
public static AvailableParameters fromWebData(AvailableParametersWeb w) {
AvailableParameters out = new AvailableParameters();
out.humidity = w.hasHumidity;
out.windSpeed = w.hasWind;
out.windGusts = w.hasWind;
out.windDirection = w.hasWind;
out.qnh = w.hasQnh;
out.airTemperature = true;
out.rain = w.hasRain;
return out;
}
public static AvailableParameters fromStation(StationDefinition s) {
AvailableParameters out = new AvailableParameters();

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import com.google.gson.JsonObject;

Wyświetl plik

@ -0,0 +1,61 @@
package cc.pogoda.mobile.meteosystem.type;
import android.os.Parcel;
import android.os.Parcelable;
public class ParceableFavsCallReason implements Parcelable {
public enum Reason {
FAVOURITES,
EXPORT_SELECT,
ALL_STATIONS
}
public Reason getReason() {
return reason;
}
private Reason reason;
public ParceableFavsCallReason(Reason r) {
this.reason = r;
}
protected ParceableFavsCallReason(Parcel in) {
int reasonInt = in.readInt();
switch (reasonInt) {
case 1: reason = Reason.FAVOURITES; break;
case 2: reason = Reason.EXPORT_SELECT; break;
case 3: reason = Reason.ALL_STATIONS; break;
default: reason = null;
}
}
@Override
public void writeToParcel(Parcel dest, int flags) {
switch (reason) {
case FAVOURITES: dest.writeInt(1); break;
case EXPORT_SELECT: dest.writeInt(2); break;
case ALL_STATIONS: dest.writeInt(3); break;
}
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ParceableFavsCallReason> CREATOR = new Creator<ParceableFavsCallReason>() {
@Override
public ParceableFavsCallReason createFromParcel(Parcel in) {
return new ParceableFavsCallReason(in);
}
@Override
public ParceableFavsCallReason[] newArray(int size) {
return new ParceableFavsCallReason[size];
}
};
}

Wyświetl plik

@ -0,0 +1,132 @@
package cc.pogoda.mobile.meteosystem.type;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class ParceableStationsList implements Parcelable {
ArrayList<WeatherStation> list;
int listSize;
public ArrayList<WeatherStation> getList() {
return list;
}
public static ParceableStationsList createFromStdList(List<WeatherStation> stationList) {
ParceableStationsList out = new ParceableStationsList();
out.list = new ArrayList<>(stationList);
out.listSize = stationList.size();
return out;
}
public static final Creator<ParceableStationsList> CREATOR = new Creator<ParceableStationsList>() {
@Override
public ParceableStationsList createFromParcel(Parcel in) {
return new ParceableStationsList(in);
}
@Override
public ParceableStationsList[] newArray(int size) {
return new ParceableStationsList[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
if (list != null) {
listSize = list.size();
parcel.writeInt(listSize);
for (WeatherStation s : list) {
parcel.writeString(s.getSystemName());
parcel.writeString(s.getDisplayedName());
parcel.writeString(s.getDisplayedLocation());
parcel.writeString(s.getSponsorUrl());
parcel.writeString(s.getImageUrl());
parcel.writeString(s.getTimezone());
parcel.writeString(s.getCallsignSsid());
parcel.writeInt(s.getImageAlign());
parcel.writeInt(s.getStationNameTextColor());
parcel.writeFloat(s.getLat());
parcel.writeFloat(s.getLon());
parcel.writeString(s.getMoreInfo());
parcel.writeInt(s.getAvailableParameters().humidity ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().qnh ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().windDirection ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().windGusts ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().windSpeed ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().rain ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().waterTemperature ? 1 : 0);
parcel.writeInt(s.getAvailableParameters().airTemperature ? 1 : 0);
}
}
}
protected ParceableStationsList(Parcel in) {
list = new ArrayList<>();
listSize = in.readInt();
for (int i = 0; i < listSize; i++) {
WeatherStation wx = new WeatherStation();
wx.systemName = in.readString();
wx.displayedName = in.readString();
wx.displayedLocation = in.readString();
wx.sponsorUrl = in.readString();
wx.imageUrl = in.readString();
wx.timezone = in.readString();
wx.callsignSsid = in.readString();
wx.imageAlign = in.readInt();
wx.stationNameTextColor = in.readInt();
wx.lat = in.readFloat();
wx.lon = in.readFloat();
wx.moreInfo = in.readString();
AvailableParameters params = new AvailableParameters();
params.humidity = (in.readInt() > 0) ? true : false;
params.qnh = (in.readInt() > 0) ? true : false;
params.windDirection = (in.readInt() > 0) ? true : false;
params.windGusts = (in.readInt() > 0) ? true : false;
params.windSpeed = (in.readInt() > 0) ? true : false;
params.rain = (in.readInt() > 0) ? true : false;
params.waterTemperature = (in.readInt() > 0) ? true : false;
params.airTemperature = (in.readInt() > 0) ? true : false;
wx.setAvailableParameters(params);
list.add(wx);
}
}
public ParceableStationsList(ParceableStationsList in ) {
this.list = new ArrayList<>(in.getList());
this.listSize = this.list.size();
}
public ParceableStationsList() {
}
}

Wyświetl plik

@ -0,0 +1,4 @@
package cc.pogoda.mobile.meteosystem.type;
public class StartStationsRefreshEvent {
}

Wyświetl plik

@ -1,8 +1,8 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import android.app.Activity;
import cc.pogoda.mobile.pogodacc.type.web.Summary;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
/**
* This is an interface which is used to implement classes used for updating the activity content

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import com.github.mikephil.charting.data.Entry;

Wyświetl plik

@ -1,22 +1,19 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
import org.threeten.bp.Duration;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.temporal.ChronoUnit;
import org.tinylog.Logger;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.type.web.QualityFactor;
import cc.pogoda.mobile.pogodacc.type.web.Summary;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.type.web.QualityFactor;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
public class StationSummaryActElements implements StationActivityElements {
@ -29,7 +26,10 @@ public class StationSummaryActElements implements StationActivityElements {
public TextView humidity_val = null;
public TextView message = null;
private String convertDegreesToDir(int directionInDegrees) {
public int goodColor = 0;
public int badColor = 0;
public static String convertDegreesToDir(int directionInDegrees) {
String out = null;
if (directionInDegrees <= 11 || directionInDegrees >= 349)
@ -94,6 +94,8 @@ public class StationSummaryActElements implements StationActivityElements {
long minutes_difference = last_station_data.until(current, ChronoUnit.MINUTES);
Logger.debug("[last_station_data = " + last_station_data.format(DateTimeFormatter. ISO_LOCAL_DATE_TIME) +"]");
// calculate the duration between
Duration duration = Duration.between(last_station_data, current);
@ -108,43 +110,80 @@ public class StationSummaryActElements implements StationActivityElements {
message.setTextColor(Color.argb(0xFF, 0xFF, 0x0, 0x0));
}
if (!s.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE) && enabledForStation.windSpeed) {
wind_speed_val.setText(String.format("%.1f m/s", s.average_speed));
if (enabledForStation.windSpeed) {
wind_speed_val.setText(String.format("%s", s.getWindspeedStr(true)));
if (goodColor != 0 && !s.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
wind_speed_val.setTextColor(goodColor);
}
else if (badColor != 0) {
wind_speed_val.setTextColor(badColor);
}
}
else {
wind_speed_val.setText("---");
}
if (!s.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE) && enabledForStation.windGusts) {
wind_gusts_val.setText(String.format("%.1f m/s", s.gusts));
if (enabledForStation.windGusts) {
wind_gusts_val.setText(String.format("%s", s.getWindgustsStr(true)));
if (goodColor != 0 && !s.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
wind_gusts_val.setTextColor(goodColor);
}
else if (badColor != 0) {
wind_gusts_val.setText(badColor);
}
}
else {
wind_gusts_val.setText("---");
}
if (!s.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE) && enabledForStation.windDirection) {
if (enabledForStation.windDirection) {
wind_dir_val.setText(this.convertDegreesToDir(s.direction));
if (goodColor != 0 && !s.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
wind_dir_val.setTextColor(goodColor);
}
else if (badColor != 0){
wind_dir_val.setTextColor(badColor);
}
}
else {
wind_dir_val.setText("---");
}
if (!s.temperature_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
temperature_val.setText(String.format("%.1f °C", s.avg_temperature));
temperature_val.setText(String.format("%s", s.getTemperatureStr(true, false)));
if (goodColor != 0 && !s.temperature_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
temperature_val.setTextColor(goodColor);
}
else {
temperature_val.setText("---");
else if (badColor != 0){
temperature_val.setTextColor(badColor);
}
// TODO
if (!s.qnh_qf_native.equals(QualityFactor.NOT_AVALIABLE) && enabledForStation.qnh) {
if (enabledForStation.qnh) {
qnh_val.setText(String.format("%d hPa", s.qnh));
if (goodColor != 0 && !s.qnh_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
qnh_val.setTextColor(goodColor);
}
else if (badColor != 0) {
qnh_val.setTextColor(badColor);
}
}
else {
qnh_val.setText("---");
}
if (!s.humidity_qf_native.equals(QualityFactor.NOT_AVALIABLE) && enabledForStation.humidity) {
if (enabledForStation.humidity) {
humidity_val.setText(String.format("%d %%", s.humidity));
if (goodColor != 0 && !s.humidity_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
humidity_val.setTextColor(goodColor);
}
else {
humidity_val.setTextColor(badColor);
}
}
else {
humidity_val.setText("---");

Wyświetl plik

@ -1,7 +1,6 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.widget.ImageView;
import android.widget.TextView;
@ -9,11 +8,12 @@ import android.widget.TextView;
import org.threeten.bp.Duration;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZonedDateTime;
import org.w3c.dom.Text;
import org.threeten.bp.format.DateTimeFormatter;
import org.tinylog.Logger;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.type.web.QualityFactor;
import cc.pogoda.mobile.pogodacc.type.web.Summary;
import cc.pogoda.mobile.meteosystem.R;
import cc.pogoda.mobile.meteosystem.type.web.QualityFactor;
import cc.pogoda.mobile.meteosystem.type.web.Summary;
public class StationWindRoseActElements implements StationActivityElements {
@ -37,6 +37,9 @@ public class StationWindRoseActElements implements StationActivityElements {
*/
public TextView minAverage;
public int goodColor;
public int badColor;
Activity activity;
public StationWindRoseActElements() {
@ -84,6 +87,8 @@ public class StationWindRoseActElements implements StationActivityElements {
// current date and time (in current time zone set in system configuration)
LocalDateTime current = LocalDateTime.now();
Logger.debug("[last_station_data = " + last_station_data.format(DateTimeFormatter. ISO_LOCAL_DATE_TIME) +"]");
// calculate the duration between
Duration duration = Duration.between(last_station_data, current);
@ -93,6 +98,12 @@ public class StationWindRoseActElements implements StationActivityElements {
}
}
Logger.debug("[no_data = " + no_data +"][old_data = " + old_data+"]");
// create strings with wind speed, gusts etc
String average_speed = String.format("%s", data.getWindspeedStr(true));
String gusts_speed = String.format("%s", data.getWindgustsStr(true));
// check if wind data is avaliable in the input data set
if (!no_data && !data.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
windArrow.setRotation(data.direction - 225.0f);
@ -103,35 +114,54 @@ public class StationWindRoseActElements implements StationActivityElements {
}
if (!no_data && !data.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
windSpeed.setText(activity.getResources().getString(R.string.mean_value) + '\n' + data.average_speed + "m/s");
windSpeed.setText(average_speed);
windSpeed.setTextColor(goodColor);
} else {
windSpeed.setText(activity.getResources().getString(R.string.mean_value) + '\n' + "---");
windSpeed.setText("---");
}
if (!no_data && !data.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
windGusts.setText(activity.getResources().getString(R.string.wind_gust_short) + '\n' + data.gusts + "m/s");
windGusts.setText(gusts_speed);
windGusts.setTextColor(goodColor);
} else {
windGusts.setText(activity.getResources().getString(R.string.wind_gust_short) + '\n' + "---");
windGusts.setText("---");
}
if (!no_data && !data.wind_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
windDirection.setText(activity.getResources().getString(R.string.wind_direction_short) + '\n' + data.direction + activity.getResources().getString(R.string.degrees_sign));
windDirection.setText(String.valueOf(data.direction) + activity.getResources().getString(R.string.degrees_sign));
windDirection.setTextColor(goodColor);
} else {
windDirection.setText(activity.getResources().getString(R.string.wind_direction_short) + '\n' + "---");
windDirection.setText("---");
}
// check if temperature is avaliable in input data set
if (!no_data && !data.temperature_qf_native.equals(QualityFactor.NOT_AVALIABLE)) {
temperature.setText(activity.getResources().getString(R.string.temperature_short) + '\n' + String.format("%.1f", data.avg_temperature) + "°C");
if (!no_data) {
temperature.setText(String.format("%s", data.getTemperatureStr(true, false)));
if (!data.temperature_qf_native.equals(QualityFactor.NOT_AVALIABLE) && goodColor != 0) {
temperature.setTextColor(goodColor);
}
else if (badColor != 0) {
temperature.setTextColor(badColor);
}
} else {
temperature.setText(activity.getResources().getString(R.string.temperature_short) + '\n' + "---");
temperature.setText("---");
}
if (!no_data && !old_data) {
String hour_max_gusts = String.format("%s", data.getHourWindgustsStr(true));
String hour_min_avg = String.format("%s", data.getHourMinWindspeedStr(true));
pressure.setText(activity.getResources().getString(R.string.qnh) + ": " + String.format("%d hPa", data.qnh));
maxGust.setText(activity.getResources().getString(R.string.max_1h_gust) + ": " + data.hour_gusts + "m/s");
minAverage.setText(activity.getResources().getString(R.string.min_1h_avg) + ": " + data.hour_min_average_speed + "m/s");
maxGust.setText(activity.getResources().getString(R.string.max_1h_gust) + ": " + hour_max_gusts);
minAverage.setText(activity.getResources().getString(R.string.min_1h_avg) + ": " + hour_min_avg);
if (goodColor != 0) {
pressure.setTextColor(goodColor);
maxGust.setTextColor(goodColor);
minAverage.setTextColor(goodColor);
}
} else if (!no_data && old_data) {
maxGust.setText(activity.getResources().getString(R.string.warning));
maxGust.setTextColor(Color.RED);

Wyświetl plik

@ -0,0 +1,11 @@
package cc.pogoda.mobile.meteosystem.type;
public class ThemeColours {
public int colorPrimary;
public int colorPrimaryVariant;
public int colorOnPrimary;
public int colorSecondary;
public int colorSecondaryVariant;
public int colorOnSecondary;
}

Wyświetl plik

@ -1,11 +1,9 @@
package cc.pogoda.mobile.pogodacc.type;
package cc.pogoda.mobile.meteosystem.type;
import androidx.annotation.Nullable;
import java.io.Serializable;
import cc.pogoda.mobile.pogodacc.activity.trend.pressure.PressureTrendFragment;
public class WeatherStation implements Serializable {
public WeatherStation() {
@ -73,7 +71,12 @@ public class WeatherStation implements Serializable {
}
public int getStationNameTextColor() {
return stationNameTextColor;
if (stationNameTextColor == 0) {
return -16777216;
}
else {
return stationNameTextColor;
}
}
public void setStationNameTextColor(int stationNameTextColor) {
@ -126,10 +129,35 @@ public class WeatherStation implements Serializable {
String displayedLocation;
public String getCallsignSsid() {
return callsignSsid;
}
public void setCallsignSsid(String callsign, int ssid) {
if (ssid < 16)
this.callsignSsid = callsign + "-" + ssid;
}
public void setCallsignSsid(String callsignSsid) {
this.callsignSsid = callsignSsid;
}
String callsignSsid;
String sponsorUrl;
String imageUrl;
public String getTimezone() {
return timezone.trim();
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
String timezone;
int imageAlign;
int stationNameTextColor;

Wyświetl plik

@ -0,0 +1,34 @@
package cc.pogoda.mobile.meteosystem.type;
import androidx.annotation.NonNull;
public class WeatherStationListEvent {
public enum EventReason {
ADD,
DELETE;
}
WeatherStation station;
EventReason eventReason;
public WeatherStationListEvent(WeatherStation wx, EventReason reason) {
station = wx;
eventReason = reason;
}
public WeatherStation getStation() {
return station;
}
public EventReason getEventReason() {
return eventReason;
}
@NonNull
@Override
public String toString() {
return "[station.systemName = " + station.systemName + "][eventReason = " + eventReason + "]";
}
}

Wyświetl plik

@ -0,0 +1,15 @@
package cc.pogoda.mobile.meteosystem.type.web;
public class AvailableParametersWeb {
public boolean hasWind;
public boolean hasQnh;
public boolean hasHumidity;
public boolean hasRain;
public byte telemetryVersion;
}

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type.web;
package cc.pogoda.mobile.meteosystem.type.web;
public class ListOfAllStations {

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type.web;
package cc.pogoda.mobile.meteosystem.type.web;
public class ListOfStationData {

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type.web;
package cc.pogoda.mobile.meteosystem.type.web;
public enum QualityFactor {
UNSET,

Wyświetl plik

@ -1,8 +1,6 @@
package cc.pogoda.mobile.pogodacc.type.web;
package cc.pogoda.mobile.meteosystem.type.web;
import java.time.LocalDateTime;
import cc.pogoda.mobile.pogodacc.type.CustomLocalDateTime;
import cc.pogoda.mobile.meteosystem.type.CustomLocalDateTime;
public class StationData {

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type.web;
package cc.pogoda.mobile.meteosystem.type.web;
public class StationDefinition {
@ -26,6 +26,8 @@ public class StationDefinition {
public String moreInfo;
public String timezone;
public float lat;
public float lon;

Wyświetl plik

@ -0,0 +1,327 @@
package cc.pogoda.mobile.meteosystem.type.web;
import cc.pogoda.mobile.meteosystem.config.AppConfiguration;
public class Summary {
private static final String SPACE = " ";
private static final String NO_SPACE = "";
public long last_timestamp;
public int number_of_measurements;
private float avg_temperature;
public String temperature_qf;
public QualityFactor temperature_qf_native;
public short qnh;
public String qnh_qf;
public QualityFactor qnh_qf_native;
public byte humidity;
public String humidity_qf;
public QualityFactor humidity_qf_native;
public short direction;
private float average_speed;
private float gusts;
private float hour_gusts;
private float hour_max_average_speed;
private float hour_min_average_speed;
public String wind_qf;
public QualityFactor wind_qf_native;
public Summary() {
temperature_qf_native = QualityFactor.UNSET;
humidity_qf_native = QualityFactor.UNSET;
wind_qf_native = QualityFactor.UNSET;
}
public float getAvgTemperature() {
return avg_temperature;
}
public float getAverageSpeed() {
return average_speed;
}
public float getGusts() {
return gusts;
}
public float getHourGusts() {
return hour_gusts;
}
public float getHourMaxAverageSpeed() {
return hour_max_average_speed;
}
public float getHourMinAverageSpeed() {
return hour_min_average_speed;
}
public String getTemperatureStr(boolean space, boolean round) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (round) {
out = String.format("%d%s°C", Math.round(avg_temperature), s);
}
else {
out = String.format("%.1f%s°C", avg_temperature, s);
}
out = out.replace(',', '.');
return out;
}
public String getWindspeedStr(boolean space) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (AppConfiguration.replaceMsWithKnots) {
float knots = this.average_speed * 1.94f;
out = String.format("%2d%skn", Math.round(knots), s);
}
else {
out = String.format("%4.1f%sm/s", this.average_speed, s);
}
out = out.replace(',', '.');
return out;
}
public String getHourMinWindspeedStr(boolean space) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (AppConfiguration.replaceMsWithKnots) {
float knots = this.hour_min_average_speed * 1.94f;
out = String.format("%2d%skn", Math.round(knots), s);
}
else {
out = String.format("%4.1f%sm/s", this.hour_min_average_speed, s);
}
out = out.replace(',', '.');
return out;
}
public String getHourMaxWindspeedStr(boolean space) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (AppConfiguration.replaceMsWithKnots) {
float knots = this.hour_max_average_speed * 1.94f;
out = String.format("%2d%skn", Math.round(knots), s);
}
else {
out = String.format("%4.1f%sm/s", this.hour_max_average_speed, s);
}
out = out.replace(',', '.');
return out;
}
public String getWindgustsStr(boolean space) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (AppConfiguration.replaceMsWithKnots) {
float knots = this.gusts * 1.94f;
out = String.format("%2d%skn", Math.round(knots), s);
}
else {
out = String.format("%4.1f%sm/s", this.gusts, s);
}
out = out.replace(',', '.');
return out;
}
public String getHourWindgustsStr(boolean space) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (AppConfiguration.replaceMsWithKnots) {
float knots = this.hour_gusts * 1.94f;
out = String.format("%2d%skn", Math.round(knots), s);
}
else {
out = String.format("%4.1f%sm/s", this.hour_gusts, s);
}
out = out.replace(',', '.');
return out;
}
public String getWindDirStr() {
String out;
if (direction <= 11 || direction >= 349) {
out = String.format("%5s", "N");
}
else if (direction <= 34 && direction > 11) {
out = String.format("%5s", "N NE");
}
else if (direction <= 56 && direction > 34) {
out = String.format("%5s", "NE");
}
else if (direction <= 79 && direction > 56) {
out = String.format("%5s", "E NE");
}
else if (direction <= 101 && direction > 79) {
out = String.format("%5s", "E");
}
else if (direction <= 124 && direction > 101) {
out = String.format("%5s", "E SE");
}
else if (direction <= 146 && direction > 124) {
out = String.format("%5s", "SE");
}
else if (direction <= 169 && direction > 146) {
out = String.format("%5s", "S SE");
}
else if (direction <= 191 && direction > 169) {
out = String.format("%5s", "S");
}
else if (direction <= 214 && direction > 191) {
out = String.format("%5s", "S SW");
}
else if (direction <= 236 && direction > 214) {
out = String.format("%5s", "SW");
}
else if (direction <= 259 && direction > 236) {
out = String.format("%5s", "W SW");
}
else if (direction <= 281 && direction > 259) {
out = String.format("%5s", "W");
}
else if (direction <= 304 && direction > 281) {
out = String.format("%5s", "W NW");
}
else if (direction <= 327 && direction > 304) {
out = String.format("%5s", "NW");
}
else if (direction <= 349 && direction > 327) {
out = String.format("%5s", "N NW");
}
else {
out = "";
}
return out;
}
/**
*
if (WX.wind_direction <= 11 && WX.wind_direction >= 349)
html << "- N";
else if (WX.wind_direction <= 34 && WX.wind_direction > 11)
html << "- N NE";
else if (WX.wind_direction <= 56 && WX.wind_direction > 34)
html << "- NE";
else if (WX.wind_direction <= 79 && WX.wind_direction > 56)
html << "- E NE";
else if (WX.wind_direction <= 101 && WX.wind_direction > 79)
html << "- E";
else if (WX.wind_direction <= 124 && WX.wind_direction > 101)
html << "- E SE";
else if (WX.wind_direction <= 146 && WX.wind_direction > 124)
html << "- SE";
else if (WX.wind_direction <= 169 && WX.wind_direction > 146)
html << "- S SE";
else if (WX.wind_direction <= 191 && WX.wind_direction > 169)
html << "- S";
else if (WX.wind_direction <= 214 && WX.wind_direction > 191)
html << "- S SW";
else if (WX.wind_direction <= 236 && WX.wind_direction > 214)
html << "- SW";
else if (WX.wind_direction <= 259 && WX.wind_direction > 236)
html <<"- W SW";
else if (WX.wind_direction <= 281 && WX.wind_direction > 259)
html << "- W";
else if (WX.wind_direction <= 304 && WX.wind_direction > 281)
html << "- W NW";
else if (WX.wind_direction <= 327 && WX.wind_direction > 304)
html << "- NW";
else if (WX.wind_direction <= 349 && WX.wind_direction > 327)
html << "- N NW";
else;
*/
}

Wyświetl plik

@ -1,4 +1,4 @@
package cc.pogoda.mobile.pogodacc.type.web;
package cc.pogoda.mobile.meteosystem.type.web;
public class Trend {

Wyświetl plik

@ -0,0 +1,139 @@
package cc.pogoda.mobile.meteosystem.type.web;
public class TrendData {
private static final String SPACE = " ";
private static final String NO_SPACE = "";
private float current_value;
private float two_hours_value;
private float four_hours_value;
private float six_hours_value;
private float eight_hours_value;
public String getCurrentVal(boolean space, boolean round) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (round) {
out = String.format("%d%s", Math.round(current_value), s);
}
else {
out = String.format("%.1f%s", current_value, s);
}
out = out.replace(',', '.');
return out;
}
public String getTwoHoursVal(boolean space, boolean round) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (round) {
out = String.format("%d%s", Math.round(two_hours_value), s);
}
else {
out = String.format("%.1f%s", two_hours_value, s);
}
out = out.replace(',', '.');
return out;
}
public String getFourHoursVal(boolean space, boolean round) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (round) {
out = String.format("%d%s", Math.round(four_hours_value), s);
}
else {
out = String.format("%.1f%s", four_hours_value, s);
}
out = out.replace(',', '.');
return out;
}
public String getSixHoursVal(boolean space, boolean round) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (round) {
out = String.format("%d%s", Math.round(six_hours_value), s);
}
else {
out = String.format("%.1f%s", six_hours_value, s);
}
out = out.replace(',', '.');
return out;
}
public String getEightHoursVal(boolean space, boolean round) {
String out;
String s;
if (space) {
s = SPACE;
}
else {
s = NO_SPACE;
}
if (round) {
out = String.format("%d%s", Math.round(eight_hours_value), s);
}
else {
out = String.format("%.1f%s", eight_hours_value, s);
}
out = out.replace(',', '.');
return out;
}
}

Wyświetl plik

@ -0,0 +1,12 @@
package cc.pogoda.mobile.meteosystem.web;
import cc.pogoda.mobile.meteosystem.type.web.AvailableParametersWeb;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface AvailableParametersConsumer {
@GET("meteo_backend/station/{name}/availableParameters")
Call<AvailableParametersWeb> getParametersForStation(@Path("name") String name);
}

Wyświetl plik

@ -1,14 +1,15 @@
package cc.pogoda.mobile.pogodacc.web;
package cc.pogoda.mobile.meteosystem.web;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.meteosystem.type.web.ListOfStationData;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface LastStationDataConsumer {
@GET("meteo_backend/lastStationData/")
Call<ListOfStationData> getLastDataForStation(@Query("station")String station,
@GET("meteo_backend/station/{stationName}/lastStationData/")
Call<ListOfStationData> getLastDataForStation(@Path("stationName")String station,
@Query("ascendingOrder")boolean ascendingOrder,
@Query("isLong")boolean isLong);
}

Wyświetl plik

@ -0,0 +1,40 @@
package cc.pogoda.mobile.meteosystem.web;
import static cc.pogoda.mobile.meteosystem.config.WebIoConfig.TIMEOUT_SECOND;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.concurrent.TimeUnit;
import cc.pogoda.mobile.meteosystem.type.CustomLocalDateTime;
import cc.pogoda.mobile.meteosystem.web.deserializer.CustomLocalDateTimeDeserializer;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RestClientConfig {
public Retrofit getWeatherStationClient() {
Retrofit out = null;
Gson gson = new GsonBuilder().registerTypeAdapter(CustomLocalDateTime.class, new CustomLocalDateTimeDeserializer()).setLenient().create();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.readTimeout(TIMEOUT_SECOND, TimeUnit.SECONDS);
builder.writeTimeout(TIMEOUT_SECOND, TimeUnit.SECONDS);
builder.connectTimeout(TIMEOUT_SECOND, TimeUnit.SECONDS);
builder.callTimeout(TIMEOUT_SECOND, TimeUnit.SECONDS);
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient client = builder.addInterceptor(loggingInterceptor).build();//new OkHttpClient(builder);
out = new Retrofit.Builder().baseUrl("http://pogoda.cc:8080/").addConverterFactory(GsonConverterFactory.create(gson)).client(client).build();
return out;
}
}

Wyświetl plik

@ -0,0 +1,49 @@
package cc.pogoda.mobile.meteosystem.web;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.tinylog.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import cc.pogoda.mobile.meteosystem.type.WeatherStation;
public class StationBackgroundDownloader implements Runnable {
private WeatherStation station;
public Bitmap getBitmap() {
return bitmap;
}
private Bitmap bitmap;
public StationBackgroundDownloader(WeatherStation _wx_station) {
station = _wx_station;
bitmap = null;
}
@Override
public void run() {
InputStream in = null;
try {
URL url = new java.net.URL(station.getImageUrl());
Logger.debug("[url = " + url.toString() +"]");
in = url.openStream();
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (IOException e) {
Logger.error("[IOException][e = " + e.getLocalizedMessage() +"]");
e.printStackTrace();
bitmap = null;
}
}
}

Some files were not shown because too many files have changed in this diff Show More