new activities in station details with wind directiom, temperature and humidity plots

pull/1/head
Mateusz Lubecki 2021-01-12 22:43:14 +01:00
rodzic 5a91b95eb2
commit 920958a7ca
25 zmienionych plików z 971 dodań i 80 usunięć

Wyświetl plik

@ -13,6 +13,8 @@
android:theme="@style/Theme.Pogodacc">
<activity android:name=".activity.StationDetailsWindRoseActivity"></activity>
<activity android:name=".activity.StationDetailsPlotsWind" />
<activity android:name=".activity.StationDetailsPlotsDirection" />
<activity android:name=".activity.StationDetailsPlotsTemperature" />
<activity android:name=".activity.StationDetailsSummaryActivity" />
<activity android:name=".activity.StationDetailsActivity" />
<activity android:name=".activity.AllStationsActivity" />

Wyświetl plik

@ -4,7 +4,6 @@ import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ImageButton;
@ -14,7 +13,9 @@ import android.widget.TextView;
import java.io.InputStream;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActPlotsButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActTemperaturePlotButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActWindDirectionPlotsButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActWindSpeedPlotsButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActSummaryButtonClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.StationDetailsActWindRoseButtonClickEvent;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
@ -29,13 +30,30 @@ public class StationDetailsActivity extends AppCompatActivity {
TextView stationSponsorUrl = null;
ImageButton summaryButton = null;
ImageButton plotsButton = null;
ImageButton windSpeedPlotsButton = null;
ImageButton windDirectionPlotsButton = null;
ImageButton temperatureButton = null;
ImageButton windRoseButton = null;
ImageView topBackground = null;
/**
* Click event on Station Summary Button
*/
StationDetailsActSummaryButtonClickEvent summaryClickEvent = null;
StationDetailsActPlotsButtonClickEvent plotsClickEvent = null;
/**
* Click event on Wind Speed Button
*/
StationDetailsActWindSpeedPlotsButtonClickEvent windSpeedPlotsClickEvent = null;
StationDetailsActWindDirectionPlotsButtonClickEvent windDirectionPlotsClickEvent = null;
StationDetailsActTemperaturePlotButtonClickEvent temperaturePlotButtonClickEvent = null;
/**
*
*/
StationDetailsActWindRoseButtonClickEvent windRoseClickEvent = null;
/**
@ -113,18 +131,26 @@ public class StationDetailsActivity extends AppCompatActivity {
if (station != null && stationName != null) {
summaryClickEvent = new StationDetailsActSummaryButtonClickEvent(station, this);
plotsClickEvent = new StationDetailsActPlotsButtonClickEvent(station, this);
windSpeedPlotsClickEvent = new StationDetailsActWindSpeedPlotsButtonClickEvent(station, this);
windDirectionPlotsClickEvent = new StationDetailsActWindDirectionPlotsButtonClickEvent(station, this);
temperaturePlotButtonClickEvent = new StationDetailsActTemperaturePlotButtonClickEvent(station, this);
windRoseClickEvent = new StationDetailsActWindRoseButtonClickEvent(station, this);
summaryButton = findViewById(R.id.imageButtonCurrent);
summaryButton.setOnClickListener(summaryClickEvent);
plotsButton = findViewById(R.id.imageButtonPlotsWind);
plotsButton.setOnClickListener(plotsClickEvent);
windSpeedPlotsButton = findViewById(R.id.imageButtonPlotsWindSpeed);
windSpeedPlotsButton.setOnClickListener(windSpeedPlotsClickEvent);
windDirectionPlotsButton = findViewById(R.id.imageButtonPlotsWindDirection);
windDirectionPlotsButton.setOnClickListener(windDirectionPlotsClickEvent);
windRoseButton = findViewById(R.id.imageButtonWindRose);
windRoseButton.setOnClickListener(windRoseClickEvent);
temperatureButton = findViewById(R.id.imageButtonPlotsTemperature);
temperatureButton.setOnClickListener(temperaturePlotButtonClickEvent);
topBackground = findViewById(R.id.imageViewStationPng);
switch (station.getImageAlign()) {
case 0:

Wyświetl plik

@ -0,0 +1,319 @@
package cc.pogoda.mobile.pogodacc.activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import java.util.ArrayList;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.pogodacc.config.AppConfiguration;
import cc.pogoda.mobile.pogodacc.dao.LastStationDataDao;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.type.web.StationData;
public class StationDetailsPlotsDirection extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
private LineChart chart = null;
private SeekBar seekBarX = null;
private TextView textViewTimestamp = null;
private TextView textViewSpeed = null;
private TextView textViewGusts = null;
private LastStationDataDao lastStationDataDao;
private WeatherStation station;
private PlotClickEvent plotClickEvent;
private ArrayList<Entry> valuesWindDirection;
private class ValueFormatter extends com.github.mikephil.charting.formatter.ValueFormatter {
@Override
public String getFormattedValue(float value) {
long millis = (long) value;
// the web service and the plot always stores the entries as UTC. So first convert epoch timestamp to the LocalDateTime
LocalDateTime utcDateTime = LocalDateTime.ofEpochSecond(millis / 1000, 0, ZoneOffset.UTC);
// and then shift to the user timezone for convinient display
ZonedDateTime localDateTime = utcDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault());
// format only the time to keep X axis clean
String dt = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(localDateTime);
return dt;
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// first and last index to display on plot
int first_index = 0, last_index = 0;
// display only 20% of the set at once
int window_size = (int) (valuesWindDirection.size() * 0.2f);
last_index = (int) ((seekBarX.getProgress() / 100.0f) * valuesWindDirection.size());
first_index = last_index - window_size;
if (first_index < 0) {
first_index = 0;
last_index = window_size;
}
this.setData(first_index, last_index, false);
// redraw
chart.invalidate();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station_details_plots);
station = (WeatherStation) getIntent().getSerializableExtra("station");
// download data from web service
this.downloadDataFromWebservice();
Typeface tfLight = Typeface.MONOSPACE;
setTitle(R.string.wind_direction_plots);
textViewTimestamp = findViewById(R.id.textViewPlotsWindTimestamp);
textViewSpeed = findViewById(R.id.textViewPlotsWindMean);
textViewGusts = findViewById(R.id.textViewPlotsWindGusts);
seekBarX = findViewById(R.id.seekBarPlotsWind);
chart = findViewById(R.id.chartPlotsWind);
// enable scaling and dragging
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
chart.setDrawGridBackground(false);
chart.setHighlightPerDragEnabled(true);
// set an alternative background color
chart.setBackgroundColor(Color.WHITE);
chart.setViewPortOffsets(0f, 0f, 0f, 0f);
// add data
seekBarX.setProgress(100);
seekBarX.setOnSeekBarChangeListener(this);
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);
xAxis.setTypeface(tfLight);
xAxis.setTextSize(10f);
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawAxisLine(false);
xAxis.setDrawGridLines(true);
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setValueFormatter(new StationDetailsPlotsDirection.ValueFormatter());
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
leftAxis.setTypeface(tfLight);
leftAxis.setTextColor(ColorTemplate.getHoloBlue());
leftAxis.setDrawGridLines(true);
leftAxis.setGranularityEnabled(true);
leftAxis.setAxisMinimum(0.0f);
leftAxis.setAxisMaximum(360.0f);
leftAxis.setYOffset(0.0f);
leftAxis.setTextColor(Color.rgb(255, 192, 56));
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
int lastDataIndex = valuesWindDirection.size() - 1;
// display only the last data (20% of newest data)
this.setData((long) (0.8 * (lastDataIndex)), lastDataIndex, false);
// set bar to maximum value
seekBarX.setProgress(100);
}
/**
* Updates labels placed at the top of the chart with values at the point selected by an user.
* @param date Date & time string in local timezone
*/
public void updateLabels(String date, Entry entry) {
float direction = 0.0f;
// get a timestamp from the entry
long timestamp = (long) entry.getX();
// look for the windspeed coresponding to that timestamp
for (Entry e : valuesWindDirection) {
// if this is what we are looking for
if (e.getX() == entry.getX()) {
direction = e.getY();
}
}
if (this.textViewSpeed != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewSpeed.setText(getString(R.string.wind_direction_short) + String.format(": %d", (int)direction));
}
else {
return;
}
}
/**
*
* @param from
* @param to
* @param index_or_timestamp if set to false 'to' and 'from' are treated as an index, if they are set
* to true this method will use it as epoch timestamps (in seconds)
*/
public void setData(long from, long to, boolean index_or_timestamp) {
// if only some part of input set needs to be displayed use this intermediate buffer
ArrayList<Entry> narrowed_set, narrowed_set_gusts;
// data set to be displayed on the plot
LineDataSet set_wind_direction;
if (valuesWindDirection.size() > 0) {
if (from != 0 || to != 0) {
// if 'from' and 'to' are the index values
if (!index_or_timestamp) {
// make a sublist
narrowed_set = new ArrayList<>(valuesWindDirection.subList((int)from, (int)to));
}
else {
// get first and last entry from the set
Entry first = valuesWindDirection.get(0);
Entry last = valuesWindDirection.get(valuesWindDirection.size() - 1 );
// check if 'from' and 'to' timestamp epoch covers any data from the input set
if ( (long)first.getX() > (to * 1000) ||
(long)last.getX() < (from * 1000)) {
// if there is no data to display exit from an function
return;
}
else {
narrowed_set = new ArrayList<>();
narrowed_set_gusts = new ArrayList<>();
// if not copy matching elements to narrowed set
valuesWindDirection.forEach((Entry e) -> {
if (e.getX() > (from * 1000) &&
e.getX() < (to * 1000)) {
narrowed_set.add(e);
}
});
}
}
// and generate the set from it
set_wind_direction = new LineDataSet(narrowed_set, "Wind Speed");
}
else {
// use 'values_wind_speed' directly as a whole
set_wind_direction = new LineDataSet(valuesWindDirection, "Wind Speed");
}
// create a dataset and give it a type
set_wind_direction.setAxisDependency(YAxis.AxisDependency.LEFT);
set_wind_direction.setColor(ColorTemplate.getHoloBlue());
set_wind_direction.setValueTextColor(ColorTemplate.getHoloBlue());
set_wind_direction.setLineWidth(3.5f);
set_wind_direction.setDrawCircles(true);
set_wind_direction.setDrawValues(true);
set_wind_direction.setFillAlpha(65);
set_wind_direction.setFillColor(ColorTemplate.getHoloBlue());
set_wind_direction.setHighLightColor(Color.rgb(244, 117, 117));
set_wind_direction.setDrawCircleHole(false);
// create a data object with the data sets
LineData line_data = new LineData();
line_data.addDataSet(set_wind_direction);
line_data.setValueTextColor(Color.WHITE);
line_data.setValueTextSize(9f);
// set data
chart.setData(line_data);
chart.setDoubleTapToZoomEnabled(false);
chart.setOnChartValueSelectedListener(plotClickEvent);
}
}
/**
* Downloads the data from the web service and stores it as entries ready to be displayed on the
* plot. Web Service gives the data with the epoch timestamp in second resolution, but the plot
* shows the data in millisecond resolution
*/
private void downloadDataFromWebservice() {
ListOfStationData data = lastStationDataDao.getLastStationData(station.getSystemName());
valuesWindDirection = new ArrayList<>();
if (data instanceof ListOfStationData) {
for (StationData d : data.listOfStationData) {
valuesWindDirection.add(new Entry(d.epoch * 1000, d.winddir));
}
}
}
public StationDetailsPlotsDirection() {
lastStationDataDao = new LastStationDataDao();
plotClickEvent = new PlotClickEvent(this);
}
}

