diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1780484..7fd9275 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,6 +15,12 @@ android:supportsRtl="true" android:theme="@style/Theme.AirQuality" tools:targetApi="31"> + + diff --git a/app/src/main/java/com/example/airquality/DetailsActivity.java b/app/src/main/java/com/example/airquality/DetailsActivity.java index 8a846e8..f13f711 100644 --- a/app/src/main/java/com/example/airquality/DetailsActivity.java +++ b/app/src/main/java/com/example/airquality/DetailsActivity.java @@ -5,12 +5,6 @@ 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 com.android.volley.RequestQueue; import com.android.volley.VolleyError; 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.databinding.ActivityDetailsBinding; 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.utils.PreferencesManager; 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 { @@ -54,7 +42,7 @@ public class DetailsActivity extends ToolbarCompatActivity { } protected void updateData() { - FormattedTemp formattedTemp = weather3h.formattedTemp(this); + FormattedTemperature formattedTemperature = weather3h.formattedTemp(this); if(checkInternet()) { @@ -70,10 +58,10 @@ public class DetailsActivity extends ToolbarCompatActivity { binding.iconCode.setText(weather3h.getIconCode()); } - binding.cityText.setText(city.name); + binding.cityText.setText(city.toString()); binding.datetimeText.setText(weather3h.getDateTime()); - binding.tempWeatherText.setText(formattedTemp.tempText + " | " + weather3h.getDescription()); - binding.tempText.setText(formattedTemp.tempMinText + " ~ " + formattedTemp.tempMaxText); + binding.tempWeatherText.setText(formattedTemperature.tempText + " | " + weather3h.getDescription()); + binding.tempText.setText(formattedTemperature.tempMinText + " ~ " + formattedTemperature.tempMaxText); binding.pressureText.setText(weather3h.getPressure() + " hPa"); binding.humidityText.setText(weather3h.getHumidity() + "%"); binding.windSpeedText.setText(weather3h.getWindSpeed() + " m/s"); @@ -81,6 +69,11 @@ public class DetailsActivity extends ToolbarCompatActivity { @Override 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); RequestQueue queue = Volley.newRequestQueue(this); diff --git a/app/src/main/java/com/example/airquality/FavoritesActivity.java b/app/src/main/java/com/example/airquality/FavoritesActivity.java new file mode 100644 index 0000000..45c5485 --- /dev/null +++ b/app/src/main/java/com/example/airquality/FavoritesActivity.java @@ -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 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); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/airquality/MainActivity.java b/app/src/main/java/com/example/airquality/MainActivity.java index ebeca17..ed1273b 100644 --- a/app/src/main/java/com/example/airquality/MainActivity.java +++ b/app/src/main/java/com/example/airquality/MainActivity.java @@ -1,23 +1,15 @@ package com.example.airquality; -import android.content.Intent; import android.os.Bundle; -import android.view.MenuInflater; -import android.widget.ListView; import android.widget.Toast; import androidx.activity.EdgeToEdge; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.android.volley.Request; import com.android.volley.RequestQueue; -import com.android.volley.Response; import com.android.volley.VolleyError; -import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.Volley; import com.example.airquality.api.ForecastAPIRequest; 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.ToolbarCompatActivity; import com.example.airquality.utils.Weather3hAdapter; -import com.example.airquality.utils.Weather3hParser; - -import org.json.JSONObject; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class MainActivity extends ToolbarCompatActivity { List prognoza; private RecyclerView recyclerView; - private static final Map 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 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -61,13 +38,26 @@ public class MainActivity extends ToolbarCompatActivity { initToolbar(); } + @Override protected void onResume() { super.onResume(); loadForecast(); } + private void saveOffline(Weather3h[] weathers) { + // Save to db + } + private Weather3h[] loadOffline() { + // Load from db + return new Weather3h[] { }; + } + @Override 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); } @@ -79,10 +69,18 @@ public class MainActivity extends ToolbarCompatActivity { int days = PreferencesManager.getDays(this); String units = PreferencesManager.getUnits(this); - setToolbarTitle(city.name); 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; } @@ -91,14 +89,12 @@ public class MainActivity extends ToolbarCompatActivity { ForecastAPIRequest forecastAPI = new ForecastAPIRequest(this, city, units) { @Override public void onSuccess(Weather3h[] weatherList) { - Weather3h[] arr = Arrays.copyOfRange(weatherList, 0, days); - prognoza = Arrays.asList(arr); - - Weather3hAdapter adapter = new Weather3hAdapter(MainActivity.this, prognoza, city); - recyclerView.setAdapter(adapter); + displayRecycler(weatherList, city, days); if(isUpdated) Toast.makeText(MainActivity.this, "List Updated!", Toast.LENGTH_SHORT).show(); + + saveOffline(weatherList); } @Override @@ -109,4 +105,16 @@ public class MainActivity extends ToolbarCompatActivity { 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); + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/airquality/SearchCityActivity.java b/app/src/main/java/com/example/airquality/SearchCityActivity.java new file mode 100644 index 0000000..6a65788 --- /dev/null +++ b/app/src/main/java/com/example/airquality/SearchCityActivity.java @@ -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()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/airquality/SettingsActivity.java b/app/src/main/java/com/example/airquality/SettingsActivity.java index 64dbfd3..9e4e30c 100644 --- a/app/src/main/java/com/example/airquality/SettingsActivity.java +++ b/app/src/main/java/com/example/airquality/SettingsActivity.java @@ -7,47 +7,35 @@ import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; -import android.widget.CheckBox; import android.widget.RadioGroup; import android.widget.Spinner; +import android.widget.TextView; -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.example.airquality.types.City; import com.example.airquality.utils.BaseCompatActivity; +import com.example.airquality.utils.PreferencesManager; public class SettingsActivity extends BaseCompatActivity { Spinner spinnerCity; RadioGroup radioGroupDays, radioGroupUnits; Button buttonSave; - - String[] cities = {"Subotica", "Novi Sad", "Beograd", "San Francisko", "Sidnej"}; + TextView cityNameText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); - spinnerCity = findViewById(R.id.spinnerCity); radioGroupDays = findViewById(R.id.radioGroupDays); radioGroupUnits = findViewById(R.id.radioGroupUnits); buttonSave = findViewById(R.id.buttonSave); - - // Podesi spinner - ArrayAdapter adapter = new ArrayAdapter<>(this, - android.R.layout.simple_spinner_item, cities); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinnerCity.setAdapter(adapter); + cityNameText = findViewById(R.id.cityName); buttonSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - String selectedCity = spinnerCity.getSelectedItem().toString(); - int days = 7; // podrazumevano + int days = 1; // podrazumevano if (radioGroupDays.getCheckedRadioButtonId() == R.id.radio3days) { days = 3; } else if (radioGroupDays.getCheckedRadioButtonId() == R.id.radio5days) { @@ -59,15 +47,22 @@ public class SettingsActivity extends BaseCompatActivity { units = "imperial"; } - SharedPreferences prefs = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString("city", selectedCity); - editor.putInt("days", days); - editor.putString("units", units); - editor.apply(); + PreferencesManager.savePreferences(SettingsActivity.this, days, units); 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()); + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/airquality/api/CityAPIRequest.java b/app/src/main/java/com/example/airquality/api/CityAPIRequest.java new file mode 100644 index 0000000..c9858d8 --- /dev/null +++ b/app/src/main/java/com/example/airquality/api/CityAPIRequest.java @@ -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 { + + @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() { + @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) { + + } +} diff --git a/app/src/main/java/com/example/airquality/api/ForecastAPIRequest.java b/app/src/main/java/com/example/airquality/api/ForecastAPIRequest.java index ab7dfbd..392f4d6 100644 --- a/app/src/main/java/com/example/airquality/api/ForecastAPIRequest.java +++ b/app/src/main/java/com/example/airquality/api/ForecastAPIRequest.java @@ -16,7 +16,7 @@ import org.json.JSONObject; import java.util.Arrays; -public class ForecastAPIRequest extends JsonAPIRequest { +public class ForecastAPIRequest extends JsonAPIRequest { @SuppressLint("DefaultLocale") 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) { } } \ No newline at end of file diff --git a/app/src/main/java/com/example/airquality/api/JsonAPIRequest.java b/app/src/main/java/com/example/airquality/api/JsonAPIRequest.java index 1a1e0aa..b196f25 100644 --- a/app/src/main/java/com/example/airquality/api/JsonAPIRequest.java +++ b/app/src/main/java/com/example/airquality/api/JsonAPIRequest.java @@ -9,12 +9,13 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import com.example.airquality.MainActivity; import com.example.airquality.R; +import com.example.airquality.types.Weather3h; import com.example.airquality.utils.Weather3hAdapter; import com.example.airquality.utils.Weather3hParser; import org.json.JSONObject; -public abstract class JsonAPIRequest { +public abstract class JsonAPIRequest { private Context appContext; protected String url; @@ -28,5 +29,8 @@ public abstract class JsonAPIRequest { { 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); } diff --git a/app/src/main/java/com/example/airquality/types/City.java b/app/src/main/java/com/example/airquality/types/City.java index 322ed8c..f5aeaae 100644 --- a/app/src/main/java/com/example/airquality/types/City.java +++ b/app/src/main/java/com/example/airquality/types/City.java @@ -1,15 +1,30 @@ package com.example.airquality.types; +import androidx.annotation.NonNull; + import java.io.Serializable; public class City implements Serializable { public String name; + public String country; public double latitude; 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.country = country; this.latitude = latitude; 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 + ")"; } } diff --git a/app/src/main/java/com/example/airquality/types/FormattedTemp.java b/app/src/main/java/com/example/airquality/types/FormattedTemperature.java similarity index 72% rename from app/src/main/java/com/example/airquality/types/FormattedTemp.java rename to app/src/main/java/com/example/airquality/types/FormattedTemperature.java index 613e589..af59c90 100644 --- a/app/src/main/java/com/example/airquality/types/FormattedTemp.java +++ b/app/src/main/java/com/example/airquality/types/FormattedTemperature.java @@ -2,18 +2,14 @@ package com.example.airquality.types; import android.content.Context; -import androidx.annotation.NonNull; - import com.example.airquality.utils.PreferencesManager; -import java.util.Objects; - -public class FormattedTemp { +public class FormattedTemperature { public String tempText; public String tempMinText; 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); diff --git a/app/src/main/java/com/example/airquality/types/Weather3h.java b/app/src/main/java/com/example/airquality/types/Weather3h.java index a4cba6b..c87d501 100644 --- a/app/src/main/java/com/example/airquality/types/Weather3h.java +++ b/app/src/main/java/com/example/airquality/types/Weather3h.java @@ -49,8 +49,8 @@ public class Weather3h implements Serializable { return tempMax; } - public FormattedTemp formattedTemp(Context context) { - return new FormattedTemp(context, temp, tempMin, tempMax); + public FormattedTemperature formattedTemp(Context context) { + return new FormattedTemperature(context, temp, tempMin, tempMax); } public int getDt() { diff --git a/app/src/main/java/com/example/airquality/utils/BaseCompatActivity.java b/app/src/main/java/com/example/airquality/utils/BaseCompatActivity.java index 5c76eb0..9d8da41 100644 --- a/app/src/main/java/com/example/airquality/utils/BaseCompatActivity.java +++ b/app/src/main/java/com/example/airquality/utils/BaseCompatActivity.java @@ -3,6 +3,7 @@ package com.example.airquality.utils; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.view.View; import androidx.appcompat.app.AppCompatActivity; @@ -13,4 +14,9 @@ public class BaseCompatActivity extends AppCompatActivity { NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); } + + public void onBackButton(View view) + { + finish(); + } } diff --git a/app/src/main/java/com/example/airquality/utils/CityAdapter.java b/app/src/main/java/com/example/airquality/utils/CityAdapter.java new file mode 100644 index 0000000..2e65c85 --- /dev/null +++ b/app/src/main/java/com/example/airquality/utils/CityAdapter.java @@ -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 { + + private Context context; + private List cityList; + private String applyBtnText; + + public CityAdapter(Context context, List cityList) { + this(context, cityList, "Select"); + } + public CityAdapter(Context context, List 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) { } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/airquality/utils/CityParser.java b/app/src/main/java/com/example/airquality/utils/CityParser.java new file mode 100644 index 0000000..cd0c6ee --- /dev/null +++ b/app/src/main/java/com/example/airquality/utils/CityParser.java @@ -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 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]); + } +} diff --git a/app/src/main/java/com/example/airquality/utils/PreferencesManager.java b/app/src/main/java/com/example/airquality/utils/PreferencesManager.java index 3a11d3f..d94c489 100644 --- a/app/src/main/java/com/example/airquality/utils/PreferencesManager.java +++ b/app/src/main/java/com/example/airquality/utils/PreferencesManager.java @@ -11,7 +11,7 @@ public class PreferencesManager { private static final String KEY_DAYS = "days"; 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.Editor editor = prefs.edit(); editor.putInt(KEY_DAYS, days); @@ -20,13 +20,28 @@ public class PreferencesManager { } public static City getCity(Context context) { - // DAVID: Realizovati iz sqlite - return new City("Subotica", 46.1, 19.6667); + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + 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) { 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) { diff --git a/app/src/main/java/com/example/airquality/utils/Weather3hAdapter.java b/app/src/main/java/com/example/airquality/utils/Weather3hAdapter.java index 1f81963..a2fb869 100644 --- a/app/src/main/java/com/example/airquality/utils/Weather3hAdapter.java +++ b/app/src/main/java/com/example/airquality/utils/Weather3hAdapter.java @@ -5,17 +5,14 @@ import android.content.Intent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.TextView; -import android.widget.Toast; import androidx.recyclerview.widget.RecyclerView; import com.example.airquality.DetailsActivity; -import com.example.airquality.MainActivity; import com.example.airquality.R; 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 java.util.List; @@ -31,8 +28,6 @@ public class Weather3hAdapter extends RecyclerView.Adapter + + + + diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml index 283b320..c8a44cf 100644 --- a/app/src/main/res/layout/activity_details.xml +++ b/app/src/main/res/layout/activity_details.xml @@ -17,6 +17,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/include_toolbar" app:layout_constraintBottom_toBottomOf="parent" + android:background="@color/white" android:padding="20dp" > @@ -57,12 +58,9 @@ > + android:text="City name"/> + + + + +