Professional Documents
Culture Documents
Fragment Main
Fragment Main
java
package com.example.final_project.hike;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.final_project.Constants;
import com.example.final_project.R;
import com.example.final_project.databinding.FragmentMainBinding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
ViewGroup container,
@Nullable Bundle savedInstanceState) {
// Init the menu bar
AppCompatActivity app = (AppCompatActivity) getActivity();
ActionBar ab = app.getSupportActionBar();
ab.setHomeButtonEnabled(false);
ab.setDisplayShowHomeEnabled(false);
ab.setDisplayHomeAsUpEnabled(false);
setHasOptionsMenu(true);
// Binding
binding = FragmentMainBinding.inflate(inflater, container, false);
Navigation.findNavController(getView()).navigate(R.id.fragmentEdit, bundle);
}
});
return binding.getRoot();
}
@Override
public void onResume() {
super.onResume();
Log.i(this.getClass().getName(), "On Resume");
dao.getAllHike();
}
@Override
public void onItemClick(HikeEntity hikeInput) {
Navigation.findNavController(getView()).navigate(R.id.fragmentEdit, bundle);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_delete_all) {
// Handle the delete all action
deleteAllData();
return true;
}
return super.onOptionsItemSelected(item);
}
private void deleteAllData() {
AlertDialog.Builder builder = new
AlertDialog.Builder(requireContext());
builder.setTitle("Confirm Deletion");
builder.setMessage("Are you sure you want to delete all data?");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
// User clicked Yes, delete all data
dao.deleteAllHikes();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
// User clicked No, do nothing
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
The main task of the FragmentMain.java file is to display a list of hikes, add new hikes to the list,
allow editing or viewing hike details, search and delete. All information about the hike.
// Init the menu bar
AppCompatActivity app = (AppCompatActivity) getActivity();
ActionBar ab = app.getSupportActionBar();
ab.setHomeButtonEnabled(false);
ab.setDisplayShowHomeEnabled(false);
ab.setDisplayHomeAsUpEnabled(false);
setHasOptionsMenu(true);
This block of code is used by the author to adjust and tweak the fragment's title bar, including
hiding or disabling certain elements of the ActionBar.
Navigation.findNavController(getView()).navigate(R.id.fragmentEdit, bundle);
}
The above code is used when a hike is clicked. onItemClick(HikeEntity hikeInput) this method
takes a HikeEntity object as an argument representing the pressed data, which will then use the
dao object to get information about the ride based on the pressed ID. The author uses Bundle
to package and transfer data between Fragments. Finally, it will redirect to fragmentEdit and
pass along the data in the bundle used to edit information about the hike.
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater
inflater) {
inflater.inflate(R.menu.menu_main, menu);
super.onCreateOptionsMenu(menu, inflater);
searchView = (SearchView)
menu.findItem(R.id.action_search).getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
dao.searchHike(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
dao.searchHike(newText);
return false;
}
});
}
This code is an overridden method from the interface class that is responsible for initializing the
menu bar for searching. This line of code inflater.inflate(R.menu.menu_main, menu) uses
inflater to add menu items from the memu_main.xml file
searchView = (SearchView)menu.findItem(R.id.action_search).getActionView() this line searches
for the menu item with ID action_search and gets its ActionView object then converts it to a
SearchView object to enter and search data Whether.
onQueryTextSubmit(String query) This method is called when the user presses the search
button
onQueryTextChange(String newText) this method is called when the text in the SearchView
changes
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_delete_all) {
// Handle the delete all action
deleteAllData();
return true;
}
return super.onOptionsItemSelected(item);
}
private void deleteAllData() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("Confirm Deletion");
builder.setMessage("Are you sure you want to delete all data?");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// User clicked Yes, delete all data
dao.deleteAllHikes();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// User clicked No, do nothing
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
The above code handles the event when the user selects the delete icon on the application bar.
After selecting the deletion icon, there will be a confirmation dialog box to delete all data and
hikes. The code line int id = item.getItemID() will get the ID of the hikes to be deleted., then that
will check if the selected item is action_delete_all or not. If correct, all data will be deleted.
2. FragmentEdit.java
package com.example.final_project.hike;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import android.preference.PreferenceManager;
import android.text.InputType;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Switch;
import com.example.final_project.Constants;
import com.example.final_project.DateHandling;
import com.example.final_project.R;
import com.example.final_project.databinding.FragmentEditBinding;
import java.util.Calendar;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
ViewGroup container,
@Nullable Bundle savedInstanceState){
AppCompatActivity app = (AppCompatActivity)getActivity();
ActionBar ab = app.getSupportActionBar();
ab.setHomeButtonEnabled(true);
ab.setDisplayShowHomeEnabled(true);
ab.setDisplayHomeAsUpEnabled(true);
ab.setHomeAsUpIndicator(R.drawable.baseline_save_24);
setHasOptionsMenu(true);
//Observing the changes and set text for the editor view from the
bundle sent from main
dao.hike.observe(
getViewLifecycleOwner(),
hike ->{
binding.editNameHike.setText(bundleReceived.getString("name"));
binding.editLocation.setText(bundleReceived.getString("location"));
binding.editDateHike.setText(bundleReceived.getString("date"));
binding.selectParking.setText(bundleReceived.getString("parking_available"));
binding.editLengthOfHike.setText(bundleReceived.getString("length"));
binding.editDifficulty.setText(bundleReceived.getString("difficulty"));
binding.editDescription.setText(bundleReceived.getString("description"));
requireActivity().invalidateOptionsMenu();
}
);
binding.selectParking.setInputType(InputType.TYPE_NULL);
aSwitch = binding.switchParking;
sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(getContext());
aSwitch.setOnCheckedChangeListener(new
CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean
isChecked) {
if (isChecked) {
binding.selectParking.setText("Parking available");
} else {
binding.selectParking.setText("No parking available");
}
saveSwitchState(isChecked);
}
});
riskCheck = sharedPreferences.getBoolean("Notification", true);
aSwitch.setChecked(riskCheck);
//DatePicker
editTextDate = binding.editDateHike;
editTextDate.setInputType(InputType.TYPE_NULL);
editTextDate.setText(DateHandling.getTodayDate());
editTextDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
initDatePicker();
showDateDialog();
}
});
return binding.getRoot();
}
@Override
public void onPrepareOptionsMenu(@NonNull Menu menu) {
super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
if (this.validate()) return saveAndReturn();
else return false;
} else if (item.getItemId() == R.id.action_delete) {
return deleteAndReturn();
} else if (item.getItemId() == R.id.observationsDetail) {
return toObservation();
} else {
return super.onOptionsItemSelected(item);
}
}
private boolean toObservation() {
Bundle bundleReceived = getArguments();
Navigation.findNavController(getView()).navigate(R.id.fragmentObservationMain,
bundleReceived);
return true;
}
if (name.getText().toString().equals(Constants.EMPTY_STRING)){
name.setError("Name of the hike is required");
isValidated = false;
}
if (location.getText().toString().equals(Constants.EMPTY_STRING)){
location.setError("Location of the hike is required");
isValidated = false;
}
if (date.getText().toString().equals(Constants.EMPTY_STRING)){
date.setError("Date of the hike is required");
isValidated = false;
}
if (difficutly.getText().toString().equals(Constants.EMPTY_STRING)){
difficutly.setError("Difficutly of the hike is required");
isValidated = false;
}
if (length.getText().toString().equals(Constants.EMPTY_STRING)){
length.setError("Length of the hike is required");
isValidated = false;
}
if (parking.getText().toString().equals(Constants.EMPTY_STRING)){
parking.setError("Please fill in the parking available or we will
assume that you do not need any parking");
binding.selectParking.setText("No parking available");
isValidated = false;
}
return isValidated;
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater
inflater) {
if(getArguments().getString("id") != Constants.NEW_HIKE_ID){
inflater.inflate(R.menu.menu_hike, menu);
}
super.onCreateOptionsMenu(menu, inflater);
}
private boolean saveAndReturn() {
Log.i(this.getClass().getName(), "Saved and return");
hike.setName(binding.editNameHike.getText().toString());
hike.setLocation(binding.editLocation.getText().toString());
hike.setDate(binding.editDateHike.getText().toString());
hike.setParkingAvailable(binding.selectParking.getText().toString());
hike.setLength(binding.editLengthOfHike.getText().toString());
hike.setDifficulty(binding.editDifficulty.getText().toString());
hike.setDescription(binding.editDescription.getText().toString());
//Calling the DAO and get the observation by ID sent from MainFragment
and it returns the observation
String idReceived = getArguments().getString("id");
Bundle bundleReceived = getArguments();
//Observing the changes and set text for the editor view from the bundle
sent from main
dao.hike.observe(
getViewLifecycleOwner(),
hike ->{
binding.editNameHike.setText(bundleReceived.getString("name"));
binding.editLocation.setText(bundleReceived.getString("location"));
binding.editDateHike.setText(bundleReceived.getString("date"));
binding.selectParking.setText(bundleReceived.getString("parking_available"));
binding.editLengthOfHike.setText(bundleReceived.getString("length"));
binding.editDifficulty.setText(bundleReceived.getString("difficulty"));
binding.editDescription.setText(bundleReceived.getString("description"));
requireActivity().invalidateOptionsMenu();
}
);
binding.selectParking.setInputType(InputType.TYPE_NULL);
aSwitch = binding.switchParking;
sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(getContext());
aSwitch.setOnCheckedChangeListener(new
CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean
isChecked) {
if (isChecked) {
binding.selectParking.setText("Parking available");
} else {
binding.selectParking.setText("No parking available");
}
saveSwitchState(isChecked);
}
});
riskCheck = sharedPreferences.getBoolean("Notification", true);
aSwitch.setChecked(riskCheck);
//DatePicker
editTextDate = binding.editDateHike;
editTextDate.setInputType(InputType.TYPE_NULL);
editTextDate.setText(DateHandling.getTodayDate());
editTextDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
initDatePicker();
showDateDialog();
}
});
return binding.getRoot();
}
First, the author will set up AppCompatActvity's ActionBar to display the Save function button,
then trigger the event to show the options menu in the ActionBar with
setHasOptionMenu(true). Next, the author uses FragmentEditBinding to connect the interface
components and create a HikeDAO object to perform database access operations. The author
will get the ID of the hike from the Bundle argument and check if it is not a new hike then use
DAO to get the details and update the value of dao.hike.
The author will set up listener events for the Switch to update the status and display the
corresponding text. Use SharedPreferences to save the Switch's state.
Finally the author sets the default editTextDate field to display the current date and when
entered will open the date picker dialog box and then return the binding.getRoot() of the
initialized UI.
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
if (this.validate()) return saveAndReturn();
else return false;
} else if (item.getItemId() == R.id.action_delete) {
return deleteAndReturn();
} else if (item.getItemId() == R.id.observationsDetail) {
return toObservation();
} else {
return super.onOptionsItemSelected(item);
}
}
The above code will handle the event when an item in the options menu is selected. If the user
clicks on the Save icon, it will save and exit. Pressing the action_delete item will delete the
hiking and exit the Fragment. If the user presses the observationsDetail item, it will redirect to
another Fragment to view the observations of the hike and if not in the above cases, the
system's default handling will be performed.
private boolean toObservation() {
Bundle bundleReceived = getArguments();
Navigation.findNavController(getView()).navigate(R.id.fragmentObservationMain,
bundleReceived);
return true;
}
The toObservation method is used to redirect to fragmentObservationMain and pass along the
data (Bundle) received from the current Fragment's argument. After redirection, the method
returns true.
private boolean validate() {
EditText name = binding.editNameHike;
EditText location = binding.editLocation;
EditText date = binding.editDateHike;
EditText parking= binding.selectParking;
EditText length = binding.editLengthOfHike;
EditText difficutly = binding.editDifficulty;
boolean isValidated = true;
if (name.getText().toString().equals(Constants.EMPTY_STRING)){
name.setError("Name of the hike is required");
isValidated = false;
}
if (location.getText().toString().equals(Constants.EMPTY_STRING)){
location.setError("Location of the hike is required");
isValidated = false;
}
if (date.getText().toString().equals(Constants.EMPTY_STRING)){
date.setError("Date of the hike is required");
isValidated = false;
}
if (difficutly.getText().toString().equals(Constants.EMPTY_STRING)){
difficutly.setError("Difficutly of the hike is required");
isValidated = false;
}
if (length.getText().toString().equals(Constants.EMPTY_STRING)){
length.setError("Length of the hike is required");
isValidated = false;
}
if (parking.getText().toString().equals(Constants.EMPTY_STRING)){
parking.setError("Please fill in the parking available or we will
assume that you do not need any parking");
binding.selectParking.setText("No parking available");
isValidated = false;
}
return isValidated;
}
This is the code that validates the required fields in fragmentEdit. If any case is empty it will
display a message and return false otherwise it will return true
private boolean saveAndReturn() {
Log.i(this.getClass().getName(), "Saved and return");
hike.setName(binding.editNameHike.getText().toString());
hike.setLocation(binding.editLocation.getText().toString());
hike.setDate(binding.editDateHike.getText().toString());
hike.setParkingAvailable(binding.selectParking.getText().toString());
hike.setLength(binding.editLengthOfHike.getText().toString());
hike.setDifficulty(binding.editDifficulty.getText().toString());
hike.setDescription(binding.editDescription.getText().toString());