Wyświetl plik

@ -0,0 +1,329 @@
package cc.pogoda.mobile.pogodacc.activity;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IFillFormatter;
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import java.util.ArrayList;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.pogodacc.config.AppConfiguration;
import cc.pogoda.mobile.pogodacc.dao.LastStationDataDao;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.type.web.StationData;
public class StationDetailsPlotsTemperature extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
WeatherStation station = null;
private LineChart chart = null;
private SeekBar seekBarX = null;
private TextView textViewTimestamp = null;
private TextView textViewSpeed = null;
private ArrayList<Entry> valuesTemperature;
private LastStationDataDao lastStationDataDao;
PlotClickEvent clickEvent;
private class ValueFormatter extends com.github.mikephil.charting.formatter.ValueFormatter {
@Override
public String getFormattedValue(float value) {
long millis = (long) value;
// the web service and the plot always stores the entries as UTC. So first convert epoch timestamp to the LocalDateTime
LocalDateTime utcDateTime = LocalDateTime.ofEpochSecond(millis / 1000, 0, ZoneOffset.UTC);
// and then shift to the user timezone for convinient display
ZonedDateTime localDateTime = utcDateTime.atZone(ZoneOffset.UTC).withZoneSameInstant(ZoneId.systemDefault());
// format only the time to keep X axis clean
String dt = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(localDateTime);
return dt;
}
}
public StationDetailsPlotsTemperature() {
valuesTemperature = new ArrayList<Entry>();
lastStationDataDao = new LastStationDataDao();
}
private void downloadDataFromWebservice() {
ListOfStationData data = lastStationDataDao.getLastStationData(station.getSystemName());
if (data instanceof ListOfStationData) {
for (StationData d : data.listOfStationData) {
valuesTemperature.add(new Entry(d.epoch * 1000, d.temperature));
}
}
}
/**
* Updates labels placed at the top of the chart with values at the point selected by an user.
* @param date Date & time string in local timezone
*/
public void updateLabels(String date, Entry entry) {
float temperature = 0.0f;
// get a timestamp from the entry
long timestamp = (long) entry.getX();
// look for the windspeed coresponding to that timestamp
for (Entry e : valuesTemperature) {
// if this is what we are looking for
if (e.getX() == entry.getX()) {
temperature = e.getY();
}
}
// use wind speed label (on the left) to display the temperature
if (this.textViewSpeed != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewSpeed.setText(getString(R.string.temperature) + String.format(": %.1f°C", temperature));
}
else {
return;
}
}
/**
*
* @param from
* @param to
* @param index_or_timestamp if set to false 'to' and 'from' are treated as an index, if they are set
* to true this method will use it as epoch timestamps (in seconds)
*/
public void setData(long from, long to, boolean index_or_timestamp) {
// if only some part of input set needs to be displayed use this intermediate buffer
ArrayList<Entry> narrowed_set, narrowed_set_gusts;
// data set to be
LineDataSet set_temperature;
if (valuesTemperature.size() > 0) {
if (from != 0 || to != 0) {
// if 'from' and 'to' are the index values
if (!index_or_timestamp) {
// make a sublist
narrowed_set = new ArrayList<>(valuesTemperature.subList((int)from, (int)to));
}
else {
// get first and last entry from the set
Entry first = valuesTemperature.get(0);
Entry last = valuesTemperature.get(valuesTemperature.size() - 1 );
// check if 'from' and 'to' timestamp epoch covers any data from the input set
if ( (long)first.getX() > (to * 1000) ||
(long)last.getX() < (from * 1000)) {
// if there is no data to display exit from an function
return;
}
else {
narrowed_set = new ArrayList<>();
narrowed_set_gusts = new ArrayList<>();
// if not copy matching elements to narrowed set
valuesTemperature.forEach((Entry e) -> {
if (e.getX() > (from * 1000) &&
e.getX() < (to * 1000)) {
narrowed_set.add(e);
}
});
}
}
// and generate the set from it
set_temperature = new LineDataSet(narrowed_set, getString(R.string.temperature));
}
else {
// use 'values_wind_speed' directly as a whole
set_temperature = new LineDataSet(valuesTemperature, getString(R.string.temperature));
}
// create a dataset and give it a type
set_temperature.setMode(LineDataSet.Mode.CUBIC_BEZIER); // filled area instead of only line with points
set_temperature.setCubicIntensity(0.2f);
set_temperature.setDrawFilled(true);
set_temperature.setAxisDependency(YAxis.AxisDependency.LEFT);
set_temperature.setColor(ColorTemplate.getHoloBlue());
set_temperature.setValueTextColor(ColorTemplate.getHoloBlue());
set_temperature.setLineWidth(3.5f);
set_temperature.setDrawCircles(false);
set_temperature.setDrawValues(true);
set_temperature.setFillAlpha(65);
set_temperature.setFillColor(ColorTemplate.getHoloBlue());
set_temperature.setHighLightColor(Color.rgb(244, 117, 117));
set_temperature.setDrawCircleHole(false);
set_temperature.setFillFormatter((dataSet, dataProvider) -> 0.0f); // set this to draw an area between
// the line and zero axis
// create a data object with the data sets
LineData line_data = new LineData();
line_data.addDataSet(set_temperature);
line_data.setValueTextColor(Color.WHITE);
line_data.setValueTextSize(9f);
// set data
chart.setData(line_data);
chart.setDoubleTapToZoomEnabled(false);
chart.setOnChartValueSelectedListener(clickEvent);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// this activity layout is common for all plots
setContentView(R.layout.activity_station_details_plots);
station = (WeatherStation) getIntent().getSerializableExtra("station");
// exit from the function if station object hasn't been added to the intent
if (station == null) {
return;
}
// create click event class
clickEvent = new PlotClickEvent(this);
this.downloadDataFromWebservice();
// window title
setTitle(R.string.wind_direction_plots);
textViewTimestamp = findViewById(R.id.textViewPlotsWindTimestamp);
textViewSpeed = findViewById(R.id.textViewPlotsWindMean);
seekBarX = findViewById(R.id.seekBarPlotsWind);
chart = findViewById(R.id.chartPlotsWind);
// enable scaling and dragging
chart.setDragEnabled(true);
chart.setScaleEnabled(true);
chart.setDrawGridBackground(false);
chart.setHighlightPerDragEnabled(true);
// set an alternative background color
chart.setBackgroundColor(Color.WHITE);
chart.setViewPortOffsets(0f, 0f, 0f, 0f);
// add data
seekBarX.setProgress(100);
seekBarX.setOnSeekBarChangeListener(this);
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM_INSIDE);
xAxis.setTypeface(Typeface.MONOSPACE);
xAxis.setTextSize(10f);
xAxis.setTextColor(Color.WHITE);
xAxis.setDrawAxisLine(false);
xAxis.setDrawGridLines(true);
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setValueFormatter(new StationDetailsPlotsTemperature.ValueFormatter());
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
leftAxis.setTypeface(Typeface.MONOSPACE);
leftAxis.setTextColor(ColorTemplate.getHoloBlue());
leftAxis.setDrawGridLines(true);
leftAxis.setGranularityEnabled(true);
leftAxis.setAxisMinimum(-30.0f);
leftAxis.setAxisMaximum(40.0f);
leftAxis.setYOffset(0.0f);
leftAxis.setTextColor(Color.rgb(255, 192, 56));
YAxis rightAxis = chart.getAxisRight();
rightAxis.setEnabled(false);
int lastDataIndex = valuesTemperature.size() - 1;
// display only the last data (20% of newest data)
this.setData((long) (0.8 * (lastDataIndex)), lastDataIndex, false);
// set bar to maximum value
seekBarX.setProgress(100);
//lastDataIndex = valuesWindSpeed.size() - 1;
}
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// first and last index to display on plot
int first_index = 0, last_index = 0;
// display only 20% of the set at once
int window_size = (int) (valuesTemperature.size() * 0.2f);
last_index = (int) ((seekBarX.getProgress() / 100.0f) * valuesTemperature.size());
first_index = last_index - window_size;
if (first_index < 0) {
first_index = 0;
last_index = window_size;
}
this.setData(first_index, last_index, false);
// redraw
chart.invalidate();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
}

