Completed 5, 6, 7 tasks
This commit is contained in:
parent
e65180b143
commit
39447cc237
@ -15,6 +15,12 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.AirQuality"
|
android:theme="@style/Theme.AirQuality"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name=".SearchCityActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
<activity
|
||||||
|
android:name=".FavoritesActivity"
|
||||||
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".DetailsActivity"
|
android:name=".DetailsActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|||||||
@ -5,12 +5,6 @@ import android.os.Bundle;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.graphics.Insets;
|
|
||||||
import androidx.core.view.ViewCompat;
|
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
|
||||||
|
|
||||||
import com.android.volley.RequestQueue;
|
import com.android.volley.RequestQueue;
|
||||||
import com.android.volley.VolleyError;
|
import com.android.volley.VolleyError;
|
||||||
import com.android.volley.toolbox.Volley;
|
import com.android.volley.toolbox.Volley;
|
||||||
@ -18,16 +12,10 @@ import com.bumptech.glide.Glide;
|
|||||||
import com.example.airquality.api.ForecastAPIRequest;
|
import com.example.airquality.api.ForecastAPIRequest;
|
||||||
import com.example.airquality.databinding.ActivityDetailsBinding;
|
import com.example.airquality.databinding.ActivityDetailsBinding;
|
||||||
import com.example.airquality.types.City;
|
import com.example.airquality.types.City;
|
||||||
import com.example.airquality.types.FormattedTemp;
|
import com.example.airquality.types.FormattedTemperature;
|
||||||
import com.example.airquality.types.Weather3h;
|
import com.example.airquality.types.Weather3h;
|
||||||
import com.example.airquality.utils.PreferencesManager;
|
import com.example.airquality.utils.PreferencesManager;
|
||||||
import com.example.airquality.utils.ToolbarCompatActivity;
|
import com.example.airquality.utils.ToolbarCompatActivity;
|
||||||
import com.example.airquality.utils.Weather3hAdapter;
|
|
||||||
import com.example.airquality.utils.Weather3hParser;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class DetailsActivity extends ToolbarCompatActivity {
|
public class DetailsActivity extends ToolbarCompatActivity {
|
||||||
|
|
||||||
@ -54,7 +42,7 @@ public class DetailsActivity extends ToolbarCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateData() {
|
protected void updateData() {
|
||||||
FormattedTemp formattedTemp = weather3h.formattedTemp(this);
|
FormattedTemperature formattedTemperature = weather3h.formattedTemp(this);
|
||||||
|
|
||||||
if(checkInternet())
|
if(checkInternet())
|
||||||
{
|
{
|
||||||
@ -70,10 +58,10 @@ public class DetailsActivity extends ToolbarCompatActivity {
|
|||||||
binding.iconCode.setText(weather3h.getIconCode());
|
binding.iconCode.setText(weather3h.getIconCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.cityText.setText(city.name);
|
binding.cityText.setText(city.toString());
|
||||||
binding.datetimeText.setText(weather3h.getDateTime());
|
binding.datetimeText.setText(weather3h.getDateTime());
|
||||||
binding.tempWeatherText.setText(formattedTemp.tempText + " | " + weather3h.getDescription());
|
binding.tempWeatherText.setText(formattedTemperature.tempText + " | " + weather3h.getDescription());
|
||||||
binding.tempText.setText(formattedTemp.tempMinText + " ~ " + formattedTemp.tempMaxText);
|
binding.tempText.setText(formattedTemperature.tempMinText + " ~ " + formattedTemperature.tempMaxText);
|
||||||
binding.pressureText.setText(weather3h.getPressure() + " hPa");
|
binding.pressureText.setText(weather3h.getPressure() + " hPa");
|
||||||
binding.humidityText.setText(weather3h.getHumidity() + "%");
|
binding.humidityText.setText(weather3h.getHumidity() + "%");
|
||||||
binding.windSpeedText.setText(weather3h.getWindSpeed() + " m/s");
|
binding.windSpeedText.setText(weather3h.getWindSpeed() + " m/s");
|
||||||
@ -81,6 +69,11 @@ public class DetailsActivity extends ToolbarCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRefreshOptionToolbar() {
|
protected void onRefreshOptionToolbar() {
|
||||||
|
if(!checkInternet()) {
|
||||||
|
Toast.makeText(this, "You can't load data from internet on offline mode", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String units = PreferencesManager.getUnits(this);
|
String units = PreferencesManager.getUnits(this);
|
||||||
RequestQueue queue = Volley.newRequestQueue(this);
|
RequestQueue queue = Volley.newRequestQueue(this);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,81 @@
|
|||||||
|
package com.example.airquality;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.EdgeToEdge;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.graphics.Insets;
|
||||||
|
import androidx.core.view.ViewCompat;
|
||||||
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
|
import com.example.airquality.databinding.ActivityFavoritesBinding;
|
||||||
|
import com.example.airquality.types.City;
|
||||||
|
import com.example.airquality.utils.BaseCompatActivity;
|
||||||
|
import com.example.airquality.utils.CityAdapter;
|
||||||
|
import com.example.airquality.utils.PreferencesManager;
|
||||||
|
import com.example.airquality.utils.Weather3hAdapter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FavoritesActivity extends BaseCompatActivity {
|
||||||
|
|
||||||
|
private ActivityFavoritesBinding binding;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
EdgeToEdge.enable(this);
|
||||||
|
|
||||||
|
binding = ActivityFavoritesBinding.inflate(getLayoutInflater());
|
||||||
|
View view = binding.getRoot();
|
||||||
|
setContentView(view);
|
||||||
|
|
||||||
|
binding.cityFavoriteList.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
}
|
||||||
|
public void onSearchActivityBtn(View view) {
|
||||||
|
Intent intent = new Intent(this, SearchCityActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
loadFavoriteList();
|
||||||
|
}
|
||||||
|
private City[] getFavoriteList()
|
||||||
|
{
|
||||||
|
// Get from db
|
||||||
|
City[] cities = new City[] {
|
||||||
|
new City("Belgrade", "RS", 44.7866, 20.4489, "2025-07-04 12:30"),
|
||||||
|
new City("Novi Sad", "RS", 45.2671, 19.8335, "2025-07-03 09:15"),
|
||||||
|
new City("Niš", "RS", 43.3209, 21.8958, "2025-07-02 18:45"),
|
||||||
|
new City("Subotica", "RS", 46.1000, 19.6667, "2025-07-01 14:10"),
|
||||||
|
new City("Kragujevac", "RS", 44.0128, 20.9110, "2025-06-30 07:50")
|
||||||
|
};
|
||||||
|
|
||||||
|
return cities;
|
||||||
|
}
|
||||||
|
private void setEnteredDateTime(City city) {
|
||||||
|
// Search one item by city.name and change for him enteredAt to now()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadFavoriteList() {
|
||||||
|
List<City> cities = Arrays.asList(getFavoriteList());
|
||||||
|
|
||||||
|
CityAdapter adapter = new CityAdapter(this, cities) {
|
||||||
|
@Override
|
||||||
|
public void onSelectCity(City city) {
|
||||||
|
PreferencesManager.setCity(FavoritesActivity.this, city);
|
||||||
|
setEnteredDateTime(city);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
binding.cityFavoriteList.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,23 +1,15 @@
|
|||||||
package com.example.airquality;
|
package com.example.airquality;
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.android.volley.Request;
|
|
||||||
import com.android.volley.RequestQueue;
|
import com.android.volley.RequestQueue;
|
||||||
import com.android.volley.Response;
|
|
||||||
import com.android.volley.VolleyError;
|
import com.android.volley.VolleyError;
|
||||||
import com.android.volley.toolbox.JsonObjectRequest;
|
|
||||||
import com.android.volley.toolbox.Volley;
|
import com.android.volley.toolbox.Volley;
|
||||||
import com.example.airquality.api.ForecastAPIRequest;
|
import com.example.airquality.api.ForecastAPIRequest;
|
||||||
import com.example.airquality.types.City;
|
import com.example.airquality.types.City;
|
||||||
@ -25,30 +17,15 @@ import com.example.airquality.types.Weather3h;
|
|||||||
import com.example.airquality.utils.PreferencesManager;
|
import com.example.airquality.utils.PreferencesManager;
|
||||||
import com.example.airquality.utils.ToolbarCompatActivity;
|
import com.example.airquality.utils.ToolbarCompatActivity;
|
||||||
import com.example.airquality.utils.Weather3hAdapter;
|
import com.example.airquality.utils.Weather3hAdapter;
|
||||||
import com.example.airquality.utils.Weather3hParser;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class MainActivity extends ToolbarCompatActivity {
|
public class MainActivity extends ToolbarCompatActivity {
|
||||||
List<Weather3h> prognoza;
|
List<Weather3h> prognoza;
|
||||||
|
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
|
|
||||||
private static final Map<String, double[]> cityCoordinates = new HashMap<>();
|
|
||||||
static {
|
|
||||||
cityCoordinates.put("Subotica", new double[]{46.1, 19.6667});
|
|
||||||
cityCoordinates.put("Novi Sad", new double[]{45.2517, 19.8369});
|
|
||||||
cityCoordinates.put("Beograd", new double[]{44.804, 20.4651});
|
|
||||||
cityCoordinates.put("San Francisko", new double[]{37.7749, -122.4194});
|
|
||||||
cityCoordinates.put("Sidnej", new double[]{-33.8679, 151.2073});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -61,13 +38,26 @@ public class MainActivity extends ToolbarCompatActivity {
|
|||||||
initToolbar();
|
initToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
loadForecast();
|
loadForecast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveOffline(Weather3h[] weathers) {
|
||||||
|
// Save to db
|
||||||
|
}
|
||||||
|
private Weather3h[] loadOffline() {
|
||||||
|
// Load from db
|
||||||
|
return new Weather3h[] { };
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRefreshOptionToolbar() {
|
protected void onRefreshOptionToolbar() {
|
||||||
|
if(!checkInternet()) {
|
||||||
|
Toast.makeText(MainActivity.this, "You can't load data from internet on offline mode", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
loadForecast(true);
|
loadForecast(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,10 +69,18 @@ public class MainActivity extends ToolbarCompatActivity {
|
|||||||
int days = PreferencesManager.getDays(this);
|
int days = PreferencesManager.getDays(this);
|
||||||
String units = PreferencesManager.getUnits(this);
|
String units = PreferencesManager.getUnits(this);
|
||||||
|
|
||||||
setToolbarTitle(city.name);
|
|
||||||
|
|
||||||
if (city == null) {
|
if (city == null) {
|
||||||
Toast.makeText(this, "Unknown city: " + city.name, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "Unknown city", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolbarTitle(city.toString());
|
||||||
|
|
||||||
|
// If no internet
|
||||||
|
if(!checkInternet()) {
|
||||||
|
displayRecycler(loadOffline(), city, days);
|
||||||
|
Toast.makeText(MainActivity.this, "You are on offline mode", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +89,12 @@ public class MainActivity extends ToolbarCompatActivity {
|
|||||||
ForecastAPIRequest forecastAPI = new ForecastAPIRequest(this, city, units) {
|
ForecastAPIRequest forecastAPI = new ForecastAPIRequest(this, city, units) {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Weather3h[] weatherList) {
|
public void onSuccess(Weather3h[] weatherList) {
|
||||||
Weather3h[] arr = Arrays.copyOfRange(weatherList, 0, days);
|
displayRecycler(weatherList, city, days);
|
||||||
prognoza = Arrays.asList(arr);
|
|
||||||
|
|
||||||
Weather3hAdapter adapter = new Weather3hAdapter(MainActivity.this, prognoza, city);
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
|
|
||||||
if(isUpdated)
|
if(isUpdated)
|
||||||
Toast.makeText(MainActivity.this, "List Updated!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(MainActivity.this, "List Updated!", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
saveOffline(weatherList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -109,4 +105,16 @@ public class MainActivity extends ToolbarCompatActivity {
|
|||||||
|
|
||||||
queue.add(forecastAPI.getRequest());
|
queue.add(forecastAPI.getRequest());
|
||||||
}
|
}
|
||||||
|
private void displayRecycler(Weather3h[] weathers, City city, int days) {
|
||||||
|
if(weathers.length > 0) {
|
||||||
|
Weather3h[] weatherDaysRange = Arrays.copyOfRange(weathers, 0, days * 8);
|
||||||
|
prognoza = Arrays.asList(weatherDaysRange);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prognoza.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Weather3hAdapter adapter = new Weather3hAdapter(this, prognoza, city);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
package com.example.airquality;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.EdgeToEdge;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.graphics.Insets;
|
||||||
|
import androidx.core.view.ViewCompat;
|
||||||
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
|
import com.android.volley.RequestQueue;
|
||||||
|
import com.android.volley.VolleyError;
|
||||||
|
import com.android.volley.toolbox.Volley;
|
||||||
|
import com.example.airquality.api.CityAPIRequest;
|
||||||
|
import com.example.airquality.databinding.ActivitySearchCityBinding;
|
||||||
|
import com.example.airquality.types.City;
|
||||||
|
import com.example.airquality.utils.BaseCompatActivity;
|
||||||
|
import com.example.airquality.utils.CityAdapter;
|
||||||
|
import com.example.airquality.utils.PreferencesManager;
|
||||||
|
import com.example.airquality.utils.Weather3hAdapter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class SearchCityActivity extends BaseCompatActivity {
|
||||||
|
|
||||||
|
private ActivitySearchCityBinding binding;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
EdgeToEdge.enable(this);
|
||||||
|
|
||||||
|
binding = ActivitySearchCityBinding.inflate(getLayoutInflater());
|
||||||
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
|
binding.citySearchResult.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSearchBtn(View view) {
|
||||||
|
loadCities();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToFavorite(City city) {
|
||||||
|
// Add to db
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCities() {
|
||||||
|
String searchQuery = binding.searchEditText.getText().toString();
|
||||||
|
|
||||||
|
// If no internet
|
||||||
|
if(!checkInternet()) {
|
||||||
|
Toast.makeText(this, "You are on offline mode", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RequestQueue queue = Volley.newRequestQueue(this);
|
||||||
|
|
||||||
|
CityAPIRequest cityAPIRequest = new CityAPIRequest(this, searchQuery) {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(City[] objectList) {
|
||||||
|
CityAdapter adapter = new CityAdapter(SearchCityActivity.this, Arrays.asList(objectList), "Add") {
|
||||||
|
@Override
|
||||||
|
public void onSelectCity(City city) {
|
||||||
|
addToFavorite(city);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
binding.citySearchResult.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(VolleyError error) {
|
||||||
|
Toast.makeText(SearchCityActivity.this, "Failed to load weather data", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
queue.add(cityAPIRequest.getRequest());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,47 +7,35 @@ import android.os.Bundle;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import com.example.airquality.types.City;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.graphics.Insets;
|
|
||||||
import androidx.core.view.ViewCompat;
|
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
|
||||||
|
|
||||||
import com.example.airquality.utils.BaseCompatActivity;
|
import com.example.airquality.utils.BaseCompatActivity;
|
||||||
|
import com.example.airquality.utils.PreferencesManager;
|
||||||
|
|
||||||
public class SettingsActivity extends BaseCompatActivity {
|
public class SettingsActivity extends BaseCompatActivity {
|
||||||
Spinner spinnerCity;
|
Spinner spinnerCity;
|
||||||
RadioGroup radioGroupDays, radioGroupUnits;
|
RadioGroup radioGroupDays, radioGroupUnits;
|
||||||
Button buttonSave;
|
Button buttonSave;
|
||||||
|
TextView cityNameText;
|
||||||
String[] cities = {"Subotica", "Novi Sad", "Beograd", "San Francisko", "Sidnej"};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_settings);
|
setContentView(R.layout.activity_settings);
|
||||||
|
|
||||||
spinnerCity = findViewById(R.id.spinnerCity);
|
|
||||||
radioGroupDays = findViewById(R.id.radioGroupDays);
|
radioGroupDays = findViewById(R.id.radioGroupDays);
|
||||||
radioGroupUnits = findViewById(R.id.radioGroupUnits);
|
radioGroupUnits = findViewById(R.id.radioGroupUnits);
|
||||||
buttonSave = findViewById(R.id.buttonSave);
|
buttonSave = findViewById(R.id.buttonSave);
|
||||||
|
cityNameText = findViewById(R.id.cityName);
|
||||||
// Podesi spinner
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
|
|
||||||
android.R.layout.simple_spinner_item, cities);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
spinnerCity.setAdapter(adapter);
|
|
||||||
|
|
||||||
buttonSave.setOnClickListener(new View.OnClickListener() {
|
buttonSave.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
String selectedCity = spinnerCity.getSelectedItem().toString();
|
|
||||||
|
|
||||||
int days = 7; // podrazumevano
|
int days = 1; // podrazumevano
|
||||||
if (radioGroupDays.getCheckedRadioButtonId() == R.id.radio3days) {
|
if (radioGroupDays.getCheckedRadioButtonId() == R.id.radio3days) {
|
||||||
days = 3;
|
days = 3;
|
||||||
} else if (radioGroupDays.getCheckedRadioButtonId() == R.id.radio5days) {
|
} else if (radioGroupDays.getCheckedRadioButtonId() == R.id.radio5days) {
|
||||||
@ -59,15 +47,22 @@ public class SettingsActivity extends BaseCompatActivity {
|
|||||||
units = "imperial";
|
units = "imperial";
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPreferences prefs = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
|
PreferencesManager.savePreferences(SettingsActivity.this, days, units);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
|
||||||
editor.putString("city", selectedCity);
|
|
||||||
editor.putInt("days", days);
|
|
||||||
editor.putString("units", units);
|
|
||||||
editor.apply();
|
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onFavoriteBtn(View view) {
|
||||||
|
Intent intent = new Intent(this, FavoritesActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
City currentCity = PreferencesManager.getCity(this);
|
||||||
|
cityNameText.setText(currentCity.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.example.airquality.api;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.android.volley.Request;
|
||||||
|
import com.android.volley.Response;
|
||||||
|
import com.android.volley.VolleyError;
|
||||||
|
import com.android.volley.toolbox.JsonArrayRequest;
|
||||||
|
import com.android.volley.toolbox.JsonObjectRequest;
|
||||||
|
import com.example.airquality.types.City;
|
||||||
|
import com.example.airquality.utils.CityParser;
|
||||||
|
import com.example.airquality.utils.Weather3hParser;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class CityAPIRequest extends JsonAPIRequest<City, JsonArrayRequest> {
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public CityAPIRequest(Context context, String query) {
|
||||||
|
super(context);
|
||||||
|
this.url = String.format(
|
||||||
|
"https://api.openweathermap.org/geo/1.0/direct?q=%s&limit=10&appid=%s",
|
||||||
|
query, getKey()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public JsonArrayRequest getRequest() {
|
||||||
|
return new JsonArrayRequest(
|
||||||
|
Request.Method.GET,
|
||||||
|
url,
|
||||||
|
null,
|
||||||
|
new Response.Listener<JSONArray>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(JSONArray response) {
|
||||||
|
onSuccess(CityParser.parse(response));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Response.ErrorListener() {
|
||||||
|
@Override
|
||||||
|
public void onErrorResponse(VolleyError error) {
|
||||||
|
error.printStackTrace();
|
||||||
|
onError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(City[] objectList) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(VolleyError error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class ForecastAPIRequest extends JsonAPIRequest {
|
public class ForecastAPIRequest extends JsonAPIRequest<Weather3h, JsonObjectRequest> {
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
public ForecastAPIRequest(Context context, City city, String units) {
|
public ForecastAPIRequest(Context context, City city, String units) {
|
||||||
@ -49,6 +49,6 @@ public class ForecastAPIRequest extends JsonAPIRequest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSuccess(Weather3h[] weatherList) { }
|
public void onSuccess(Weather3h[] objectList) { }
|
||||||
public void onError(VolleyError error) { }
|
public void onError(VolleyError error) { }
|
||||||
}
|
}
|
||||||
@ -9,12 +9,13 @@ import com.android.volley.VolleyError;
|
|||||||
import com.android.volley.toolbox.JsonObjectRequest;
|
import com.android.volley.toolbox.JsonObjectRequest;
|
||||||
import com.example.airquality.MainActivity;
|
import com.example.airquality.MainActivity;
|
||||||
import com.example.airquality.R;
|
import com.example.airquality.R;
|
||||||
|
import com.example.airquality.types.Weather3h;
|
||||||
import com.example.airquality.utils.Weather3hAdapter;
|
import com.example.airquality.utils.Weather3hAdapter;
|
||||||
import com.example.airquality.utils.Weather3hParser;
|
import com.example.airquality.utils.Weather3hParser;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
public abstract class JsonAPIRequest {
|
public abstract class JsonAPIRequest<T, JR> {
|
||||||
|
|
||||||
private Context appContext;
|
private Context appContext;
|
||||||
protected String url;
|
protected String url;
|
||||||
@ -28,5 +29,8 @@ public abstract class JsonAPIRequest {
|
|||||||
{
|
{
|
||||||
return this.appContext.getString(R.string.weather_api_key);
|
return this.appContext.getString(R.string.weather_api_key);
|
||||||
}
|
}
|
||||||
public abstract JsonObjectRequest getRequest();
|
public abstract JR getRequest();
|
||||||
|
|
||||||
|
public abstract void onSuccess(T[] objectList);
|
||||||
|
public abstract void onError(VolleyError error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,30 @@
|
|||||||
package com.example.airquality.types;
|
package com.example.airquality.types;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class City implements Serializable {
|
public class City implements Serializable {
|
||||||
public String name;
|
public String name;
|
||||||
|
public String country;
|
||||||
public double latitude;
|
public double latitude;
|
||||||
public double longitude;
|
public double longitude;
|
||||||
|
public String lastEnteredAt;
|
||||||
|
|
||||||
public City(String name, double latitude, double longitude) {
|
public City(String name, String country, double latitude, double longitude, String lastEnteredAt) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.country = country;
|
||||||
this.latitude = latitude;
|
this.latitude = latitude;
|
||||||
this.longitude = longitude;
|
this.longitude = longitude;
|
||||||
|
this.lastEnteredAt = lastEnteredAt;
|
||||||
|
}
|
||||||
|
public City(String name, String country, double latitude, double longitude) {
|
||||||
|
this(name, country, latitude, longitude, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name + " (" + this.country + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,18 +2,14 @@ package com.example.airquality.types;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.example.airquality.utils.PreferencesManager;
|
import com.example.airquality.utils.PreferencesManager;
|
||||||
|
|
||||||
import java.util.Objects;
|
public class FormattedTemperature {
|
||||||
|
|
||||||
public class FormattedTemp {
|
|
||||||
public String tempText;
|
public String tempText;
|
||||||
public String tempMinText;
|
public String tempMinText;
|
||||||
public String tempMaxText;
|
public String tempMaxText;
|
||||||
|
|
||||||
public FormattedTemp(Context context, double temp, double tempMin, double tempMax)
|
public FormattedTemperature(Context context, double temp, double tempMin, double tempMax)
|
||||||
{
|
{
|
||||||
String units = PreferencesManager.getUnits(context);
|
String units = PreferencesManager.getUnits(context);
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ public class Weather3h implements Serializable {
|
|||||||
return tempMax;
|
return tempMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FormattedTemp formattedTemp(Context context) {
|
public FormattedTemperature formattedTemp(Context context) {
|
||||||
return new FormattedTemp(context, temp, tempMin, tempMax);
|
return new FormattedTemperature(context, temp, tempMin, tempMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDt() {
|
public int getDt() {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.example.airquality.utils;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
@ -13,4 +14,9 @@ public class BaseCompatActivity extends AppCompatActivity {
|
|||||||
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
|
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
|
||||||
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
|
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onBackButton(View view)
|
||||||
|
{
|
||||||
|
finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,74 @@
|
|||||||
|
package com.example.airquality.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.example.airquality.R;
|
||||||
|
import com.example.airquality.types.City;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CityAdapter extends RecyclerView.Adapter<CityAdapter.CityViewHolder> {
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
private List<City> cityList;
|
||||||
|
private String applyBtnText;
|
||||||
|
|
||||||
|
public CityAdapter(Context context, List<City> cityList) {
|
||||||
|
this(context, cityList, "Select");
|
||||||
|
}
|
||||||
|
public CityAdapter(Context context, List<City> cityList, String applyBtnText) {
|
||||||
|
this.context = context;
|
||||||
|
this.cityList = cityList;
|
||||||
|
this.applyBtnText = applyBtnText;
|
||||||
|
}
|
||||||
|
public static class CityViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView cityName, cityCoords, lastEnteredTime;
|
||||||
|
Button selectBtn;
|
||||||
|
|
||||||
|
public CityViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
cityName = itemView.findViewById(R.id.cityName);
|
||||||
|
cityCoords = itemView.findViewById(R.id.cityCoords);
|
||||||
|
selectBtn = itemView.findViewById(R.id.selectBtn);
|
||||||
|
lastEnteredTime = itemView.findViewById(R.id.lastEnteredTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CityViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(context).inflate(R.layout.item_city, parent, false);
|
||||||
|
return new CityViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(CityViewHolder holder, int position) {
|
||||||
|
City item = cityList.get(position);
|
||||||
|
holder.cityName.setText(item.toString());
|
||||||
|
holder.cityCoords.setText(
|
||||||
|
"Long: " + String.format("%.3f", item.longitude) + ", Lat: " + String.format("%.3f", item.latitude));
|
||||||
|
holder.lastEnteredTime.setText(item.lastEnteredAt);
|
||||||
|
|
||||||
|
holder.selectBtn.setText(this.applyBtnText);
|
||||||
|
|
||||||
|
holder.selectBtn.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onSelectCity(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return cityList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSelectCity(City city) { }
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package com.example.airquality.utils;
|
||||||
|
|
||||||
|
import com.example.airquality.types.City;
|
||||||
|
import com.example.airquality.types.Weather3h;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CityParser {
|
||||||
|
public static City[] parse(JSONArray jsonArray) {
|
||||||
|
List<City> cities = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for(int i = 0; i < jsonArray.length(); i++) {
|
||||||
|
JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||||
|
|
||||||
|
String cityName = jsonObject.getString("name");
|
||||||
|
double lon = jsonObject.getDouble("lon");
|
||||||
|
double lat = jsonObject.getDouble("lat");
|
||||||
|
String countryName = jsonObject.getString("country");
|
||||||
|
|
||||||
|
City city = new City(cityName, countryName, lat, lon);
|
||||||
|
cities.add(city);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cities.toArray(new City[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@ public class PreferencesManager {
|
|||||||
private static final String KEY_DAYS = "days";
|
private static final String KEY_DAYS = "days";
|
||||||
private static final String KEY_UNITS = "units";
|
private static final String KEY_UNITS = "units";
|
||||||
|
|
||||||
public static void savePreferences(Context context, String city, int days, String units) {
|
public static void savePreferences(Context context, int days, String units) {
|
||||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
editor.putInt(KEY_DAYS, days);
|
editor.putInt(KEY_DAYS, days);
|
||||||
@ -20,13 +20,28 @@ public class PreferencesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static City getCity(Context context) {
|
public static City getCity(Context context) {
|
||||||
// DAVID: Realizovati iz sqlite
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
return new City("Subotica", 46.1, 19.6667);
|
String cityName = prefs.getString("city_name", "Subotica");
|
||||||
|
String country = prefs.getString("city_country", "RS");
|
||||||
|
double longitude = prefs.getFloat("city_longitude", 46.1f);
|
||||||
|
double latitude = prefs.getFloat("city_latitude", 19.6667f);
|
||||||
|
|
||||||
|
return new City(cityName, country, longitude, latitude);
|
||||||
|
}
|
||||||
|
public static void setCity(Context context, City city) {
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
|
||||||
|
editor.putString("city_name", city.name);
|
||||||
|
editor.putString("city_country", city.country);
|
||||||
|
editor.putFloat("city_longitude", (float)city.longitude);
|
||||||
|
editor.putFloat("city_latitude", (float)city.latitude);
|
||||||
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getDays(Context context) {
|
public static int getDays(Context context) {
|
||||||
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
return prefs.getInt(KEY_DAYS, 7); // default: 7 dana
|
return prefs.getInt(KEY_DAYS, 1); // default: 1 dana
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getUnits(Context context) {
|
public static String getUnits(Context context) {
|
||||||
|
|||||||
@ -5,17 +5,14 @@ import android.content.Intent;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.BaseAdapter;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.example.airquality.DetailsActivity;
|
import com.example.airquality.DetailsActivity;
|
||||||
import com.example.airquality.MainActivity;
|
|
||||||
import com.example.airquality.R;
|
import com.example.airquality.R;
|
||||||
import com.example.airquality.types.City;
|
import com.example.airquality.types.City;
|
||||||
import com.example.airquality.types.FormattedTemp;
|
import com.example.airquality.types.FormattedTemperature;
|
||||||
import com.example.airquality.types.Weather3h;
|
import com.example.airquality.types.Weather3h;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -31,8 +28,6 @@ public class Weather3hAdapter extends RecyclerView.Adapter<Weather3hAdapter.Weat
|
|||||||
this.weatherList = weatherList;
|
this.weatherList = weatherList;
|
||||||
this.city = city;
|
this.city = city;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ViewHolder описывает и хранит ссылки на элементы layout
|
|
||||||
public static class WeatherViewHolder extends RecyclerView.ViewHolder {
|
public static class WeatherViewHolder extends RecyclerView.ViewHolder {
|
||||||
TextView txtDate, txtTemp, txtDesc;
|
TextView txtDate, txtTemp, txtDesc;
|
||||||
|
|
||||||
@ -53,10 +48,10 @@ public class Weather3hAdapter extends RecyclerView.Adapter<Weather3hAdapter.Weat
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(WeatherViewHolder holder, int position) {
|
public void onBindViewHolder(WeatherViewHolder holder, int position) {
|
||||||
Weather3h item = weatherList.get(position);
|
Weather3h item = weatherList.get(position);
|
||||||
FormattedTemp formattedTemp = item.formattedTemp(context);
|
FormattedTemperature formattedTemperature = item.formattedTemp(context);
|
||||||
|
|
||||||
holder.txtDate.setText(item.getDateTime());
|
holder.txtDate.setText(item.getDateTime());
|
||||||
holder.txtTemp.setText(formattedTemp.tempText);
|
holder.txtTemp.setText(formattedTemperature.tempText);
|
||||||
holder.txtDesc.setText(item.getDescription());
|
holder.txtDesc.setText(item.getDescription());
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
|||||||
5
app/src/main/res/drawable/baseline_arrow_back.xml
Normal file
5
app/src/main/res/drawable/baseline_arrow_back.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||||
|
|
||||||
|
</vector>
|
||||||
@ -17,6 +17,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/include_toolbar"
|
app:layout_constraintTop_toBottomOf="@id/include_toolbar"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:background="@color/white"
|
||||||
android:padding="20dp"
|
android:padding="20dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
@ -57,12 +58,9 @@
|
|||||||
>
|
>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
style="@style/headerText"
|
||||||
android:id="@+id/cityText"
|
android:id="@+id/cityText"
|
||||||
android:layout_width="wrap_content"
|
android:text="City name"/>
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="City name"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="20sp"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/datetimeText"
|
android:id="@+id/datetimeText"
|
||||||
|
|||||||
54
app/src/main/res/layout/activity_favorites.xml
Normal file
54
app/src/main/res/layout/activity_favorites.xml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
tools:context=".FavoritesActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/BackButton"
|
||||||
|
android:onClick="onBackButton" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/headerText"
|
||||||
|
android:text="Favorite cities" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/newCityBtn"
|
||||||
|
style="@style/GreenButtonStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:maxWidth="320dp"
|
||||||
|
android:text="Add new city"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:onClick="onSearchActivityBtn"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/linearLayout" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/cityFavoriteList"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:dividerHeight="1dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/newCityBtn"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
72
app/src/main/res/layout/activity_search_city.xml
Normal file
72
app/src/main/res/layout/activity_search_city.xml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
tools:context=".SearchCityActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/BackButton"
|
||||||
|
android:onClick="onBackButton" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/headerText"
|
||||||
|
android:text="Search city" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/fieldset"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/linearLayout"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/searchEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/searchBtn"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/GreenButtonStyle"
|
||||||
|
android:id="@+id/searchBtn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Search"
|
||||||
|
android:onClick="onSearchBtn"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/citySearchResult"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:dividerHeight="1dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/fieldset"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -2,6 +2,7 @@
|
|||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
android:background="@color/white">
|
android:background="@color/white">
|
||||||
|
|
||||||
@ -10,9 +11,24 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style="@style/BackButton"
|
||||||
|
android:onClick="onBackButton"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
style="@style/headerText"
|
||||||
|
android:text="Settings"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- GRAD -->
|
<!-- GRAD -->
|
||||||
<TextView
|
<TextView
|
||||||
android:text="Choose City:"
|
android:text="City"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#444444"
|
android:textColor="#444444"
|
||||||
@ -20,24 +36,37 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<Spinner
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/spinnerCity"
|
android:layout_marginTop="20dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="wrap_content">
|
||||||
android:spinnerMode="dropdown"
|
|
||||||
|
|
||||||
android:popupBackground="@color/green_popup"/>
|
<TextView
|
||||||
|
android:id="@+id/cityName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="City name"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/selectCityBtn"
|
||||||
|
style="@style/GreenSmallButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Select"
|
||||||
|
android:onClick="onFavoriteBtn"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<!-- separator -->
|
<!-- separator -->
|
||||||
<View
|
<include layout="@layout/component_settings_separator" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:background="#0F9D58" />
|
|
||||||
|
|
||||||
<!-- BROJ DANA -->
|
<!-- BROJ DANA -->
|
||||||
<TextView
|
<TextView
|
||||||
android:text="Forecast Duration:"
|
android:text="Forecast Duration"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#444444"
|
android:textColor="#444444"
|
||||||
@ -49,6 +78,10 @@
|
|||||||
android:id="@+id/radioGroupDays"
|
android:id="@+id/radioGroupDays"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
<RadioButton android:id="@+id/radio1days"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="1 day" />
|
||||||
<RadioButton android:id="@+id/radio3days"
|
<RadioButton android:id="@+id/radio3days"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -57,22 +90,14 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="5 days" />
|
android:text="5 days" />
|
||||||
<RadioButton android:id="@+id/radio7days"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="7 days" />
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<!-- separator -->
|
<!-- separator -->
|
||||||
<View
|
<include layout="@layout/component_settings_separator" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:background="#0F9D58" />
|
|
||||||
|
|
||||||
<!-- JEDINICE -->
|
<!-- JEDINICE -->
|
||||||
<TextView
|
<TextView
|
||||||
android:text="Units:"
|
android:text="Units"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:textColor="#444444"
|
android:textColor="#444444"
|
||||||
@ -95,19 +120,14 @@
|
|||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<!-- separator -->
|
<!-- separator -->
|
||||||
<View
|
<include layout="@layout/component_settings_separator" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:background="#0F9D58" />
|
|
||||||
|
|
||||||
|
|
||||||
<!-- DUGME -->
|
<!-- DUGME -->
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/buttonSave"
|
android:id="@+id/buttonSave"
|
||||||
|
style="@style/GreenButtonStyle"
|
||||||
android:text="Save and Return"
|
android:text="Save and Return"
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:backgroundTint="#0F9D58"
|
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
7
app/src/main/res/layout/component_settings_separator.xml
Normal file
7
app/src/main/res/layout/component_settings_separator.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<View
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:background="#0F9D58" />
|
||||||
45
app/src/main/res/layout/item_city.xml
Normal file
45
app/src/main/res/layout/item_city.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cityName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Subotica"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cityCoords"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="long: 21.12, lat: 342.21"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cityName" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/lastEnteredTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="20.12.2025 21:00:00"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cityCoords" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/selectBtn"
|
||||||
|
style="@style/GreenSmallButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Select"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -5,5 +5,33 @@
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="BackButton">
|
||||||
|
<item name="android:backgroundTint">#C5C5C5</item>
|
||||||
|
<item name="android:drawableLeft">@drawable/baseline_arrow_back</item>
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:minWidth">0dp</item>
|
||||||
|
<item name="android:minHeight">0dp</item>
|
||||||
|
<item name="android:layout_marginRight">15dp</item>
|
||||||
|
<item name="android:textSize">20sp</item>
|
||||||
|
</style>
|
||||||
|
<style name="GreenButtonStyle">
|
||||||
|
<item name="android:textColor">@android:color/white</item>
|
||||||
|
<item name="android:backgroundTint">#0F9D58</item>
|
||||||
|
</style>
|
||||||
|
<style name="GreenSmallButtonStyle">
|
||||||
|
<item name="android:textColor">@android:color/white</item>
|
||||||
|
<item name="android:backgroundTint">#0F9D58</item>
|
||||||
|
<item name="android:textSize">13sp</item>
|
||||||
|
<item name="android:minWidth">0dp</item>
|
||||||
|
<item name="android:minHeight">0dp</item>
|
||||||
|
</style>
|
||||||
|
<style name="headerText">
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:textSize">24sp</item>
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="Theme.AirQuality" parent="Base.Theme.AirQuality" />
|
<style name="Theme.AirQuality" parent="Base.Theme.AirQuality" />
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
x
Reference in New Issue
Block a user