MeteoriteDB

Log | Files | Refs | README

MainActivity.java (12826B)


      1 package com.example.project_assignment;
      2 
      3 import android.Manifest;
      4 
      5 import androidx.annotation.NonNull;
      6 import androidx.appcompat.app.AppCompatActivity;
      7 import androidx.constraintlayout.widget.ConstraintLayout;
      8 import androidx.core.app.ActivityCompat;
      9 import androidx.recyclerview.widget.LinearLayoutManager;
     10 import androidx.recyclerview.widget.RecyclerView;
     11 
     12 import android.content.Context;
     13 import android.content.Intent;
     14 import android.content.SharedPreferences;
     15 import android.content.pm.PackageManager;
     16 import android.location.Location;
     17 import android.location.LocationListener;
     18 import android.location.LocationManager;
     19 import android.os.Bundle;
     20 import android.util.Log;
     21 import android.view.Gravity;
     22 import android.view.LayoutInflater;
     23 import android.view.View;
     24 import android.widget.Button;
     25 import android.widget.EditText;
     26 import android.widget.PopupWindow;
     27 import android.widget.RadioGroup;
     28 import android.widget.SeekBar;
     29 import android.widget.TextView;
     30 import android.widget.Toast;
     31 
     32 import com.example.project_assignment.comparators.SortByLocation;
     33 import com.example.project_assignment.comparators.SortByName;
     34 import com.example.project_assignment.comparators.SortByWeight;
     35 import com.google.android.material.floatingactionbutton.FloatingActionButton;
     36 import com.google.gson.Gson;
     37 import com.google.gson.reflect.TypeToken;
     38 
     39 import java.lang.reflect.Type;
     40 import java.util.ArrayList;
     41 import java.util.Collections;
     42 import java.util.List;
     43 
     44 @SuppressWarnings("FieldCanBeLocal")
     45 public class MainActivity extends AppCompatActivity implements JsonTask.JsonTaskListener, LocationListener {
     46 
     47     //private final String JSON_URL = "https://data.nasa.gov/resource/y77d-th95.json";
     48     private final String JSON_URL = "https://mobprog.webug.se/json-api?login=a22willi";
     49     private LocationManager locationManager;
     50     private SharedPreferences preference;
     51     private SharedPreferences.Editor preferenceEditor;
     52 
     53     private ArrayList<Meteorite> meteorites;
     54     private ArrayList<Meteorite> unalteredMeteoriteList;
     55 
     56     private RecyclerViewAdapter adapter;
     57 
     58     private boolean distanceSet = false;
     59 
     60     @Override
     61     protected void onCreate(Bundle savedInstanceState) {
     62         super.onCreate(savedInstanceState);
     63         setContentView(R.layout.activity_main);
     64 
     65         new JsonTask(this).execute(JSON_URL);
     66 
     67         preference = getSharedPreferences("preferences", MODE_PRIVATE);
     68         preferenceEditor = preference.edit();
     69 
     70         locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
     71 
     72         //request permission to use location services: fine location and coarse location.
     73         if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
     74 
     75             Toast.makeText(MainActivity.this, "The app needs access to location services.", Toast.LENGTH_LONG);
     76             ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 1);
     77             return;
     78         }
     79         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
     80 
     81         FloatingActionButton showSortingOptionsButton = findViewById(R.id.showSortingOptionsButton);
     82         showSortingOptionsButton.setOnClickListener(new View.OnClickListener() {
     83             @Override
     84             public void onClick(View view) {
     85                 showFilterOptions(view);
     86             }
     87         });
     88 
     89         FloatingActionButton showAboutButton = findViewById(R.id.showAboutSectionButton);
     90         showAboutButton.setOnClickListener(new View.OnClickListener() {
     91             @Override
     92             public void onClick(View view) {
     93                 Intent intent = new Intent(MainActivity.this, AboutActivity.class);
     94                 startActivity(intent);
     95             }
     96         });
     97     }
     98 
     99     /**
    100      * This function runs after JSON data has been fetched from remote database.
    101      *
    102      * @param json
    103      */
    104     @Override
    105     public void onPostExecute(String json) {
    106         Gson gson = new Gson();
    107 
    108         Type type = new TypeToken<List<Meteorite>>() {
    109         }.getType();
    110         meteorites = gson.fromJson(json, type);
    111         unalteredMeteoriteList = new ArrayList<Meteorite>();
    112         unalteredMeteoriteList.addAll(meteorites);
    113 
    114         for (Meteorite m : meteorites) {
    115             Log.d("Meteorite: ", m.toString());
    116         }
    117 
    118 
    119         //Initialize recyclerview and inject meteorite data.
    120         RecyclerView recyclerView = findViewById(R.id.recyclerView);
    121         adapter = new RecyclerViewAdapter(this, meteorites);
    122         recyclerView.setAdapter(adapter);
    123         recyclerView.setLayoutManager(new LinearLayoutManager(this));
    124         adapter.notifyDataSetChanged();
    125     }
    126 
    127     /**
    128      * Open popupwindow that shows all possible filter options.
    129      *
    130      * @param view Current view (MainActivity)
    131      */
    132     private void showFilterOptions(View view) {
    133 
    134         //initialize layoutInflater
    135         LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    136         View popupView = inflater.inflate(R.layout.filter_popup, null);
    137 
    138         int width = ConstraintLayout.LayoutParams.MATCH_PARENT;
    139         int height = ConstraintLayout.LayoutParams.MATCH_PARENT;
    140         boolean focusable = true;
    141         final PopupWindow popupWindow = new PopupWindow(popupView, width, height, focusable);
    142         popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
    143 
    144         //fetch all necessary views and widgets in popup.
    145         TextView distanceProgress = popupView.findViewById(R.id.distanceProgress);
    146         Button confirmButton = popupView.findViewById(R.id.confirmFilterButton);
    147         Button cancelButton = popupView.findViewById(R.id.cancelFilterButton);
    148         SeekBar seekBar = popupView.findViewById(R.id.distanceBar);
    149         EditText minMass = popupView.findViewById(R.id.setMinimumMass);
    150         EditText maxMass = popupView.findViewById(R.id.setMaximumMass);
    151         EditText minYear = popupView.findViewById(R.id.setMinimumYear);
    152         EditText maxYear = popupView.findViewById(R.id.setMaximumYear);
    153         RadioGroup sorting = popupView.findViewById(R.id.sortingGroup);
    154 
    155 
    156         //set all listeners
    157         confirmButton.setOnClickListener(new View.OnClickListener() {
    158             @Override
    159             public void onClick(View view) {
    160 
    161                 //reinitialize saved meteorites.
    162                 meteorites.clear();
    163                 meteorites.addAll(unalteredMeteoriteList);
    164 
    165                 //fetch all editText data.
    166                 int intMinMass = fetchEditTextData(minMass);
    167                 int intMaxMass = fetchEditTextData(maxMass);
    168                 int intMinYear = fetchEditTextData(minYear);
    169                 int intMaxYear = fetchEditTextData(maxYear);
    170                 int distance = Integer.parseInt(String.valueOf(seekBar.getProgress()));
    171                 int selectedSortingButton = sorting.getCheckedRadioButtonId();
    172 
    173                 ArrayList<Meteorite> toRemove = new ArrayList<Meteorite>();
    174 
    175                 //check if meteorites match filter settings.
    176                 for (Meteorite m : meteorites) {
    177                     boolean matchingFilter = m.matchingFilter(intMinMass, intMaxMass, intMinYear, intMaxYear, distance);
    178                     if (!matchingFilter) {
    179                         toRemove.add(m);
    180                     }
    181                 }
    182 
    183                 //remove meteorites that did not match the filter settings.
    184                 for (Meteorite m : toRemove) {
    185                     meteorites.remove(m);
    186                 }
    187 
    188                 switch (selectedSortingButton) {
    189                     case R.id.radioButtonSortLocation:
    190                         Collections.sort(meteorites, new SortByLocation());
    191                         preferenceEditor.putString("sort", "location");
    192                         break;
    193                     case R.id.radioButtonSortWeight:
    194                         Collections.sort(meteorites, new SortByWeight());
    195                         preferenceEditor.putString("sort", "mass");
    196                         break;
    197                     default:
    198                         Collections.sort(meteorites, new SortByName());
    199                         preferenceEditor.putString("name", "name");
    200                 }
    201 
    202                 //save filter options.
    203                 preferenceEditor.putInt("minMass", intMinMass);
    204                 preferenceEditor.putInt("maxMass", intMaxMass);
    205                 preferenceEditor.putInt("minYear", intMinYear);
    206                 preferenceEditor.putInt("maxYear", intMaxYear);
    207                 preferenceEditor.putInt("distance", distance);
    208                 preferenceEditor.apply();
    209 
    210                 adapter.notifyDataSetChanged();
    211 
    212                 try {
    213                     Thread.sleep(100);
    214                 } catch (InterruptedException e) {
    215                     throw new RuntimeException(e);
    216                 }
    217                 popupWindow.dismiss();
    218             }
    219         });
    220 
    221         cancelButton.setOnClickListener(new View.OnClickListener() {
    222             @Override
    223             public void onClick(View view) {
    224                 try {
    225                     Thread.sleep(100);
    226                 } catch (InterruptedException e) {
    227                     throw new RuntimeException(e);
    228                 }
    229                 popupWindow.dismiss();
    230             }
    231         });
    232 
    233         seekBar.setMax(10000); //set max value of seekbar to 20000km
    234         seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    235             @Override
    236             public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
    237                 distanceProgress.setText(seekBar.getProgress() + "km");
    238             }
    239 
    240             @Override
    241             public void onStartTrackingTouch(SeekBar seekBar) {
    242 
    243             }
    244 
    245             @Override
    246             public void onStopTrackingTouch(SeekBar seekBar) {
    247 
    248             }
    249         });
    250     }
    251 
    252     private int fetchEditTextData(EditText editText) {
    253         int output = 0;
    254         if (!String.valueOf(editText.getText()).isEmpty()) {
    255             output = Integer.parseInt(String.valueOf(editText.getText()));
    256             return output;
    257         }
    258         return output;
    259     }
    260 
    261 
    262     /**
    263      * Runs after location has been pulled.
    264      *
    265      * @param location the users current location data.
    266      */
    267     @Override
    268     public void onLocationChanged(@NonNull Location location) {
    269         /* Prevent meteorite locations from being recaculated each time users location changes,
    270          * Or the meteorites have not yet been fetched from database. */
    271         if (distanceSet || meteorites.isEmpty()) {
    272             return;
    273         }
    274 
    275         Toast.makeText(this, "Loaded location", Toast.LENGTH_SHORT).show();
    276 
    277         for (Meteorite m : meteorites) {
    278             m.generateDistanceFrom(location.getLatitude(), location.getLongitude());
    279         }
    280 
    281         distanceSet = true;
    282 
    283         //apply stored filter settings.
    284         filterMeteorites();
    285     }
    286 
    287     /**
    288      * Used to filter meteorites based on their mass, date and relative location to the user.
    289      */
    290     public void filterMeteorites() {
    291         //if there are saved filter settings, load them.
    292         if (preference.contains("minMass")) {
    293             Toast.makeText(MainActivity.this, "Loaded stored filter", Toast.LENGTH_SHORT).show();
    294             ArrayList<Meteorite> toRemove = new ArrayList<>();
    295 
    296             /*
    297             Since the list which is being iterated through cannot be changed during its iterations.
    298             Append all meteorites which are to be removed to a new list.
    299              */
    300             for (Meteorite m : meteorites) {
    301                 boolean matchingFilter = m.matchingFilter(preference.getInt("minMass", 0), preference.getInt("maxMass", 0), preference.getInt("minYear", 0), preference.getInt("maxYear", 0), preference.getInt("distance", 0));
    302                 if (!matchingFilter) {
    303                     toRemove.add(m);
    304                 }
    305             }
    306             //remove meteorites that did not match the filter settings.
    307             for (Meteorite m : toRemove) {
    308                 meteorites.remove(m);
    309             }
    310 
    311             //sort the meteories based on the users preferred sorting method.
    312             switch (preference.getString("sort", "")) {
    313                 case "location":
    314                     Collections.sort(meteorites, new SortByLocation());
    315                     break;
    316                 case "mass":
    317                     Collections.sort(meteorites, new SortByWeight());
    318                     break;
    319                 default:
    320                     Collections.sort(meteorites, new SortByName());
    321             }
    322             adapter.notifyDataSetChanged();
    323         }
    324     }
    325 }
    326