diff --git a/app/build.gradle b/app/build.gradle index 78feb6e..c8075fb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,6 +31,7 @@ repositories { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:preference-v7:27.1.1' implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:design:27.1.1' implementation 'com.android.support:support-v4:27.1.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 54170df..ed85fed 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,6 @@ - @@ -45,18 +44,16 @@ android:label="@string/title_activity_login" android:launchMode="singleTask" android:noHistory="true" /> - + android:exported="false" + android:launchMode="singleTop" /> - + \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java index 9bfc6a5..e08ad48 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/SharingFragment.java @@ -2,6 +2,7 @@ package com.uam.wmi.findmytutor.activity; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.FragmentTransaction; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -9,16 +10,26 @@ import android.os.Build; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.Toast; +import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; import com.uam.wmi.findmytutor.R; +import com.uam.wmi.findmytutor.model.Feedback; +import com.uam.wmi.findmytutor.network.ApiClient; import com.uam.wmi.findmytutor.service.BackgroundLocalizationService; +import com.uam.wmi.findmytutor.service.FeedbackService; +import com.uam.wmi.findmytutor.service.PredefinedStatusesService; import com.uam.wmi.findmytutor.utils.PrefUtils; + +import com.uam.wmi.findmytutor.utils.RestApiHelper; +import com.uam.wmi.findmytutor.utils.RightButtonPreference; import com.uam.wmi.findmytutor.utils.SharingLevel; import java.util.Arrays; @@ -29,58 +40,145 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.observers.DisposableSingleObserver; +import io.reactivex.schedulers.Schedulers; +import okhttp3.ResponseBody; +import retrofit2.Response; + import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; public class SharingFragment extends PreferenceFragment { private HashMap locationLevelMapping; -// private HashMap statusMapping; + private HashMap statusMapping; + private PredefinedStatusesService statusesService; + private CompositeDisposable disposable; + protected Preference locationSharing; + protected Preference locationMode; + protected Preference manualLocationList; + protected PreferenceCategory preferenceCategory; + protected RightButtonPreference manualLocationButton; + protected Preference manualStatus; + protected ListPreference statusList; + + void getStatuses(CompositeDisposable disposable){ + disposable.add(statusesService.getUserPredefinedStatuses(PrefUtils.getUserId(getApplicationContext())) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableSingleObserver>() { + @Override + public void onSuccess(List strings) { + setListPreferenceData(statusList.getKey(),strings.toArray(new String[strings.size()])); + } + + @Override + public void onError(Throwable e) { + Toast.makeText(getApplicationContext(), "Error handling status fetch", Toast.LENGTH_SHORT).show(); + + } + })); + } @SuppressLint("ResourceType") @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - locationLevelMapping = new HashMap(); + addPreferencesFromResource(R.layout.pref_sharing); + locationSharing = findPreference("key_sharing_enabled"); + locationMode = findPreference("key_location_level"); + preferenceCategory = (PreferenceCategory) findPreference("category_sharing"); + manualLocationList = findPreference("key_manual_location_value"); + manualLocationButton = (RightButtonPreference) findPreference("manual_location_button"); + manualStatus = findPreference("key_manual_status"); + statusList =(ListPreference) findPreference("key_status_value"); + + statusesService = ApiClient.getClient(getApplicationContext()).create(PredefinedStatusesService.class); + disposable = new CompositeDisposable(); + getStatuses(disposable); + + locationLevelMapping = new HashMap(); locationLevelMapping.put(0, SharingLevel.PRESENCE.toString()); locationLevelMapping.put(1, SharingLevel.APPROXIMATED.toString()); locationLevelMapping.put(2, SharingLevel.EXACT.toString()); locationLevelMapping.put(3, SharingLevel.MANUAL.toString()); - addPreferencesFromResource(R.layout.pref_sharing); - Preference manualStatus = findPreference("key_manual_status"); - Preference locationSharing = findPreference("key_sharing_enabled"); - Preference locationMode = findPreference("key_location_level"); - Preference statusList = findPreference("key_status_value"); - - - manualStatus.setOnPreferenceChangeListener((preference, newValue) -> { - ListPreference lp = (ListPreference) findPreference("key_status_value"); - updateListPreference(lp, newValue, "manual_statuses"); - PrefUtils.storeStatus(getApplicationContext(),(String) newValue); + statusMapping = new HashMap(); + statusMapping.put(0,"available"); + statusMapping.put(1,"consultation"); + statusMapping.put(2,"busy"); + /** Main sharing switch**/ + locationSharing.setOnPreferenceChangeListener((buttonView, newValue) -> { + PrefUtils.storeEnableSharingLocalization(getApplicationContext(), (Boolean) newValue); + ((MapActivity)getActivity()).handleBackgroundTaskLifeCycle(); return true; }); + /** Sharing level list **/ locationMode.setOnPreferenceChangeListener((preference, newValue) -> { PrefUtils.storeLocationMode(getApplicationContext(),locationLevelMapping.get(Integer.parseInt((String) newValue))); + if(PrefUtils.getLocationLevel(getApplicationContext()) == "manual"){ + preferenceCategory.addPreference(manualLocationList); + preferenceCategory.addPreference(manualLocationButton); + }else{ + preferenceCategory.removePreference(manualLocationList); + preferenceCategory.removePreference(manualLocationButton); + } return true; }); + /** Manual location category hiding when location level is != manual **/ + if(!PrefUtils.getLocationLevel(getApplicationContext()).equals("manual")){ + preferenceCategory.removePreference(manualLocationList); + preferenceCategory.removePreference(manualLocationButton); + } + /** Custom manual location list change listener **/ + manualLocationList.setOnPreferenceChangeListener((preference, newValue) -> { + ListPreference lp = (ListPreference) preference; + //ToDo handle manual location change + + return true; + }); + /** Button 'choose from map' button listener **/ + manualLocationButton.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object o) { + //ToDO wywołanie wybierania lokalizacji z mapy + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.hide(SharingFragment.this); + fragmentTransaction.commit(); + return true; + } + }); + + /** Status list change listener **/ statusList.setOnPreferenceChangeListener((preference, newValue) -> { ListPreference lp = (ListPreference) preference; CharSequence [] entries = lp.getEntries(); PrefUtils.storeStatus(getApplicationContext(),(String) entries[Integer.parseInt((String) newValue)]); +// PrefUtils.storeStatus(getApplicationContext(),statusMapping.get(Integer.parseInt((String) newValue))); + + return true; + }); + /** Custom status list change listener **/ + manualStatus.setOnPreferenceChangeListener((preference, newValue) -> { +// ListPreference lp = (ListPreference) findPreference("key_status_value"); +// updateListPreference(lp, newValue, "manual_statuses"); +// PrefUtils.storeStatus(getApplicationContext(),(String) newValue); +// statusList.setValue((String) newValue); + disposable.add(statusesService.postUserPredefinedStatus(PrefUtils.getUserId(getApplicationContext()),(String) newValue) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleResponse, this::handleError)); + return true; }); - locationSharing.setOnPreferenceChangeListener((buttonView, newValue) -> { - PrefUtils.storeEnableSharingLocalization(getApplicationContext(), (Boolean) newValue); - ((MapActivity)getActivity()).handleBackgroundTaskLifeCycle(); - return true; - }); } public static SharingFragment newInstance() { @@ -109,8 +207,9 @@ public class SharingFragment extends PreferenceFragment { Set manualStatusSet = sharedPref.getStringSet(storageKey,defaultEntries); manualStatusSet.add((String) newValue); String [] manualStatusArr = manualStatusSet.toArray(new String[0]); - Arrays.sort(manualStatusArr); + //Arrays.sort(manualStatusArr); setListPreferenceData(lp.getKey(),manualStatusArr); +// lp.setValue((String) newValue); SharedPreferences.Editor editor = sharedPref.edit(); editor.putStringSet(storageKey,manualStatusSet); @@ -118,6 +217,7 @@ public class SharingFragment extends PreferenceFragment { } protected void setListPreferenceData(String lp_name, String [] entries) { + //todo bug z pustym statusem ListPreference lp = (ListPreference) findPreference(lp_name); lp.setEntries(entries); CharSequence[] entryValues = new CharSequence [entries.length]; @@ -129,4 +229,27 @@ public class SharingFragment extends PreferenceFragment { lp.setDefaultValue("1"); lp.setEntryValues(entryValues); } + private void handleResponse(List resp) { + getStatuses(disposable); + String newStatus = resp.toArray(new String[resp.size()])[resp.size()-1]; +// Toast.makeText(getApplicationContext(), newStatus, Toast.LENGTH_SHORT).show(); + + statusList.setValue(Integer.toString(resp.size()-1)); + statusList.setSummary(newStatus); + } + + private void handleError(Throwable error) { + if (error instanceof HttpException) { + + ResponseBody responseBody = ((HttpException) error).response().errorBody(); + Toast.makeText(getApplicationContext(), + RestApiHelper.getErrorMessage(responseBody), Toast.LENGTH_SHORT).show(); + + } else { + Toast.makeText(getApplicationContext(), + "Network error " + error.getMessage(), Toast.LENGTH_SHORT).show(); + Log.d("FEEDBACK",error.getMessage()); + } + } + } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/model/PredefinedCoordViewModel.java b/app/src/main/java/com/uam/wmi/findmytutor/model/PredefinedCoordViewModel.java new file mode 100644 index 0000000..78b4897 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/model/PredefinedCoordViewModel.java @@ -0,0 +1,187 @@ +package com.uam.wmi.findmytutor.model; +import java.util.UUID; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class PredefinedCoordViewModel { + + @SerializedName("predefinedCoordinateId") + @Expose + private UUID predefinedCoordinateId; + /** + * + * (Required) + * + */ + @SerializedName("latitude") + @Expose + private Double latitude; + /** + * + * (Required) + * + */ + @SerializedName("longitude") + @Expose + private Double longitude; + /** + * + * (Required) + * + */ + @SerializedName("altitude") + @Expose + private Double altitude; + /** + * + * (Required) + * + */ + @SerializedName("userId") + @Expose + private String userId; + @SerializedName("approximatedLocation") + @Expose + private String approximatedLocation; + @SerializedName("displayMode") + @Expose + private String displayMode = "predefined"; + @SerializedName("label") + @Expose + private String label; + + /** + * No args constructor for use in serialization + * + */ + public PredefinedCoordViewModel() { + } + + /** + * + * @param altitude + * @param userId + * @param displayMode + * @param label + * @param longitude + * @param latitude + * @param approximatedLocation + * @param predefinedCoordinateId + */ + public PredefinedCoordViewModel(UUID predefinedCoordinateId, Double latitude, Double longitude, Double altitude, String userId, String approximatedLocation, String displayMode, String label) { + super(); + this.predefinedCoordinateId = predefinedCoordinateId; + this.latitude = latitude; + this.longitude = longitude; + this.altitude = altitude; + this.userId = userId; + this.approximatedLocation = approximatedLocation; + this.displayMode = displayMode; + this.label = label; + } + + public UUID getPredefinedCoordinateId() { + return predefinedCoordinateId; + } + + public void setPredefinedCoordinateId(UUID predefinedCoordinateId) { + this.predefinedCoordinateId = predefinedCoordinateId; + } + + /** + * + * (Required) + * + */ + public Double getLatitude() { + return latitude; + } + + /** + * + * (Required) + * + */ + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + /** + * + * (Required) + * + */ + public Double getLongitude() { + return longitude; + } + + /** + * + * (Required) + * + */ + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + /** + * + * (Required) + * + */ + public Double getAltitude() { + return altitude; + } + + /** + * + * (Required) + * + */ + public void setAltitude(Double altitude) { + this.altitude = altitude; + } + + /** + * + * (Required) + * + */ + public String getUserId() { + return userId; + } + + /** + * + * (Required) + * + */ + public void setUserId(String userId) { + this.userId = userId; + } + + public String getApproximatedLocation() { + return approximatedLocation; + } + + public void setApproximatedLocation(String approximatedLocation) { + this.approximatedLocation = approximatedLocation; + } + + public String getDisplayMode() { + return displayMode; + } + + public void setDisplayMode(String displayMode) { + this.displayMode = displayMode; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java index 331e703..b257bfd 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundLocalizationService.java @@ -321,7 +321,7 @@ public class BackgroundLocalizationService extends Service { longitude, altitude, approximatedBuildingPart, - PrefUtils.getUserStatus(getApplicationContext()), + (PrefUtils.isStatusEnabled(getApplicationContext())) ? PrefUtils.getUserStatus(getApplicationContext()) : "", PrefUtils.getUserId(getApplicationContext()), PrefUtils.getLocationLevel(getApplicationContext()) ); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedStatusesService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedStatusesService.java new file mode 100644 index 0000000..b52d79e --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedStatusesService.java @@ -0,0 +1,29 @@ +package com.uam.wmi.findmytutor.service; +import com.uam.wmi.findmytutor.model.PredefinedCoordViewModel; +import java.util.List; +import io.reactivex.Single; +import retrofit2.http.Body; +import retrofit2.http.DELETE; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; + +public interface PredefinedStatusesService { + @GET("api/users/predefined/status/{tutorId}") + Single> getUserPredefinedStatuses(@Path("tutorId") String tutorId); + + @POST("api/users/predefined/status/{tutorId}") + Single> postUserPredefinedStatus(@Path("tutorId") String tutorId, @Body String status); + + @DELETE("api/users/predefined/status/{tutorId}") + Single> deleteUserPredefinedStatus(@Path("tutorId") String tutorId, @Body String status); + + @GET("api/users/predefined/coordinate/{tutorId}") + Single> getUserPredefinedCoords(@Path("tutorId") String tutorId); + + @POST("api/users/predefined/coordinate/{tutorId}") + Single> postUserPredefinedCoord(@Path("tutorId") String tutorId, @Body PredefinedCoordViewModel coord); + + @DELETE("api/users/predefined/coordinate/{tutorId}") + Single> deleteUserPredefinedCoord(@Path("tutorId") String tutorId, @Body PredefinedCoordViewModel coord); +} diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/FeedbackUtils.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/FeedbackUtils.java index afb3acd..ab12f54 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/FeedbackUtils.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/FeedbackUtils.java @@ -38,7 +38,7 @@ public class FeedbackUtils { LayoutInflater layoutInflaterAndroid = LayoutInflater.from(activityContext); View view = layoutInflaterAndroid.inflate(R.layout.feedback_modal, null); AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(activityContext); - alertDialogBuilderUserInput.setView(view).setPositiveButton("SEND",null); + alertDialogBuilderUserInput.setView(view).setPositiveButton(activityContext.getString(R.string.modal_feedback_send),null); final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); EditText modalUserInput = view.findViewById(R.id.feedback_input); @@ -46,11 +46,10 @@ public class FeedbackUtils { TextView modalTitle = view.findViewById(R.id.feedback_modal_title); TextView modalSubtitle = view.findViewById(R.id.feedback_modal_subtitle); modalTitle.setText(subject); - if( subject == "BUG REPORT"){ - modalSubtitle.setText("Tell us what you noticed!(max 1000 characters)"); - } else if (subject == "FEEDBACK") - { - modalSubtitle.setText("Tell us what you think!(max 1000 characters)"); + if( subject.equals(activityContext.getString(R.string.title_bug_report)) ){ + modalSubtitle.setText(activityContext.getString(R.string.title_bug_report_notice)); + } else { + modalSubtitle.setText(activityContext.getString(R.string.title_feedback_report_notice)); } alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override @@ -61,7 +60,7 @@ public class FeedbackUtils { public void onClick(View view) { String body = modalUserInput.getText().toString(); if(TextUtils.isEmpty(body)){ - Toast.makeText(activityContext, "Please describe your insights.", Toast.LENGTH_SHORT).show(); + Toast.makeText(activityContext, activityContext.getString(R.string.modal_feedback_hint), Toast.LENGTH_SHORT).show(); modalUserInput.requestFocus(); }else{ boolean mode = modalIsAnonymous.isChecked(); @@ -103,7 +102,7 @@ public class FeedbackUtils { .subscribe(this::handleResponse, this::handleError)); } private void handleResponse(Response resp) { - Toast.makeText(activityContext, "Thank you for subbmiting your feedback", Toast.LENGTH_SHORT).show(); + Toast.makeText(activityContext, activityContext.getString(R.string.modal_feedback_thankyou), Toast.LENGTH_SHORT).show(); } private void handleError(Throwable error) { diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java index 88a31a4..6a8793b 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/PrefUtils.java @@ -54,6 +54,10 @@ public class PrefUtils { return getSharedPreferences(context).getString("USER_ID", null); } + public static boolean isStatusEnabled(Context context){ + return getSharedPreferences(context).getBoolean("key_status_enabled",false); + + } public static String getUserStatus(Context context) { return getSharedPreferences(context).getString("status_entry", "Available"); } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/RightButtonPreference.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/RightButtonPreference.java new file mode 100644 index 0000000..5fdf137 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/RightButtonPreference.java @@ -0,0 +1,40 @@ +package com.uam.wmi.findmytutor.utils; +import android.content.Context; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import com.uam.wmi.findmytutor.R; + +public class RightButtonPreference extends Preference { + + public RightButtonPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setWidgetLayoutResource(R.layout.preference_button_widget); + } + @Override + protected View onCreateView(ViewGroup parent) { + View view = super.onCreateView(parent); +// LayoutInflater li = (LayoutInflater)getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE ); +// View temp =li.inflate( R.layout.preference_button_widget, parent, false); + return view; + } + @Override + protected void onBindView(View view) + { + super.onBindView(view); + Button button = (Button)view.findViewById(R.id.button_choose_from_map); + if(button != null) + { + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + callChangeListener(null); + notifyChanged(); + } + }); + } + } + +} diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/SharingLevel.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/SharingLevel.java index 9b0a027..b9b04f2 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/SharingLevel.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/SharingLevel.java @@ -4,7 +4,7 @@ public enum SharingLevel { PRESENCE("presence"), APPROXIMATED("approximated"), EXACT("exact"), - MANUAL("manuak"); + MANUAL("manual"); private final String text; diff --git a/app/src/main/res/layout/feedback_modal.xml b/app/src/main/res/layout/feedback_modal.xml index c3b8aa2..375a923 100644 --- a/app/src/main/res/layout/feedback_modal.xml +++ b/app/src/main/res/layout/feedback_modal.xml @@ -63,6 +63,5 @@ android:layout_alignEnd="@+id/feedback_input" android:layout_marginEnd="0dp" android:layout_marginBottom="-50dp" - android:text="Tell us what you think (max 1000 characters)" android:textSize="14sp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/pref_sharing.xml b/app/src/main/res/layout/pref_sharing.xml index 95817ac..73f957b 100644 --- a/app/src/main/res/layout/pref_sharing.xml +++ b/app/src/main/res/layout/pref_sharing.xml @@ -6,7 +6,9 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + + + @@ -32,7 +44,7 @@ android:title="@string/status_switch_title"/> - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/preference_button_widget.xml b/app/src/main/res/layout/preference_button_widget.xml new file mode 100644 index 0000000..afb935d --- /dev/null +++ b/app/src/main/res/layout/preference_button_widget.xml @@ -0,0 +1,13 @@ + + +