├── tempsqml.png ├── android ├── libssl.so ├── libcrypto.so ├── res │ ├── drawable-hdpi │ │ └── icon.png │ ├── drawable-ldpi │ │ └── icon.png │ ├── drawable-mdpi │ │ └── icon.png │ └── values │ │ └── libs.xml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── build.gradle ├── gradlew.bat ├── AndroidManifest.xml └── gradlew ├── qml ├── images │ ├── app.png │ ├── map.png │ ├── snow.png │ ├── humidity.png │ ├── umbrella.png │ ├── background.png │ ├── checkboxes.png │ ├── icons │ │ ├── 01d.png │ │ ├── 01dW.png │ │ ├── 01n.png │ │ ├── 01nW.png │ │ ├── 02d.png │ │ ├── 02dW.png │ │ ├── 02n.png │ │ ├── 02nW.png │ │ ├── 03d.png │ │ ├── 03dW.png │ │ ├── 03n.png │ │ ├── 03nW.png │ │ ├── 04d.png │ │ ├── 04dW.png │ │ ├── 04n.png │ │ ├── 04nW.png │ │ ├── 09d.png │ │ ├── 09dW.png │ │ ├── 09n.png │ │ ├── 09nW.png │ │ ├── 10d.png │ │ ├── 10dW.png │ │ ├── 10n.png │ │ ├── 10nW.png │ │ ├── 11d.png │ │ ├── 11dW.png │ │ ├── 11n.png │ │ ├── 11nW.png │ │ ├── 12d.png │ │ ├── 12dW.png │ │ ├── 12n.png │ │ ├── 12nW.png │ │ ├── 13d.png │ │ ├── 13dW.png │ │ ├── 13n.png │ │ ├── 13nW.png │ │ ├── 50d.png │ │ ├── 50dW.png │ │ ├── 50n.png │ │ ├── 50nW.png │ │ ├── menu.png │ │ ├── 01d@2x.png │ │ ├── 01dW@2x.png │ │ ├── 01n@2x.png │ │ ├── 01nW@2x.png │ │ ├── 02d@2x.png │ │ ├── 02dW@2x.png │ │ ├── 02n@2x.png │ │ ├── 02nW@2x.png │ │ ├── 03d@2x.png │ │ ├── 03dW@2x.png │ │ ├── 03n@2x.png │ │ ├── 03nW@2x.png │ │ ├── 04d@2x.png │ │ ├── 04dW@2x.png │ │ ├── 04n@2x.png │ │ ├── 04nW@2x.png │ │ ├── 09d@2x.png │ │ ├── 09dW@2x.png │ │ ├── 09n@2x.png │ │ ├── 09nW@2x.png │ │ ├── 10d@2x.png │ │ ├── 10dW@2x.png │ │ ├── 10n@2x.png │ │ ├── 10nW@2x.png │ │ ├── 11d@2x.png │ │ ├── 11dW@2x.png │ │ ├── 11n@2x.png │ │ ├── 11nW@2x.png │ │ ├── 12d@2x.png │ │ ├── 12dW@2x.png │ │ ├── 12n@2x.png │ │ ├── 12nW@2x.png │ │ ├── 13d@2x.png │ │ ├── 13dW@2x.png │ │ ├── 13n@2x.png │ │ ├── 13nW@2x.png │ │ ├── 50d@2x.png │ │ ├── 50dW@2x.png │ │ ├── 50n@2x.png │ │ ├── 50nW@2x.png │ │ ├── menu@2x.png │ │ ├── menu@3x.png │ │ ├── menu@4x.png │ │ ├── 01dTemplate.png │ │ ├── 01nTemplate.png │ │ ├── 02dTemplate.png │ │ ├── 02nTemplate.png │ │ ├── 03dTemplate.png │ │ ├── 03nTemplate.png │ │ ├── 04dTemplate.png │ │ ├── 04nTemplate.png │ │ ├── 09dTemplate.png │ │ ├── 09nTemplate.png │ │ ├── 10dTemplate.png │ │ ├── 10nTemplate.png │ │ ├── 11dTemplate.png │ │ ├── 11nTemplate.png │ │ ├── 12dTemplate.png │ │ ├── 12nTemplate.png │ │ ├── 13dTemplate.png │ │ ├── 13nTemplate.png │ │ ├── 50dTemplate.png │ │ ├── 50nTemplate.png │ │ ├── 01dTemplate@2x.png │ │ ├── 01nTemplate@2x.png │ │ ├── 02dTemplate@2x.png │ │ ├── 02nTemplate@2x.png │ │ ├── 03dTemplate@2x.png │ │ ├── 03nTemplate@2x.png │ │ ├── 04dTemplate@2x.png │ │ ├── 04nTemplate@2x.png │ │ ├── 09dTemplate@2x.png │ │ ├── 09nTemplate@2x.png │ │ ├── 10dTemplate@2x.png │ │ ├── 10nTemplate@2x.png │ │ ├── 11dTemplate@2x.png │ │ ├── 11nTemplate@2x.png │ │ ├── 12dTemplate@2x.png │ │ ├── 12nTemplate@2x.png │ │ ├── 13dTemplate@2x.png │ │ ├── 13nTemplate@2x.png │ │ ├── 50dTemplate@2x.png │ │ ├── 50nTemplate@2x.png │ │ ├── IconTemplate@02d.png │ │ ├── 01n.svg │ │ ├── 50d.svg │ │ ├── 50n.svg │ │ ├── 03d.svg │ │ ├── 03n.svg │ │ ├── 02n.svg │ │ ├── 04d.svg │ │ ├── 04n.svg │ │ ├── 12d.svg │ │ ├── 12n.svg │ │ ├── 09d.svg │ │ ├── 09n.svg │ │ ├── 11n.svg │ │ ├── 13n.svg │ │ ├── 01d.svg │ │ ├── 10n.svg │ │ ├── 02d.svg │ │ ├── 11d.svg │ │ ├── 13d.svg │ │ └── 10d.svg │ ├── termometer.png │ ├── wind-arrow.png │ ├── checkboxes@2x.png │ ├── IconTemplate@2x.png │ ├── round-clock-icon.png │ └── earth.svg ├── SnowFlake.qml ├── RainDrop.qml ├── PartialImage.qml ├── Wind.qml ├── SettingsRadio.qml ├── ColoredImage.qml ├── SettingsCheck.qml ├── SettingsButton.qml ├── MenuClose.qml ├── WeatherMap.qml ├── Indicators.qml ├── main.qml ├── WeatherDelegate.qml ├── SettingsPage.qml ├── MainPage.qml ├── EditableCombo.qml ├── WeatherGraph.qml └── WaiwedItem.qml ├── qtquickcontrols2.conf ├── README.md ├── src ├── systemtrayicon.cpp ├── systemtrayicon.h ├── googlebrowserlocation.h ├── settings.h ├── main.cpp ├── weatherdailymodel.h ├── googlebrowserlocation.cpp ├── weathermodel.h ├── weathercommon.h ├── weatherdata.h ├── weatherdata.cpp ├── weatherdailymodel.cpp └── weathercommon.cpp ├── .gitignore ├── LICENSE ├── tempsQML.pro └── qml.qrc /tempsqml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/tempsqml.png -------------------------------------------------------------------------------- /android/libssl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/android/libssl.so -------------------------------------------------------------------------------- /qml/images/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/app.png -------------------------------------------------------------------------------- /qml/images/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/map.png -------------------------------------------------------------------------------- /android/libcrypto.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/android/libcrypto.so -------------------------------------------------------------------------------- /qml/images/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/snow.png -------------------------------------------------------------------------------- /qml/images/humidity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/humidity.png -------------------------------------------------------------------------------- /qml/images/umbrella.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/umbrella.png -------------------------------------------------------------------------------- /qml/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/background.png -------------------------------------------------------------------------------- /qml/images/checkboxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/checkboxes.png -------------------------------------------------------------------------------- /qml/images/icons/01d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01d.png -------------------------------------------------------------------------------- /qml/images/icons/01dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01dW.png -------------------------------------------------------------------------------- /qml/images/icons/01n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01n.png -------------------------------------------------------------------------------- /qml/images/icons/01nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01nW.png -------------------------------------------------------------------------------- /qml/images/icons/02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02d.png -------------------------------------------------------------------------------- /qml/images/icons/02dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02dW.png -------------------------------------------------------------------------------- /qml/images/icons/02n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02n.png -------------------------------------------------------------------------------- /qml/images/icons/02nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02nW.png -------------------------------------------------------------------------------- /qml/images/icons/03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03d.png -------------------------------------------------------------------------------- /qml/images/icons/03dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03dW.png -------------------------------------------------------------------------------- /qml/images/icons/03n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03n.png -------------------------------------------------------------------------------- /qml/images/icons/03nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03nW.png -------------------------------------------------------------------------------- /qml/images/icons/04d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04d.png -------------------------------------------------------------------------------- /qml/images/icons/04dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04dW.png -------------------------------------------------------------------------------- /qml/images/icons/04n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04n.png -------------------------------------------------------------------------------- /qml/images/icons/04nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04nW.png -------------------------------------------------------------------------------- /qml/images/icons/09d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09d.png -------------------------------------------------------------------------------- /qml/images/icons/09dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09dW.png -------------------------------------------------------------------------------- /qml/images/icons/09n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09n.png -------------------------------------------------------------------------------- /qml/images/icons/09nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09nW.png -------------------------------------------------------------------------------- /qml/images/icons/10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10d.png -------------------------------------------------------------------------------- /qml/images/icons/10dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10dW.png -------------------------------------------------------------------------------- /qml/images/icons/10n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10n.png -------------------------------------------------------------------------------- /qml/images/icons/10nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10nW.png -------------------------------------------------------------------------------- /qml/images/icons/11d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11d.png -------------------------------------------------------------------------------- /qml/images/icons/11dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11dW.png -------------------------------------------------------------------------------- /qml/images/icons/11n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11n.png -------------------------------------------------------------------------------- /qml/images/icons/11nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11nW.png -------------------------------------------------------------------------------- /qml/images/icons/12d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12d.png -------------------------------------------------------------------------------- /qml/images/icons/12dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12dW.png -------------------------------------------------------------------------------- /qml/images/icons/12n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12n.png -------------------------------------------------------------------------------- /qml/images/icons/12nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12nW.png -------------------------------------------------------------------------------- /qml/images/icons/13d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13d.png -------------------------------------------------------------------------------- /qml/images/icons/13dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13dW.png -------------------------------------------------------------------------------- /qml/images/icons/13n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13n.png -------------------------------------------------------------------------------- /qml/images/icons/13nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13nW.png -------------------------------------------------------------------------------- /qml/images/icons/50d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50d.png -------------------------------------------------------------------------------- /qml/images/icons/50dW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50dW.png -------------------------------------------------------------------------------- /qml/images/icons/50n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50n.png -------------------------------------------------------------------------------- /qml/images/icons/50nW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50nW.png -------------------------------------------------------------------------------- /qml/images/icons/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/menu.png -------------------------------------------------------------------------------- /qml/images/termometer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/termometer.png -------------------------------------------------------------------------------- /qml/images/wind-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/wind-arrow.png -------------------------------------------------------------------------------- /qml/images/checkboxes@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/checkboxes@2x.png -------------------------------------------------------------------------------- /qml/images/icons/01d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/01dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/01n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/01nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/02d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/02dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/02n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/02nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/03d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/03dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/03n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/03nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/04d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/04dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/04n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/04nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/09d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/09dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/09n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/09nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/10d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/10dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/10n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/10nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/11d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/11dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/11n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/11nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/12d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/12dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/12n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/12nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/13d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/13dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/13n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/13nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/50d@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50d@2x.png -------------------------------------------------------------------------------- /qml/images/icons/50dW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50dW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/50n@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50n@2x.png -------------------------------------------------------------------------------- /qml/images/icons/50nW@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50nW@2x.png -------------------------------------------------------------------------------- /qml/images/icons/menu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/menu@2x.png -------------------------------------------------------------------------------- /qml/images/icons/menu@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/menu@3x.png -------------------------------------------------------------------------------- /qml/images/icons/menu@4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/menu@4x.png -------------------------------------------------------------------------------- /qml/images/IconTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/IconTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/01dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/01nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/02dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/02nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/03dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/03nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/04dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/04nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/09dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/09nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/10dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/10nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/11dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/11nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/12dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/12nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/13dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/13nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13nTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/50dTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50dTemplate.png -------------------------------------------------------------------------------- /qml/images/icons/50nTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50nTemplate.png -------------------------------------------------------------------------------- /qml/images/round-clock-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/round-clock-icon.png -------------------------------------------------------------------------------- /android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /qml/images/icons/01dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/01nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/01nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/02dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/02nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/02nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/03dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/03nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/03nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/04dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/04nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/04nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/09dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/09nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/09nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/10dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/10nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/10nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/11dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/11nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/11nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/12dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/12nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/12nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/13dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/13nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/13nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/50dTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50dTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/50nTemplate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/50nTemplate@2x.png -------------------------------------------------------------------------------- /qml/images/icons/IconTemplate@02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/qml/images/icons/IconTemplate@02d.png -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladest/tempsQML/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /qml/SnowFlake.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Rectangle { 4 | color: "white" 5 | width: 3 6 | height: 3 7 | radius: 1.5 8 | } 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /qml/RainDrop.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Rectangle { 4 | gradient: Gradient { 5 | GradientStop { position: 0.0; color: Qt.rgba(13, 52, 58, 1) } 6 | GradientStop { position: 1.0; color: Qt.rgba(255, 255, 255, .6) } 7 | } 8 | color: Qt.rgba(255, 255, 255, 0.2); 9 | width: 1 10 | height: 50 11 | } 12 | -------------------------------------------------------------------------------- /qtquickcontrols2.conf: -------------------------------------------------------------------------------- 1 | ; This file can be edited to change the style of the application 2 | ; See Styling Qt Quick Controls 2 in the documentation for details: 3 | ; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html 4 | 5 | [Controls] 6 | Style=Default 7 | 8 | [Universal] 9 | Theme=Light 10 | ;Accent=Steel 11 | 12 | [Material] 13 | Theme=Light 14 | ;Accent=BlueGrey 15 | ;Primary=BlueGray 16 | -------------------------------------------------------------------------------- /qml/PartialImage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtGraphicalEffects 1.0 3 | Item { 4 | property real imageOffsetX: 0 5 | property real imageOffsetY: 0 6 | clip: true 7 | 8 | Image { 9 | id: img 10 | source: "images/checkboxes@2x.png" 11 | cache: false 12 | x: imageOffsetX 13 | y: imageOffsetY 14 | sourceSize.height: 20 15 | sourceSize.width: 140 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /qml/Wind.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Row { 4 | property real angle: 0 5 | property real speed: 0 6 | 7 | spacing: 5 8 | ColoredImage { 9 | height: parent.height 10 | width: parent.height 11 | rotation: angle 12 | source: "images/wind-arrow.png" 13 | overlayColor: weatherCommon.backgroundColor 14 | } 15 | 16 | Text { 17 | font.pixelSize: 10 18 | color: "#999999" 19 | text: speed.toFixed(1) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tempsQML 2 | QML port of temps project 3 | 4 | The project is created for demonstrations purposes, inspired by https://jackd248.github.io/temps/ 5 | 6 | The idea is to demostrate the ways of creating Qt/QML apps using mixed C++/QML/JS approach, which gives addition flexibility and performance comparing to pure QML/JS solutions 7 | 8 | Tested with Qt 5.7 9 | 10 | Weather map is using OpenWeatherMap QtLocation plugin which is written for this app 11 | It will be available later 12 | 13 | If some have better idea on UI/UX you are welcome :) 14 | 15 | Videos playable under Android, now available 16 | -------------------------------------------------------------------------------- /src/systemtrayicon.cpp: -------------------------------------------------------------------------------- 1 | #include "systemtrayicon.h" 2 | 3 | SystemTrayIcon::SystemTrayIcon(QObject *parent) : QSystemTrayIcon(parent) 4 | , m_available(QSystemTrayIcon::isSystemTrayAvailable()) 5 | { 6 | if (m_available) { 7 | setIcon(QIcon(":/qml/images/app.png")); 8 | show(); 9 | } 10 | emit availableChanged(m_available); 11 | } 12 | 13 | bool SystemTrayIcon::available() const 14 | { 15 | return m_available; 16 | } 17 | 18 | void SystemTrayIcon::setNewIcon(const QString &iconPath) { 19 | if (m_available) { 20 | setIcon(QIcon(":/qml/images/" + iconPath)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /qml/SettingsRadio.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | 4 | RadioButton { 5 | id: control 6 | 7 | indicator: PartialImage { 8 | x: control.leftPadding 9 | y: parent.height / 2 - height / 2 10 | scale: appscale 11 | width: 20; height: 20; 12 | imageOffsetX: control.checked ? -60 : -40 13 | } 14 | 15 | contentItem: Text { 16 | text: control.text 17 | font: control.font 18 | opacity: enabled ? 1.0 : 0.3 19 | color: "#000000" 20 | leftPadding: control.indicator.width*appscale + control.spacing 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /qml/ColoredImage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtGraphicalEffects 1.0 3 | 4 | //Draw an image where all pixels except transparent will be colored to a given color 5 | Item { 6 | property color overlayColor: "#000000" 7 | property alias source: img.source 8 | Image { 9 | id: img 10 | height: parent.height 11 | width: parent.width 12 | //antialiasing: true 13 | smooth: true 14 | visible: false 15 | } 16 | ColorOverlay { 17 | anchors.fill: img 18 | source: img 19 | color: overlayColor // make image like it lays under red glass 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/systemtrayicon.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSTEMTRAYICON_H 2 | #define SYSTEMTRAYICON_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | class SystemTrayIcon : public QSystemTrayIcon 9 | { 10 | Q_OBJECT 11 | 12 | Q_PROPERTY(bool available READ available NOTIFY availableChanged) 13 | 14 | public: 15 | SystemTrayIcon(QObject * parent = nullptr); 16 | bool available() const; 17 | 18 | public slots: 19 | void setNewIcon(const QString &iconPath); 20 | 21 | signals: 22 | void availableChanged(bool available); 23 | 24 | private: 25 | bool m_available; 26 | }; 27 | 28 | #endif // SYSTEMTRAYICON_H 29 | -------------------------------------------------------------------------------- /qml/SettingsCheck.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | 4 | CheckBox { 5 | id: control 6 | font.pixelSize: appRoot.height/32 7 | 8 | indicator: PartialImage { 9 | x: control.leftPadding 10 | y: parent.height / 2 - height / 2 11 | scale: appscale 12 | width: 20; 13 | height: 20; 14 | imageOffsetX: control.checked ? -20 : 0 15 | } 16 | 17 | 18 | contentItem: Text { 19 | text: control.text 20 | font: control.font 21 | opacity: enabled ? 1.0 : 0.3 22 | color: "#999999" 23 | leftPadding: control.leftPadding + indicator.width + 10 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /qml/SettingsButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | 4 | Button { 5 | id: control 6 | 7 | font.pixelSize: appRoot.height/32 8 | 9 | contentItem: Text { 10 | text: control.text 11 | font: control.font 12 | opacity: enabled ? 1.0 : 0.3 13 | color: hovered ? "#FFFFFF" : "#000000" 14 | horizontalAlignment: Text.AlignHCenter 15 | verticalAlignment: Text.AlignVCenter 16 | elide: Text.ElideRight 17 | } 18 | 19 | background: Rectangle { 20 | opacity: enabled ? 1 : 0.3 21 | color: hovered || control.pressed ? "#80BBB2" : "#FFFFFF" 22 | border.width: 1 23 | border.color: "#CCCCCC" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://download.qt.io/ministro/android/qt5/qt-5.7 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /qml/images/icons/01n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Vladyslav Stelmakhovskyi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /qml/images/icons/50d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | -------------------------------------------------------------------------------- /qml/images/icons/50n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /qml/images/icons/03d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 12 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /qml/images/icons/03n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 12 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/googlebrowserlocation.h: -------------------------------------------------------------------------------- 1 | #ifndef GOOGLEBROWSERLOCATION_H 2 | #define GOOGLEBROWSERLOCATION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class GoogleBrowserLocation : public QObject 10 | { 11 | Q_OBJECT 12 | Q_PROPERTY(QGeoCoordinate browserCoordinate READ browserCoordinate NOTIFY browserCoordinateChanged) 13 | Q_PROPERTY(int tzoffset READ tzoffset WRITE setTzoffset NOTIFY tzoffsetChanged) 14 | 15 | public: 16 | explicit GoogleBrowserLocation(QObject *parent = nullptr); 17 | QGeoCoordinate browserCoordinate() const; 18 | Q_INVOKABLE void requestCoordinates(); 19 | int tzoffset() const; 20 | 21 | signals: 22 | void browserCoordinateChanged(QGeoCoordinate browserCoordinate); 23 | void tzoffsetChanged(int tzoffset); 24 | 25 | private slots: 26 | void onFinished(); 27 | void onTimezoneFinished(); 28 | private: 29 | void setBrowserCoordinate(QGeoCoordinate browserCoordinate); 30 | void setTzoffset(int tzoffset); 31 | void requestTimezone(const QGeoCoordinate &coord); 32 | 33 | QGeoCoordinate m_browserCoordinate; 34 | QNetworkAccessManager nam; 35 | int m_tzoffset; 36 | }; 37 | 38 | #endif // GOOGLEBROWSERLOCATION_H 39 | -------------------------------------------------------------------------------- /qml/images/icons/02n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | 13 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /qml/images/icons/04d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 11 | 15 | 16 | 18 | 19 | -------------------------------------------------------------------------------- /qml/images/icons/04n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 11 | 12 | 16 | 17 | 19 | 20 | -------------------------------------------------------------------------------- /qml/images/icons/12d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /qml/images/icons/12n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /qml/images/icons/09d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /qml/images/icons/09n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/settings.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_H 2 | #define SETTINGS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Settings : public QSettings 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit Settings(QObject *parent = 0) : QSettings(QSettings::IniFormat, 14 | QSettings::UserScope, 15 | QCoreApplication::instance()->organizationName(), 16 | QCoreApplication::instance()->applicationName(), 17 | parent) {} 18 | 19 | Q_INVOKABLE inline void setValue(const QString &key, const QVariant &value, const QString &group = QString()) { 20 | QSettings settings; 21 | if (!group.isEmpty()) 22 | settings.beginGroup(group); 23 | if (key.isEmpty() && value.toString().isEmpty()) 24 | settings.remove(""); 25 | else 26 | settings.setValue(key, value); 27 | if (!group.isEmpty()) 28 | settings.endGroup(); 29 | } 30 | Q_INVOKABLE inline QVariant value(const QString &key, const QVariant &defaultValue = QVariant(), const QString &group = QString()) const { 31 | QSettings settings; 32 | if (!group.isEmpty()) 33 | settings.beginGroup(group); 34 | QVariant v = settings.value(key, defaultValue); 35 | if (!group.isEmpty()) 36 | settings.endGroup(); 37 | return v; 38 | } 39 | }; 40 | 41 | Q_DECLARE_METATYPE(Settings*) 42 | 43 | #endif // SETTINGS_H 44 | 45 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:1.1.0' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | } 15 | } 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | dependencies { 20 | compile fileTree(dir: 'libs', include: ['*.jar']) 21 | } 22 | 23 | android { 24 | /******************************************************* 25 | * The following variables: 26 | * - androidBuildToolsVersion, 27 | * - androidCompileSdkVersion 28 | * - qt5AndroidDir - holds the path to qt android files 29 | * needed to build any Qt application 30 | * on Android. 31 | * 32 | * are defined in gradle.properties file. This file is 33 | * updated by QtCreator and androiddeployqt tools. 34 | * Changing them manually might break the compilation! 35 | *******************************************************/ 36 | 37 | compileSdkVersion androidCompileSdkVersion.toInteger() 38 | 39 | buildToolsVersion androidBuildToolsVersion 40 | 41 | sourceSets { 42 | main { 43 | manifest.srcFile 'AndroidManifest.xml' 44 | java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] 45 | aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] 46 | res.srcDirs = [qt5AndroidDir + '/res', 'res'] 47 | resources.srcDirs = ['src'] 48 | renderscript.srcDirs = ['src'] 49 | assets.srcDirs = ['assets'] 50 | jniLibs.srcDirs = ['libs'] 51 | } 52 | } 53 | 54 | lintOptions { 55 | abortOnError false 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /qml/images/icons/11n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 11 | 13 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /qml/images/icons/13n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 11 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /qml/images/icons/01d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 23 | 24 | 26 | 27 | 29 | 30 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /qml/images/icons/10n.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | 13 | 14 | 16 | 17 | 21 | 22 | 24 | 25 | 27 | 28 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /qml/images/icons/02d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 10 | 11 | 13 | 14 | 15 | 18 | 19 | 21 | 22 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /qml/MenuClose.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Item { 4 | id: mainRect 5 | 6 | property real radius: 3 7 | property color color: "white" 8 | 9 | Rectangle { 10 | id: bar1 11 | x: 0 12 | y: parent.height * .25 13 | width: parent.width 14 | height: parent.height * .15 15 | radius: parent.radius 16 | antialiasing: true 17 | color: mainRect.color 18 | } 19 | 20 | Rectangle { 21 | id: bar2 22 | x: 0 23 | y: parent.height * .5 24 | width: parent.width 25 | height: parent.height * .15 26 | radius: parent.radius 27 | antialiasing: true 28 | color: mainRect.color 29 | } 30 | 31 | Rectangle { 32 | id: bar3 33 | x: 0 34 | y: parent.height * .75 35 | width: parent.width 36 | height: parent.height * .15 37 | radius: parent.radius 38 | antialiasing: true 39 | color: mainRect.color 40 | } 41 | 42 | property int animationDuration: 350 43 | 44 | state: "menu" 45 | states: [ 46 | State { 47 | name: "menu" 48 | }, 49 | 50 | State { 51 | name: "back" 52 | PropertyChanges { target: mainRect; rotation: 180 } 53 | PropertyChanges { target: bar1; rotation: 45; width: mainRect.width * .6; x: mainRect.width * .48; y: mainRect.height * .33 - bar1.height } 54 | PropertyChanges { target: bar2; width: mainRect.width * .8; x: mainRect.width * .2; y: mainRect.height * .5 - bar2.height } 55 | PropertyChanges { target: bar3; rotation: -45; width: mainRect.width * .6; x: mainRect.width * .48; y: mainRect.height * .67 - bar3.height } 56 | } 57 | ] 58 | 59 | transitions: [ 60 | Transition { 61 | RotationAnimation { target: mainRect; direction: RotationAnimation.Clockwise; duration: animationDuration; easing.type: Easing.InOutQuad } 62 | PropertyAnimation { target: bar1; properties: "rotation, width, x, y"; duration: animationDuration; easing.type: Easing.InOutQuad } 63 | PropertyAnimation { target: bar2; properties: "rotation, width, x, y"; duration: animationDuration; easing.type: Easing.InOutQuad } 64 | PropertyAnimation { target: bar3; properties: "rotation, width, x, y"; duration: animationDuration; easing.type: Easing.InOutQuad } 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /tempsQML.pro: -------------------------------------------------------------------------------- 1 | QT += qml quick positioning location widgets svg multimedia 2 | 3 | CONFIG += c++11 flat 4 | 5 | SOURCES += src/main.cpp \ 6 | src/googlebrowserlocation.cpp \ 7 | src/weathermodel.cpp \ 8 | src/weatherdata.cpp \ 9 | src/weatherdailymodel.cpp \ 10 | src/systemtrayicon.cpp \ 11 | src/weathercommon.cpp 12 | 13 | RESOURCES += qml.qrc 14 | 15 | SRCMOC = .moc 16 | MOC_DIR = .moc 17 | OBJECTS_DIR = .obj 18 | 19 | INCLUDEPATH +=src 20 | # Additional import path used to resolve QML modules in Qt Creator's code model 21 | QML_IMPORT_PATH = 22 | 23 | # Additional import path used to resolve QML modules just for Qt Quick Designer 24 | QML_DESIGNER_IMPORT_PATH = 25 | 26 | # The following define makes your compiler emit warnings if you use 27 | # any feature of Qt which as been marked deprecated (the exact warnings 28 | # depend on your compiler). Please consult the documentation of the 29 | # deprecated API in order to know how to port your code away from it. 30 | DEFINES += QT_DEPRECATED_WARNINGS 31 | 32 | # You can also make your code fail to compile if you use deprecated APIs. 33 | # In order to do so, uncomment the following line. 34 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 35 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 36 | 37 | # Default rules for deployment. 38 | qnx: target.path = /tmp/$${TARGET}/bin 39 | else: unix:!android: target.path = /opt/$${TARGET}/bin 40 | !isEmpty(target.path): INSTALLS += target 41 | 42 | HEADERS += \ 43 | src/googlebrowserlocation.h \ 44 | src/weathermodel.h \ 45 | src/weatherdata.h \ 46 | src/weatherdailymodel.h \ 47 | src/systemtrayicon.h \ 48 | src/weathercommon.h \ 49 | src/settings.h 50 | 51 | DISTFILES += \ 52 | android/AndroidManifest.xml \ 53 | android/gradle/wrapper/gradle-wrapper.jar \ 54 | android/gradlew \ 55 | android/res/values/libs.xml \ 56 | android/build.gradle \ 57 | android/gradle/wrapper/gradle-wrapper.properties \ 58 | android/gradlew.bat 59 | 60 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 61 | 62 | contains(ANDROID_TARGET_ARCH,armeabi-v7a) { 63 | ANDROID_EXTRA_LIBS = \ 64 | $$PWD/android/libcrypto.so \ 65 | $$PWD/android/libssl.so 66 | 67 | LIBS += -L$$PWD/android -lcrypto -lssl 68 | } 69 | -------------------------------------------------------------------------------- /qml/WeatherMap.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtLocation 5.9 3 | import QtPositioning 5.8 4 | import QtQuick.Controls 2.2 5 | 6 | Item { 7 | property var centerCoordinate: browserCoordinate.browserCoordinate 8 | Map { 9 | id: baseMap 10 | anchors.fill: parent 11 | center: weatherMap.center 12 | zoomLevel: weatherMap.zoomLevel 13 | activeMapType: supportedMapTypes[0] 14 | 15 | plugin: Plugin { 16 | allowExperimental: true 17 | name: "osm" 18 | locales: "en_EN" 19 | } 20 | } 21 | Map { 22 | id: weatherMap 23 | anchors.fill: parent 24 | z: baseMap.z + 1 25 | center: centerCoordinate 26 | gesture.acceptedGestures: MapGestureArea.PanGesture | MapGestureArea.FlickGesture | MapGestureArea.PinchGesture 27 | gesture.flickDeceleration: 3000 28 | gesture.enabled: true 29 | focus: true 30 | color: "transparent" 31 | activeMapType: supportedMapTypes[0] 32 | 33 | plugin: Plugin { 34 | allowExperimental: true 35 | name: "openweathermaps" 36 | locales: "en_EN" 37 | PluginParameter { 38 | name: "openweathermaps.appkey" 39 | value: "483240f16c1aa9e5feab1fa41c9d273a" 40 | } 41 | } 42 | } 43 | ListModel { 44 | id: layersListModel 45 | } 46 | 47 | Row { 48 | width: parent.width 49 | anchors { left: parent.left; top: parent.top; margins: 10; right: parent.right } 50 | z: 1000 51 | spacing: 10 52 | MenuClose { 53 | state: "back" 54 | height: 30*appscale 55 | width: 30*appscale 56 | 57 | MouseArea { 58 | anchors.fill: parent 59 | onClicked: mainView.pop() 60 | } 61 | } 62 | ComboBox { 63 | model: layersListModel 64 | width: parent.width - 50 65 | currentIndex: 0 66 | onCurrentIndexChanged: weatherMap.activeMapType = weatherMap.supportedMapTypes[currentIndex] 67 | } 68 | } 69 | Component.onCompleted: { 70 | for (var i = 0; i < weatherMap.supportedMapTypes.length; i++) { 71 | layersListModel.append({display: weatherMap.supportedMapTypes[i].name}) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /qml/Indicators.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | 3 | Column { 4 | property real itemHeight: 16 5 | spacing: 0 6 | 7 | Item { 8 | height: parent.itemHeight 9 | width: height 10 | Image { 11 | height: parent.height/2 12 | width: parent.width/2 13 | anchors.centerIn: parent 14 | source: "Images/round-clock-icon.png" 15 | } 16 | } 17 | //empty item 18 | Item { 19 | height: parent.itemHeight 20 | width: height 21 | } 22 | Text { 23 | height: parent.itemHeight 24 | width: height 25 | horizontalAlignment: Text.AlignHCenter 26 | anchors.horizontalCenter: parent.horizontalCenter 27 | text: "C\u00B0" 28 | verticalAlignment: Text.AlignVCenter 29 | } 30 | Item { 31 | height: parent.itemHeight 32 | width: height 33 | Image { 34 | height: parent.height/2 35 | width: parent.width/2 36 | anchors.centerIn: parent 37 | source: "Images/termometer.png" 38 | } 39 | } 40 | Text { 41 | height: parent.itemHeight 42 | width: height 43 | horizontalAlignment: Text.AlignHCenter 44 | verticalAlignment: Text.AlignVCenter 45 | text: "kt" 46 | } 47 | Text { 48 | height: parent.itemHeight 49 | width: height 50 | horizontalAlignment: Text.AlignHCenter 51 | verticalAlignment: Text.AlignVCenter 52 | text: "hPa" 53 | } 54 | Item { 55 | height: parent.itemHeight 56 | width: height 57 | Image { 58 | height: parent.height/2 59 | width: parent.width/2 60 | anchors.centerIn: parent 61 | source: "Images/humidity.png" 62 | } 63 | } 64 | Item { 65 | height: parent.itemHeight 66 | width: height 67 | Image { 68 | height: parent.height/2 69 | width: parent.width/2 70 | anchors.centerIn: parent 71 | source: "Images/umbrella.png" 72 | } 73 | } 74 | Item { 75 | height: parent.itemHeight 76 | width: height 77 | Image { 78 | height: parent.height/2 79 | width: parent.width/2 80 | anchors.centerIn: parent 81 | source: "Images/snow.png" 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /qml/images/icons/11d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 12 | 15 | 18 | 19 | 21 | 22 | 24 | 25 | 27 | 28 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /qml/images/icons/13d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 26 | 27 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /qml/images/earth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 18 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include "weathercommon.h" 9 | #include "weathermodel.h" 10 | #include "weatherdailymodel.h" 11 | #include "systemtrayicon.h" 12 | #include "settings.h" 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | const QByteArray additionalLibraryPaths = qgetenv("QTLOCATION_EXTRA_LIBRARY_PATH"); 17 | for (const QByteArray &p : additionalLibraryPaths.split(':')) 18 | QCoreApplication::addLibraryPath(QString(p)); 19 | 20 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 21 | QCoreApplication::setApplicationName("tempsQML"); 22 | QCoreApplication::setOrganizationName("vladest"); 23 | QCoreApplication::setOrganizationDomain("vladest.org"); 24 | 25 | QApplication app(argc, argv); 26 | 27 | #ifdef Q_OS_LINUX 28 | QApplication::setWindowIcon(QIcon(":/tempsqml.png")); 29 | #endif /* Q_OS_LINUX */ 30 | 31 | QQmlApplicationEngine engine; 32 | SystemTrayIcon *trayIcon = new SystemTrayIcon; 33 | 34 | QNetworkProxyFactory::setUseSystemConfiguration(true); 35 | 36 | qmlRegisterType("weathermodel", 1, 0, "WeatherData"); 37 | qmlRegisterType("weathermodel", 1, 0, "WeatherCommon"); 38 | 39 | GoogleBrowserLocation gbl; 40 | WeatherCommon wcmn; 41 | WeatherModel wModel(&wcmn); 42 | WeatherDailyModel wDailyModel(&wcmn); 43 | SortFilterProxyModel filteredWeatherModel; 44 | 45 | filteredWeatherModel.setSourceModel(&wModel); 46 | 47 | QObject::connect(&gbl, &GoogleBrowserLocation::browserCoordinateChanged, &wcmn, &WeatherCommon::setCoordinates); 48 | QObject::connect(&gbl, &GoogleBrowserLocation::tzoffsetChanged, &wcmn, &WeatherCommon::setTimezoneOffset); 49 | 50 | Settings settings; 51 | 52 | engine.rootContext()->setContextProperty("weatherCommon", &wcmn); 53 | engine.rootContext()->setContextProperty("systemTrayIcon", trayIcon); 54 | engine.rootContext()->setContextProperty("browserCoordinate", &gbl); 55 | engine.rootContext()->setContextProperty("weatherModel", &wModel); 56 | engine.rootContext()->setContextProperty("weatherDailyModel", &wDailyModel); 57 | engine.rootContext()->setContextProperty("filteredWeatherModel", &filteredWeatherModel); 58 | engine.rootContext()->setContextProperty("settings", &settings); 59 | 60 | engine.load(QUrl(QLatin1String("qrc:/qml/main.qml"))); 61 | 62 | int ret = app.exec(); 63 | 64 | delete trayIcon; 65 | 66 | return ret; 67 | } 68 | -------------------------------------------------------------------------------- /qml/images/icons/10d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 11 | 12 | 14 | 15 | 18 | 19 | 21 | 22 | 24 | 25 | 26 | 27 | 29 | 30 | 32 | 33 | 35 | 36 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /qml/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | import QtQuick.Layouts 1.3 4 | import "." 5 | 6 | ApplicationWindow { 7 | id: appRoot 8 | visible: true 9 | 10 | width: 280 11 | height: 480 12 | title: qsTr("tempsQML") 13 | property alias backgr: mainView.background 14 | property alias mainView: mainView 15 | property real appscale: appRoot.height/480 16 | 17 | //store items, pushed to StackView 18 | property Item itemSettings: null 19 | property Item itemMain: null 20 | 21 | signal settingsClicked 22 | 23 | MenuClose { 24 | id: menuButton 25 | height: appRoot.height/24 26 | width: height 27 | z: 1000 28 | onStateChanged: { 29 | settingsClicked() 30 | } 31 | 32 | anchors { left: parent.left; top: parent.top; 33 | leftMargin: appRoot.width/28; 34 | topMargin: appRoot.height/28; 35 | } 36 | 37 | MouseArea { 38 | anchors.fill: parent 39 | onClicked: menuButton.state = (menuButton.state == "menu" ? "back" : "menu") 40 | } 41 | } 42 | 43 | StackView { 44 | id: mainView 45 | padding: 0 46 | anchors.fill: parent 47 | initialItem: mainComponent 48 | popEnter: Transition { 49 | PropertyAnimation { property: "opacity"; from: 0; to: 1; duration: 800 } 50 | } 51 | popExit: Transition { 52 | PropertyAnimation { property: "opacity"; from: 1; to: 0; duration: 800 } 53 | } 54 | pushEnter: Transition { 55 | PropertyAnimation { property: "opacity"; from: 0; to: 1; duration: 800 } 56 | } 57 | pushExit: Transition { 58 | PropertyAnimation { property: "opacity"; from: 1; to: 0; duration: 800 } 59 | } 60 | 61 | background: WaiwedItem { 62 | id: waiwedItem 63 | Connections { 64 | target: menuButton 65 | onStateChanged: { 66 | if (menuButton.state === "menu") { 67 | mainView.pop() 68 | } else { 69 | itemSettings = mainView.push(settingsComponent) 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | Component { 77 | id: settingsComponent 78 | SettingsPage {} 79 | } 80 | 81 | Component { 82 | id: mainComponent 83 | MainPage {} 84 | } 85 | 86 | Component { 87 | id: mapComponent 88 | WeatherMap {} 89 | } 90 | 91 | Component.onCompleted: { 92 | browserCoordinate.requestCoordinates() 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/weatherdailymodel.h: -------------------------------------------------------------------------------- 1 | #ifndef WEATHERDAILYMODEL_H 2 | #define WEATHERDAILYMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "weatherdata.h" 12 | #include "weathercommon.h" 13 | 14 | class WeatherDailyModel : public QAbstractListModel 15 | { 16 | Q_OBJECT 17 | 18 | Q_PROPERTY(QString cityName READ cityName WRITE setCityName NOTIFY cityNameChanged) 19 | Q_PROPERTY(QString countryID READ countryID WRITE setCountryID NOTIFY countryIDChanged) 20 | Q_PROPERTY(int daysNumber READ daysNumber NOTIFY daysNumberChanged) 21 | 22 | public: 23 | 24 | enum WeatherRoles { 25 | TimestampRole = Qt::UserRole + 1, 26 | TemperatureDayRole, 27 | TemperatureMinRole, 28 | TemperatureMaxRole, 29 | TemperatureNightRole, 30 | TemperatureEveRole, 31 | TemperatureMornRole, 32 | PressureRole, 33 | HumidityRole, 34 | WeatherConditionIdRole, 35 | WeatherConditionNameRole, 36 | WeatherConditionDescriptionRole, 37 | WeatherConditionIconIdRole, 38 | CloudsCoverageRole, 39 | WindSpeedRole, 40 | WindDegreesRole, 41 | WindGustRole, 42 | RainRole, 43 | SnowRole, 44 | SunriseRole, 45 | SunsetRole 46 | }; 47 | 48 | explicit WeatherDailyModel(WeatherCommon *wcommon, QAbstractListModel *parent = nullptr); 49 | virtual ~WeatherDailyModel() {} 50 | 51 | QString cityName() const; 52 | QString countryID() const; 53 | 54 | QHash roleNames() const; 55 | int rowCount(const QModelIndex &parent = QModelIndex()) const; 56 | QVariant data(const QModelIndex &index, int role) const; 57 | Q_INVOKABLE void setUpdateInterval(int updateInterval); 58 | int daysNumber() const; 59 | void setSearchCriteria(const WeatherCommon::SearchCriteria &searchCriteria); 60 | 61 | signals: 62 | void cityNameChanged(QString cityName); 63 | void countryIDChanged(QString countryID); 64 | void daysNumberChanged(int daysNumber); 65 | 66 | private slots: 67 | void onWeatherDailyRequestFinished(); 68 | void setDaysNumber(int daysNumber); 69 | 70 | public slots: 71 | void requestWeatherUpdate(); 72 | void setCityName(QString cityName); 73 | void setCountryID(QString countryID); 74 | 75 | private: 76 | QNetworkAccessManager _nam; 77 | qint64 _lastTs; 78 | QString m_cityName; 79 | QString m_countryID; 80 | QVector m_dailyList; 81 | QTimer _updateTimer; 82 | int _updateInterval; 83 | int m_daysNumber; 84 | WeatherCommon *m_wcommon; 85 | QNetworkReply *replyDaily; 86 | }; 87 | 88 | #endif // WEATHERDAILYMODEL_H 89 | -------------------------------------------------------------------------------- /qml/WeatherDelegate.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtGraphicalEffects 1.0 3 | 4 | Item { 5 | width: ListView.view.width / 4 6 | height: col.implicitHeight 7 | 8 | Rectangle { 9 | id: border 10 | anchors.left: parent.left 11 | height: col.implicitHeight 12 | width: 2 13 | color: "#f9f9f9" 14 | } 15 | 16 | Column { 17 | id: col 18 | anchors.left: border.right 19 | width: parent.width - 2 20 | height: parent.height 21 | spacing: 1 22 | 23 | Text { 24 | width: parent.width 25 | color: "#999999" 26 | font.pixelSize: appRoot.height / 48 27 | text: Qt.formatDateTime(timestamp, "ddd") 28 | horizontalAlignment: Text.AlignHCenter 29 | verticalAlignment: Text.AlignVCenter 30 | } 31 | 32 | ColoredImage { 33 | anchors.horizontalCenter: parent.horizontalCenter 34 | height: appRoot.height / 8 35 | width: appRoot.height / 8 36 | source: "images/icons/" + weather_codition_icon_id + ".svg" 37 | overlayColor: weatherCommon.backgroundColor 38 | } 39 | 40 | Text { 41 | width: parent.width 42 | color: "#999999" 43 | font.pixelSize: appRoot.height / 34 44 | text: weatherCommon.roundup(weatherCommon.convertToCurrentScale(temp_day)) + "\u00B0" 45 | horizontalAlignment: Text.AlignHCenter 46 | verticalAlignment: Text.AlignVCenter 47 | } 48 | Item { 49 | height: appRoot.height / 30 50 | anchors.horizontalCenter: parent.horizontalCenter 51 | width: parent.width 52 | Wind { 53 | height: parent.height 54 | anchors.centerIn: parent 55 | angle: wind_degrees 56 | speed: wind_speed 57 | } 58 | } 59 | Text { 60 | width: parent.width 61 | font.pixelSize: appRoot.height / 48 62 | color: "#999999" 63 | text: weatherCommon.roundup(pressure) 64 | horizontalAlignment: Text.AlignHCenter 65 | verticalAlignment: Text.AlignVCenter 66 | } 67 | Text { 68 | width: parent.width 69 | font.pixelSize: appRoot.height / 48 70 | color: "#999999" 71 | text: weatherCommon.roundup(humidity) + "%" 72 | horizontalAlignment: Text.AlignHCenter 73 | verticalAlignment: Text.AlignVCenter 74 | } 75 | // Text { 76 | // height: indicators.itemHeight 77 | // width: parent.width 78 | // text: rain_3h.toFixed(0) + " mm" 79 | // horizontalAlignment: Text.AlignHCenter 80 | // verticalAlignment: Text.AlignVCenter 81 | // } 82 | // Text { 83 | // height: indicators.itemHeight 84 | // width: parent.width 85 | // text: snow_3h.toFixed(0) + " mm" 86 | // horizontalAlignment: Text.AlignHCenter 87 | // verticalAlignment: Text.AlignVCenter 88 | // } 89 | } 90 | 91 | } 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/googlebrowserlocation.cpp: -------------------------------------------------------------------------------- 1 | #include "googlebrowserlocation.h" 2 | #include 3 | #include 4 | #include 5 | 6 | GoogleBrowserLocation::GoogleBrowserLocation(QObject *parent) : QObject(parent), m_tzoffset(0) { 7 | } 8 | 9 | QGeoCoordinate GoogleBrowserLocation::browserCoordinate() const 10 | { 11 | return m_browserCoordinate; 12 | } 13 | 14 | void GoogleBrowserLocation::requestTimezone(const QGeoCoordinate &coord) 15 | { 16 | QUrl url(QStringLiteral("https://maps.googleapis.com/maps/api/timezone/json")); 17 | QUrlQuery query; 18 | query.addQueryItem("location", QString("%1,%2").arg(coord.latitude(),0, 'f').arg(coord.longitude(),0, 'f')); 19 | query.addQueryItem("timestamp", QString::number(QDateTime::currentDateTime().toTime_t()/1000)); 20 | query.addQueryItem("key", "AIzaSyCDBVNwnbTjzXCZbKdJEJmkCwVKIK-aFlo"); 21 | url.setQuery(query); 22 | QNetworkRequest req(url); 23 | req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); 24 | QNetworkReply *r = nam.get(req); 25 | connect(r, &QNetworkReply::finished, this, &GoogleBrowserLocation::onTimezoneFinished); 26 | } 27 | 28 | void GoogleBrowserLocation::requestCoordinates() 29 | { 30 | QUrl url(QStringLiteral("https://maps.googleapis.com/maps/api/browserlocation/json")); 31 | QUrlQuery query; 32 | query.addQueryItem("browser", "chromium"); 33 | query.addQueryItem("sensor", "true"); 34 | url.setQuery(query); 35 | QNetworkRequest req(url); 36 | req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); 37 | QNetworkReply *r = nam.get(req); 38 | connect(r, &QNetworkReply::finished, this, &GoogleBrowserLocation::onFinished); 39 | } 40 | 41 | int GoogleBrowserLocation::tzoffset() const 42 | { 43 | return m_tzoffset; 44 | } 45 | 46 | void GoogleBrowserLocation::setTzoffset(int tzoffset) 47 | { 48 | m_tzoffset = tzoffset; 49 | emit tzoffsetChanged(tzoffset); 50 | } 51 | 52 | void GoogleBrowserLocation::onFinished() { 53 | QNetworkReply *r = static_cast(sender()); 54 | if (!r) 55 | return; 56 | r->deleteLater(); 57 | if (r->error() == QNetworkReply::NoError) { 58 | QJsonDocument doc = QJsonDocument::fromJson(r->readAll()); 59 | if (!doc.isEmpty() && doc.isObject()) { 60 | QJsonObject o = doc.object(); 61 | if (o.value("status").toString() == "OK") { 62 | QJsonObject loc = o.value("location").toObject(); 63 | QGeoCoordinate coord; 64 | coord.setLatitude(loc.value("lat").toDouble()); 65 | coord.setLongitude(loc.value("lng").toDouble()); 66 | setBrowserCoordinate(coord); 67 | } 68 | } 69 | } else { 70 | qDebug() << "request error" << r->error() << r->url(); 71 | } 72 | } 73 | 74 | void GoogleBrowserLocation::onTimezoneFinished() 75 | { 76 | QNetworkReply *r = static_cast(sender()); 77 | if (!r) 78 | return; 79 | r->deleteLater(); 80 | if (r->error() == QNetworkReply::NoError) { 81 | QJsonDocument doc = QJsonDocument::fromJson(r->readAll()); 82 | if (!doc.isEmpty() && doc.isObject()) { 83 | QJsonObject o = doc.object(); 84 | if (o.value("status").toString() == "OK") { 85 | int dstOffset = o.value("dstOffset").toInt(); 86 | int rawOffset = o.value("rawOffset").toInt(); 87 | setTzoffset(dstOffset + rawOffset); 88 | } 89 | } 90 | } else { 91 | qDebug() << "request error" << r->error() << r->url(); 92 | } 93 | } 94 | 95 | void GoogleBrowserLocation::setBrowserCoordinate(QGeoCoordinate browserCoordinate) 96 | { 97 | if (m_browserCoordinate == browserCoordinate) 98 | return; 99 | 100 | //qDebug() << "coord" << browserCoordinate; 101 | m_browserCoordinate = browserCoordinate; 102 | emit browserCoordinateChanged(browserCoordinate); 103 | requestTimezone(m_browserCoordinate); 104 | } 105 | -------------------------------------------------------------------------------- /src/weathermodel.h: -------------------------------------------------------------------------------- 1 | #ifndef WEATHERMODEL_H 2 | #define WEATHERMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "weatherdata.h" 11 | #include "weathercommon.h" 12 | 13 | class SortFilterProxyModel : public QSortFilterProxyModel 14 | { 15 | Q_OBJECT 16 | 17 | Q_PROPERTY(int count READ count NOTIFY countChanged) 18 | 19 | public: 20 | explicit SortFilterProxyModel(QObject *parent = 0); 21 | 22 | Q_INVOKABLE void setWeatherDateIndex(int weatherIndex); 23 | 24 | int count() const; 25 | 26 | public slots: 27 | void setCount(int count); 28 | 29 | signals: 30 | void countChanged(int count); 31 | 32 | protected: 33 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; 34 | 35 | private: 36 | int _weatherDateIndex; 37 | int m_count; 38 | }; 39 | 40 | //TODO: subclass from WeatherDailyModel 41 | class WeatherModel : public QAbstractListModel 42 | { 43 | Q_OBJECT 44 | 45 | Q_PROPERTY(QString cityName READ cityName WRITE setCityName NOTIFY cityNameChanged) 46 | Q_PROPERTY(QString countryID READ countryID WRITE setCountryID NOTIFY countryIDChanged) 47 | Q_PROPERTY(int daysNumber READ daysNumber NOTIFY daysNumberChanged) 48 | Q_PROPERTY(WeatherData* currentWeather READ currentWeather WRITE setCurrentWeather NOTIFY currentWeatherChanged) 49 | 50 | public: 51 | 52 | enum WeatherRoles { 53 | TimestampRole = Qt::UserRole + 1, 54 | TemperatureRole, 55 | TemperatureMinRole, 56 | TemperatureMaxRole, 57 | PressureRole, 58 | PressureSeaLevelRole, 59 | PressureGroundLevelRole, 60 | HumidityRole, 61 | WeatherConditionIdRole, 62 | WeatherConditionNameRole, 63 | WeatherConditionDescriptionRole, 64 | WeatherConditionIconIdRole, 65 | CloudsCoverageRole, 66 | WindSpeedRole, 67 | WindDegreesRole, 68 | WindGustRole, 69 | Rain3HRole, 70 | Snow3HRole, 71 | TimestampStringRole, 72 | SunriseRole, 73 | SunsetRole 74 | }; 75 | 76 | explicit WeatherModel(WeatherCommon *wcommon, QAbstractListModel *parent = 0); 77 | virtual ~WeatherModel(); 78 | 79 | QString cityName() const; 80 | QString countryID() const; 81 | 82 | QHash roleNames() const; 83 | int rowCount(const QModelIndex &parent = QModelIndex()) const; 84 | QVariant data(const QModelIndex &index, int role) const; 85 | 86 | Q_INVOKABLE void setUpdateInterval(int updateInterval); 87 | 88 | int daysNumber() const; 89 | 90 | WeatherData *currentWeather() const; 91 | 92 | public slots: 93 | void requestWeatherUpdate(); 94 | 95 | void setCityName(QString cityName); 96 | void setCountryID(QString countryID); 97 | int measuresForDate(const QDateTime &date) const; 98 | int measuresForDate(int index) const; 99 | void setCurrentWeather(WeatherData* currentWeather); 100 | 101 | signals: 102 | void cityNameChanged(QString cityName); 103 | void countryIDChanged(QString countryID); 104 | void daysNumberChanged(int daysNumber); 105 | void currentWeatherChanged(WeatherData* currentWeather); 106 | 107 | private slots: 108 | void onWeatherForecastRequestFinished(); 109 | void onWeatherCurrentRequestFinished(); 110 | void setDaysNumber(int daysNumber); 111 | private: 112 | WeatherCommon * m_wcommon; 113 | QNetworkAccessManager _nam; 114 | qint64 _lastTs; 115 | QString m_cityName; 116 | QString m_countryID; 117 | QVector m_forecastList; 118 | QMap m_forecastDates; 119 | QTimer _updateTimer; 120 | int _updateInterval; 121 | int m_daysNumber; 122 | QLocale _locale; 123 | friend class SortFilterProxyModel; 124 | WeatherData* m_currentWeather; 125 | 126 | QNetworkReply *replyForecast; 127 | QNetworkReply *replyCurrent; 128 | }; 129 | 130 | 131 | 132 | 133 | #endif // WEATHERMODEL_H 134 | -------------------------------------------------------------------------------- /src/weathercommon.h: -------------------------------------------------------------------------------- 1 | #ifndef WEATHERCOMMON_H 2 | #define WEATHERCOMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "weatherdata.h" 9 | 10 | class WeatherCommon : public QObject 11 | { 12 | Q_OBJECT 13 | 14 | Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundColorChanged) 15 | Q_PROPERTY(QString temperatureScale READ temperatureScale NOTIFY temperatureScaleChanged) 16 | Q_PROPERTY(QString currentVideo READ currentVideo NOTIFY currentVideoChanged) 17 | Q_PROPERTY(bool showAnimation READ showAnimation WRITE setShowAnimation NOTIFY showAnimationChanged) 18 | Q_PROPERTY(bool showVideo READ showVideo WRITE setShowVideo NOTIFY showVideoChanged) 19 | Q_PROPERTY(bool menuBarWeather READ menuBarWeather WRITE setMenuBarWeather NOTIFY menuBarWeatherChanged) 20 | Q_PROPERTY(bool runAtStartup READ runAtStartup WRITE setRunAtStartup NOTIFY runAtStartupChanged) 21 | Q_PROPERTY(TemperatureScales tempScale READ tempScale WRITE setTempScale NOTIFY tempScaleChanged) 22 | 23 | public: 24 | explicit WeatherCommon(QObject *parent = nullptr); 25 | virtual ~WeatherCommon() {} 26 | 27 | enum TemperatureScales { 28 | Celsium, 29 | Fahrenheit 30 | }; 31 | Q_ENUM(TemperatureScales) 32 | 33 | enum SearchCriteria { 34 | Coordinates, 35 | CityName 36 | }; 37 | Q_ENUM(SearchCriteria) 38 | 39 | enum WeatherType { 40 | Current, 41 | Daily, 42 | Forecast 43 | }; 44 | Q_ENUM(WeatherType) 45 | 46 | Q_INVOKABLE static qreal kelvin2celsius(qreal kelvin) { return (kelvin - 273.15); } 47 | Q_INVOKABLE static qreal kelvin2fahrenheit(qreal kelvin) { return (kelvin * (9.0/5.0) - 459.67); } 48 | Q_INVOKABLE static int roundup(qreal value) { return qRound(value); } 49 | 50 | Q_INVOKABLE qreal convertToCurrentScale(qreal temp_k); 51 | 52 | QColor backgroundColor() const; 53 | int getTimezoneOffset() const; 54 | static QList colorsTable(); 55 | 56 | QString temperatureScale() const; 57 | bool showAnimation() const; 58 | bool menuBarWeather() const; 59 | bool runAtStartup() const; 60 | void setTempScale(TemperatureScales tempScale); 61 | TemperatureScales tempScale() const; 62 | QGeoCoordinate getCoordinate() const; 63 | WeatherCommon::SearchCriteria getSearchCriteria() const; 64 | QString getSearchCity() const; 65 | QString currentVideo() const; 66 | void setCurrentVideo(const WeatherData &wdata); 67 | bool showVideo() const; 68 | 69 | signals: 70 | void backgroundColorChanged(QColor backgroundColor); 71 | void temperatureScaleChanged(QString temperatureScale); 72 | void showAnimationChanged(bool showAnimation); 73 | void menuBarWeatherChanged(bool menuBarWeather); 74 | void runAtStartupChanged(bool runAtStartup); 75 | void tempScaleChanged(TemperatureScales tempScale); 76 | void requestWeatherUpdate(); 77 | void weatherDownloadError(WeatherType weatherType, int weatherError); 78 | void currentVideoChanged(QString currentVideo); 79 | void showVideoChanged(bool showVideo); 80 | 81 | public slots: 82 | void setCoordinates(const QGeoCoordinate &coordinate); 83 | void setBackgroundColor(qreal temp); 84 | void setTimezoneOffset(int TimezoneOffset); 85 | void setShowAnimation(bool showAnimation); 86 | void setMenuBarWeather(bool menuBarWeather); 87 | void setRunAtStartup(bool runAtStartup); 88 | 89 | void search(const QString &city); 90 | void search(); 91 | 92 | /// @brief Saves city name, coordinates and last selected search criteria: by coordinate or by city 93 | void saveLastRequestedWeather(const QString &city); 94 | void setShowVideo(bool showVideo); 95 | 96 | private: 97 | QGeoCoordinate m_coordinate; 98 | QColor m_backgroundColor; 99 | int m_TimezoneOffset; 100 | static QList _colorsTable; 101 | static QMap, QString> _videoNamesTable; 102 | static QMap, QString> _videoNamesNightTable; 103 | bool m_showAnimation; 104 | bool m_menuBarWeather; 105 | bool m_runAtStartup; 106 | bool m_showVideo; 107 | TemperatureScales m_tempScale; 108 | QSettings settings; 109 | WeatherCommon::SearchCriteria m_searchCriteria; 110 | QString m_searchCity; 111 | QString m_currentVideo; 112 | QString m_currentVideoBasePath; 113 | bool m_currentVideoChanged; 114 | }; 115 | 116 | #endif // WEATHERCOMMON_H 117 | -------------------------------------------------------------------------------- /qml/SettingsPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | import weathermodel 1.0 4 | 5 | Item { 6 | 7 | StackView.onStatusChanged: { 8 | if (StackView.status === StackView.Activating) { 9 | cityEdit.loadCities() 10 | } else if (StackView.status === StackView.Deactivating) { 11 | cityEdit.saveCities() 12 | } 13 | } 14 | 15 | Column { 16 | width: parent.width - 20 17 | anchors.horizontalCenter: parent.horizontalCenter 18 | anchors.bottom: parent.bottom 19 | anchors.bottomMargin: 20 20 | spacing: 10 21 | 22 | Row { 23 | anchors.horizontalCenter: parent.horizontalCenter 24 | spacing: 5 25 | 26 | Image { 27 | source: "images/app.png" 28 | width: appRoot.height / 10 29 | height: width 30 | } 31 | 32 | Text { 33 | text: "tempsQML" 34 | font.pixelSize: appRoot.height / 15 35 | font.bold: true 36 | anchors.verticalCenter: parent.verticalCenter 37 | } 38 | 39 | Image { 40 | id: smallSun 41 | width: appRoot.height / 24 42 | height: width 43 | source: "images/IconTemplate@2x.png" 44 | PropertyAnimation { 45 | target: smallSun 46 | running: true; property: "rotation" 47 | from: 0; to: 359; duration: 5000; loops: Animation.Infinite } 48 | } 49 | } 50 | 51 | Text { 52 | text: qsTr("City") 53 | color: "#999999" 54 | font.pixelSize: appRoot.height / 35 55 | } 56 | 57 | EditableCombo { 58 | id: cityEdit 59 | width: parent.width 60 | onEnterPressed: { 61 | weatherCommon.search(editText) 62 | } 63 | } 64 | 65 | Row { 66 | width: parent.width 67 | 68 | Text { 69 | font.pixelSize: appRoot.height/32 70 | anchors.verticalCenter: parent.verticalCenter 71 | text: qsTr("Temperature scale") 72 | color: "#999999" 73 | } 74 | 75 | Item { 76 | width: 20*appscale; height: 1 77 | } 78 | 79 | ButtonGroup { id: scaleGroup } 80 | 81 | SettingsRadio { 82 | id: cels 83 | font.pixelSize: appRoot.height/26 84 | text: "\u00B0C" 85 | checked: weatherCommon.tempScale === WeatherCommon.Celsium 86 | ButtonGroup.group: scaleGroup 87 | } 88 | 89 | Item { 90 | width: 5*appscale; height: 1 91 | } 92 | 93 | SettingsRadio { 94 | id: fahr 95 | font.pixelSize: appRoot.height/26 96 | text: "\u00B0F" 97 | checked: weatherCommon.tempScale === WeatherCommon.Fahrenheit 98 | ButtonGroup.group: scaleGroup 99 | } 100 | } 101 | 102 | SettingsCheck { 103 | id: systray 104 | width: parent.width 105 | leftPadding: 0 106 | text: qsTr("Show weather in menubar") 107 | checked: weatherCommon.menuBarWeather 108 | } 109 | 110 | SettingsCheck { 111 | id: startup 112 | width: parent.width 113 | leftPadding: 0 114 | text: qsTr("Start at login") 115 | checked: weatherCommon.runAtStartup 116 | } 117 | 118 | SettingsCheck { 119 | id: anim 120 | width: parent.width 121 | leftPadding: 0 122 | text: qsTr("Show weather animation") 123 | checked: weatherCommon.showAnimation 124 | } 125 | 126 | SettingsCheck { 127 | id: showVideo 128 | width: parent.width 129 | leftPadding: 0 130 | text: qsTr("Show weather video") 131 | checked: weatherCommon.showVideo 132 | } 133 | 134 | Row { 135 | width: parent.width 136 | spacing: 10 137 | SettingsButton { 138 | width: parent.width/2 - 5 139 | text: qsTr("Apply") 140 | onClicked: { 141 | weatherCommon.menuBarWeather = systray.checked 142 | weatherCommon.runAtStartup = startup.checked 143 | weatherCommon.showAnimation = anim.checked 144 | weatherCommon.showVideo = showVideo.checked 145 | weatherCommon.tempScale = fahr.checked ? WeatherCommon.Fahrenheit : WeatherCommon.Celsium 146 | menuButton.state = "menu" 147 | weatherCommon.requestWeatherUpdate() 148 | } 149 | } 150 | SettingsButton { 151 | width: parent.width/2 - 5 152 | text: qsTr("Quit") 153 | onClicked: Qt.quit() 154 | } 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /qml/MainPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | 4 | Item { 5 | id: root 6 | 7 | MouseArea { 8 | anchors.fill: parent 9 | onClicked: subdetails.showdetailsindex = -1 10 | } 11 | 12 | Button { 13 | height: appRoot.height/24 14 | width: height 15 | anchors { top: parent.top; topMargin: appRoot.height/24+appRoot.height/28*2; left: parent.left; leftMargin: parent.width / 28; } 16 | background: ColoredImage { 17 | overlayColor: "white" 18 | source: "images/earth.svg" 19 | } 20 | onClicked: { 21 | mainView.push(mapComponent) 22 | } 23 | } 24 | ColoredImage { 25 | width: appRoot.height / 4.8 26 | height: width 27 | overlayColor: "white" 28 | anchors { top: parent.top; topMargin: parent.height * 0.14; right: parent.right; rightMargin: parent.width * 0.04; } 29 | source: weatherModel.currentWeather.weather_codition_icon_id === "" ? 30 | "images/icons/IconTemplate@02d.png" : 31 | "images/icons/" + weatherModel.currentWeather.weather_codition_icon_id + ".svg" 32 | } 33 | Column { 34 | anchors.top: parent.top 35 | anchors.topMargin: appRoot.height / 4 36 | anchors.horizontalCenter: parent.horizontalCenter 37 | height: appRoot.height / 4.8 38 | 39 | Row { 40 | id: degrow 41 | anchors.horizontalCenter: parent.horizontalCenter 42 | anchors.horizontalCenterOffset: degree.paintedWidth/2 43 | spacing: 0 44 | Text { 45 | font.pixelSize: root.height / 10 46 | color: "white" 47 | text: weatherCommon.roundup(weatherCommon.convertToCurrentScale(weatherModel.currentWeather.temp)) 48 | } 49 | Text { 50 | id: degree 51 | font.pixelSize: root.height / 10 52 | color: "white" 53 | text: "\u00B0" 54 | } 55 | 56 | } 57 | Rectangle { 58 | anchors.horizontalCenter: parent.horizontalCenter 59 | color: "white" 60 | //opacity: 0.5 61 | width: degrow.width 62 | height: 2 63 | } 64 | 65 | Text { 66 | anchors.horizontalCenter: parent.horizontalCenter 67 | font.pixelSize: root.height / 26 68 | color: "white" 69 | opacity: 0.5 70 | text: weatherModel.currentWeather.weather_codition_description 71 | } 72 | } 73 | Item { 74 | id: details 75 | anchors.bottom: parent.bottom 76 | width: parent.width 77 | height: appRoot.height / 3 78 | Row { 79 | id: row 80 | width: parent.width 81 | spacing: 0 82 | anchors.top: parent.top 83 | 84 | Text { 85 | width: parent.width/2 86 | font.pixelSize: appRoot.height / 40 87 | color: "#999999" 88 | text: Qt.formatDate(weatherModel.currentWeather.timestamp, "dddd, MMM d") 89 | horizontalAlignment: Text.AlignHCenter 90 | } 91 | 92 | Text { 93 | width: parent.width/2 94 | font.pixelSize: appRoot.height / 40 95 | color: "#999999" 96 | text: weatherModel.cityName.toLowerCase() + ", " + weatherModel.countryID.toLowerCase() 97 | horizontalAlignment: Text.AlignHCenter 98 | } 99 | } 100 | Flipable { 101 | id: subdetails 102 | anchors.bottom: parent.bottom 103 | width: parent.width 104 | anchors.top: row.bottom 105 | property int showdetailsindex: -1 106 | 107 | transform: Rotation { 108 | id: rotation 109 | origin.x: subdetails.width/2 110 | origin.y: subdetails.height/2 111 | axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis 112 | angle: 0 // the default angle 113 | } 114 | 115 | states: State { 116 | name: "back" 117 | PropertyChanges { target: rotation; angle: 180 } 118 | when: subdetails.showdetailsindex >= 0 119 | } 120 | 121 | transitions: Transition { 122 | NumberAnimation { target: rotation; property: "angle"; duration: 1000 } 123 | } 124 | 125 | front: ListView { 126 | id: view 127 | model: weatherDailyModel 128 | anchors.fill: parent 129 | anchors.margins: 10 130 | clip: false 131 | interactive: true 132 | focus: true 133 | orientation: ListView.Horizontal 134 | highlightFollowsCurrentItem: true 135 | 136 | delegate: WeatherDelegate { 137 | MouseArea { 138 | anchors.fill: parent 139 | onClicked: { 140 | if (index >= 0 && index < weatherModel.daysNumber) { 141 | subdetails.showdetailsindex = index 142 | filteredWeatherModel.setWeatherDateIndex(index) 143 | } 144 | } 145 | } 146 | } 147 | } 148 | back: WeatherGraph { 149 | anchors.fill: parent 150 | dayIndex: subdetails.showdetailsindex 151 | } 152 | } 153 | } 154 | } 155 | 156 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /qml/EditableCombo.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.2 3 | 4 | ComboBox { 5 | id: combo 6 | 7 | property int searchDelay: 1000 8 | property alias interval: findTimer.interval 9 | signal enterPressed() 10 | 11 | model: citiesModel 12 | height: 24*appscale 13 | font.pixelSize: height / 2 14 | padding: 2*appscale 15 | rightPadding: 2*appscale 16 | 17 | ListModel { 18 | id: citiesModel 19 | } 20 | 21 | Connections { 22 | target: weatherModel 23 | onCurrentWeatherChanged: { 24 | //console.log("current weather changed", weatherModel.cityName, weatherModel.countryID) 25 | if (weatherModel.cityName !== "" && weatherModel.countryID !== "") { 26 | combo.editText = weatherModel.cityName + ", " + weatherModel.countryID 27 | } 28 | } 29 | } 30 | 31 | function loadCities() { 32 | citiesModel.clear() 33 | var i = 0 34 | 35 | do { 36 | var val = settings.value(i,"", "cities"); 37 | if (val === undefined || val === "") 38 | break; 39 | i++ 40 | console.log("appending city", val) 41 | addCity(val); 42 | } while(true); 43 | 44 | var _city = weatherModel.cityName + ", " + weatherModel.countryID; 45 | if (_city.length > 2) { 46 | if (citiesModel.count == 0) { 47 | //nothing gets loaded 48 | citiesModel.append({ city: _city}); 49 | currentIndex = 0; 50 | } else { 51 | currentIndex = searchCity(_city) 52 | } 53 | } 54 | } 55 | 56 | function saveCities() { 57 | settings.setValue("", "", "cities"); // clear group 58 | for (var i = 0; i < citiesModel.count; i++) { 59 | var city = citiesModel.get(i).city 60 | if (city !== "") { 61 | settings.setValue(i, city , "cities"); 62 | } 63 | } 64 | } 65 | 66 | function searchCity(cityName) { 67 | if (cityName.length <= 2) { 68 | return -1; //emty or just ", " 69 | } 70 | for (var i = 0; i < citiesModel.count; i++) { 71 | //console.log("comparing", cityName.toUpperCase(), citiesModel.get(i).city.toUpperCase(), i) 72 | if (cityName.toUpperCase() === citiesModel.get(i).city.toUpperCase()) { 73 | return i; 74 | } 75 | } 76 | return -1; 77 | } 78 | 79 | function addCity(cityName) { 80 | if (searchCity(cityName) === -1) { 81 | citiesModel.append({ city: cityName }); 82 | } 83 | } 84 | 85 | function queryCityWeather(city) { 86 | combo.contentItem.placeholderText = qsTr("Querying...") 87 | weatherCommon.search(city) 88 | } 89 | 90 | Timer { 91 | id: findTimer 92 | repeat: false 93 | interval: searchDelay 94 | onTriggered: { 95 | queryCityWeather(combo.editText) 96 | var ind = combo.find(combo.editText, Qt.MatchContains)//searchCity(combo.currentText); 97 | fav.checkState = ind >= 0 ? Qt.Checked : Qt.Unchecked; 98 | } 99 | } 100 | 101 | background: Item { 102 | width: parent.width 103 | height: parent.height 104 | 105 | Row { 106 | id: backgrrow 107 | height: parent.height 108 | anchors.right: parent.right 109 | anchors.rightMargin: combo.indicator.width - combo.padding 110 | spacing: 0 111 | Button { 112 | id: button 113 | anchors.verticalCenter: parent.verticalCenter 114 | height: parent.height 115 | width: height 116 | background: PartialImage { 117 | anchors.centerIn: parent 118 | width: 20; height: 20; 119 | imageOffsetX: -120 120 | scale: button.pressed ? 0.80*appscale : appscale 121 | } 122 | onClicked: { 123 | weatherCommon.search() 124 | } 125 | } 126 | 127 | CheckBox { 128 | id: fav 129 | anchors.verticalCenter: parent.verticalCenter 130 | height: parent.height 131 | width: height 132 | indicator: PartialImage { 133 | width: 20; height: 20; 134 | anchors.centerIn: parent 135 | scale: appscale 136 | imageOffsetX: fav.checked ? -100 : -80 137 | } 138 | onCheckedChanged: { 139 | if (checked) { 140 | addCity(combo.editText) 141 | //makes sur its selected by ComboBox 142 | combo.currentIndex = citiesModel.count - 1 143 | } else { 144 | console.log("remove index", combo.currentIndex) 145 | citiesModel.remove(combo.currentIndex, 1) 146 | } 147 | } 148 | } 149 | } 150 | Rectangle { 151 | width: parent.width 152 | height: 2*appscale 153 | y: parent.height + 2*appscale 154 | color: "#999999" 155 | } 156 | } 157 | flat: true 158 | editable: true 159 | onCurrentIndexChanged: { 160 | //console.log("current index", currentIndex) 161 | if (currentIndex >= 0) { 162 | combo.editText = citiesModel.get(currentIndex).city 163 | queryCityWeather(citiesModel.get(currentIndex).city) 164 | } 165 | } 166 | 167 | Connections { 168 | target: contentItem 169 | onTextEdited: { 170 | //console.log("text edited") 171 | if (combo.editText !== "") { 172 | findTimer.restart() 173 | } else { 174 | findTimer.stop() 175 | } 176 | } 177 | } 178 | 179 | // onEditTextChanged: { 180 | // console.log("edit text [" + editText + "] [" + currentText + "] [" + displayText + "]") 181 | // } 182 | 183 | Component.onCompleted: { 184 | combo.contentItem.width = Qt.binding(function() { return combo.width - backgrrow.width - 185 | indicator.width}) 186 | if (weatherModel.cityName !== "" && weatherModel.countryID !== "") { 187 | combo.editText = weatherModel.cityName + ", " + weatherModel.countryID 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /qml/WeatherGraph.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtCharts 2.2 3 | import QtQml.Models 2.2 4 | import weathermodel 1.0 5 | 6 | Item { 7 | id: weatherChart 8 | property int graphPoints: 0 9 | property int dayIndex: 0 10 | 11 | onVisibleChanged: if (!visible) weatherLegend.visible = false 12 | 13 | Connections { 14 | target: weatherModel 15 | onCurrentWeatherChanged: { 16 | visualModel.model = null 17 | visualModel.model = weatherModel 18 | } 19 | } 20 | 21 | Text { 22 | id: currentGraphDate 23 | anchors.top: parent.top 24 | anchors.topMargin: 2*appscale 25 | anchors.horizontalCenter: parent.horizontalCenter 26 | verticalAlignment: Text.AlignVCenter 27 | horizontalAlignment: Text.AlignHCenter 28 | color: "#999999" 29 | font.pixelSize: 16*appscale 30 | } 31 | 32 | //delegate model used as a proxy to extract filtered data 33 | DelegateModel { 34 | id: visualModel 35 | model: weatherModel 36 | delegate: Item {} 37 | onCountChanged: { 38 | //console.log("filtered count", count) 39 | if (count > 0) { 40 | tempsSeries.removePoints(0, graphPoints) 41 | valueAxisX.max = Math.max(count - 1, 1) 42 | var min = weatherCommon.roundup(weatherCommon.convertToCurrentScale(model.data(visualModel.modelIndex(0), 258))) 43 | tempsSeries.append(0, min) 44 | var max = min 45 | if (count === 1) { 46 | //simulating line 47 | tempsSeries.append(1, min) 48 | } else { 49 | 50 | for (var i = 1; i < count; i++) { 51 | var val = weatherCommon.roundup(weatherCommon.convertToCurrentScale(model.data(visualModel.modelIndex(i), 258))) 52 | tempsSeries.append(i, val) 53 | if (val > max) 54 | max = val 55 | else if (val < min) 56 | min = val 57 | //console.log(val) 58 | } 59 | } 60 | 61 | graphPoints = Math.max(count, 2) 62 | 63 | valueAxisY.min = min - 1 64 | valueAxisY.max = max + 1 65 | } 66 | } 67 | } 68 | 69 | Flickable { 70 | id: flickable 71 | anchors.fill: parent 72 | contentHeight: chartView.height 73 | contentWidth: chartView.width 74 | contentX: weatherChart.width*dayIndex 75 | onContentXChanged: { 76 | var index = parseInt((contentX/weatherChart.width)*weatherModel.daysNumber) + 1 77 | var time = Qt.formatDateTime(visualModel.model.data(visualModel.modelIndex(index), 257), "ddd dd/MM") 78 | currentGraphDate.text = time 79 | } 80 | 81 | ChartView { 82 | id: chartView 83 | width: weatherChart.width*weatherModel.daysNumber 84 | height: weatherChart.height 85 | legend.visible: false 86 | margins.bottom: 0 87 | margins.top: 0 88 | margins.left: 0 89 | margins.right: 0 90 | backgroundColor: "transparent" 91 | backgroundRoundness: 0 92 | dropShadowEnabled: false 93 | antialiasing: true 94 | clip: false 95 | 96 | ValueAxis { 97 | visible: false 98 | id: valueAxisX 99 | min: 0 100 | max: 1 101 | } 102 | 103 | ValueAxis{ 104 | visible: false 105 | id: valueAxisY 106 | min: 0 107 | max: 5 108 | } 109 | 110 | SplineSeries { 111 | id: tempsSeries 112 | width: 4*appscale 113 | style: Qt.SolidLine 114 | capStyle: Qt.RoundCap 115 | pointLabelsClipping: false 116 | pointLabelsVisible: true 117 | pointLabelsColor: "#999999" 118 | pointLabelsFont.pixelSize: 12*appscale 119 | pointLabelsFormat: weatherCommon.tempScale === WeatherCommon.Celsium ? "@yPoint \u00B0C" : "@yPoint \u00B0F" 120 | axisX: valueAxisX 121 | axisY: valueAxisY 122 | color: weatherCommon.backgroundColor 123 | pointsVisible: true 124 | //useOpenGL: true 125 | 126 | function updateWeather(point) { 127 | var _index = Math.round(point.x) 128 | //index safety 129 | if (_index >= visualModel.model.count && visualModel.model.count > 0) 130 | _index = visualModel.model.count - 1 131 | weatherLegend.x = chartView.width/graphPoints * point.x - flickable.contentX 132 | - weatherLegend.width / 2 133 | weatherLegend._temp = weatherCommon.roundup(point.y) 134 | weatherLegend._time = Qt.formatDateTime(visualModel.model.data(visualModel.modelIndex(_index), 257), "ddd hh:mm") 135 | weatherLegend._iconid = visualModel.model.data(visualModel.modelIndex(_index), 268) 136 | } 137 | 138 | onPressed: { 139 | //console.log("point pressed", point) 140 | weatherLegend.visible = true 141 | updateWeather(point) 142 | } 143 | 144 | //only for systems with mouse 145 | onHovered: { 146 | weatherLegend.visible = state 147 | 148 | if (state) { 149 | updateWeather(point) 150 | } 151 | } 152 | } 153 | } 154 | } 155 | 156 | Item { 157 | id: weatherLegend 158 | visible: false 159 | property int _temp: 0 160 | property string _iconid: "" 161 | property string _time: "" 162 | anchors.bottom: parent.bottom 163 | anchors.bottomMargin: 5*appscale 164 | height: 50*appscale 165 | width: 60*appscale 166 | Column { 167 | Row { 168 | anchors.horizontalCenter: parent.horizontalCenter 169 | ColoredImage { 170 | source: weatherLegend._iconid !== "" ? "images/icons/" + weatherLegend._iconid + ".svg" : "" 171 | width: 32*appscale 172 | height: 32*appscale 173 | overlayColor: "#999999" 174 | } 175 | Text { 176 | anchors.verticalCenter: parent.verticalCenter 177 | text: weatherLegend._temp + "\u00B0"+weatherCommon.temperatureScale 178 | color: "#999999" 179 | font.pixelSize: 18*appscale 180 | } 181 | } 182 | Text { 183 | anchors.horizontalCenter: parent.horizontalCenter 184 | text: weatherLegend._time 185 | verticalAlignment: Text.AlignVCenter 186 | horizontalAlignment: Text.AlignHCenter 187 | color: "#999999" 188 | font.pixelSize: 12*appscale 189 | } 190 | } 191 | } 192 | } 193 | 194 | -------------------------------------------------------------------------------- /src/weatherdata.h: -------------------------------------------------------------------------------- 1 | #ifndef WEATHERFORECASTDATA_H 2 | #define WEATHERFORECASTDATA_H 3 | 4 | #include 5 | #include 6 | 7 | class WeatherData: public QObject { 8 | Q_OBJECT 9 | 10 | Q_PROPERTY(QDateTime timestamp READ timestamp WRITE set_timestamp NOTIFY timestamp_changed) 11 | Q_PROPERTY(qreal temp READ temp WRITE set_temp NOTIFY temp_changed) 12 | Q_PROPERTY(qreal temp_min READ temp_min WRITE set_temp_min NOTIFY temp_min_changed) 13 | Q_PROPERTY(qreal temp_max READ temp_max WRITE set_temp_max NOTIFY temp_max_changed) 14 | Q_PROPERTY(qreal temp_morn READ temp_morn WRITE set_temp_morn NOTIFY temp_morn_changed) 15 | Q_PROPERTY(qreal temp_eve READ temp_eve WRITE set_temp_eve NOTIFY temp_eve_changed) 16 | Q_PROPERTY(qreal temp_night READ temp_night WRITE set_temp_night NOTIFY temp_night_changed) 17 | Q_PROPERTY(qreal pressure READ pressure WRITE set_pressure NOTIFY pressure_changed) 18 | Q_PROPERTY(qreal pressure_sea_level READ pressure_sea_level WRITE set_pressure_sea_level NOTIFY pressure_sea_level_changed) 19 | Q_PROPERTY(qreal pressure_grnd_level READ pressure_grnd_level WRITE set_pressure_grnd_level NOTIFY pressure_grnd_level_changed) 20 | Q_PROPERTY(qreal humidity READ humidity WRITE set_humidity NOTIFY humidity_changed) 21 | Q_PROPERTY(int weather_codition_id READ weather_codition_id WRITE set_weather_codition_id NOTIFY weather_codition_id_changed) 22 | Q_PROPERTY(QString weather_codition_name READ weather_codition_name WRITE set_weather_codition_name NOTIFY weather_codition_name_changed) 23 | Q_PROPERTY(QString weather_codition_description READ weather_codition_description WRITE set_weather_codition_description NOTIFY weather_codition_description_changed) 24 | Q_PROPERTY(QString weather_codition_icon_id READ weather_codition_icon_id WRITE set_weather_codition_icon_id NOTIFY weather_codition_icon_id_changed) 25 | Q_PROPERTY(qreal clouds_coverage READ clouds_coverage WRITE set_clouds_coverage NOTIFY clouds_coverage_changed) 26 | Q_PROPERTY(qreal wind_speed READ wind_speed WRITE set_wind_speed NOTIFY wind_speed_changed) 27 | Q_PROPERTY(qreal wind_degrees READ wind_degrees WRITE set_wind_degrees NOTIFY wind_degrees_changed) 28 | Q_PROPERTY(qreal wind_gust READ wind_gust WRITE set_wind_gust NOTIFY wind_gust_changed) 29 | Q_PROPERTY(qreal rain_3h READ rain_3h WRITE set_rain_3h NOTIFY rain_3h_changed) 30 | Q_PROPERTY(qreal snow_3h READ snow_3h WRITE set_snow_3h NOTIFY snow_3h_changed) 31 | Q_PROPERTY(QString timestamp_string READ timestamp_string WRITE set_timestamp_string NOTIFY timestamp_string_changed) 32 | Q_PROPERTY(QDateTime sunrise READ sunrise WRITE set_sunrise NOTIFY sunrise_changed) 33 | Q_PROPERTY(QDateTime sunset READ sunset WRITE set_sunset NOTIFY sunset_changed) 34 | public: 35 | WeatherData(QObject *parent = 0); 36 | virtual ~WeatherData() {} 37 | const QString dump(); 38 | 39 | QDateTime timestamp() const; 40 | qreal temp() const; 41 | qreal temp_min() const; 42 | qreal temp_max() const; 43 | qreal pressure() const; 44 | qreal pressure_sea_level() const; 45 | qreal pressure_grnd_level() const; 46 | qreal humidity() const; 47 | int weather_codition_id() const; 48 | QString weather_codition_name() const; 49 | QString weather_codition_description() const; 50 | QString weather_codition_icon_id() const; 51 | qreal clouds_coverage() const; 52 | qreal wind_speed() const; 53 | qreal wind_degrees() const; 54 | qreal wind_gust() const; 55 | qreal rain_3h() const; 56 | qreal snow_3h() const; 57 | QString timestamp_string() const; 58 | // bool operator<(const WeatherForecastData &i1) const 59 | // { 60 | // return m_timestamp < i1.m_timestamp; 61 | // } 62 | // inline bool operator<(const WeatherForecastData &w1, const WeatherForecastData &w2) 63 | // { 64 | // return w1.timestamp() < w2.timestamp(); 65 | // } 66 | qreal temp_morn() const; 67 | qreal temp_eve() const; 68 | qreal temp_night() const; 69 | 70 | QDateTime sunrise() const 71 | { 72 | return m_sunrise; 73 | } 74 | 75 | QDateTime sunset() const 76 | { 77 | return m_sunset; 78 | } 79 | 80 | public slots: 81 | void set_timestamp(QDateTime timestamp); 82 | void set_temp(qreal temp); 83 | void set_temp_min(qreal temp_min); 84 | void set_temp_max(qreal temp_max); 85 | void set_pressure(qreal pressure); 86 | void set_pressure_sea_level(qreal pressure_sea_level); 87 | void set_humidity(qreal humidity); 88 | void set_weather_codition_id(int weather_codition_id); 89 | void set_weather_codition_name(QString weather_codition_name); 90 | void set_weather_codition_description(QString weather_codition_description); 91 | void set_weather_codition_icon_id(QString weather_codition_icon_id); 92 | void set_clouds_coverage(qreal clouds_coverage); 93 | void set_wind_speed(qreal wind_speed); 94 | void set_wind_degrees(qreal wind_degrees); 95 | void set_wind_gust(qreal wind_gust); 96 | void set_rain_3h(qreal rain_3h); 97 | void set_snow_3h(qreal snow_3h); 98 | void set_timestamp_string(QString timestamp_string); 99 | void set_pressure_grnd_level(qreal pressure_grnd_level); 100 | void set_temp_morn(qreal temp_morn); 101 | void set_temp_eve(qreal temp_eve); 102 | void set_temp_night(qreal temp_night); 103 | 104 | void set_sunrise(QDateTime sunrise) 105 | { 106 | if (m_sunrise == sunrise) 107 | return; 108 | 109 | m_sunrise = sunrise; 110 | emit sunrise_changed(sunrise); 111 | } 112 | 113 | void set_sunset(QDateTime sunset) 114 | { 115 | if (m_sunset == sunset) 116 | return; 117 | 118 | m_sunset = sunset; 119 | emit sunset_changed(sunset); 120 | } 121 | 122 | signals: 123 | void timestamp_changed(QDateTime timestamp); 124 | void temp_changed(qreal temp); 125 | void temp_min_changed(qreal temp_min); 126 | void temp_max_changed(qreal temp_max); 127 | void pressure_changed(qreal pressure); 128 | void pressure_sea_level_changed(qreal pressure_sea_level); 129 | void humidity_changed(qreal humidity); 130 | void weather_codition_id_changed(int weather_codition_id); 131 | void weather_codition_name_changed(QString weather_codition_name); 132 | void weather_codition_description_changed(QString weather_codition_description); 133 | void weather_codition_icon_id_changed(QString weather_codition_icon_id); 134 | void clouds_coverage_changed(qreal clouds_coverage); 135 | void wind_speed_changed(qreal wind_speed); 136 | void wind_degrees_changed(qreal wind_degrees); 137 | void wind_gust_changed(qreal wind_gust); 138 | void rain_3h_changed(qreal rain_3h); 139 | void snow_3h_changed(qreal snow_3h); 140 | void timestamp_string_changed(QString timestamp_string); 141 | void pressure_grnd_level_changed(qreal pressure_grnd_level); 142 | void temp_morn_changed(qreal temp_morn); 143 | void temp_eve_changed(qreal temp_eve); 144 | void temp_night_changed(qreal temp_night); 145 | void sunrise_changed(QDateTime sunrize); 146 | void sunset_changed(QDateTime sunset); 147 | 148 | private: 149 | 150 | QDateTime m_timestamp; 151 | qreal m_temp; 152 | qreal m_temp_min; 153 | qreal m_temp_max; 154 | qreal m_pressure; 155 | qreal m_pressure_sea_level; 156 | qreal m_pressure_grnd_level; 157 | qreal m_humidity; 158 | int m_weather_codition_id; 159 | QString m_weather_codition_name; 160 | QString m_weather_codition_description; 161 | QString m_weather_codition_icon_id; 162 | qreal m_clouds_coverage; 163 | qreal m_wind_speed; 164 | qreal m_wind_degrees; 165 | qreal m_wind_gust; 166 | qreal m_rain_3h; 167 | qreal m_snow_3h; 168 | QString m_timestamp_string; 169 | qreal m_temp_morn; 170 | qreal m_temp_eve; 171 | qreal m_temp_night; 172 | QDateTime m_sunrise; 173 | QDateTime m_sunset; 174 | }; 175 | 176 | 177 | #endif // WEATHERFORECASTDATA_H 178 | -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qtquickcontrols2.conf 4 | qml/images/icons/01d.png 5 | qml/images/icons/01d.svg 6 | qml/images/icons/01d@2x.png 7 | qml/images/icons/01dTemplate.png 8 | qml/images/icons/01dTemplate@2x.png 9 | qml/images/icons/01dW.png 10 | qml/images/icons/01dW@2x.png 11 | qml/images/icons/01n.png 12 | qml/images/icons/01n.svg 13 | qml/images/icons/01n@2x.png 14 | qml/images/icons/01nTemplate.png 15 | qml/images/icons/01nTemplate@2x.png 16 | qml/images/icons/01nW.png 17 | qml/images/icons/01nW@2x.png 18 | qml/images/icons/02d.png 19 | qml/images/icons/02d.svg 20 | qml/images/icons/02d@2x.png 21 | qml/images/icons/02dTemplate.png 22 | qml/images/icons/02dTemplate@2x.png 23 | qml/images/icons/02dW.png 24 | qml/images/icons/02dW@2x.png 25 | qml/images/icons/02n.png 26 | qml/images/icons/02n.svg 27 | qml/images/icons/02n@2x.png 28 | qml/images/icons/02nTemplate.png 29 | qml/images/icons/02nTemplate@2x.png 30 | qml/images/icons/02nW.png 31 | qml/images/icons/02nW@2x.png 32 | qml/images/icons/03d.png 33 | qml/images/icons/03d.svg 34 | qml/images/icons/03d@2x.png 35 | qml/images/icons/03dTemplate.png 36 | qml/images/icons/03dTemplate@2x.png 37 | qml/images/icons/03dW.png 38 | qml/images/icons/03dW@2x.png 39 | qml/images/icons/03n.png 40 | qml/images/icons/03n.svg 41 | qml/images/icons/03n@2x.png 42 | qml/images/icons/03nTemplate.png 43 | qml/images/icons/03nTemplate@2x.png 44 | qml/images/icons/03nW.png 45 | qml/images/icons/03nW@2x.png 46 | qml/images/icons/04d.png 47 | qml/images/icons/04d.svg 48 | qml/images/icons/04d@2x.png 49 | qml/images/icons/04dTemplate.png 50 | qml/images/icons/04dTemplate@2x.png 51 | qml/images/icons/04dW.png 52 | qml/images/icons/04dW@2x.png 53 | qml/images/icons/04n.png 54 | qml/images/icons/04n.svg 55 | qml/images/icons/04n@2x.png 56 | qml/images/icons/04nTemplate.png 57 | qml/images/icons/04nTemplate@2x.png 58 | qml/images/icons/04nW.png 59 | qml/images/icons/04nW@2x.png 60 | qml/images/icons/09d.png 61 | qml/images/icons/09d.svg 62 | qml/images/icons/09d@2x.png 63 | qml/images/icons/09dTemplate.png 64 | qml/images/icons/09dTemplate@2x.png 65 | qml/images/icons/09dW.png 66 | qml/images/icons/09dW@2x.png 67 | qml/images/icons/09n.png 68 | qml/images/icons/09n.svg 69 | qml/images/icons/09n@2x.png 70 | qml/images/icons/09nTemplate.png 71 | qml/images/icons/09nTemplate@2x.png 72 | qml/images/icons/09nW.png 73 | qml/images/icons/09nW@2x.png 74 | qml/images/icons/10d.png 75 | qml/images/icons/10d.svg 76 | qml/images/icons/10d@2x.png 77 | qml/images/icons/10dTemplate.png 78 | qml/images/icons/10dTemplate@2x.png 79 | qml/images/icons/10dW.png 80 | qml/images/icons/10dW@2x.png 81 | qml/images/icons/10n.png 82 | qml/images/icons/10n.svg 83 | qml/images/icons/10n@2x.png 84 | qml/images/icons/10nTemplate.png 85 | qml/images/icons/10nTemplate@2x.png 86 | qml/images/icons/10nW.png 87 | qml/images/icons/10nW@2x.png 88 | qml/images/icons/11d.png 89 | qml/images/icons/11d.svg 90 | qml/images/icons/11d@2x.png 91 | qml/images/icons/11dTemplate.png 92 | qml/images/icons/11dTemplate@2x.png 93 | qml/images/icons/11dW.png 94 | qml/images/icons/11dW@2x.png 95 | qml/images/icons/11n.png 96 | qml/images/icons/11n.svg 97 | qml/images/icons/11n@2x.png 98 | qml/images/icons/11nTemplate.png 99 | qml/images/icons/11nTemplate@2x.png 100 | qml/images/icons/11nW.png 101 | qml/images/icons/11nW@2x.png 102 | qml/images/icons/12d.png 103 | qml/images/icons/12d.svg 104 | qml/images/icons/12d@2x.png 105 | qml/images/icons/12dTemplate.png 106 | qml/images/icons/12dTemplate@2x.png 107 | qml/images/icons/12dW.png 108 | qml/images/icons/12dW@2x.png 109 | qml/images/icons/12n.png 110 | qml/images/icons/12n.svg 111 | qml/images/icons/12n@2x.png 112 | qml/images/icons/12nTemplate.png 113 | qml/images/icons/12nTemplate@2x.png 114 | qml/images/icons/12nW.png 115 | qml/images/icons/12nW@2x.png 116 | qml/images/icons/13d.png 117 | qml/images/icons/13d.svg 118 | qml/images/icons/13d@2x.png 119 | qml/images/icons/13dTemplate.png 120 | qml/images/icons/13dTemplate@2x.png 121 | qml/images/icons/13dW.png 122 | qml/images/icons/13dW@2x.png 123 | qml/images/icons/13n.png 124 | qml/images/icons/13n.svg 125 | qml/images/icons/13n@2x.png 126 | qml/images/icons/13nTemplate.png 127 | qml/images/icons/13nTemplate@2x.png 128 | qml/images/icons/13nW.png 129 | qml/images/icons/13nW@2x.png 130 | qml/images/icons/50d.png 131 | qml/images/icons/50d.svg 132 | qml/images/icons/50d@2x.png 133 | qml/images/icons/50dTemplate.png 134 | qml/images/icons/50dTemplate@2x.png 135 | qml/images/icons/50dW.png 136 | qml/images/icons/50dW@2x.png 137 | qml/images/icons/50n.png 138 | qml/images/icons/50n.svg 139 | qml/images/icons/50n@2x.png 140 | qml/images/icons/50nTemplate.png 141 | qml/images/icons/50nTemplate@2x.png 142 | qml/images/icons/50nW.png 143 | qml/images/icons/50nW@2x.png 144 | qml/images/icons/IconTemplate@02d.png 145 | qml/images/icons/menu.png 146 | qml/images/icons/menu@2x.png 147 | qml/images/icons/menu@3x.png 148 | qml/images/icons/menu@4x.png 149 | qml/ColoredImage.qml 150 | qml/Indicators.qml 151 | qml/main.qml 152 | qml/MenuClose.qml 153 | qml/WaiwedItem.qml 154 | qml/WeatherDelegate.qml 155 | qml/Wind.qml 156 | qml/images/background.png 157 | qml/images/checkboxes.png 158 | qml/images/checkboxes@2x.png 159 | qml/images/humidity.png 160 | qml/images/round-clock-icon.png 161 | qml/images/snow.png 162 | qml/images/termometer.png 163 | qml/images/umbrella.png 164 | qml/images/wind-arrow.png 165 | qml/RainDrop.qml 166 | qml/SnowFlake.qml 167 | qml/SettingsPage.qml 168 | qml/MainPage.qml 169 | qml/images/app.png 170 | qml/images/IconTemplate@2x.png 171 | qml/SettingsButton.qml 172 | qml/SettingsCheck.qml 173 | qml/SettingsRadio.qml 174 | qml/EditableCombo.qml 175 | qml/PartialImage.qml 176 | qml/WeatherGraph.qml 177 | qml/WeatherMap.qml 178 | qml/images/map.png 179 | qml/images/earth.svg 180 | tempsqml.png 181 | 182 | 183 | -------------------------------------------------------------------------------- /src/weatherdata.cpp: -------------------------------------------------------------------------------- 1 | #include "weatherdata.h" 2 | #include 3 | #include "weathercommon.h" 4 | 5 | WeatherData::WeatherData(QObject *parent): QObject(parent) 6 | { 7 | //init values 8 | m_temp = 273.0; 9 | m_temp_min = 273.0; 10 | m_temp_max = 273.0; 11 | m_temp_night = 273.0; 12 | m_temp_eve = 273.0; 13 | m_temp_morn = 273.0; 14 | m_pressure = 0.0; 15 | m_pressure_sea_level = 0.0; 16 | m_pressure_grnd_level = 0.0; 17 | m_humidity = 0.0; 18 | m_weather_codition_id = 0; 19 | m_clouds_coverage = 0.0; 20 | m_wind_speed = 0.0; 21 | m_wind_degrees = 0.0; 22 | m_wind_gust = 0.0; 23 | m_rain_3h = 0.0; 24 | m_snow_3h = 0.0; 25 | } 26 | 27 | const QString WeatherData::dump() { 28 | 29 | return QString("Weather data dump:" \ 30 | " at: %1 string: %2." \ 31 | " temperature: %3." \ 32 | " temperature min: %4." \ 33 | " temperature max: %5." \ 34 | " pressure: %6." \ 35 | " pressure ground: %7." \ 36 | " pressure sea: %8." \ 37 | " humidity: %9." \ 38 | " id: %10. name: %11" \ 39 | " description: %12 icon id: %13." \ 40 | " clouds coverage: %14." \ 41 | " wind speed: %15 degrees: %16 gust: %17." \ 42 | " rain_3h: %18." \ 43 | " snow_3h: %19") 44 | .arg(timestamp().toString()) 45 | .arg(timestamp_string()) 46 | .arg(WeatherCommon::kelvin2celsius(temp())) 47 | .arg(WeatherCommon::kelvin2celsius(temp_min())) 48 | .arg(WeatherCommon::kelvin2celsius(temp_max())) 49 | .arg(pressure()) 50 | .arg(pressure_grnd_level()) 51 | .arg(pressure_sea_level()) 52 | .arg(humidity()) 53 | .arg(weather_codition_id()) 54 | .arg(weather_codition_name()) 55 | .arg(weather_codition_description()) 56 | .arg(weather_codition_icon_id()) 57 | .arg(clouds_coverage()) 58 | .arg(wind_speed()) 59 | .arg(wind_degrees()) 60 | .arg(wind_gust()) 61 | .arg(rain_3h()) 62 | .arg(snow_3h()); 63 | } 64 | 65 | QDateTime WeatherData::timestamp() const 66 | { 67 | return m_timestamp; 68 | } 69 | 70 | qreal WeatherData::temp() const 71 | { 72 | return m_temp; 73 | } 74 | 75 | qreal WeatherData::temp_min() const 76 | { 77 | return m_temp_min; 78 | } 79 | 80 | qreal WeatherData::temp_max() const 81 | { 82 | return m_temp_max; 83 | } 84 | 85 | qreal WeatherData::pressure() const 86 | { 87 | return m_pressure; 88 | } 89 | 90 | qreal WeatherData::pressure_sea_level() const 91 | { 92 | return m_pressure_sea_level; 93 | } 94 | 95 | qreal WeatherData::pressure_grnd_level() const 96 | { 97 | return m_pressure_grnd_level; 98 | } 99 | 100 | qreal WeatherData::humidity() const 101 | { 102 | return m_humidity; 103 | } 104 | 105 | int WeatherData::weather_codition_id() const 106 | { 107 | return m_weather_codition_id; 108 | } 109 | 110 | QString WeatherData::weather_codition_name() const 111 | { 112 | return m_weather_codition_name; 113 | } 114 | 115 | QString WeatherData::weather_codition_description() const 116 | { 117 | return m_weather_codition_description; 118 | } 119 | 120 | QString WeatherData::weather_codition_icon_id() const 121 | { 122 | return m_weather_codition_icon_id; 123 | } 124 | 125 | qreal WeatherData::clouds_coverage() const 126 | { 127 | return m_clouds_coverage; 128 | } 129 | 130 | qreal WeatherData::wind_speed() const 131 | { 132 | return m_wind_speed; 133 | } 134 | 135 | qreal WeatherData::wind_degrees() const 136 | { 137 | return m_wind_degrees; 138 | } 139 | 140 | qreal WeatherData::wind_gust() const 141 | { 142 | return m_wind_gust; 143 | } 144 | 145 | qreal WeatherData::rain_3h() const 146 | { 147 | return m_rain_3h; 148 | } 149 | 150 | qreal WeatherData::snow_3h() const 151 | { 152 | return m_snow_3h; 153 | } 154 | 155 | QString WeatherData::timestamp_string() const 156 | { 157 | return m_timestamp_string; 158 | } 159 | 160 | qreal WeatherData::temp_morn() const 161 | { 162 | return m_temp_morn; 163 | } 164 | 165 | qreal WeatherData::temp_eve() const 166 | { 167 | return m_temp_eve; 168 | } 169 | 170 | qreal WeatherData::temp_night() const 171 | { 172 | return m_temp_night; 173 | } 174 | 175 | void WeatherData::set_timestamp(QDateTime timestamp) 176 | { 177 | if (m_timestamp == timestamp) 178 | return; 179 | 180 | m_timestamp = timestamp; 181 | emit timestamp_changed(timestamp); 182 | } 183 | 184 | void WeatherData::set_temp(qreal temp) 185 | { 186 | if (m_temp == temp) 187 | return; 188 | 189 | m_temp = temp; 190 | emit temp_changed(temp); 191 | } 192 | 193 | void WeatherData::set_temp_min(qreal temp_min) 194 | { 195 | if (m_temp_min == temp_min) 196 | return; 197 | 198 | m_temp_min = temp_min; 199 | emit temp_min_changed(temp_min); 200 | } 201 | 202 | void WeatherData::set_temp_max(qreal temp_max) 203 | { 204 | if (m_temp_max == temp_max) 205 | return; 206 | 207 | m_temp_max = temp_max; 208 | emit temp_max_changed(temp_max); 209 | } 210 | 211 | void WeatherData::set_pressure(qreal pressure) 212 | { 213 | if (m_pressure == pressure) 214 | return; 215 | 216 | m_pressure = pressure; 217 | emit pressure_changed(pressure); 218 | } 219 | 220 | void WeatherData::set_pressure_sea_level(qreal pressure_sea_level) 221 | { 222 | if (m_pressure_sea_level == pressure_sea_level) 223 | return; 224 | 225 | m_pressure_sea_level = pressure_sea_level; 226 | emit pressure_sea_level_changed(pressure_sea_level); 227 | } 228 | 229 | void WeatherData::set_humidity(qreal humidity) 230 | { 231 | if (m_humidity == humidity) 232 | return; 233 | 234 | m_humidity = humidity; 235 | emit humidity_changed(humidity); 236 | } 237 | 238 | void WeatherData::set_weather_codition_id(int weather_codition_id) 239 | { 240 | if (m_weather_codition_id == weather_codition_id) 241 | return; 242 | 243 | m_weather_codition_id = weather_codition_id; 244 | emit weather_codition_id_changed(weather_codition_id); 245 | } 246 | 247 | void WeatherData::set_weather_codition_name(QString weather_codition_name) 248 | { 249 | if (m_weather_codition_name == weather_codition_name) 250 | return; 251 | 252 | m_weather_codition_name = weather_codition_name; 253 | emit weather_codition_name_changed(weather_codition_name); 254 | } 255 | 256 | void WeatherData::set_weather_codition_description(QString weather_codition_description) 257 | { 258 | if (m_weather_codition_description == weather_codition_description) 259 | return; 260 | 261 | m_weather_codition_description = weather_codition_description; 262 | emit weather_codition_description_changed(weather_codition_description); 263 | } 264 | 265 | void WeatherData::set_weather_codition_icon_id(QString weather_codition_icon_id) 266 | { 267 | if (m_weather_codition_icon_id == weather_codition_icon_id) 268 | return; 269 | 270 | m_weather_codition_icon_id = weather_codition_icon_id; 271 | emit weather_codition_icon_id_changed(weather_codition_icon_id); 272 | } 273 | 274 | void WeatherData::set_clouds_coverage(qreal clouds_coverage) 275 | { 276 | if (m_clouds_coverage == clouds_coverage) 277 | return; 278 | 279 | m_clouds_coverage = clouds_coverage; 280 | emit clouds_coverage_changed(clouds_coverage); 281 | } 282 | 283 | void WeatherData::set_wind_speed(qreal wind_speed) 284 | { 285 | if (m_wind_speed == wind_speed) 286 | return; 287 | 288 | m_wind_speed = wind_speed; 289 | emit wind_speed_changed(wind_speed); 290 | } 291 | 292 | void WeatherData::set_wind_degrees(qreal wind_degrees) 293 | { 294 | if (m_wind_degrees == wind_degrees) 295 | return; 296 | 297 | m_wind_degrees = wind_degrees; 298 | emit wind_degrees_changed(wind_degrees); 299 | } 300 | 301 | void WeatherData::set_wind_gust(qreal wind_gust) 302 | { 303 | if (m_wind_gust == wind_gust) 304 | return; 305 | 306 | m_wind_gust = wind_gust; 307 | emit wind_gust_changed(wind_gust); 308 | } 309 | 310 | void WeatherData::set_rain_3h(qreal rain_3h) 311 | { 312 | if (m_rain_3h == rain_3h) 313 | return; 314 | 315 | m_rain_3h = rain_3h; 316 | emit rain_3h_changed(rain_3h); 317 | } 318 | 319 | void WeatherData::set_snow_3h(qreal snow_3h) 320 | { 321 | if (m_snow_3h == snow_3h) 322 | return; 323 | 324 | m_snow_3h = snow_3h; 325 | emit snow_3h_changed(snow_3h); 326 | } 327 | 328 | void WeatherData::set_timestamp_string(QString timestamp_string) 329 | { 330 | if (m_timestamp_string == timestamp_string) 331 | return; 332 | 333 | m_timestamp_string = timestamp_string; 334 | emit timestamp_string_changed(timestamp_string); 335 | } 336 | 337 | void WeatherData::set_pressure_grnd_level(qreal pressure_grnd_level) 338 | { 339 | if (m_pressure_grnd_level == pressure_grnd_level) 340 | return; 341 | 342 | m_pressure_grnd_level = pressure_grnd_level; 343 | emit pressure_grnd_level_changed(pressure_grnd_level); 344 | } 345 | 346 | void WeatherData::set_temp_morn(qreal temp_morn) 347 | { 348 | if (m_temp_morn == temp_morn) 349 | return; 350 | 351 | m_temp_morn = temp_morn; 352 | emit temp_morn_changed(temp_morn); 353 | } 354 | 355 | void WeatherData::set_temp_eve(qreal temp_eve) 356 | { 357 | if (m_temp_eve == temp_eve) 358 | return; 359 | 360 | m_temp_eve = temp_eve; 361 | emit temp_eve_changed(temp_eve); 362 | } 363 | 364 | void WeatherData::set_temp_night(qreal temp_night) 365 | { 366 | if (m_temp_night == temp_night) 367 | return; 368 | 369 | m_temp_night = temp_night; 370 | emit temp_night_changed(temp_night); 371 | } 372 | -------------------------------------------------------------------------------- /qml/WaiwedItem.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Particles 2.0 3 | import weathermodel 1.0 4 | import QtMultimedia 5.9 5 | 6 | Rectangle { 7 | id: root 8 | property real yPage: menuButton.state === "menu" ? appRoot.height / 1.6 : appRoot.height / 4.8 9 | color: weatherCommon.backgroundColor 10 | state: "none" 11 | 12 | //onColorChanged: console.log("color", color) 13 | Timer { 14 | id: pauseTimer 15 | interval: 1 16 | repeat: false 17 | onTriggered: mediaPlayer.pause(); 18 | } 19 | 20 | MediaPlayer { 21 | id: mediaPlayer 22 | loops: 1 23 | source: weatherCommon.showVideo ? weatherCommon.currentVideo: "" 24 | onErrorChanged: console.log("video error", error, errorString) 25 | 26 | onStatusChanged: { 27 | console.log("video status", status) 28 | if (status === MediaPlayer.Loaded) { 29 | mediaPlayer.play() 30 | } 31 | } 32 | onPositionChanged: { 33 | if (mediaPlayer.position > 1000 && mediaPlayer.duration - mediaPlayer.position < 1100) { 34 | pauseTimer.start() 35 | } 36 | } 37 | onSourceChanged: { 38 | console.log("video", source) 39 | } 40 | } 41 | 42 | VideoOutput { 43 | id: videoOutput 44 | visible: weatherCommon.showVideo 45 | //anchors.centerIn: parent 46 | y: appRoot.height / 5 47 | width: parent.width 48 | smooth: false 49 | height: width / (840/640) 50 | source: mediaPlayer 51 | fillMode: VideoOutput.Stretch 52 | MouseArea { 53 | anchors.fill: parent 54 | onClicked: { 55 | mediaPlayer.seek(0) 56 | mediaPlayer.play() 57 | } 58 | } 59 | ShaderEffect { 60 | id: videoBlendingShader 61 | visible: weatherCommon.showVideo 62 | property variant source: ShaderEffectSource { 63 | sourceItem: parent; 64 | //textureMirroring: ShaderEffectSource.MirrorHorizontally 65 | smooth: false 66 | hideSource: true 67 | } 68 | 69 | property color backgroundSourceColor: weatherCommon.backgroundColor 70 | anchors.fill: parent 71 | smooth: false 72 | blending: false 73 | onLogChanged: console.log(log) 74 | 75 | //change Alpha w/o changing color: 76 | //PC0 - original color 77 | //BC - background color 78 | //PA0 - original Alpha 79 | //PA1 - new Alpha 80 | //PC1 = (PC0*PA0 + BC*(1-PA0) - BC*(1-PA1)) / PA1 81 | fragmentShader: " 82 | precision mediump float; 83 | uniform sampler2D source; 84 | uniform float qt_Opacity; 85 | uniform lowp vec4 backgroundSourceColor; 86 | varying lowp vec2 qt_TexCoord0; 87 | 88 | float alphaCalc(float inpC, float keyC) { 89 | if ( keyC < 0.1 ) 90 | return inpC; 91 | else if ( inpC > keyC + 0.00001 ) 92 | return (inpC - keyC) / (1.0 - keyC); 93 | else if ( inpC < keyC - 0.00001 ) 94 | return (keyC - inpC) / keyC; 95 | else 96 | return 0.0; 97 | } 98 | 99 | vec3 saturation(vec3 rgb, float adjustment) { 100 | const vec3 W = vec3(0.2125, 0.7154, 0.0721); 101 | vec3 intensity = vec3(dot(rgb, W)); 102 | return mix(intensity, rgb, adjustment); 103 | } 104 | 105 | void main() { 106 | vec4 in_v = texture2D(source, qt_TexCoord0.xy); 107 | //vec4 color = vec4(0.21569, 0.54902, 0.0, 1.0); 108 | vec4 color = texture2D(source, vec2(0.01, 0.01)); 109 | 110 | vec4 out_v = in_v; 111 | vec4 alpha; 112 | 113 | alpha.w = in_v.w; 114 | 115 | alpha.x = alphaCalc(in_v.x, color.x); 116 | alpha.y = alphaCalc(in_v.y, color.y); 117 | alpha.z = alphaCalc(in_v.z, color.z); 118 | 119 | if (alpha.x > alpha.y) { 120 | if (alpha.x > alpha.z) 121 | out_v.w = alpha.x; 122 | else 123 | out_v.w = alpha.z; 124 | } else if (alpha.y > alpha.z) { 125 | out_v.w = alpha.y; 126 | } else { 127 | out_v.w = alpha.z; 128 | } 129 | if (out_v.w > .00001) { 130 | out_v.xyz = mix(backgroundSourceColor.xyz, (out_v.xyz - color.xyz) / out_v.www + color.xyz, out_v.w); 131 | if (out_v.w > .2) 132 | out_v.xyz = saturation(out_v.xyz, 0.2); 133 | 134 | out_v.w *= alpha.w; 135 | } else { 136 | out_v.xyz = backgroundSourceColor.xyz; 137 | } 138 | gl_FragColor = qt_Opacity*out_v; 139 | }" 140 | } 141 | } 142 | 143 | //flash effect 144 | SequentialAnimation { 145 | id: rainAnimation 146 | //running only on certain weather conditions 147 | running: weatherModel.currentWeather.weather_codition_icon_id === "11d" || 148 | weatherModel.currentWeather.weather_codition_icon_id === "11n" 149 | loops: Animation.Infinite 150 | 151 | //the idea is to quick change opacity... 152 | PropertyAnimation { 153 | target: root 154 | property: "opacity" 155 | from: 0 156 | to: 1 157 | duration: 500; 158 | easing.type: Easing.OutElastic 159 | } 160 | 161 | //..and then random pause between 1 and 7 seconds between flashes 162 | PauseAnimation { 163 | duration: Math.ceil(Math.random() * 6000) + 1000 164 | } 165 | } 166 | 167 | //setup snow or rain particles 168 | //using particles subsystem 169 | Connections { 170 | target: weatherModel 171 | onCurrentWeatherChanged: { 172 | if (systemTrayIcon.available) { 173 | systemTrayIcon.setNewIcon("icons/"+weatherModel.currentWeather.weather_codition_icon_id + ".svg") 174 | systemTrayIcon.toolTip = weatherModel.currentWeather.weather_codition_description 175 | systemTrayIcon.show() 176 | systemTrayIcon.showMessage(weatherModel.currentWeather.weather_codition_name, 177 | weatherModel.currentWeather.weather_codition_description 178 | + " " + weatherCommon.roundup(weatherCommon.convertToCurrentScale(weatherModel.currentWeather.temp)) 179 | + "\u00B0" + weatherCommon.temperatureScale, 0, 3000) 180 | } 181 | if (weatherModel.currentWeather.weather_codition_description.indexOf('rain') !== -1) { 182 | if (weatherModel.currentWeather.weather_codition_description.indexOf('light') !== -1) { 183 | rainEmitter.emitRate = 5 184 | } else if (weatherModel.currentWeather.weather_codition_description.indexOf('heavy') !== -1) { 185 | rainEmitter.emitRate = 20 186 | } else { 187 | rainEmitter.emitRate = 10 188 | } 189 | root.state = "rain" 190 | } else if (weatherModel.currentWeather.weather_codition_name === 'Snow') { 191 | snowEmitter.emitRate = 10 192 | root.state = "snow" 193 | } 194 | 195 | } 196 | } 197 | 198 | ParticleSystem { 199 | id: sysRain 200 | running: root.state === "rain" && weatherCommon.showAnimation 201 | onRunningChanged: { 202 | if (!running) 203 | reset() 204 | } 205 | } 206 | 207 | Emitter { 208 | id: rainEmitter 209 | system: sysRain 210 | emitRate: 10 211 | lifeSpan: 2000 212 | velocity: AngleDirection {angle: 90; magnitude: 500;} 213 | width: parent.width 214 | height: yPage 215 | } 216 | 217 | ParticleSystem { 218 | id: sysSnow 219 | running: root.state === "snow" && weatherCommon.showAnimation 220 | onRunningChanged: { 221 | if (!running) 222 | reset() 223 | } 224 | } 225 | 226 | Emitter { 227 | id: snowEmitter 228 | system: sysSnow 229 | emitRate: 20 230 | lifeSpan: 5000 231 | //snow flakes slower than rain drops 232 | velocity: AngleDirection {angle: 90; magnitude: 50;} 233 | width: parent.width 234 | height: yPage 235 | } 236 | 237 | ItemParticle { 238 | id: snowparticles 239 | anchors.fill: parent 240 | system: sysSnow 241 | delegate: SnowFlake {} 242 | fade: true 243 | } 244 | 245 | ItemParticle { 246 | id: rainparticles 247 | anchors.fill: parent 248 | system: sysRain 249 | delegate: RainDrop {} 250 | fade: true 251 | } 252 | 253 | Behavior on color { PropertyAnimation { duration: 500; } } 254 | 255 | Text { 256 | id: clock 257 | height: appRoot.height / 24 258 | z: 100 259 | anchors { right: parent.right; top: parent.top; rightMargin: appRoot.width / 48; topMargin: appRoot.height / 48; } 260 | font.pixelSize: appRoot.height / 40 261 | color: "white" 262 | Timer { 263 | interval: 5000 264 | repeat: true 265 | triggeredOnStart: true 266 | running: true 267 | onTriggered: { 268 | clock.text = Qt.formatDateTime(new Date(), "hh:mm") 269 | } 270 | } 271 | } 272 | 273 | Image { 274 | id: img 275 | width: parent.width 276 | y: root.yPage - 40// + sourceSize.height 277 | source: "images/background.png" 278 | Behavior on y { PropertyAnimation { duration: 630 } } 279 | } 280 | 281 | Rectangle { 282 | color: "white" 283 | width: parent.width 284 | height: parent.height - img.y - img.sourceSize.height 285 | anchors.bottom: parent.bottom 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /src/weatherdailymodel.cpp: -------------------------------------------------------------------------------- 1 | #include "weatherdailymodel.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | const QString weatherDailyUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?"; 13 | const QString appID = "&appid=483240f16c1aa9e5feab1fa41c9d273a"; 14 | 15 | WeatherDailyModel::WeatherDailyModel(WeatherCommon *wcommon, QAbstractListModel *parent) : QAbstractListModel(parent) 16 | , _updateInterval(-1) 17 | , m_daysNumber(0) 18 | , m_wcommon(wcommon) 19 | , replyDaily(nullptr) 20 | { 21 | connect(&_updateTimer, &QTimer::timeout, this, &WeatherDailyModel::requestWeatherUpdate); 22 | connect(wcommon, &WeatherCommon::requestWeatherUpdate, this, &WeatherDailyModel::requestWeatherUpdate); 23 | _updateTimer.setSingleShot(false); 24 | } 25 | 26 | void WeatherDailyModel::requestWeatherUpdate() 27 | { 28 | QUrl dailyurl; 29 | 30 | if (replyDaily) 31 | replyDaily->abort(); 32 | if (m_wcommon->getSearchCriteria() == WeatherCommon::Coordinates) { 33 | const QGeoCoordinate &coord = m_wcommon->getCoordinate(); 34 | dailyurl = QUrl(QString("%1lat=%2&lon=%3%4").arg(weatherDailyUrl).arg(coord.latitude()).arg(coord.longitude()).arg(appID)); 35 | } else { 36 | dailyurl = QUrl(QString("%1q=%2%3").arg(weatherDailyUrl).arg(m_wcommon->getSearchCity()).arg(appID)); 37 | } 38 | QNetworkRequest req = QNetworkRequest(dailyurl); 39 | req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); 40 | QNetworkReply *replyDaily = _nam.get(QNetworkRequest(req)); 41 | connect(replyDaily, &QNetworkReply::finished, this, &WeatherDailyModel::onWeatherDailyRequestFinished); 42 | qDebug() << "requested daily city" << m_wcommon->getSearchCity(); 43 | } 44 | 45 | QString WeatherDailyModel::cityName() const 46 | { 47 | return m_cityName; 48 | } 49 | 50 | QString WeatherDailyModel::countryID() const 51 | { 52 | return m_countryID; 53 | } 54 | 55 | QHash WeatherDailyModel::roleNames() const { 56 | QHash roles; 57 | roles[TimestampRole] = "timestamp"; 58 | roles[TemperatureDayRole] = "temp_day"; 59 | roles[TemperatureMinRole] = "temp_min"; 60 | roles[TemperatureMaxRole] = "temp_max"; 61 | roles[TemperatureNightRole] = "temp_night"; 62 | roles[TemperatureEveRole] = "temp_eve"; 63 | roles[TemperatureMornRole] = "temp_morn"; 64 | roles[PressureRole] = "pressure"; 65 | roles[HumidityRole] = "humidity"; 66 | roles[WeatherConditionIdRole] = "weather_codition_id"; 67 | roles[WeatherConditionNameRole] = "weather_codition_name"; 68 | roles[WeatherConditionDescriptionRole] = "weather_codition_description"; 69 | roles[WeatherConditionIconIdRole] = "weather_codition_icon_id"; 70 | roles[CloudsCoverageRole] = "clouds_coverage"; 71 | roles[WindSpeedRole] = "wind_speed"; 72 | roles[WindDegreesRole] = "wind_degrees"; 73 | roles[WindGustRole] = "wind_gust"; 74 | roles[RainRole] = "rain"; 75 | roles[SnowRole] = "snow"; 76 | roles[SunriseRole] = "sunrise"; 77 | roles[SunsetRole] = "sunset"; 78 | return roles; 79 | } 80 | 81 | int WeatherDailyModel::rowCount(const QModelIndex &parent) const 82 | { 83 | Q_UNUSED(parent) 84 | return m_dailyList.size(); 85 | } 86 | 87 | QVariant WeatherDailyModel::data(const QModelIndex &index, int role) const 88 | { 89 | if (!index.isValid()) 90 | return QVariant(); 91 | 92 | if (index.row() >= m_dailyList.size()) 93 | return QVariant(); 94 | 95 | if (role == Qt::DisplayRole || role == WeatherConditionNameRole) 96 | return m_dailyList.at(index.row())->weather_codition_name(); 97 | else if (role == TimestampRole) 98 | return m_dailyList.at(index.row())->timestamp(); 99 | else if (role == TemperatureDayRole) 100 | return m_dailyList.at(index.row())->temp(); 101 | else if (role == TemperatureMinRole) 102 | return m_dailyList.at(index.row())->temp_min(); 103 | else if (role == TemperatureMaxRole) 104 | return m_dailyList.at(index.row())->temp_max(); 105 | else if (role == TemperatureEveRole) 106 | return m_dailyList.at(index.row())->temp_eve(); 107 | else if (role == TemperatureMornRole) 108 | return m_dailyList.at(index.row())->temp_morn(); 109 | else if (role == TemperatureNightRole) 110 | return m_dailyList.at(index.row())->temp_night(); 111 | else if (role == PressureRole) 112 | return m_dailyList.at(index.row())->pressure(); 113 | else if (role == HumidityRole) 114 | return m_dailyList.at(index.row())->humidity(); 115 | else if (role == WeatherConditionIdRole) 116 | return m_dailyList.at(index.row())->weather_codition_id(); 117 | else if (role == WeatherConditionDescriptionRole) 118 | return m_dailyList.at(index.row())->weather_codition_description(); 119 | else if (role == WeatherConditionIconIdRole) 120 | return m_dailyList.at(index.row())->weather_codition_icon_id(); 121 | else if (role == CloudsCoverageRole) 122 | return m_dailyList.at(index.row())->clouds_coverage(); 123 | else if (role == WindSpeedRole) 124 | return m_dailyList.at(index.row())->wind_speed(); 125 | else if (role == WindDegreesRole) 126 | return m_dailyList.at(index.row())->wind_degrees(); 127 | else if (role == WindGustRole) 128 | return m_dailyList.at(index.row())->wind_gust(); 129 | else if (role == RainRole) 130 | return m_dailyList.at(index.row())->rain_3h(); 131 | else if (role == SnowRole) 132 | return m_dailyList.at(index.row())->snow_3h(); 133 | else if (role == SunriseRole) 134 | return m_dailyList.at(index.row())->sunrise(); 135 | else if (role == SunsetRole) 136 | return m_dailyList.at(index.row())->sunset(); 137 | else 138 | return QVariant(); 139 | } 140 | 141 | void WeatherDailyModel::setCityName(QString cityName) 142 | { 143 | if (m_cityName == cityName) 144 | return; 145 | 146 | m_cityName = cityName; 147 | emit cityNameChanged(cityName); 148 | } 149 | 150 | void WeatherDailyModel::setCountryID(QString countryID) 151 | { 152 | if (m_countryID == countryID) 153 | return; 154 | 155 | m_countryID = countryID; 156 | emit countryIDChanged(countryID); 157 | } 158 | 159 | void WeatherDailyModel::setDaysNumber(int daysNumber) 160 | { 161 | if (m_daysNumber == daysNumber) 162 | return; 163 | 164 | m_daysNumber = daysNumber; 165 | qDebug() << "days number" << daysNumber; 166 | emit daysNumberChanged(daysNumber); 167 | } 168 | 169 | void WeatherDailyModel::onWeatherDailyRequestFinished() 170 | { 171 | QNetworkReply *reply = static_cast(sender()); 172 | reply->deleteLater(); 173 | if(reply->error() == QNetworkReply::NoError){ 174 | QByteArray arr = reply->readAll(); 175 | QJsonDocument jsonDoc = QJsonDocument::fromJson(arr); 176 | 177 | QJsonObject obj = jsonDoc.object(); 178 | 179 | int cod = obj.value("cod").toString().toInt(); 180 | if (cod != 200) { 181 | qDebug() << "Error requestin daily weather data" << cod << reply->url(); 182 | emit m_wcommon->weatherDownloadError(WeatherCommon::Daily, cod); 183 | replyDaily = nullptr; 184 | return; 185 | } 186 | 187 | QJsonArray weatherList = obj.value("list").toArray(); 188 | beginResetModel(); 189 | qDeleteAll(m_dailyList); 190 | m_dailyList.clear(); 191 | 192 | foreach (const QJsonValue & value, weatherList) { 193 | QJsonObject obj1 = value.toObject(); 194 | if (!obj1.isEmpty()) { 195 | WeatherData *wData = new WeatherData; 196 | QQmlEngine::setObjectOwnership(wData, QQmlEngine::CppOwnership); 197 | wData->set_timestamp(QDateTime::fromTime_t(obj1.value("dt").toInt(), Qt::UTC, m_wcommon->getTimezoneOffset())); 198 | QJsonObject tempObj = obj1.value("temp").toObject(); 199 | 200 | if (!tempObj.isEmpty()) { 201 | wData->set_temp(tempObj.value("day").toDouble()); 202 | wData->set_temp_min(tempObj.value("min").toDouble()); 203 | wData->set_temp_max(tempObj.value("max").toDouble()); 204 | wData->set_temp_eve(tempObj.value("eve").toDouble()); 205 | wData->set_temp_morn(tempObj.value("morn").toDouble()); 206 | wData->set_temp_night(tempObj.value("night").toDouble()); 207 | } 208 | 209 | wData->set_pressure(obj1.value("pressure").toDouble()); 210 | wData->set_humidity(obj1.value("humidity").toDouble()); 211 | wData->set_wind_speed(obj1.value("speed").toDouble()); 212 | wData->set_wind_degrees(obj1.value("deg").toDouble()); 213 | wData->set_clouds_coverage(obj1.value("clouds").toDouble()); 214 | 215 | QJsonArray weatherarray = obj1.value("weather").toArray(); 216 | foreach (const QJsonValue & wvalue, weatherarray) { 217 | const QJsonObject &weatherObj = wvalue.toObject(); 218 | if (!weatherObj.isEmpty()) { 219 | wData->set_weather_codition_name(weatherObj.value("main").toString()); 220 | wData->set_weather_codition_id(weatherObj.value("id").toInt()); 221 | wData->set_weather_codition_icon_id(weatherObj.value("icon").toString()); 222 | wData->set_weather_codition_description(weatherObj.value("description").toString()); 223 | } 224 | break; 225 | } 226 | 227 | wData->set_rain_3h(obj1.value("rain").toDouble()); 228 | wData->set_snow_3h(obj1.value("snow").toDouble()); 229 | m_dailyList.append(wData); 230 | //qDebug() << wData->dump() << "\n"; 231 | } 232 | } 233 | endResetModel(); 234 | } else { 235 | qDebug() << "Error requestin daily weather data" << reply->error() << reply->url(); 236 | emit m_wcommon->weatherDownloadError(WeatherCommon::Daily, reply->error()); 237 | if (reply->error() != QNetworkReply::OperationCanceledError) 238 | m_wcommon->setBackgroundColor(0.0f); 239 | 240 | } 241 | replyDaily = nullptr; 242 | } 243 | 244 | void WeatherDailyModel::setUpdateInterval(int updateInterval) 245 | { 246 | _updateInterval = updateInterval; 247 | if (updateInterval > 0) { 248 | _updateTimer.setInterval(updateInterval*1000); 249 | _updateTimer.start(); 250 | } else { 251 | _updateTimer.stop(); 252 | } 253 | } 254 | 255 | int WeatherDailyModel::daysNumber() const 256 | { 257 | return m_daysNumber; 258 | } 259 | -------------------------------------------------------------------------------- /src/weathercommon.cpp: -------------------------------------------------------------------------------- 1 | #include "weathercommon.h" 2 | #include 3 | 4 | QList WeatherCommon::_colorsTable = QList() 5 | << QColor("#444444") //error 6 | << QColor("#b1695a") 7 | << QColor("#DB9864") 8 | << QColor("#E3BB88") 9 | << QColor("#D0C7A8") 10 | << QColor("#B1C2A3") 11 | << QColor("#80BBB2") 12 | << QColor("#6D9E96") 13 | << QColor("#8F95A5") 14 | << QColor("#6F7685"); 15 | 16 | QMap, QString> WeatherCommon::_videoNamesTable = QMap, QString>(); 17 | QMap, QString> WeatherCommon::_videoNamesNightTable = QMap, QString>(); 18 | 19 | WeatherCommon::WeatherCommon(QObject *parent) : QObject(parent) 20 | , m_backgroundColor(QColor("#CCCCCC")) 21 | , m_TimezoneOffset(0) 22 | , m_showAnimation(true) 23 | , m_menuBarWeather(true) 24 | , m_runAtStartup(true) 25 | , m_tempScale(Celsium) 26 | , m_searchCriteria(WeatherCommon::Coordinates) 27 | { 28 | setTempScale((TemperatureScales)settings.value("temp_scale", Celsium).toInt()); 29 | setMenuBarWeather(settings.value("sys_tray", true).toBool()); 30 | setRunAtStartup(settings.value("run_startup", true).toBool()); 31 | setShowAnimation(settings.value("animation_fx", true).toBool()); 32 | setShowVideo(settings.value("video_fx", false).toBool()); 33 | //check what was requested last and made request again 34 | m_searchCriteria = (WeatherCommon::SearchCriteria)(settings.value("last_searchcriteria", WeatherCommon::Coordinates).toInt()); 35 | m_searchCity = settings.value("last_city", QVariant("")).toString(); 36 | //read and parse coordinates 37 | double _lat = settings.value("last_lat", 0.0f).toFloat(); 38 | double _lng = settings.value("last_long", 0.0f).toFloat(); 39 | m_coordinate = QGeoCoordinate(_lat, _lng); 40 | 41 | if (m_searchCriteria == WeatherCommon::Coordinates && m_coordinate.isValid()) { 42 | search(); 43 | } else if (m_searchCriteria == WeatherCommon::CityName && !m_searchCity.isEmpty()) { 44 | search(m_searchCity); 45 | } 46 | //fill up video files table 47 | _videoNamesTable.insert(QList() << 611 << 612 << 615 << 616, "Clouds-Snow-Rain"); 48 | _videoNamesTable.insert(QList() << 600 << 601 << 602 << 620 << 621 << 622, "Clouds-Snow"); 49 | _videoNamesTable.insert(QList() << 503 << 504 << 521 << 522 << 531 50 | << 300 << 301 << 302 << 310 << 311 << 312 << 313 << 314 << 321, 51 | "HeavyDarkClouds-Rain"); 52 | _videoNamesTable.insert(QList() << 500 << 501 << 502 << 520, "Sun-HeavyDarkClouds-Rain"); 53 | _videoNamesTable.insert(QList() << 202 << 211 << 212 << 221 << 231 << 232, "HeavyDarkClouds-Rain-Storm"); 54 | _videoNamesTable.insert(QList() << 200 << 201 << 210 << 230, "Sun-HeavyDarkClouds-Rain-Storm"); 55 | _videoNamesTable.insert(QList() << 800, "Sun"); 56 | _videoNamesTable.insert(QList() << 801, "Sun-SemiSmallCloudComing"); 57 | _videoNamesTable.insert(QList() << 802, "Sun-SmallClouds-Coming"); 58 | _videoNamesTable.insert(QList() << 803, "Sun-SemiDarkCloud"); 59 | _videoNamesTable.insert(QList() << 804, "Sun-HavyDarkClouds"); 60 | _videoNamesTable.insert(QList() << 781 << 900 << 902 << 960 << 961 << 962, "Tornado-Twister"); 61 | _videoNamesTable.insert(QList() << 904, "HotSun"); 62 | _videoNamesTable.insert(QList() << 905 << 955 << 957 << 958 , "Wind"); 63 | _videoNamesTable.insert(QList() << 701 << 711 << 741, "smallClouds-Coming"); 64 | _videoNamesTable.insert(QList() << 721 , "Sun-smallClouds-GoingAway"); 65 | 66 | _videoNamesNightTable.insert(QList() << 500, "ClearSky-Rain"); 67 | _videoNamesNightTable.insert(QList() << 803, "Moon-Full-BigClouds-GoingAway"); 68 | _videoNamesNightTable.insert(QList() << 0, "Moon-Half-Cloudy-GoingAway"); 69 | _videoNamesNightTable.insert(QList() << 804, "Moon-HavyClouds"); 70 | _videoNamesNightTable.insert(QList() << 600 << 601 << 602 << 611 << 612 << 615 << 616 << 620 << 621 << 622, 71 | "Moon-Snow"); 72 | _videoNamesNightTable.insert(QList() << 0, "Moon-Young"); 73 | _videoNamesNightTable.insert(QList() << 300 << 301 << 302 << 310 << 311 << 312 << 313 << 314, "Moon-Clouds-Rain"); 74 | _videoNamesNightTable.insert(QList() << 0, "Moon-Full-BigClouds"); 75 | _videoNamesNightTable.insert(QList() << 0, "Moon-Half-Cloudy"); 76 | _videoNamesNightTable.insert(QList() << 200 << 201 << 202 << 210 << 211 << 212 << 221 << 230 << 231 << 232, 77 | "Moon-HavyRain-Thunder"); 78 | _videoNamesNightTable.insert(QList() << 0, "Moon-Young-Clouds-Coming"); 79 | _videoNamesNightTable.insert(QList() << 321 << 501 << 502 << 503 << 504 << 511 << 520 << 521 << 522 << 531, 80 | "Moon-Clouds-Showers"); 81 | _videoNamesNightTable.insert(QList() << 802, "Moon-Full-Cloudy"); 82 | _videoNamesNightTable.insert(QList() << 0, "Moon-Half-Fog"); 83 | _videoNamesNightTable.insert(QList() << 801, "Moon-SmallClouds-Coming"); 84 | _videoNamesNightTable.insert(QList() << 0, "Moon-Young-Clouds-GoingAway"); 85 | _videoNamesNightTable.insert(QList() << 741 << 701, "Moon-Fog"); 86 | _videoNamesNightTable.insert(QList() << 800, "Moon-Full"); 87 | _videoNamesNightTable.insert(QList() << 0, "Moon-Half"); 88 | _videoNamesNightTable.insert(QList() << 0, "Moon-SmallClouds-GoingAway"); 89 | _videoNamesNightTable.insert(QList() << 0, "Moon-Young-Fog"); 90 | 91 | if (qgetenv("TEMPSQML_VIDEO_BASE").size() > 0) 92 | m_currentVideoBasePath = QString(qgetenv("TEMPSQML_VIDEO_BASE")); 93 | else 94 | m_currentVideoBasePath = QStringLiteral("http://www.vladest.org/weather/videos/"); 95 | } 96 | 97 | QString WeatherCommon::currentVideo() const 98 | { 99 | return m_currentVideo; 100 | } 101 | 102 | void WeatherCommon::setCurrentVideo(const WeatherData &wdata) 103 | { 104 | const QTime &_now = QDateTime::currentDateTime().time(); 105 | bool isNight = ((_now >= wdata.sunset().time() && _now <= QTime(23,59,59)) || 106 | (_now >= QTime(0,1,1) && _now < wdata.sunrise().time() )); 107 | const QMap, QString> &table = isNight ? _videoNamesNightTable : _videoNamesTable; 108 | for (int i = 0; i < table.keys().size(); i++) { 109 | const QList ids = table.keys().at(i); 110 | if (ids.contains(wdata.weather_codition_id())) { 111 | m_currentVideo = m_currentVideoBasePath; 112 | if (isNight) 113 | m_currentVideo += QStringLiteral("night/"); 114 | m_currentVideo += table[ids] + QStringLiteral(".mp4"); 115 | emit currentVideoChanged(m_currentVideo); 116 | return; 117 | } 118 | } 119 | qWarning() << "Did not found any media for weather id" << wdata.weather_codition_id() << "is night" << isNight; 120 | } 121 | 122 | qreal WeatherCommon::convertToCurrentScale(qreal temp_k) 123 | { 124 | return m_tempScale == Celsium ? kelvin2celsius(temp_k) : kelvin2fahrenheit(temp_k); 125 | } 126 | 127 | QColor WeatherCommon::backgroundColor() const 128 | { 129 | return m_backgroundColor; 130 | } 131 | 132 | void WeatherCommon::setBackgroundColor(qreal temp) 133 | { 134 | int index = 9; 135 | qreal temp_c = roundup(kelvin2celsius(temp)); 136 | if (temp_c > 30) { 137 | index = 1; 138 | } else if (temp_c > 26) { 139 | index = 2; 140 | } else if (temp_c > 22) { 141 | index = 3; 142 | } else if (temp_c > 18) { 143 | index = 4; 144 | } else if (temp_c > 14) { 145 | index = 5; 146 | } else if (temp_c > 10) { 147 | index = 6; 148 | } else if (temp_c > 6) { 149 | index = 7; 150 | } else if (temp_c > 2) { 151 | index = 8; 152 | } else if (temp_c < -273.0) { ///error 153 | index = 0; 154 | } 155 | 156 | m_backgroundColor = _colorsTable.at(index); 157 | emit backgroundColorChanged(temp); 158 | } 159 | void WeatherCommon::setTempScale(TemperatureScales tempScale) 160 | { 161 | m_tempScale = tempScale; 162 | settings.setValue("temp_scale", tempScale); 163 | emit tempScaleChanged(tempScale); 164 | emit temperatureScaleChanged(temperatureScale()); 165 | } 166 | 167 | WeatherCommon::TemperatureScales WeatherCommon::tempScale() const 168 | { 169 | return m_tempScale; 170 | } 171 | 172 | QList WeatherCommon::colorsTable() 173 | { 174 | return _colorsTable; 175 | } 176 | 177 | QString WeatherCommon::temperatureScale() const 178 | { 179 | return m_tempScale == Celsium ? "C" :"F"; 180 | } 181 | 182 | bool WeatherCommon::showAnimation() const 183 | { 184 | return m_showAnimation; 185 | } 186 | 187 | bool WeatherCommon::showVideo() const 188 | { 189 | return m_showVideo; 190 | } 191 | 192 | bool WeatherCommon::menuBarWeather() const 193 | { 194 | return m_menuBarWeather; 195 | } 196 | 197 | bool WeatherCommon::runAtStartup() const 198 | { 199 | return m_runAtStartup; 200 | } 201 | 202 | int WeatherCommon::getTimezoneOffset() const 203 | { 204 | return m_TimezoneOffset; 205 | } 206 | 207 | void WeatherCommon::setCoordinates(const QGeoCoordinate &coordinate) 208 | { 209 | if (coordinate != m_coordinate) { 210 | m_coordinate = coordinate; 211 | emit requestWeatherUpdate(); 212 | } 213 | } 214 | 215 | void WeatherCommon::setTimezoneOffset(int TimezoneOffset) 216 | { 217 | m_TimezoneOffset = TimezoneOffset; 218 | emit requestWeatherUpdate(); 219 | } 220 | 221 | void WeatherCommon::setShowAnimation(bool showAnimation) 222 | { 223 | if (m_showAnimation == showAnimation) 224 | return; 225 | 226 | m_showAnimation = showAnimation; 227 | emit showAnimationChanged(showAnimation); 228 | settings.setValue("animation_fx", showAnimation); 229 | } 230 | 231 | void WeatherCommon::setShowVideo(bool showVideo) 232 | { 233 | if (m_showVideo == showVideo) 234 | return; 235 | 236 | m_showVideo = showVideo; 237 | emit showVideoChanged(showVideo); 238 | settings.setValue("video_fx", showVideo); 239 | } 240 | 241 | void WeatherCommon::setMenuBarWeather(bool menuBarWeather) 242 | { 243 | if (m_menuBarWeather == menuBarWeather) 244 | return; 245 | 246 | m_menuBarWeather = menuBarWeather; 247 | emit menuBarWeatherChanged(menuBarWeather); 248 | settings.setValue("sys_tray", menuBarWeather); 249 | } 250 | 251 | void WeatherCommon::setRunAtStartup(bool runAtStartup) 252 | { 253 | if (m_runAtStartup == runAtStartup) 254 | return; 255 | 256 | m_runAtStartup = runAtStartup; 257 | emit runAtStartupChanged(runAtStartup); 258 | settings.setValue("run_startup", runAtStartup); 259 | } 260 | 261 | void WeatherCommon::search(const QString &city) { 262 | if (!city.isEmpty()) { 263 | m_searchCity = city; 264 | m_searchCriteria = CityName; 265 | emit requestWeatherUpdate(); 266 | } 267 | } 268 | 269 | void WeatherCommon::search() 270 | { 271 | if (m_coordinate.isValid()) { 272 | m_searchCriteria = Coordinates; 273 | emit requestWeatherUpdate(); 274 | } 275 | } 276 | 277 | void WeatherCommon::saveLastRequestedWeather(const QString &city) 278 | { 279 | if (!city.isEmpty()) { 280 | settings.setValue("last_city", city); 281 | } 282 | if (m_coordinate.isValid()) { 283 | settings.setValue("last_lat", m_coordinate.latitude()); 284 | settings.setValue("last_long", m_coordinate.longitude()); 285 | } 286 | settings.setValue("last_searchcriteria", m_searchCriteria); 287 | } 288 | 289 | QString WeatherCommon::getSearchCity() const 290 | { 291 | return m_searchCity; 292 | } 293 | 294 | WeatherCommon::SearchCriteria WeatherCommon::getSearchCriteria() const 295 | { 296 | return m_searchCriteria; 297 | } 298 | 299 | QGeoCoordinate WeatherCommon::getCoordinate() const 300 | { 301 | return m_coordinate; 302 | } 303 | --------------------------------------------------------------------------------