diff --git a/app/build.gradle b/app/build.gradle index 003cd15..8bcfb89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -53,7 +53,14 @@ dependencies { //osm bonus pack implementation 'com.github.MKergall:osmbonuspack:6.6.0' + //BeforeEach + testImplementation(platform('org.junit:junit-bom:5.7.0')) + testImplementation 'org.junit.jupiter:junit-jupiter' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' testImplementation 'org.mockito:mockito-core:2.7.22' + androidTestImplementation 'com.21buttons:fragment-test-rule:2.0.1' + androidTestImplementation 'androidx.test:rules:1.3.0-beta01' + androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0-alpha02' } \ No newline at end of file diff --git a/app/src/androidTest/java/com/a1/nextlocation/CouponFragmentTest.java b/app/src/androidTest/java/com/a1/nextlocation/CouponFragmentTest.java new file mode 100644 index 0000000..49b7ee5 --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/CouponFragmentTest.java @@ -0,0 +1,50 @@ +package com.a1.nextlocation; + +import androidx.test.espresso.Root; +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.matcher.RootMatchers; +import androidx.test.espresso.matcher.ViewMatchers; +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.CouponFragment; +import com.a1.nextlocation.fragments.LocationFragment; + +import org.junit.Rule; +import org.junit.Test; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isChecked; +import static androidx.test.espresso.matcher.ViewMatchers.isClickable; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +public class CouponFragmentTest { + + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + @Test + public void clickBackButton() throws Exception{ + //Here we click the back button and then we check if the statisticsFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new CouponFragment()).commit(); + onView(withId(R.id.coupon_back_button)).perform(click()); + onView(withId(R.id.statisticsFragment)).check(matches(isDisplayed())); + } + + @Test + public void clickDetailButton() throws Exception{ + //Here we click a coupon and then a popup dialog shows, we press the "activeren" button in it and if the next dialog with the code and with + //the button "Klaar" is shown then the test works + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new CouponFragment()).commit(); + onView(withId(R.id.coupon_recyclerview)).perform(RecyclerViewActions.actionOnItemAtPosition(1, click())); + onView(withText("activeren")).inRoot(RootMatchers.isDialog()).perform(click()); + onView(withText("Klaar")).inRoot(RootMatchers.isDialog()).check(matches(isDisplayed())); + + + } + +} diff --git a/app/src/androidTest/java/com/a1/nextlocation/LocationDetailFragment.java b/app/src/androidTest/java/com/a1/nextlocation/LocationDetailFragment.java new file mode 100644 index 0000000..3942ba0 --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/LocationDetailFragment.java @@ -0,0 +1,27 @@ +package com.a1.nextlocation; + +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.CouponFragment; + +import org.junit.Rule; +import org.junit.Test; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; + +public class LocationDetailFragment { + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + @Test + public void clickBackButton() throws Exception{ + //Here we click the back button and then we check if the locationFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new com.a1.nextlocation.fragments.LocationDetailFragment()).commit(); + onView(withId(R.id.detail_location_back_button)).perform(click()); + onView(withId(R.id.locationFragment)).check(matches(isDisplayed())); + } +} diff --git a/app/src/androidTest/java/com/a1/nextlocation/LocationFragmentTest.java b/app/src/androidTest/java/com/a1/nextlocation/LocationFragmentTest.java new file mode 100644 index 0000000..77ac98d --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/LocationFragmentTest.java @@ -0,0 +1,42 @@ +package com.a1.nextlocation; + +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.LocationFragment; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; + +import static androidx.test.espresso.Espresso.*; +import static androidx.test.espresso.action.ViewActions.*; +import static androidx.test.espresso.assertion.ViewAssertions.*; +import static androidx.test.espresso.matcher.ViewMatchers.*; + + +public class LocationFragmentTest { + + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + @Test + public void clickBackButton() throws Exception{ + //Here we click the back button and then we check if the homeFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new LocationFragment()).commit(); + onView(withId(R.id.location_back_button)).perform(click()); + onView(withId(R.id.homeFragment)).check(matches(isDisplayed())); + } + + @Test + public void clickDetailButton() throws Exception{ + //Here we click an item in the recyclerview and then check if the routeDetailFragment is called + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new LocationFragment()).commit(); + onView(withId(R.id.location_recyclerview)).perform(RecyclerViewActions.actionOnItemAtPosition(1, click())); + onView(withId(R.id.locationDetailFragment)).check(matches(isDisplayed())); + + } + +} diff --git a/app/src/androidTest/java/com/a1/nextlocation/MainActivityTest.java b/app/src/androidTest/java/com/a1/nextlocation/MainActivityTest.java new file mode 100644 index 0000000..c448f9f --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/MainActivityTest.java @@ -0,0 +1,64 @@ +package com.a1.nextlocation; + +import android.app.LauncherActivity; +import android.widget.Button; + +import androidx.test.espresso.contrib.NavigationViewActions; +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.matcher.RootMatchers; +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.CouponFragment; +import com.google.android.material.bottomnavigation.BottomNavigationItemView; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; + +public class MainActivityTest { + + + + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + @Test + public void clickLocationsNavBar() throws Exception{ + //Here we click the back button and then we check if the statisticsFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().commit(); + onView(withId(R.id.locations)).perform(click()); + onView(withId(R.id.homeFragment)).check(matches(isDisplayed())); + } + + @Test + public void clickRouteNavBar() throws Exception{ + //Here we click the back button and then we check if the statisticsFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().commit(); + onView(withId(R.id.routes)).perform((click())); + onView(withId(R.id.routeFragment)).check(matches(isDisplayed())); + } + + @Test + public void clickStatisticsNavBar() throws Exception{ + //Here we click the back button and then we check if the statisticsFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().commit(); + onView(withId(R.id.statistics)).perform(click()); + onView(withId(R.id.statisticsFragment)).check(matches(isDisplayed())); + } + + @Test + public void clickSettingNavBar() throws Exception{ + //Here we click the back button and then we check if the statisticsFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().commit(); + onView(withId(R.id.settings)).perform(click()); + onView(withId(R.id.settingFragment)).check(matches(isDisplayed())); + } + +} diff --git a/app/src/androidTest/java/com/a1/nextlocation/RouteFragmentTest.java b/app/src/androidTest/java/com/a1/nextlocation/RouteFragmentTest.java new file mode 100644 index 0000000..c42c59f --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/RouteFragmentTest.java @@ -0,0 +1,39 @@ +package com.a1.nextlocation; + +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.LocationFragment; +import com.a1.nextlocation.fragments.RouteFragment; + +import org.junit.Rule; +import org.junit.Test; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; + +public class RouteFragmentTest { + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + @Test + public void clickBackButton() throws Exception{ + //Here we click the back button and then we check if the homeFragment is shown + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new RouteFragment()).commit(); + onView(withId(R.id.route_back_button)).perform(click()); + onView(withId(R.id.homeFragment)).check(matches(isDisplayed())); + + } + + @Test + public void clickDetailButton() throws Exception{ + //Here we click an item in the recyclerview and then check if the routeDetailFragment is called + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new RouteFragment()).commit(); + onView(withId(R.id.route_recyclerview)).perform(RecyclerViewActions.actionOnItemAtPosition(0, click())); + onView(withId(R.id.routeDetailFragment)).check(matches(isDisplayed())); + + } +} diff --git a/app/src/androidTest/java/com/a1/nextlocation/SettingsFragmentTest.java b/app/src/androidTest/java/com/a1/nextlocation/SettingsFragmentTest.java new file mode 100644 index 0000000..e2d99dd --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/SettingsFragmentTest.java @@ -0,0 +1,70 @@ +package com.a1.nextlocation; + +import androidx.test.espresso.action.ViewActions; +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.matcher.RootMatchers; +import androidx.test.espresso.matcher.ViewMatchers; +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.LocationFragment; +import com.a1.nextlocation.fragments.SettingsFragment; +import com.a1.nextlocation.fragments.StatisticFragment; + +import org.hamcrest.core.AllOf; +import org.hamcrest.core.Is; +import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; + +import static androidx.test.espresso.Espresso.*; +import static androidx.test.espresso.action.ViewActions.*; +import static androidx.test.espresso.assertion.ViewAssertions.*; +import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup; +import static androidx.test.espresso.matcher.ViewMatchers.*; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; + +public class SettingsFragmentTest { + + + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + //Tests if the back button sends you back home + @Test + public void clickBackButton() throws Exception{ + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new SettingsFragment()).commit(); + onView(withId(R.id.settings_back_button)).perform(click()); + onView(withId(R.id.homeFragment)).check(matches(isDisplayed())); + } + + //Checks if the dropdown is clickable, and checks if it has children + @Test + public void dropdownTest(){ + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new SettingsFragment()).commit(); + onView(withId(R.id.dropdown_menu_Settings)).check(matches(isClickable())); + onView(withId(R.id.dropdown_menu_Settings)).check(matches(hasMinimumChildCount(1))); + } + + //Tests if all buttons are clickable, and if they get checked after being clicked. + @Test + public void buttonTest(){ + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new SettingsFragment()).commit(); + onView(withId(R.id.settingsImperialButton)).check(matches(isClickable())); + onView(withId(R.id.settingsOldButton)).check(matches(isClickable())); + onView(withId(R.id.settingsEyesButton)).check(matches(isClickable())); + + onView(withId(R.id.settingsImperialButton)).perform(click()); + onView(withId(R.id.settingsImperialButton)).check(matches(isChecked())); + + onView(withId(R.id.settingsOldButton)).perform(click()); + onView(withId(R.id.settingsOldButton)).check(matches(isChecked())); + + onView(withId(R.id.settingsEyesButton)).perform(click()); + onView(withId(R.id.settingsEyesButton)).check(matches(isChecked())); + } +} diff --git a/app/src/androidTest/java/com/a1/nextlocation/StatisticFragmentTest.java b/app/src/androidTest/java/com/a1/nextlocation/StatisticFragmentTest.java new file mode 100644 index 0000000..e04ac58 --- /dev/null +++ b/app/src/androidTest/java/com/a1/nextlocation/StatisticFragmentTest.java @@ -0,0 +1,38 @@ +package com.a1.nextlocation; + +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.rule.ActivityTestRule; + +import com.a1.nextlocation.fragments.LocationFragment; +import com.a1.nextlocation.fragments.StatisticFragment; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; + +import static androidx.test.espresso.Espresso.*; +import static androidx.test.espresso.action.ViewActions.*; +import static androidx.test.espresso.assertion.ViewAssertions.*; +import static androidx.test.espresso.matcher.ViewMatchers.*; + +public class StatisticFragmentTest { + + @Rule + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class); + + //Tests to see if all boxes get created + @Test + public void checkText() throws Exception{ + mActivityTestRule.getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainActivity, new StatisticFragment()).commit(); + onView(withId(R.id.textView)).check(matches(isDisplayed())); + onView(withId(R.id.name_box)).check(matches(isDisplayed())); + onView(withId(R.id.Box2)).check(matches(isDisplayed())); + onView(withId(R.id.Box3)).check(matches(isDisplayed())); + onView(withId(R.id.Box4)).check(matches(isDisplayed())); + } + + + +} diff --git a/app/src/main/java/com/a1/nextlocation/MainActivity.java b/app/src/main/java/com/a1/nextlocation/MainActivity.java index a615490..ef12e7d 100644 --- a/app/src/main/java/com/a1/nextlocation/MainActivity.java +++ b/app/src/main/java/com/a1/nextlocation/MainActivity.java @@ -3,6 +3,9 @@ package com.a1.nextlocation; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; @@ -23,6 +26,7 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import java.io.File; import java.util.Arrays; +import java.util.Locale; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getName(); @@ -52,9 +56,33 @@ public class MainActivity extends AppCompatActivity { RouteListManager.INSTANCE.setContext(this); RouteListManager.INSTANCE.load(); + // initialize saved language from sharedPreferences + setLocale(loadLocale()); + getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, new HomeFragment()).commit(); } + /** + * loads the saved language from SharedPreferences + * @return the language as string + */ + private String loadLocale(){ + SharedPreferences sharedPreferences = getSharedPreferences("Settings", Activity.MODE_PRIVATE); + return sharedPreferences.getString("Language", "nl"); + } + + /** + * sets the language of the application to the desired one + * @param language the desired language + */ + private void setLocale(String language){ + Locale locale = new Locale(language); + Locale.setDefault(locale); + Configuration configuration = new Configuration(); + configuration.setLocale(locale); + getBaseContext().getResources().updateConfiguration(configuration, getBaseContext().getResources().getDisplayMetrics()); + } + private BottomNavigationView.OnNavigationItemSelectedListener navListener = item -> { Fragment selectedFragment = null; diff --git a/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java index c822134..d97bc31 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/CouponFragment.java @@ -61,22 +61,18 @@ public class CouponFragment extends Fragment { private void showPopup(Coupon coupon) { AlertDialog.Builder activateBuilder = new AlertDialog.Builder(getContext()); AlertDialog.Builder couponCodeBuilder = new AlertDialog.Builder(getContext()); - // TODO: use string resources instead of hardcoded strings - activateBuilder.setMessage("Weet je zeker dat je deze coupon wilt activeren?"); + activateBuilder.setMessage(getResources().getString(R.string.activate_question)); activateBuilder.setCancelable(true); - // TODO: use string resources instead of hardcoded strings - activateBuilder.setPositiveButton("activeren", (dialog, which) -> { - // TODO: use string resources instead of hardcoded strings + activateBuilder.setPositiveButton(R.string.activate, (dialog, which) -> { dialog.cancel(); couponCodeBuilder.setMessage("Code: " + coupon.getCode()); - couponCodeBuilder.setPositiveButton("Klaar", (dialog1, which1) -> { + couponCodeBuilder.setPositiveButton(R.string.done, (dialog1, which1) -> { dialog.cancel(); }); AlertDialog couponCodePopup = couponCodeBuilder.create(); couponCodePopup.show(); }); - // TODO: use string resources instead of hardcoded strings - activateBuilder.setNegativeButton("annuleren", (dialog, which) -> dialog.cancel()); + activateBuilder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.cancel()); AlertDialog couponPopup = activateBuilder.create(); couponPopup.show(); diff --git a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java index 31a8ccc..e79659e 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java @@ -28,6 +28,7 @@ import com.a1.nextlocation.data.RouteHandler; import com.a1.nextlocation.data.StaticData; import com.a1.nextlocation.json.DirectionsResult; import com.a1.nextlocation.network.ApiHandler; +import com.a1.nextlocation.network.DirectionsListener; import com.a1.nextlocation.recyclerview.LocationListManager; import org.osmdroid.api.IMapController; diff --git a/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java index 19f73cd..dc58ce3 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java @@ -49,4 +49,8 @@ public class LocationDetailFragment extends Fragment { } return view; } + + public void setLocation(Location location) { + this.location = location; + } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java index 917a54d..c4b0654 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/RouteDetailFragment.java @@ -8,6 +8,7 @@ import androidx.fragment.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageButton; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; @@ -15,13 +16,14 @@ import android.widget.Toast; import com.a1.nextlocation.R; import com.a1.nextlocation.data.Route; import com.a1.nextlocation.data.RouteHandler; -import com.a1.nextlocation.data.StaticData; import com.a1.nextlocation.network.ApiHandler; public class RouteDetailFragment extends Fragment { private Route route; private TextView routeDetailText; + private TextView routeName; + private ImageButton imageButton; @Override public void onCreate(Bundle savedInstanceState) { @@ -36,8 +38,18 @@ public class RouteDetailFragment extends Fragment { this.route = getArguments().getParcelable("route"); } + this.routeName = view.findViewById(R.id.route_title); + this.routeName.setText(this.route.getName()); + this.routeDetailText = view.findViewById(R.id.reoute_detail_tekst); - this.routeDetailText.setText(this.route.getName()); + this.routeDetailText.setText(this.route.getDescription()); + + this.imageButton = view.findViewById(R.id.route_detail_back_button); + this.imageButton.setOnClickListener(v -> { + RouteFragment routeFragment = new RouteFragment(); + ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, routeFragment).addToBackStack(null).commit(); + }); + Button startButton = view.findViewById(R.id.start_route_button); startButton.setOnClickListener(this::startRoute); diff --git a/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java index 7fbe6a3..ff52861 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/SettingsFragment.java @@ -1,6 +1,8 @@ package com.a1.nextlocation.fragments; +import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.os.Bundle; import androidx.annotation.NonNull; @@ -8,10 +10,12 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.SwitchCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentTransaction; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.Spinner; @@ -19,8 +23,12 @@ import android.widget.Spinner; import com.a1.nextlocation.MainActivity; import com.a1.nextlocation.R; +import java.util.Locale; + public class SettingsFragment extends Fragment { + private SharedPreferences.Editor editor; + private ImageView imageButton; SwitchCompat fontChanger; @@ -28,21 +36,16 @@ public class SettingsFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + editor = getContext().getSharedPreferences("Settings", Context.MODE_PRIVATE).edit(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - return inflater.inflate(R.layout.fragment_settings, container, false); - } - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); + View view = inflater.inflate(R.layout.fragment_settings, container, false); - // Inflate the layout for this fragment - Spinner dropdown = view.findViewById(R.id.dropdown_menu_Settings); + initializeLanguageDropdown(view); this.imageButton = view.findViewById(R.id.settings_back_button); this.imageButton.setOnClickListener(v -> { @@ -79,9 +82,95 @@ public class SettingsFragment extends Fragment { editor.commit(); }); + return view; + } + + private void initializeLanguageDropdown(View view) { + Spinner languageDropdown = view.findViewById(R.id.dropdown_menu_Settings); String[] items = new String[]{"Nederlands", "Engels", "Chinees"}; ArrayAdapter arrayAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_dropdown_item, items); + languageDropdown.setAdapter(arrayAdapter); - dropdown.setAdapter(arrayAdapter); + // set the language dropdown on the currently selected language stored in the sharedPreferences + languageDropdown.setSelection(languageToDropdownPosition(getContext().getSharedPreferences("Settings", Context.MODE_PRIVATE).getString("Language", ""))); + + long previousID = languageDropdown.getSelectedItemId(); + languageDropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + setLocale(dropdownPositionToLanguage(id)); + if (id != previousID) { + Fragment currentFragment = getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment_layout); + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.detach(currentFragment); + fragmentTransaction.attach(currentFragment); + fragmentTransaction.commit(); + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + } + + /** + * converts the languageDropdown position to the belonging language + * + * @param id desired position to convert + * @return the language belonging to the position of the languageDropdown + */ + private String dropdownPositionToLanguage(long id) { + switch ((int) id) { + case 0: + return "nl"; + case 1: + return "en"; + default: + return ""; + } + } + + /** + * converts language to the languageDropdown position + * + * @param language desired language to convert + * @return the position of the language in the languageDropdown + */ + private int languageToDropdownPosition(String language) { + switch (language) { + case "nl": + return 0; + case "en": + return 1; + default: + return 1; + } + } + + /** + * reloads the fragment + */ + private void refresh() { + Fragment currentFragment = getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment_layout); + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.detach(currentFragment); + fragmentTransaction.attach(currentFragment); + fragmentTransaction.commit(); + } + + /** + * changes the current language to the desired language and saves this setting in SharedPreferences + * + * @param language the desired language to translate to + */ + private void setLocale(String language) { + Locale locale = new Locale(language); + Locale.setDefault(locale); + Configuration config = new Configuration(); + config.setLocale(locale); + getContext().getResources().updateConfiguration(config, getContext().getResources().getDisplayMetrics()); + editor.putString("Language", language); + editor.apply(); } } \ No newline at end of file diff --git a/app/src/main/res/layout-land/fragment_location_detail.xml b/app/src/main/res/layout-land/fragment_location_detail.xml index 6e87547..386d98a 100644 --- a/app/src/main/res/layout-land/fragment_location_detail.xml +++ b/app/src/main/res/layout-land/fragment_location_detail.xml @@ -12,7 +12,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" - android:text="@string/locatie_detail" + android:text="" android:textColor="@color/white" android:textSize="30sp" app:layout_constraintEnd_toEndOf="parent" @@ -35,7 +35,7 @@ android:layout_height="283dp" android:layout_marginEnd="30dp" android:background="@color/secondaryColour" - android:text="@string/locatie_detail_tekst" + android:text="" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/detail_location_name" /> diff --git a/app/src/main/res/layout-land/fragment_route_detail.xml b/app/src/main/res/layout-land/fragment_route_detail.xml index 48263eb..3fe3a2d 100644 --- a/app/src/main/res/layout-land/fragment_route_detail.xml +++ b/app/src/main/res/layout-land/fragment_route_detail.xml @@ -38,7 +38,8 @@ android:layout_height="wrap_content" android:layout_marginEnd="250dp" android:text="titel" - android:textSize="20sp" + android:textColor="@color/white" + android:textSize="30sp" app:layout_constraintBottom_toTopOf="@+id/route_detail_image" app:layout_constraintEnd_toStartOf="@+id/reoute_detail_tekst" app:layout_constraintStart_toEndOf="@id/routeDetailBackButton" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b176cc3..cc1d88c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:id="@+id/mainActivity" tools:context=".MainActivity"> @@ -26,7 +27,6 @@ android:layout_marginTop="12dp" android:background="@drawable/ic_back_button_24" android:backgroundTint="@color/buttonColour" - android:text="@string/terug" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index bebf806..c97c363 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:id="@+id/homeFragment" tools:context=".fragments.HomeFragment"> @@ -26,7 +27,6 @@ android:layout_marginTop="12dp" android:background="@drawable/ic_back_button_24" android:backgroundTint="@color/buttonColour" - android:text="@string/terug" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/fragment_location_detail.xml b/app/src/main/res/layout/fragment_location_detail.xml index 8cc524a..a89a336 100644 --- a/app/src/main/res/layout/fragment_location_detail.xml +++ b/app/src/main/res/layout/fragment_location_detail.xml @@ -5,6 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/primaryColour" + android:id="@+id/locationDetailFragment" tools:context=".fragments.LocationDetailFragment"> @@ -43,7 +46,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/secondaryColour" - android:text="@string/locatie_detail_tekst" + android:text="" /> diff --git a/app/src/main/res/layout/fragment_route.xml b/app/src/main/res/layout/fragment_route.xml index f68174e..3904b49 100644 --- a/app/src/main/res/layout/fragment_route.xml +++ b/app/src/main/res/layout/fragment_route.xml @@ -5,6 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/primaryColour" + android:id="@+id/routeFragment" tools:context=".fragments.RouteFragment"> @@ -22,7 +22,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="9dp" - android:text="@string/titel" + android:text="@string/routes" android:textSize="20sp" app:layout_constraintStart_toEndOf="@id/route_back_button" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/fragment_route_detail.xml b/app/src/main/res/layout/fragment_route_detail.xml index e365bd9..477aa5c 100644 --- a/app/src/main/res/layout/fragment_route_detail.xml +++ b/app/src/main/res/layout/fragment_route_detail.xml @@ -5,6 +5,7 @@ android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@color/primaryColour" + android:id="@+id/routeDetailFragment" tools:context=".fragments.RouteDetailFragment"> diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 6a6222a..343de74 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -5,6 +5,7 @@ android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@color/primaryColour" + android:id="@+id/settingFragment" tools:context=".fragments.SettingsFragment"> @@ -232,7 +232,6 @@ android:background="@drawable/ic_back_button_24" android:backgroundTint="@color/buttonColour" android:src="@drawable/ic_back_button_24" - android:text="@string/terug" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/location_item.xml b/app/src/main/res/layout/location_item.xml index d164865..6eb9b2f 100644 --- a/app/src/main/res/layout/location_item.xml +++ b/app/src/main/res/layout/location_item.xml @@ -5,6 +5,7 @@ android:layout_height="50dp" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@color/secondaryColour" + android:id="@+id/locationItem" android:layout_margin="20dp"> @@ -15,13 +15,13 @@ diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml new file mode 100644 index 0000000..893ffe7 --- /dev/null +++ b/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,23 @@ + + + + Next Location + Locaties + Routes + Statistieken + Instellingen + Taal + Imperiaal systeem + 65+ stand + Kleurenblind + Totale afstand: + Bezochte locaties: + Totale tijd: + Coupons gespaard: + Coupons + Start Route + Weet je zeker dat je deze coupon wilt activeren? + activeren + Klaar + annuleren + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cac68cf..1e72755 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,21 +1,22 @@ - Next Location - - Hello blank fragment - Locaties + Next Location + Location Routes - Statistieken - Instellingen - Taal - Imperiaal systeem - 65+ stand - Kleurenblind - Statistieken - Totale afstand: - Bezochte locaties: - Totale tijd: - Coupons gespaard: + Statistics + Settings + Language + Imperial system + 65+ mode + Colorblind + Total distance: + Visited locations: + Total time: + Coupons collected: Coupons Start Route + Are you sure you want to activate this coupon? + activate + Done + cancel Route stopped! \ No newline at end of file diff --git a/app/src/test/java/com/a1/nextlocation/DirectionsResultTest.java b/app/src/test/java/com/a1/nextlocation/DirectionsResultTest.java new file mode 100644 index 0000000..ad4588f --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/DirectionsResultTest.java @@ -0,0 +1,50 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.json.DirectionsResult; +import com.a1.nextlocation.json.DirectionsStep; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class DirectionsResultTest { + private DirectionsResult directionsResult; + + @Before + public void init(){ + directionsResult = new DirectionsResult(); + } + + @Test + public void testDistance(){ + directionsResult.setDistance(45.32); + double expected = 45.32; + + assertEquals(expected, directionsResult.getDistance(), 0.01); + } + + @Test + public void testDuration(){ + directionsResult.setDuration(95.123); + double expected = 95.123; + + assertEquals(expected, directionsResult.getDuration(), 0.01); + } + + @Test + public void testSteps(){ + List expected = new ArrayList<>(); + directionsResult.addStep(new DirectionsStep()); + directionsResult.addStep(new DirectionsStep()); + directionsResult.addStep(new DirectionsStep()); + directionsResult.setSteps(expected); + + assertEquals(expected, directionsResult.getSteps()); + } + + +} diff --git a/app/src/test/java/com/a1/nextlocation/DirectionsStepTest.java b/app/src/test/java/com/a1/nextlocation/DirectionsStepTest.java new file mode 100644 index 0000000..d719f4e --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/DirectionsStepTest.java @@ -0,0 +1,69 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.json.DirectionsStep; + +import org.junit.Before; +import org.junit.Test; +import org.osmdroid.util.GeoPoint; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class DirectionsStepTest { + private DirectionsStep directionsStep; + @Before + public void init(){ + directionsStep = new DirectionsStep(); + } + + @Test + public void testDistance(){ + directionsStep.setDistance(432.56); + double expected = 432.56; + assertEquals(expected, directionsStep.getDistance(), 0.01); + } + + @Test + public void testDuration(){ + directionsStep.setDuration(531.89); + double expected = 531.89; + assertEquals(expected, directionsStep.getDuration(), 0.01); + } + + @Test + public void testInstuction(){ + directionsStep.setInstruction("TESTINGINSTUCTION"); + String expected = "TESTINGINSTUCTION"; + assertEquals(expected, directionsStep.getInstruction()); + } + + @Test + public void testName(){ + directionsStep.setName("TESTINGNAME"); + String expected = "TESTINGNAME"; + assertEquals(expected, directionsStep.getName()); + } + + @Test + public void testWay_Points(){ + ArrayList expected = new ArrayList<>(); + expected.add(56); + expected.add(1123); + expected.add(23); + expected.add(73); + directionsStep.setWay_points(expected); + + assertEquals(expected, directionsStep.getWay_points()); + } + + @Test + public void testWayPoints(){ + GeoPoint[] expected = {new GeoPoint(5.1658, 4.163), new GeoPoint(2.0896, 7.158), + new GeoPoint(4.0168, 6.1450), new GeoPoint(7.1498, 9.1586), }; + directionsStep.setWaypoints(expected); + + assertEquals(expected, directionsStep.getWaypoints()); + } +} diff --git a/app/src/test/java/com/a1/nextlocation/GeometryDecoderTest.java b/app/src/test/java/com/a1/nextlocation/GeometryDecoderTest.java new file mode 100644 index 0000000..2a12c8c --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/GeometryDecoderTest.java @@ -0,0 +1,22 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.json.GeometryDecoder; +import com.google.gson.JsonArray; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class GeometryDecoderTest { + + @Test + public void geometryDecoderTest(){ + String encodedGeometryTest = ""; + + JsonArray expected = new JsonArray(); + + + + assertEquals(expected, GeometryDecoder.decodeGeometry(encodedGeometryTest, true)); + } +}