Trip planner screen - ivancrg/vis.it GitHub Wiki
In this part of application users can plan their trip. While planning users choose destination country from list, city, link or address to accommodation, date of departure and other important information.
When users click on link "Add a new plan" in navigation drawer, it redirects them to main interface (TripPlannerFragment class) for planning a trip. It consists of list of all information that they have to choose before saving the trip. Interface is shown in picture below.

All parts of the trip planning are constructed in the same way. Firstly, for every part of the list, user can click on button, for example "Add country", it redirects them to fragment responsible for that part of planning. After users choose that part of information, they can click on button "Next" if they want to confirm that or "Cancel" if they don't. After clicking "Next", the application redirects them to next fragment of planning, but after clicking "Cancel" it redirects them back to the main interface shown on the image above. In main interface, if users have already chosen some information, that information is displayed, or if not, there is a default sentence displayed, for example "No country selected". Before saving trip in the database, information is stored in static variables of TripPlanning class. Example for choosing a country is shown in the images below.

For this part of trip planning an Android Country Picker library was implemented from this link https://github.com/hbb20/AndroidCountryPicker. To add this library to the project the following dependency needs to be added:
implementation 'com.hbb20:AndroidCountryPicker._version_'
To implement country picker in XML layout of country fragment this code was used:
<com.hbb20.CountryPickerView android:id="@+id/countryPicker" android:layout_width="wrap_content" android:layout_height="wrap_content" />
And in the java code the country picker was implemented through following functions:
CountryPickerView country = view.findViewById(R.id.country_picker); String destination_country = country.getCpViewHelper().getSelectedCountry().getValue().component3();
Mentioned component3 extracts only the name of the picked country which is sent as an argument to the next fragment "City Fragment" where users can choose a city based on the country they picked in this screen.
During implementation of this library Android Studio was constantly showing the NullPointerException error concerning the problem if a country is not picked. This error was resolved in issue #46 when the code which gets the destination country was surrounded with a condition. This is the condition that needed to be checked:
country.getCpViewHelper().getSelectedCountry().getValue() != null
Another problem in this part of the trip planning was sending the information from country fragment to city fragment through the button "Next", and sending information from country fragment to trip planning fragment and later from trip planning fragment to city fragment through button "Cancel". Following code gets the information from drop down list and saves it into bundle arguments to transfer that to the fragment needed.
Bundle args = new Bundle(); args.putString("key", destination_country); CityFragment fragmentCity = new CityFragment(); fragmentCity.setArguments(args); FragmentTransaction fragmentTransaction = getActivity() .getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.fragment_container, fragmentCity); fragmentTransaction.commit();
This part of the trip planning process was implemented with a spinner which gets specific cities from chosen country through https://countriesnow.space/api/v0.1/countries/cities API. If country is not picked user gets a message to pick a country first, the next button is disabled and the cancel button becomes "Go back" button which takes the user back to the trip planning screen.

After user picks the destination country that information is sent to city fragment which uses OkHttp POST request to the mentioned API and receives all cities from the chosen country in a drop down list. Getting information from API is achieved in the following code:
OkHttpClient client = new OkHttpClient().newBuilder().build(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, "{\r\n \"country\": \""+ data + "\"\r\n}"); Request request = new Request.Builder() .url("https://countriesnow.space/api/v0.1/countries/cities") .method("POST", body) .addHeader("Content-Type", "application/json") .addHeader("Cookie", "__cfduid=db014f690fb26fc59e5c50092c509f28b1619124682") .build();
The data string which is added into body of the request variable is a string which contains the country information sent to the fragment through bundle arguments. After the data is fetched from API as a JSON object it is formatted as an array list and afterwards added into a spinner to create a drop down list.
Most errors that occurred while creating the city fragment were connected to a clash of libraries which are used to store data into database, and library to fetch data from API. First version of the code was using Retrofit in combination with Unirest for POST request, but the dependencies for the two libraries could not be implemented in the same time, so the best resolution for this problem was to use OkHttp. Second type of errors were errors which occurred during the implementation of spinner. In the function that includes information into spinner the order in which data is processed is very important, so the only way to do that correctly was by formatting the JSON response first, after that adding data to spinner and then updating the JSON adapter. Code that solved the issue is shown below.
JSONObject cities = new JSONObject(myResponse); JSONArray cityArr = cities.getJSONArray("data"); ArrayList<String> list = new ArrayList<String>(); for (int i = 0; i < cityArr.length(); i++) { list.add(cityArr.getString(i)); } ArrayAdapter<String> spinnerMenu = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1, list); spinnerMenu.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(spinnerMenu); jsonAdapter.notifyDataSetChanged();
This part of the app was implemented through Date Picker available on https://material.io/components/date-pickers. Picked date is formatted as a LocalDate variable and saved as a Date variable so it can be correctly formatted for the POST request when saving all trip information to database. In addition, selecting date before today is disabled by adding following line to the code:
datePicker.setMinDate(System.currentTimeMillis() - 1000);
A bug occurred when trip post request was implemented, that was mentioned in the issue #48. Although date of trip was correctly stored in the date variable in trip planning interface, when the information was saved to database it looked like a null object was received and the date in database was displayed like this "0000-00-00". To avoid this problem, in the last step before posting data to be saved in database the date variable is formatted to a string variable.
Accommodation, travelling mode, necessities, participants (AccommodationFragment, TravellingModeFragment, TravellingNecessitiesFragment and ParticipantsFragment classes)
All of the other fragments in the trip planning interface are structured in the same way. User writes information into a text box, and the information is forwarded to the main trip planning fragment which stores the information to database.
#15 #17 #18 #44 #45 #46 #47 #48 #49
- Main interface for trip planning - Ivana Štimac
- Post request to database - Ivana Štimac
- Interfaces for specific parts of planning - Hana Rut Lerga
- Pull request for trip planning - reviewed by Ivan Rubinić, merged by Hana Rut Lerga