Wyświetl plik

@ -27,13 +27,15 @@ import org.threeten.bp.format.FormatStyle;
import java.util.ArrayList;
import cc.pogoda.mobile.pogodacc.R;
import cc.pogoda.mobile.pogodacc.activity.handler.WindPlotClickEvent;
import cc.pogoda.mobile.pogodacc.activity.handler.PlotClickEvent;
import cc.pogoda.mobile.pogodacc.config.AppConfiguration;
import cc.pogoda.mobile.pogodacc.dao.LastStationDataDao;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.ListOfStationData;
import cc.pogoda.mobile.pogodacc.type.web.StationData;
public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener {
public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener, StationDetailsPlot {
private LineChart chart = null;
private SeekBar seekBarX = null;
@ -44,7 +46,7 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
private LastStationDataDao lastStationDataDao;
private WeatherStation station;
private WindPlotClickEvent plotClickEvent;
private PlotClickEvent plotClickEvent;
private ArrayList<Entry> valuesWindSpeed;
private ArrayList<Entry> valuesWindGusts;
@ -76,7 +78,7 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
public StationDetailsPlotsWind() {
lastStationDataDao = new LastStationDataDao();
plotClickEvent = new WindPlotClickEvent(this);
plotClickEvent = new PlotClickEvent(this);
}
@ -85,7 +87,7 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
int lastDataIndex = 0;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station_details_plots_wind);
setContentView(R.layout.activity_station_details_plots);
station = (WeatherStation) getIntent().getSerializableExtra("station");
@ -94,7 +96,7 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
Typeface tfLight = Typeface.MONOSPACE;
setTitle("LineChartTime");
setTitle(R.string.wind_speed_plots);
textViewTimestamp = findViewById(R.id.textViewPlotsWindTimestamp);
textViewSpeed = findViewById(R.id.textViewPlotsWindMean);
@ -197,6 +199,15 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
float mean = 0.0f;
float gusts = 0.0f;
String unit;
if (AppConfiguration.replaceMsWithKnots) {
unit = getString(R.string.knots);
}
else {
unit = getString(R.string.meters_per_second);
}
// get a timestamp from the entry
long timestamp = (long) entry.getX();
@ -217,8 +228,8 @@ public class StationDetailsPlotsWind extends AppCompatActivity implements SeekBa
if (this.textViewGusts != null && this.textViewSpeed != null && this.textViewTimestamp != null) {
this.textViewTimestamp.setText(date);
this.textViewSpeed.setText(getString(R.string.mean_value_short) + String.format(" %.1f", mean));
this.textViewGusts.setText(getString(R.string.max_value_short) + String.format(" %.1f", gusts));
this.textViewSpeed.setText(getString(R.string.mean_value_short) + String.format(": %.1f%s", mean, unit));
this.textViewGusts.setText(getString(R.string.wind_gust_short) + String.format(": %.1f%s", gusts, unit));
}
else {
return;

Wyświetl plik

@ -46,12 +46,16 @@ public class StationDetailsSummaryActivity extends AppCompatActivity {
elems.humidity_val = findViewById(R.id.textViewHumidityValue);
elems.message = findViewById(R.id.textViewSummaryMessage);
// get the summary data for this station
summary = summary_dao.getStationSummary(station.getSystemName());
elems.updateFromSummary(summary, station.getAvailableParameters());
// create a handler to update station data in background
handler = new Handler();
updater = new StationDetailsValuesUpdater(elems, handler, station.getSystemName());
// create a copy of updater class for this tation
updater = new StationDetailsValuesUpdater(elems, handler, station.getSystemName(), station);
if (handler != null && updater != null) {
handler.post(updater);

Wyświetl plik

@ -59,7 +59,7 @@ public class StationDetailsWindRoseActivity extends AppCompatActivity {
elements.updateFromSummary(summary, station.getAvailableParameters());
handler = new Handler();
updater = new StationDetailsValuesUpdater(elements, handler, station.getSystemName());
updater = new StationDetailsValuesUpdater(elements, handler, station.getSystemName(), station);
if (handler != null && updater != null) {
// start the handler to update the wind rose activity in background

Wyświetl plik

@ -11,16 +11,15 @@ import org.threeten.bp.ZonedDateTime;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle;
import java.text.SimpleDateFormat;
import java.util.Date;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsWind;
import cc.pogoda.mobile.pogodacc.type.StationDetailsPlot;
public class WindPlotClickEvent implements OnChartValueSelectedListener {
public class PlotClickEvent implements OnChartValueSelectedListener {
private StationDetailsPlotsWind parent;
private StationDetailsPlot parent;
public WindPlotClickEvent(StationDetailsPlotsWind parent) {
public PlotClickEvent(StationDetailsPlot parent) {
this.parent = parent;
}

Wyświetl plik

@ -0,0 +1,31 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsTemperature;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
public class StationDetailsActTemperaturePlotButtonClickEvent implements View.OnClickListener {
WeatherStation station;
AppCompatActivity p;
Intent intent;
@Override
public void onClick(View view) {
intent = new Intent(p, StationDetailsPlotsTemperature.class);
intent.putExtra("station", station);
p.startActivity(intent);
}
public StationDetailsActTemperaturePlotButtonClickEvent(WeatherStation wx, AppCompatActivity parent) {
station = wx;
p = parent;
}
}

Wyświetl plik

@ -0,0 +1,33 @@
package cc.pogoda.mobile.pogodacc.activity.handler;
import android.content.Intent;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsDirection;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsTemperature;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
public class StationDetailsActWindDirectionPlotsButtonClickEvent implements View.OnClickListener {
WeatherStation station;
AppCompatActivity p;
Intent intent;
@Override
public void onClick(View view) {
intent = new Intent(p, StationDetailsPlotsDirection.class);
intent.putExtra("station", station);
p.startActivity(intent);
}
public StationDetailsActWindDirectionPlotsButtonClickEvent(WeatherStation wx, AppCompatActivity parent) {
station = wx;
p = parent;
}
}

Wyświetl plik

@ -8,7 +8,7 @@ import androidx.appcompat.app.AppCompatActivity;
import cc.pogoda.mobile.pogodacc.activity.StationDetailsPlotsWind;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
public class StationDetailsActPlotsButtonClickEvent implements View.OnClickListener {
public class StationDetailsActWindSpeedPlotsButtonClickEvent implements View.OnClickListener {
WeatherStation station;
@ -16,7 +16,7 @@ public class StationDetailsActPlotsButtonClickEvent implements View.OnClickListe
Intent intent;
public StationDetailsActPlotsButtonClickEvent(WeatherStation wx, AppCompatActivity parent) {
public StationDetailsActWindSpeedPlotsButtonClickEvent(WeatherStation wx, AppCompatActivity parent) {
station = wx;
p = parent;

Wyświetl plik

@ -5,12 +5,14 @@ import android.os.Handler;
import cc.pogoda.mobile.pogodacc.dao.SummaryDao;
import cc.pogoda.mobile.pogodacc.type.StationActivityElements;
import cc.pogoda.mobile.pogodacc.type.StationSummaryActElements;
import cc.pogoda.mobile.pogodacc.type.WeatherStation;
import cc.pogoda.mobile.pogodacc.type.web.Summary;
/**
* Class used to update the content of Wind Rose Activity
* Class used to update the content of StationDetailsSummaryActivity and
* StationDetailsWindRoseActivity
*/
public class StationDetailsValuesUpdater implements Runnable {
@ -24,10 +26,13 @@ public class StationDetailsValuesUpdater implements Runnable {
String station_name;
public StationDetailsValuesUpdater(StationActivityElements elems, Handler h, String s) {
WeatherStation station;
public StationDetailsValuesUpdater(StationActivityElements elems, Handler h, String station_name, WeatherStation station) {
elements = elems;
handler = h;
station_name = s;
this.station_name = station_name;
this.station = station;
dao = new SummaryDao();
}
@ -44,7 +49,7 @@ public class StationDetailsValuesUpdater implements Runnable {
station_summary = dao.getStationSummary(station_name);
// null check is done inside this call
elements.updateFromSummary(station_summary);
elements.updateFromSummary(station_summary, station.getAvailableParameters());
handler.postDelayed(this, 90000);
}

Wyświetl plik

@ -0,0 +1,6 @@
package cc.pogoda.mobile.pogodacc.config;
public class AppConfiguration {
public static boolean replaceMsWithKnots = false;
}

Wyświetl plik

@ -8,6 +8,9 @@ import cc.pogoda.mobile.pogodacc.web.RestClientConfig;
import cc.pogoda.mobile.pogodacc.web.SummaryConsumer;
import retrofit2.Response;
/**
* This DAO downloads the measurements summary data for wx station given by its name
*/
public class SummaryDao {
RestClientConfig restClient;
@ -20,8 +23,10 @@ public class SummaryDao {
@Override
public void run() {
// create a new instance of factory class. This could be refactored to static invocation
restClient = new RestClientConfig();
// create a new instance of Retrofit with OkHttp client with GSON parser
SummaryConsumer consumer = restClient.getWeatherStationClient().create(SummaryConsumer.class);
try {
@ -43,15 +48,20 @@ public class SummaryDao {
worker.start();
try {
// wait for the web service response
worker.join();
// check if web service returned anything
if (response != null) {
// if yes get the response body
out = response.body();
if (out != null) {
// convert all quality factors from string representation to native format
out.temperature_qf_native = QualityFactor.valueOf(out.temperature_qf);
out.wind_qf_native = QualityFactor.valueOf(out.wind_qf);
out.humidity_qf_native = QualityFactor.valueOf(out.humidity_qf);
out.qnh_qf_native = QualityFactor.valueOf(out.qnh_qf);
}
}
} catch (InterruptedException e) {

Wyświetl plik

@ -1,8 +1,10 @@
package cc.pogoda.mobile.pogodacc.type;
import java.io.Serializable;
import cc.pogoda.mobile.pogodacc.type.web.StationDefinition;
public class AvailableParameters {
public class AvailableParameters implements Serializable {
public boolean windSpeed;

Wyświetl plik

@ -0,0 +1,8 @@
package cc.pogoda.mobile.pogodacc.type;
import com.github.mikephil.charting.data.Entry;
public interface StationDetailsPlot {
void updateLabels(String date, Entry entry);
}

Wyświetl plik

@ -135,7 +135,7 @@ public class StationSummaryActElements implements StationActivityElements {
else {
temperature_val.setText("---");
}
// TODO
if (!s.qnh_qf_native.equals(QualityFactor.NOT_AVALIABLE) && enabledForStation.qnh) {
qnh_val.setText(String.format("%d hPa", s.qnh));
}

Wyświetl plik

@ -102,7 +102,7 @@
android:layout_height="611dp">
<ImageButton
android:id="@+id/imageButtonPlotsWind"
android:id="@+id/imageButtonWindRose"
android:layout_width="176dp"
android:layout_height="180dp"
android:backgroundTint="#56039BE5"
@ -113,26 +113,25 @@
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.068"
app:layout_constraintHorizontal_bias="0.931"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.475"
app:srcCompat="@drawable/ic_baseline_equalizer_24" />
app:layout_constraintVertical_bias="0.037"
app:srcCompat="@drawable/ic_wind_rose_compass_svgrepo_com" />
<TextView
android:id="@+id/textViewPlots"
android:layout_width="128dp"
android:layout_height="24dp"
android:layout_marginStart="55dp"
android:layout_marginTop="141dp"
android:layout_marginEnd="59dp"
android:layout_marginBottom="15dp"
android:text="@string/wind_speed_plots"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="@+id/imageButtonPlotsWind"
app:layout_constraintEnd_toEndOf="@+id/imageButtonPlotsWind"
app:layout_constraintStart_toStartOf="@+id/imageButtonPlotsWind"
app:layout_constraintTop_toTopOf="@+id/imageButtonPlotsWind" />
android:id="@+id/textViewWindRose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="57dp"
android:layout_marginTop="142dp"
android:layout_marginEnd="61dp"
android:layout_marginBottom="19dp"
android:text="@string/wind_rose"
app:layout_constraintBottom_toBottomOf="@+id/imageButtonWindRose"
app:layout_constraintEnd_toEndOf="@+id/imageButtonWindRose"
app:layout_constraintStart_toStartOf="@+id/imageButtonWindRose"
app:layout_constraintTop_toTopOf="@+id/imageButtonWindRose" />
<ImageButton
android:id="@+id/imageButtonCurrent"
@ -152,24 +151,6 @@
app:layout_constraintVertical_bias="0.037"
app:srcCompat="@drawable/ic_baseline_timer_24" />
<ImageButton
android:id="@+id/imageButtonWindRose"
android:layout_width="176dp"
android:layout_height="180dp"
android:backgroundTint="#56039BE5"
android:paddingLeft="100px"
android:paddingTop="100px"
android:paddingRight="100px"
android:paddingBottom="100px"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.931"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.037"
app:srcCompat="@drawable/ic_wind_rose_compass_svgrepo_com" />
<TextView
android:id="@+id/textViewCurrent"
android:layout_width="131dp"
@ -185,19 +166,138 @@
app:layout_constraintStart_toStartOf="@+id/imageButtonCurrent"
app:layout_constraintTop_toTopOf="@+id/imageButtonCurrent" />
<ImageButton
android:id="@+id/imageButtonPlotsTemperature"
android:layout_width="176dp"
android:layout_height="180dp"
android:backgroundTint="#56039BE5"
android:paddingLeft="100px"
android:paddingTop="100px"
android:paddingRight="100px"
android:paddingBottom="100px"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.068"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.475"
app:srcCompat="@drawable/ic_baseline_equalizer_24" />
<TextView
android:id="@+id/textViewWindRose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="57dp"
android:layout_marginTop="142dp"
android:layout_marginEnd="61dp"
android:layout_marginBottom="19dp"
android:text="@string/wind_rose"
app:layout_constraintBottom_toBottomOf="@+id/imageButtonWindRose"
app:layout_constraintEnd_toEndOf="@+id/imageButtonWindRose"
app:layout_constraintStart_toStartOf="@+id/imageButtonWindRose"
app:layout_constraintTop_toTopOf="@+id/imageButtonWindRose" />
android:id="@+id/textViewPlotsTemperature"
android:layout_width="128dp"
android:layout_height="24dp"
android:layout_marginStart="55dp"
android:layout_marginTop="141dp"
android:layout_marginEnd="59dp"
android:layout_marginBottom="15dp"
android:text="@string/temperature_plot"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="@+id/imageButtonPlotsTemperature"
app:layout_constraintEnd_toEndOf="@+id/imageButtonPlotsTemperature"
app:layout_constraintStart_toStartOf="@+id/imageButtonPlotsTemperature"
app:layout_constraintTop_toTopOf="@+id/imageButtonPlotsTemperature" />
<ImageButton
android:id="@+id/imageButtonPlotsHumidity"
android:layout_width="176dp"
android:layout_height="180dp"
android:backgroundTint="#56039BE5"
android:paddingLeft="100px"
android:paddingTop="100px"
android:paddingRight="100px"
android:paddingBottom="100px"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.931"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.475"
app:srcCompat="@drawable/ic_baseline_equalizer_24" />
<TextView
android:id="@+id/textViewPlotsHumidity"
android:layout_width="128dp"
android:layout_height="24dp"
android:layout_marginStart="55dp"
android:layout_marginTop="141dp"
android:layout_marginEnd="59dp"
android:layout_marginBottom="15dp"
android:text="@string/humidity_plot"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="@id/imageButtonPlotsHumidity"
app:layout_constraintEnd_toEndOf="@id/imageButtonPlotsHumidity"
app:layout_constraintStart_toStartOf="@id/imageButtonPlotsHumidity"
app:layout_constraintTop_toTopOf="@id/imageButtonPlotsHumidity" />
<ImageButton
android:id="@+id/imageButtonPlotsWindSpeed"
android:layout_width="176dp"
android:layout_height="180dp"
android:backgroundTint="#56039BE5"
android:paddingLeft="100px"
android:paddingTop="100px"
android:paddingRight="100px"
android:paddingBottom="100px"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.068"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.915"
app:srcCompat="@drawable/ic_baseline_equalizer_24" />
<TextView
android:id="@+id/textViewPlotsWindSpeed"
android:layout_width="128dp"
android:layout_height="24dp"
android:layout_marginStart="55dp"
android:layout_marginTop="141dp"
android:layout_marginEnd="59dp"
android:layout_marginBottom="15dp"
android:text="@string/wind_speed_plots"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="@id/imageButtonPlotsWindSpeed"
app:layout_constraintEnd_toEndOf="@id/imageButtonPlotsWindSpeed"
app:layout_constraintStart_toStartOf="@id/imageButtonPlotsWindSpeed"
app:layout_constraintTop_toTopOf="@id/imageButtonPlotsWindSpeed" />
<ImageButton
android:id="@+id/imageButtonPlotsWindDirection"
android:layout_width="176dp"
android:layout_height="180dp"
android:backgroundTint="#56039BE5"
android:paddingLeft="100px"
android:paddingTop="100px"
android:paddingRight="100px"
android:paddingBottom="100px"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.931"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.915"
app:srcCompat="@drawable/ic_baseline_equalizer_24" />
<TextView
android:id="@+id/textViewPlotsWindDirection"
android:layout_width="128dp"
android:layout_height="24dp"
android:layout_marginStart="55dp"
android:layout_marginTop="141dp"
android:layout_marginEnd="59dp"
android:layout_marginBottom="15dp"
android:text="@string/wind_direction_plots"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="@id/imageButtonPlotsWindDirection"
app:layout_constraintEnd_toEndOf="@id/imageButtonPlotsWindDirection"
app:layout_constraintStart_toStartOf="@id/imageButtonPlotsWindDirection"
app:layout_constraintTop_toTopOf="@id/imageButtonPlotsWindDirection" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

Wyświetl plik

@ -21,7 +21,7 @@
android:layout_marginRight="10dp"
android:layout_marginBottom="15dp"
android:gravity="right"
android:text="testproba123"
android:text="@string/click_on_plot"
android:textAlignment="center"
android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceMedium"
@ -36,7 +36,6 @@
android:layout_marginRight="10dp"
android:layout_marginBottom="15dp"
android:gravity="right"
android:text="Avg:"
android:textAlignment="textStart"
android:textAllCaps="false"
android:textAppearance="?android:attr/textAppearanceMedium"
@ -51,7 +50,6 @@
android:layout_marginRight="10dp"
android:layout_marginBottom="15dp"
android:gravity="right"
android:text="Max:"
android:textAlignment="textEnd"
android:textAllCaps="false"
android:textAppearance="?android:attr/textAppearanceMedium"

Wyświetl plik

@ -66,4 +66,5 @@
<string name="temperature_plot">Temperature Plot</string>
<string name="humidity_plot">Humidity Plot</string>
<string name="station_doesnt_measure">The station doesn\'t measure this parameter</string>
<string name="click_on_plot">Click on point on the plot</string>
</resources>

Wyświetl plik

@ -66,4 +66,5 @@
<string name="temperature_plot">-</string>
<string name="humidity_plot">-</string>
<string name="station_doesnt_measure">-</string>
<string name="click_on_plot">-</string>
</resources>

Wyświetl plik

@ -66,5 +66,6 @@
<string name="temperature_plot">-</string>
<string name="humidity_plot">-</string>
<string name="station_doesnt_measure">-</string>
<string name="click_on_plot">-</string>
</resources>

Wyświetl plik

@ -66,4 +66,5 @@
<string name="temperature_plot">Temperatura</string>
<string name="humidity_plot">Wilgotność</string>
<string name="station_doesnt_measure">Stacja nie mierzy tego parametru</string>
<string name="click_on_plot">Kliknij na punkt na wykresie</string>
</resources>

Wyświetl plik

@ -66,4 +66,5 @@
<string name="temperature_plot">Temperatura</string>
<string name="humidity_plot">Wilgotność</string>
<string name="station_doesnt_measure">Stacja nie mierzy tego parametru</string>
<string name="click_on_plot">Kliknij na punkt na wykresie</string>
</resources>

Wyświetl plik

@ -70,4 +70,7 @@
<string name="temperature_plot">Temperature Plot</string>
<string name="humidity_plot">Humidity Plot</string>
<string name="station_doesnt_measure">The station doesn\'t measure this parameter</string>
<string name="meters_per_second" translatable="false">m/s</string>
<string name="knots" translatable="false">kts</string>
<string name="click_on_plot">Click on point on the plot</string>
</resources>