diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..d7a7dfa --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3c14510..ddf3e1a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ android { applicationId "com.uam.wmi.findmytutor" minSdkVersion 22 targetSdkVersion 27 - versionCode 1 + versionCode 3 versionName "0.9.0-alpha" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -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' @@ -58,7 +59,7 @@ dependencies { implementation 'com.auth0.android:jwtdecode:1.1.1' implementation 'com.annimon:stream:1.2.1' implementation 'com.google.android.gms:play-services-location:16.0.0' - + implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:4.0.0' // FloatingBarMenu implementation 'com.getbase:floatingactionbutton:1.10.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/assets/building.geojson b/app/src/main/assets/building.geojson new file mode 100644 index 0000000..a151032 --- /dev/null +++ b/app/src/main/assets/building.geojson @@ -0,0 +1,398 @@ +{ + "features": [ + { + "type": "Feature", + "properties": { + "name": "Skrzydło B", + "longitude" : 52.466669, + "latitude" : 16.926624 + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92618, + 52.466248 + ], + [ + 16.926435, + 52.466201 + ], + [ + 16.92646, + 52.466255 + ], + [ + 16.926516, + 52.466244 + ], + [ + 16.926999, + 52.46711 + ], + [ + 16.926796, + 52.467145 + ], + [ + 16.926782, + 52.467117 + ], + [ + 16.926784, + 52.467121 + ], + [ + 16.926691, + 52.467139 + ], + [ + 16.926662, + 52.46709 + ], + [ + 16.926757, + 52.467072 + ], + [ + 16.926544, + 52.466691 + ], + [ + 16.926434, + 52.46671 + ], + [ + 16.926396, + 52.466655 + ], + [ + 16.926519, + 52.466628 + ], + [ + 16.926323, + 52.466281 + ], + [ + 16.926213, + 52.466307 + ], + [ + 16.92618, + 52.466248 + ] + ] + ], + "type": "Polygon" + }, + "id": "41798cf663bc55c10e6c51c3fe174eda" + }, + { + "type": "Feature", + "properties": { + "name": "Biblioteka", + "longitude" : 52.467351, + "latitude" : 16.926900 + }, + "geometry": { + "coordinates": [ + [ + [ + 16.927048, + 52.46721 + ], + [ + 16.926627, + 52.467295 + ], + [ + 16.926732, + 52.467482 + ], + [ + 16.926876, + 52.467461 + ], + [ + 16.926967, + 52.467428 + ], + [ + 16.927014, + 52.467402 + ], + [ + 16.927171, + 52.467359 + ], + [ + 16.9271, + 52.467202 + ], + [ + 16.927048, + 52.46721 + ] + ] + ], + "type": "Polygon" + }, + "id": "7328c3c9dffd3e76be8d3dcef4f58ddc" + }, + { + "type": "Feature", + "properties": { + "name": "Łącznik", + "longitude" : 52.466619, + "latitude" : 16.926860 + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926759, + 52.466683 + ], + [ + 16.927088, + 52.46661 + ], + [ + 16.927019, + 52.466502 + ], + [ + 16.9267, + 52.466571 + ], + [ + 16.926759, + 52.466683 + ] + ] + ], + "type": "Polygon" + }, + "id": "8c19ee28e4c07ece9756fd21f290713b" + }, + { + "type": "Feature", + "properties": { + "name": "Skrzydło A", + "longitude" : 52.466559, + "latitude" : 16.927163 + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926771, + 52.466106 + ], + [ + 16.926898, + 52.466079 + ], + [ + 16.926926, + 52.466126 + ], + [ + 16.927026, + 52.466107 + ], + [ + 16.92723, + 52.466473 + ], + [ + 16.927184, + 52.466483 + ], + [ + 16.927243, + 52.466586 + ], + [ + 16.927334, + 52.46656 + ], + [ + 16.927602, + 52.466889 + ], + [ + 16.927275, + 52.466959 + ], + [ + 16.926771, + 52.466106 + ] + ] + ], + "type": "Polygon" + }, + "id": "c33bfba772c85cc38ae417843d31b1ff" + }, + { + "type": "Feature", + "properties": { + "name": "Aule", + "longitude" : 52.467114, + "latitude" : 16.927621 + + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92731, + 52.467158 + ], + [ + 16.927315, + 52.46718 + ], + [ + 16.927348, + 52.467199 + ], + [ + 16.927393, + 52.467224 + ], + [ + 16.927426, + 52.467239 + ], + [ + 16.927476, + 52.467258 + ], + [ + 16.92755, + 52.467264 + ], + [ + 16.927625, + 52.467263 + ], + [ + 16.927699, + 52.467246 + ], + [ + 16.92776, + 52.467212 + ], + [ + 16.927821, + 52.467158 + ], + [ + 16.927838, + 52.467099 + ], + [ + 16.927827, + 52.467059 + ], + [ + 16.927793, + 52.467012 + ], + [ + 16.927738, + 52.466976 + ], + [ + 16.927661, + 52.466949 + ], + [ + 16.927581, + 52.466939 + ], + [ + 16.927534, + 52.466938 + ], + [ + 16.927467, + 52.466949 + ], + [ + 16.927387, + 52.467047 + ], + [ + 16.927315, + 52.467153 + ], + [ + 16.92731, + 52.467158 + ] + ] + ], + "type": "Polygon" + }, + "id": "c779419e3fd7faef8555e1099547a82c" + }, + { + "type": "Feature", + "properties": { + "name": "Hol", + "longitude" : 52.4671021, + "latitude" : 16.927122 + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926625, + 52.467294 + ], + [ + 16.926568, + 52.46719 + ], + [ + 16.927008, + 52.467108 + ], + [ + 16.926953, + 52.467024 + ], + [ + 16.927463, + 52.466919 + ], + [ + 16.927467, + 52.466956 + ], + [ + 16.927316, + 52.467153 + ], + [ + 16.926907, + 52.467235 + ], + [ + 16.926625, + 52.467294 + ] + ] + ], + "type": "Polygon" + }, + "id": "facdd5349991758b9ad99d4e123c91cc" + } + ], + "type": "FeatureCollection" +} \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java index 2f4cba0..c347afc 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/BaseActivity.java @@ -1,6 +1,7 @@ package com.uam.wmi.findmytutor.activity; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Intent; @@ -24,15 +25,22 @@ import android.view.MenuItem; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; - import com.uam.wmi.findmytutor.R; import com.uam.wmi.findmytutor.service.BackgroundLocalizationService; import com.uam.wmi.findmytutor.utils.ActiveFragment; +import com.uam.wmi.findmytutor.utils.FeedbackUtils; import com.uam.wmi.findmytutor.utils.PrefUtils; +import com.uam.wmi.findmytutor.utils.RxSearchObservable; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.TimeUnit; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + import static com.uam.wmi.findmytutor.utils.PrefUtils.storeBackgroundLocationStatus; @@ -41,14 +49,10 @@ public abstract class BaseActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener { - String tag = getClass().getName(); - protected static final int REQUEST_PERMISSIONS = 100; private final static int REQUEST_CODE_ASK_PERMISSIONS = 1; - - private static final String[] REQUIRED_SDK_PERMISSIONS = new String[] { - Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS }; - + private static final String[] REQUIRED_SDK_PERMISSIONS = new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS}; public DrawerLayout drawerLayout; protected BottomNavigationView navigationView; protected NavigationView drawerNavigationView; @@ -56,43 +60,52 @@ public abstract class BaseActivity protected Toolbar toolbar; protected boolean isTutor; + String tag = getClass().getName(); + + protected FeedbackUtils feedbackUtils; + private ActionBarDrawerToggle actionBarDrawerToggle; private SharingFragment sharingFragment; private Fragment userListFragment; private ActiveFragment activeFragment = ActiveFragment.NONE; + private SearchView searchView; + @SuppressLint("CheckResult") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getContentViewId()); drawerNavigationView = findViewById(R.id.nav_view); sideDrawer = findViewById(R.id.activity_container); - + feedbackUtils = new FeedbackUtils(BaseActivity.this); drawerNavigationView.setNavigationItemSelectedListener( item -> { String itemName = (String) item.getTitle(); Intent launchIntent; - if (itemName.equals(getResources().getString(R.string.navigation_item_whitelist))) { + if (itemName.equals(getResources().getString(R.string.navigation_item_whitelist))) { /* launchIntent = new Intent(getApplicationContext(), WhitelistActivity.class); startActivity(launchIntent);*/ - } else if (itemName.equals(getResources().getString(R.string.navigation_item_blacklist))) { + } else if (itemName.equals(getResources().getString(R.string.navigation_item_blacklist))) { /* launchIntent = new Intent(getApplicationContext(), BlacklistActivity.class); startActivity(launchIntent);*/ - } else if (itemName.equals(getResources().getString(R.string.navigation_item_profile))) { + + } else if (itemName.equals(getResources().getString(R.string.navigation_item_profile))) { + /* launchIntent = new Intent(getApplicationContext(), ProfileActivity.class); startActivity(launchIntent);*/ - } else if (itemName.equals(getResources().getString(R.string.navigation_item_settings))) { + } else if (itemName.equals(getResources().getString(R.string.navigation_item_settings))) { launchIntent = new Intent(getApplicationContext(), SettingsActivity.class); startActivity(launchIntent); - } else if (itemName.equals(getResources().getString(R.string.navigation_item_logout))) { + } else if (itemName.equals(getResources().getString(R.string.navigation_item_logout))) { if(PrefUtils.isBackgroundLocationServiceRunning(getApplicationContext())) { + stopBackgroundLocalizationTask(); } - storeBackgroundLocationStatus(getApplication(),false); - PrefUtils.storeIsLoggedIn(getApplicationContext(),false); + storeBackgroundLocationStatus(getApplication(), false); + PrefUtils.storeIsLoggedIn(getApplicationContext(), false); Intent i = getBaseContext().getPackageManager() .getLaunchIntentForPackage(getBaseContext().getPackageName()); @@ -101,8 +114,14 @@ public abstract class BaseActivity } startActivity(i); finish(); + } else if (itemName.equals(getResources().getString(R.string.navigation_item_feedback))) { + feedbackUtils.showNoteDialog("FEEDBACK"); - } + /*showNoteDialog(BaseActivity.this, );*/ + } else if (itemName.equals(getResources().getString(R.string.navigation_item_bug))) { + feedbackUtils.showNoteDialog("BUG REPORT"); + /*showNoteDialog(BaseActivity.this, "BUG REPORT");*/ + } sideDrawer.closeDrawers(); @@ -116,14 +135,13 @@ public abstract class BaseActivity userListFragment = new UsersListFragment(); isTutor = PrefUtils.getIsTutor(getApplicationContext()); + if (!isTutor) { navigationView.findViewById(R.id.nav_profile).setVisibility(View.GONE); + drawerNavigationView.getMenu().setGroupVisible(R.id.drawer_group_tutor, false); } - - } - protected void checkPermissions() { final List missingPermissions = new ArrayList(); @@ -187,9 +205,9 @@ public abstract class BaseActivity Boolean shouldServiceRun = PrefUtils.isEnableSharingLocalization(getApplicationContext()) && !PrefUtils.isBackgroundLocationServiceRunning(getApplicationContext()); - if (shouldServiceRun){ + if (shouldServiceRun) { startBackgroundLocalizationTask(); - } else if(PrefUtils.isBackgroundLocationServiceRunning(getApplicationContext()) && + } else if (PrefUtils.isBackgroundLocationServiceRunning(getApplicationContext()) && !PrefUtils.isEnableSharingLocalization(getApplicationContext())) { stopBackgroundLocalizationTask(); } @@ -241,39 +259,44 @@ public abstract class BaseActivity actionBarDrawerToggle.onConfigurationChanged(newConfig); } + @SuppressLint("CheckResult") @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); MenuItem myActionMenuItem = menu.findItem(R.id.action_search); - final SearchView searchView = (SearchView) myActionMenuItem.getActionView(); - searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { - @Override - public boolean onQueryTextSubmit(String input) { - if (activeFragment.equals(ActiveFragment.USER_LIST)) { - executeUserListSearch(input); - } + searchView = (SearchView) myActionMenuItem.getActionView(); - return false; + searchView.setOnQueryTextFocusChangeListener((v, hasFocus) -> { + if (!hasFocus && activeFragment.equals(ActiveFragment.NONE)) { + restoreMapMarkers(); } - - @Override - - public boolean onQueryTextChange(String input) { - if (activeFragment.equals(ActiveFragment.USER_LIST)) { - executeUserListSearch(input); - } - - return true; - } - }); + + RxSearchObservable.fromView(searchView) + .map(String::toLowerCase) + .debounce(300, TimeUnit.MILLISECONDS) + .distinctUntilChanged() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::executeSearch); + return true; } - private void executeUserListSearch(String input) { - ((UsersListFragment) userListFragment).searchUser(input); + private void executeSearch(String input) { + if (activeFragment.equals(ActiveFragment.USER_LIST)) { + ((UsersListFragment) userListFragment).searchUser(input); + } else if (activeFragment.equals(ActiveFragment.NONE)) { + searchUser(input); + } + } + + public void searchUser(String textToSearch) { + } + + public void restoreMapMarkers() { } @Override @@ -284,7 +307,6 @@ public abstract class BaseActivity return super.onOptionsItemSelected(item); } - @Override protected void onStart() { super.onStart(); @@ -306,13 +328,13 @@ public abstract class BaseActivity @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { - navigationView.postDelayed(() -> { int itemId = item.getItemId(); if (itemId == R.id.nav_map) { removeFragment(sharingFragment); removeFragment(userListFragment); + activeFragment = ActiveFragment.NONE; } else if (itemId == R.id.nav_profile) { loadUserSettingsFragment(); } else if (itemId == R.id.nav_user_list) { @@ -352,6 +374,8 @@ public abstract class BaseActivity item.setChecked(true); } + + abstract int getNavigationMenuItemId(); abstract int getContentViewId(); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java index 53eb050..912598a 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/LoginActivity.java @@ -33,6 +33,7 @@ import com.uam.wmi.findmytutor.service.UserService; import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.RestApiHelper; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -72,12 +73,6 @@ public class LoginActivity extends AppCompatActivity { return false; }); - Switch tutorLogin = findViewById(R.id.tutor_login_switch); - - tutorLogin.setOnCheckedChangeListener((buttonView, isChecked) -> { - PrefUtils.storeIsTutor(getApplicationContext(), isChecked); - }); - Button mEmailSignInButton = findViewById(R.id.email_sign_in_button); mEmailSignInButton.setOnClickListener(view -> attemptLogin()); @@ -158,17 +153,9 @@ public class LoginActivity extends AppCompatActivity { private void loginProcess(String email, String password) { - Log.e("LOGIN", String.valueOf(PrefUtils.getIsTutor(getApplicationContext()))); + ValidateUser user = new ValidateUser(email, password); - //Fake validate - LdapUser user = new LdapUser(email, password, "admin", (PrefUtils.getIsTutor(getApplicationContext())) ? "Tutor" : "Student", "Imię", "Nazwisko", email); - - // ValidateUser user = new ValidateUser(email, password); - - // LDAP logging - // disposable.add(ldapService.validate(user) - - disposable.add(ldapService.fakeValidate(user) + disposable.add(ldapService.validate(user) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::handleResponse, this::handleError)); @@ -192,13 +179,18 @@ public class LoginActivity extends AppCompatActivity { String token = jwtToken.getToken(); JWT jwt = new JWT(token); - Claim role = jwt.getClaim("nameid"); + Claim userId = jwt.getClaim("nameid"); + Claim role = jwt.getClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role"); + if(!Objects.requireNonNull(role.asString()).equals("Student")){ + PrefUtils.storeIsTutor(getApplicationContext(), true); + } + PrefUtils.storeIsLoggedIn(getApplicationContext(), true); PrefUtils.storeApiKey(getApplicationContext(), token); - PrefUtils.storeUserId(getApplicationContext(), role.asString()); + PrefUtils.storeUserId(getApplicationContext(), userId.asString()); - getUserProfile(role.asString()); + getUserProfile(userId.asString()); Intent data = new Intent(); String txt = "Main Activity"; diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java index 47da9ea..543bf03 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/MapActivity.java @@ -4,13 +4,9 @@ import android.Manifest; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Color; import android.location.Location; import android.os.Bundle; import android.os.Handler; -import android.support.design.widget.FloatingActionButton; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.util.Log; @@ -21,6 +17,8 @@ import android.widget.Button; import android.widget.TextView; import android.widget.Toast; +import com.annimon.stream.Stream; +import com.getbase.floatingactionbutton.FloatingActionButton; import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; import com.mapbox.android.core.permissions.PermissionsListener; import com.mapbox.android.core.permissions.PermissionsManager; @@ -29,8 +27,6 @@ import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.location.LocationComponent; import com.mapbox.mapboxsdk.location.LocationComponentOptions; @@ -39,9 +35,6 @@ import com.mapbox.mapboxsdk.location.modes.RenderMode; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.style.layers.CircleLayer; -import com.mapbox.mapboxsdk.style.layers.Layer; -import com.mapbox.mapboxsdk.style.sources.VectorSource; import com.uam.wmi.findmytutor.R; import com.uam.wmi.findmytutor.model.Coordinate; import com.uam.wmi.findmytutor.model.User; @@ -56,6 +49,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Set; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; @@ -63,13 +57,6 @@ import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; import timber.log.Timber; -import java.util.Set; - -import static com.mapbox.mapboxsdk.style.layers.Property.NONE; -import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; public class MapActivity extends BaseActivity @@ -86,24 +73,30 @@ public class MapActivity extends BaseActivity private int mInterval = 10000; private Handler mHandler = new Handler(); private Runnable mStatusChecker; + private Handler manualLocHandler = new Handler(); + private Runnable manualLocStatusChecker; private MapView mapView; private MapboxMap mapboxMap; - private Marker droppedMarker; + private Button selectLocationButton; + private Button removeLocationButton; + private Marker tmpLocalMarker; + private Coordinate droppedMarkercoordinate; private HashMap coordsMap = new HashMap<>(); private HashMap markerHash = new HashMap<>(); private Set previousCoordsIds = new HashSet<>(); - + // Camera Animation params private int zoomParam = 17; private int bearingParam = 180; private int tiltParam = 30; + private String myID; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final SharedPreferences sharedPref = getSharedPreferences("fmtPrefs", Context.MODE_PRIVATE); - + myID = PrefUtils.getUserId(getApplicationContext()); // fetching coords service coordinateService = ApiClient.getClient(getApplicationContext()) .create(CoordinateService.class); @@ -119,8 +112,9 @@ public class MapActivity extends BaseActivity } }; - Bundle extras = getIntent().getExtras(); + selectLocationButton = findViewById(R.id.select_location_button); + removeLocationButton = findViewById(R.id.remove_location_button); Mapbox.getInstance(this, getString(R.string.access_token)); mapView = findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); @@ -130,7 +124,6 @@ public class MapActivity extends BaseActivity handleBackgroundTaskLifeCycle(); } - @Override public void onMapReady(MapboxMap mapboxMap) { MapActivity.this.mapboxMap = mapboxMap; @@ -138,13 +131,36 @@ public class MapActivity extends BaseActivity enableLocationPlugin(); mapboxMap.setOnMarkerClickListener(marker -> { - createMarkerModal(marker.getTitle()); + String id = marker.getTitle(); + if (id.equals(myID)) { + selectLocationButton.setVisibility(View.GONE); + removeLocationButton.setVisibility(View.VISIBLE); + + removeLocationButton.setOnClickListener(view -> { + Log.e(tag + "Manual", "manual coords sending stopped"); + // TODO to remove after BGserv + manualLocHandler.removeCallbacks(manualLocStatusChecker); + + removeLocationButton.setVisibility(View.GONE); + Toast.makeText(MapActivity.this, "Your marker will disappear in next couple minutes", Toast.LENGTH_SHORT).show(); + + }); + } else { + createMarkerModal(id); + } + return true; }); + setToggleMapBoundsArea(); setOnMapLongClickListener(); -// addStaticLayer(); + } + + private void setToggleMapBoundsArea() { + + mapUtils.setMapBoundsArea(getApplicationContext(), mapboxMap, mapView, true); + } private void createMarkerModal(String userId) { @@ -183,14 +199,13 @@ public class MapActivity extends BaseActivity showError(error); } - private void showError(Throwable e) { String message; if (e instanceof HttpException) { ResponseBody responseBody = ((HttpException) e).response().errorBody(); message = RestApiHelper.getErrorMessage(responseBody); - }else { + } else { message = "Network Error!"; } @@ -198,147 +213,104 @@ public class MapActivity extends BaseActivity Toast.makeText(MapActivity.this, message, Toast.LENGTH_SHORT).show(); } - private void setOnMapLongClickListener() { - final boolean[] cancel = {false}; - Button selectLocationButton = findViewById(R.id.select_location_button); + private void setOnMapLongClickListener() { mapboxMap.addOnMapLongClickListener((LatLng latLng) -> { selectLocationButton.setVisibility(View.VISIBLE); + removeLocationButton.setVisibility(View.GONE); Icon icon = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.green_marker); + if (tmpLocalMarker == null) { - if (droppedMarker == null) { - - droppedMarker = mapboxMap.addMarker(new MarkerOptions() + tmpLocalMarker = mapboxMap.addMarker(new MarkerOptions() .position(latLng) .icon(icon) .title("My Loc") .setSnippet("Snipecik")); - } else if (!cancel[0]) { - ValueAnimator markerAnimator = ObjectAnimator.ofObject(droppedMarker, "position", - new mapUtils.LatLngEvaluator(), droppedMarker.getPosition(), latLng); + } else { + ValueAnimator markerAnimator = ObjectAnimator.ofObject(tmpLocalMarker, "position", + new mapUtils.LatLngEvaluator(), tmpLocalMarker.getPosition(), latLng); markerAnimator.setDuration(2000); markerAnimator.start(); } selectLocationButton.setOnClickListener((View view) -> { - - if (!cancel[0] && droppedMarker != null) { + if (tmpLocalMarker != null) { // Toast instructing user to tap on the mapboxMap - - // TODO PUT MANUAL CORD try { - Coordinate coordinate = new Coordinate( + droppedMarkercoordinate = new Coordinate( latLng.getLatitude(), latLng.getLongitude(), latLng.getAltitude(), + "approx", PrefUtils.getUserFirstName(getApplicationContext()) + " " + PrefUtils.getUserLastName(getApplicationContext()), PrefUtils.getUserId(getApplicationContext()), PrefUtils.getLocationLevel(getApplicationContext()) ); - disposable.add( - coordinateService - .postCoordinate(coordinate) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeWith(new DisposableSingleObserver() { - @SuppressLint("LongLogTag") - @Override - public void onSuccess(Coordinate coord) { - Log.e(tag + "POST", String.valueOf(coord)); - } + // TODO remove after BG sending + manualLocStatusChecker = () -> { + try { + Log.e(tag + "Manual", "sending manual coords"); + // TODO ^^^ wrapper to removve + disposable.add( + coordinateService + .postCoordinate(droppedMarkercoordinate) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableSingleObserver() { + @SuppressLint("LongLogTag") + @Override + public void onSuccess(Coordinate coord) { + Log.e(tag + "POST", String.valueOf(coord)); + } - @SuppressLint("LongLogTag") - @Override - public void onError(Throwable e) { + @SuppressLint("LongLogTag") + @Override + public void onError(Throwable e) { - Log.e(tag + "onError", e.getMessage()); + Log.e(tag + "onError", e.getMessage()); + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + Log.e(tag + "onError", RestApiHelper.getErrorMessage(responseBody)); + + } + } + })); + // TODO \/\/\/\/\/ wrapper to removve + } finally { + manualLocHandler.postDelayed(manualLocStatusChecker, mInterval); + } + }; + manualLocStatusChecker.run(); - if (e instanceof HttpException) { - ResponseBody responseBody = ((HttpException) e).response().errorBody(); - Log.e(tag + "onError", RestApiHelper.getErrorMessage(responseBody)); - } - } - })); } catch (IllegalArgumentException e) { Timber.e(String.valueOf(e)); } - Toast.makeText( MapActivity.this, "Manual Locations selected!" + latLng, Toast.LENGTH_LONG ).show(); - selectLocationButton.setBackgroundColor( - ContextCompat.getColor(MapActivity.this, R.color.colorAccent)); - selectLocationButton.setText("Remove Manual location"); - selectLocationButton.setVisibility(View.VISIBLE); - cancel[0] = true; - } else { - - // TODO REMOVE Manual Locatio - mapboxMap.removeMarker(droppedMarker); - droppedMarker = null; - - Toast.makeText( - MapActivity.this, - "REMOVED!!" + latLng, - Toast.LENGTH_LONG - ).show(); - - cancel[0] = false; selectLocationButton.setVisibility(View.GONE); - selectLocationButton.setText(R.string.select_a_location); - selectLocationButton.setBackgroundColor( - ContextCompat.getColor(MapActivity.this, R.color.colorPrimary)); + mapboxMap.removeMarker(tmpLocalMarker); + tmpLocalMarker = null; } }); }); } - private void addStaticLayer() { - // Toggle layer button - final FloatingActionButton button = findViewById(R.id.toggleMarkerLayerButton); - button.setVisibility(View.VISIBLE); - - button.setOnClickListener(view -> { - - Layer layer = mapboxMap.getLayer("museums"); - if (layer != null) { - if (VISIBLE.equals(layer.getVisibility().getValue())) { - layer.setProperties(visibility(NONE)); - } else { - layer.setProperties(visibility(VISIBLE)); - } - } - }); - - // TODO here we create static layer, we are able to hide/show (but we cannot put markers inthere) - VectorSource museums = new VectorSource("museums_source", "mapbox://mapbox.2opop9hr"); - mapboxMap.addSource(museums); - - CircleLayer museumsLayer = new CircleLayer("museums", "museums_source"); - museumsLayer.setSourceLayer("museum-cusco"); - museumsLayer.setProperties( - visibility(VISIBLE), - circleRadius(8f), - circleColor(Color.argb(255, 55, 148, 179)) - ); - mapboxMap.addLayer(museumsLayer); - } - private void fetchTopCoords() { disposable.add( - // coordinateService.getTopCoordinates() coordinateService.getOnlineCoordinates() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -347,39 +319,37 @@ public class MapActivity extends BaseActivity @Override public void onSuccess(List coordsList) { - if(coordsList.isEmpty()) { - Log.e(tag, "200 empty []"); + + if (coordsList.isEmpty() && tmpLocalMarker != null) { + Timber.e("200 empty []"); mapboxMap.clear(); return; } - ArrayList tmp = new ArrayList<>(); for (Coordinate coordinate : coordsList) { tmp.add(coordinate.getUserId()); } Set currentCoordsIds = new HashSet<>(tmp); - if (previousCoordsIds.isEmpty()){ + if (previousCoordsIds.isEmpty()) { previousCoordsIds.addAll(currentCoordsIds); } else { - // here we clear + it returns bool if smthing was removed + // here we clear + it returns bool if sth was removed if (previousCoordsIds.removeAll(currentCoordsIds)) { - for (String toRemoveId: previousCoordsIds) { - Log.e(tag+ "delete: " , "removing: " + toRemoveId + ": " + markerHash.get(toRemoveId)); + for (String toRemoveId : previousCoordsIds) { + Log.e(tag + "delete: ", "removing: " + toRemoveId + ": " + markerHash.get(toRemoveId)); mapboxMap.removeMarker(markerHash.get(toRemoveId)); markerHash.remove(toRemoveId); coordsMap.remove(toRemoveId); } } else { // TODO double check when some markers api will change - Log.e(tag+ "delete: ","nothing to remove"); + Log.e(tag + "delete: ", "nothing to remove"); } } - - for (Coordinate element : coordsList) { String id = element.getUserId(); String newLabel = element.getLabel(); @@ -390,9 +360,6 @@ public class MapActivity extends BaseActivity if (coordinate != null) { Log.e(tag, "Coordin: " + coordinate.getLatitude() + " | " + coordinate.getLongitude()); -// Log.e(tag, "Element: " + element.getLatitude()+" | " + element.getLongitude()); -// Log.e(tag, "isEqual: " + coordinate.getLatitude().equals(element.getLatitude())); -// Log.e(tag, "isEqual: " + coordinate.getLongitude().equals(element.getLongitude())); boolean statement = coordinate.getLatitude().equals(element.getLatitude()) || coordinate.getLongitude().equals(element.getLongitude()); Log.e(tag, "diff || diff: " + !statement); @@ -418,13 +385,20 @@ public class MapActivity extends BaseActivity } } else { - Log.e(tag, "Marker Added: " + id); coordsMap.put(id, element); - Marker marker = mapboxMap.addMarker(new MarkerOptions() + + MarkerOptions markerOptions = new MarkerOptions() .title(id) - .position(new LatLng(element.getLatitude(), element.getLongitude()))); + .position(new LatLng(element.getLatitude(), element.getLongitude())); + // Check if this is me + if (id.equals(myID)) { + Icon icon = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.blue_marker); + markerOptions.setIcon(icon); + } + Marker marker = mapboxMap.addMarker(markerOptions); + markerHash.put(id, marker); } @@ -453,6 +427,67 @@ public class MapActivity extends BaseActivity } + @SuppressWarnings({"MissingPermission"}) + private void enableLocationPlugin() { + Log.e(tag, "enableLocationPlugin"); + + // Check if permissions are enabled and if not request + if (PermissionsManager.areLocationPermissionsGranted(this)) { + Log.e(tag, "enableLocationPlugin true"); + + + LocationComponentOptions options = LocationComponentOptions.builder(this) + .trackingGesturesManagement(false) + .accuracyColor(ContextCompat.getColor(this, R.color.mapboxGray)) + .build(); + + // Get an instance of the component + locationComponent = mapboxMap.getLocationComponent(); + + Log.e(tag + "Last", locationComponent.getLastKnownLocation() + ""); + + // Activate with options + locationComponent.activateLocationComponent(this, options); + + // Enable to make component visible + camera animation + // https://www.mapbox.com/android-docs/maps/overview/location-component/ + locationComponent.setLocationComponentEnabled(true); + + // Set the component's camera mode + locationComponent.setCameraMode(CameraMode.NONE); + locationComponent.setRenderMode(RenderMode.COMPASS); + + // Button 4 centring + FloatingActionButton myLocFAB = findViewById(R.id.myLocationButton); + myLocFAB.setVisibility(View.VISIBLE); + myLocFAB.setOnClickListener(v -> { + + Location lastKnownLocation = locationComponent.getLastKnownLocation(); + if (lastKnownLocation != null) { + mapUtils.makeNewCamera(mapboxMap, + lastKnownLocation.getLatitude(), + lastKnownLocation.getLongitude(), + zoomParam, + bearingParam, + tiltParam, + 4000); + } + + // Camera aniamtion + zoomParam = (zoomParam == 17) ? 19 : 17; + bearingParam += 90; + tiltParam = (tiltParam == 30) ? 0 : 30; + }); + } else { + Log.e(tag, "enableLocationPlugin false"); + + permissionsManager = new PermissionsManager(this); + permissionsManager.requestLocationPermissions(this); + permissionsManager.onRequestPermissionsResult(0, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new int[]{0}); + + } + } + // Add the mapView lifecycle to the activity's lifecycle methods @Override public void onResume() { @@ -489,6 +524,8 @@ public class MapActivity extends BaseActivity super.onDestroy(); mapView.onDestroy(); mHandler.removeCallbacks(mStatusChecker); + // TODO remove after BG sending + manualLocHandler.removeCallbacks(manualLocStatusChecker); disposable.dispose(); } @@ -508,69 +545,6 @@ public class MapActivity extends BaseActivity return R.id.nav_map; } - @SuppressWarnings({"MissingPermission"}) - private void enableLocationPlugin() { - Log.e(tag, "enableLocationPlugin"); - - // Check if permissions are enabled and if not request - if (PermissionsManager.areLocationPermissionsGranted(this)) { - Log.e(tag, "enableLocationPlugin true"); - - FloatingActionButton myLocationButton = findViewById(R.id.myLocationButton); - myLocationButton.setVisibility(View.VISIBLE); - - LocationComponentOptions options = LocationComponentOptions.builder(this) - .trackingGesturesManagement(true) - .accuracyColor(ContextCompat.getColor(this, R.color.mapboxGray)) - .build(); - - // Get an instance of the component - locationComponent = mapboxMap.getLocationComponent(); - - //Log.e(tag + "Last", locationComponent.getLastKnownLocation() + ""); - - // Activate with options - locationComponent.activateLocationComponent(this, options); - // Enable to make component visible - locationComponent.setLocationComponentEnabled(true); - - // Set the component's camera mode - locationComponent.setCameraMode(CameraMode.TRACKING); - locationComponent.setRenderMode(RenderMode.COMPASS); - - // Button 4 centring - FloatingActionButton myLocFAB = findViewById(R.id.myLocationButton); - myLocFAB.setOnClickListener(v -> { - - Location lastKnownLocation = locationComponent.getLastKnownLocation(); - if (lastKnownLocation != null) { - - CameraPosition position = new CameraPosition.Builder() - .target(new LatLng(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude())) // Sets the new camera position - .zoom(zoomParam) // Sets the zoom - .bearing(bearingParam) // Rotate the camera - .tilt(tiltParam) // Set the camera tilt - .build(); // Creates a CameraPosition from the builder - - mapboxMap.animateCamera(CameraUpdateFactory - .newCameraPosition(position), 4000); - } - - // Camera aniamtion - zoomParam = (zoomParam == 17) ? 19 : 17; - bearingParam += 90; - tiltParam = (tiltParam == 30) ? 0 : 30; - }); - } else { - Log.e(tag, "enableLocationPlugin false"); - - permissionsManager = new PermissionsManager(this); - permissionsManager.requestLocationPermissions(this); - permissionsManager.onRequestPermissionsResult(0, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new int[]{0}); - - } - } - @Override public void onRequestPermissionsResult(int requestCode, @android.support.annotation.NonNull String[] permissions, @android.support.annotation.NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); @@ -591,4 +565,53 @@ public class MapActivity extends BaseActivity // finish(); // } } + + + @Override + public void searchUser(String textToSearch) { + getUserFromApi(textToSearch); + } + + private void getUserFromApi(String userNameToSearch) { + disposable.add( + userService.getAllTutors() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .map(tutors -> Stream.of(tutors).filter(t -> + t.toSearchAbleUserName().toLowerCase().contains(userNameToSearch.toLowerCase())).toList()) + .subscribeWith(new DisposableSingleObserver>() { + @Override + public void onSuccess(List users) { + filterMarkers(users); + } + + @Override + public void onError(Throwable e) { + showError(e); + } + })); + } + + private void filterMarkers(List users) { + restoreMapMarkers(); + + Icon icon1 = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.custom_marker); + + List markersToSet = Stream.of(mapboxMap.getMarkers()) + .filter(m -> Stream.of(users).anyMatch(u -> u.getId().equals(m.getTitle()))) + .toList(); + + for (Marker marker : markersToSet) { + marker.setIcon(icon1); + } + } + + public void restoreMapMarkers() { + Icon icon = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.red_marker); + + for (Marker marker : mapboxMap.getMarkers()) { + marker.setIcon(icon); + } + } + } 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 839f673..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,17 +10,28 @@ 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; import java.util.HashMap; import java.util.HashSet; @@ -28,55 +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(); - locationLevelMapping.put(0,"presence"); - locationLevelMapping.put(1,"approximated"); - locationLevelMapping.put(2,"exact"); - 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"); + + 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()); - 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) -> { - ListPreference lp = (ListPreference) preference; 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() { @@ -105,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); @@ -114,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]; @@ -125,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/activity/UsersListFragment.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java index 82888b2..433ed70 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/UsersListFragment.java @@ -169,7 +169,7 @@ public class UsersListFragment extends Fragment { private void fetchAllTutors() { disposable.add( - userService.apiUsersGet() + userService.getAllTutors() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map(tutors -> { diff --git a/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java b/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java index 5c23701..9b9d580 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java @@ -44,15 +44,17 @@ public class Coordinate extends BaseResponse { @SerializedName("label") private String label; - public Coordinate (Double latitude, Double longitude, Double altitude, String label, String userId, String displayMode) { + public Coordinate (Double latitude, Double longitude, Double altitude, String approximatedLocation, String label, String userId, String displayMode) { //if (!latitudeRange.contains(latitude)) throw new IllegalArgumentException("Inappropriate latitude value" + latitude); //if (!longtitudeRange.contains(longitude)) throw new IllegalArgumentException("Inappropriate longitude value" + longitude); + //if (approximatedLocation == null) throw new IllegalArgumentException("Inappropriate approximatedLocation"); this.latitude = latitude; this.longitude = longitude; this.altitude = altitude; this.label = label; this.userId = userId; + this.approximatedLocation = approximatedLocation; this.displayMode = displayMode; } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/model/Feedback.java b/app/src/main/java/com/uam/wmi/findmytutor/model/Feedback.java new file mode 100644 index 0000000..1726c75 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/model/Feedback.java @@ -0,0 +1,47 @@ + +package com.uam.wmi.findmytutor.model; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Feedback { + + @SerializedName("isAnonymous") + @Expose + private Boolean isAnonymous; + @SerializedName("header") + @Expose + private String header; + @SerializedName("body") + @Expose + private String body; + + public Feedback(boolean isAnonymous, String header, String body){ + this.isAnonymous = isAnonymous; + this.header = header; + this.body = body; + } + public Boolean getIsAnonymous() { + return isAnonymous; + } + + public void setIsAnonymous(Boolean isAnonymous) { + this.isAnonymous = isAnonymous; + } + + public String getHeader() { + return header; + } + + public void setHeader(String header) { + this.header = header; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + +} \ No newline at end of file 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/model/User.java b/app/src/main/java/com/uam/wmi/findmytutor/model/User.java index 0e5c0d5..7788f61 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/model/User.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/model/User.java @@ -712,6 +712,15 @@ public class User extends BaseResponse { return sb.toString(); } + public String toSearchAbleUserName(){ + StringBuilder sb = new StringBuilder(); + sb.append(getFirstName()); + sb.append(getLastName()); + + return sb.toString(); + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); 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 2b3ca3c..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 @@ -27,14 +27,18 @@ import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; import com.google.android.gms.tasks.OnSuccessListener; import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; +import com.mapbox.geojson.Point; import com.uam.wmi.findmytutor.model.Coordinate; import com.uam.wmi.findmytutor.network.ApiClient; +import com.uam.wmi.findmytutor.utils.ApproximatedLocalization; +import com.uam.wmi.findmytutor.utils.Consts; import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.RestApiHelper; +import com.uam.wmi.findmytutor.utils.SharingLevel; +import com.uam.wmi.findmytutor.utils.mapUtils; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executor; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; @@ -43,6 +47,9 @@ import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; import timber.log.Timber; +import static com.uam.wmi.findmytutor.utils.Consts.presenceApproximatedName; +import static com.uam.wmi.findmytutor.utils.Consts.presenceLatitude; +import static com.uam.wmi.findmytutor.utils.Consts.presencelongitude; import static com.uam.wmi.findmytutor.utils.PrefUtils.storeBackgroundLocationStatus; public class BackgroundLocalizationService extends Service { @@ -50,7 +57,6 @@ public class BackgroundLocalizationService extends Service { private static final String TAG = "MyLocationService"; private static final int LOCATION_INTERVAL = 1000; private static final float LOCATION_DISTANCE = 5f; - public static String str_receiver = "background.location.broadcast"; private static long notify_interval = 10000; Location mLastLocation; Boolean stopService = false; @@ -64,6 +70,7 @@ public class BackgroundLocalizationService extends Service { private Runnable mStatusChecker; private FusedLocationProviderClient mFusedLocationClient; + public BackgroundLocalizationService() { providers.add(LocationManager.GPS_PROVIDER); providers.add(LocationManager.NETWORK_PROVIDER); @@ -74,6 +81,7 @@ public class BackgroundLocalizationService extends Service { new LocationListener(LocationManager.NETWORK_PROVIDER), new LocationListener(LocationManager.PASSIVE_PROVIDER) }; + } @Override @@ -90,7 +98,7 @@ public class BackgroundLocalizationService extends Service { stopService = intent.getBooleanExtra("request_stop", false); } if (stopService) { - storeBackgroundLocationStatus(getApplication(),false); + storeBackgroundLocationStatus(getApplication(), false); stopForeground(true); stopSelf(); return START_STICKY; @@ -102,7 +110,7 @@ public class BackgroundLocalizationService extends Service { @Override public void onCreate() { Log.e(TAG, "onCreate"); - storeBackgroundLocationStatus(getApplication(),true); + storeBackgroundLocationStatus(getApplication(), true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) startMyOwnForeground(); @@ -114,7 +122,6 @@ public class BackgroundLocalizationService extends Service { mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); - initializeLocationManager(); Integer providerIndex = 0; @@ -137,7 +144,7 @@ public class BackgroundLocalizationService extends Service { providerIndex++; } - if(!stopService){ + if (!stopService) { mStatusChecker = () -> { try { fn_getlocation(); @@ -202,20 +209,12 @@ public class BackgroundLocalizationService extends Service { Log.e("Best localization:", String.valueOf(bestLocation)); - /* if (bestLocation != null) - fn_update(bestLocation); -*/ - mFusedLocationClient.getLastLocation().addOnSuccessListener( - new OnSuccessListener() { - @Override - public void onSuccess(Location location) { - if (location != null) { - mLastLocation = location; - fn_update(location); - } + location -> { + if (location != null) { + mLastLocation = location; + fn_update(location); } - }); } @@ -283,11 +282,13 @@ public class BackgroundLocalizationService extends Service { } } + @SuppressLint("StaticFieldLeak") private class Task extends AsyncTask { + ApproximatedLocalization approximatedLocalization; private Double latitude; private Double longitude; private Double altitude; - + private String approximatedBuildingPart = null; private CompositeDisposable disposable = new CompositeDisposable(); private CoordinateService coordinateService = ApiClient.getClient(getApplicationContext()) .create(CoordinateService.class); @@ -296,17 +297,31 @@ public class BackgroundLocalizationService extends Service { latitude = location.getLatitude(); longitude = location.getLongitude(); altitude = location.getAltitude(); + approximatedLocalization = new ApproximatedLocalization(mapUtils.loadJsonFromAsset(getApplicationContext(), "building.geojson")); + approximatedBuildingPart = approximatedLocalization.getNameOfBuildingPart(Point.fromLngLat(longitude, latitude)); } @Override protected Object doInBackground(Object[] objects) { + if (PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.PRESENCE.toString())) { + latitude = presenceLatitude; + longitude = presencelongitude; + approximatedBuildingPart = presenceApproximatedName; + } else if (PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.APPROXIMATED.toString())) { + List points = approximatedLocalization.getMiddlePointOfBuildingPart(approximatedBuildingPart); + + latitude = points.get(0); + longitude = points.get(1); + } + try { Coordinate coordinate = new Coordinate( latitude, longitude, altitude, - PrefUtils.getUserStatus(getApplicationContext()), + approximatedBuildingPart, + (PrefUtils.isStatusEnabled(getApplicationContext())) ? PrefUtils.getUserStatus(getApplicationContext()) : "", PrefUtils.getUserId(getApplicationContext()), PrefUtils.getLocationLevel(getApplicationContext()) ); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/FeedbackService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/FeedbackService.java new file mode 100644 index 0000000..a6d166c --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/FeedbackService.java @@ -0,0 +1,17 @@ +package com.uam.wmi.findmytutor.service; + +import com.uam.wmi.findmytutor.model.Feedback; +import io.reactivex.Observable; +import io.reactivex.Single; +import retrofit2.Response; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.POST; + +public interface FeedbackService { + @POST("api/Feedback") + Observable> postFeedback(@Body Feedback feedback); + + @GET("api/Feedback") + Single getFeedback(); +} 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/service/UserService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java index aca16a4..75671ed 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/UserService.java @@ -27,6 +27,9 @@ public interface UserService { @GET("api/users") Single > apiUsersGet(); + @GET("api/users/tutors") + Single > getAllTutors(); + @POST("api/users") Completable createUser(@Body User user); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/ApproximatedLocalization.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/ApproximatedLocalization.java new file mode 100644 index 0000000..4a42bf3 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/ApproximatedLocalization.java @@ -0,0 +1,69 @@ +package com.uam.wmi.findmytutor.utils; + +import android.support.annotation.NonNull; + +import com.google.gson.GsonBuilder; +import com.mapbox.geojson.BoundingBox; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Geometry; +import com.mapbox.geojson.Point; +import com.mapbox.geojson.Polygon; +import com.mapbox.geojson.gson.BoundingBoxDeserializer; +import com.mapbox.geojson.gson.GeoJsonAdapterFactory; +import com.mapbox.geojson.gson.GeometryDeserializer; +import com.mapbox.geojson.gson.PointDeserializer; +import com.mapbox.turf.TurfJoins; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +; + +public class ApproximatedLocalization { + private FeatureCollection buildingSchema = null; + + public ApproximatedLocalization(String buildingObject) { + buildingSchema = fromJson(buildingObject); + } + + private FeatureCollection fromJson(@NonNull String json) { + GsonBuilder gson = new GsonBuilder(); + + gson.registerTypeAdapterFactory(GeoJsonAdapterFactory.create()); + gson.registerTypeAdapter(Point.class, new PointDeserializer()); + gson.registerTypeAdapter(Geometry.class, new GeometryDeserializer()); + gson.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer()); + + return gson.create().fromJson(json, FeatureCollection.class); + } + + public String getNameOfBuildingPart(Point point) { + + for (Feature feature : Objects.requireNonNull(buildingSchema.features())) { + boolean isInside = TurfJoins.inside(point, (Polygon) Objects.requireNonNull(feature.geometry())); + + if (isInside) + return Objects.requireNonNull(Objects.requireNonNull(feature.getStringProperty("name"))); + } + + return null; + } + + public List getMiddlePointOfBuildingPart(String buildingPart) { + + for (Feature feature : Objects.requireNonNull(buildingSchema.features())) { + String partName = feature.getStringProperty("name"); + + if (buildingPart != null && buildingPart.equals(partName)) { + Double longitude = feature.getNumberProperty("longitude").doubleValue(); + Double latitude = feature.getNumberProperty("latitude").doubleValue(); + + return Arrays.asList(longitude, latitude); + } + } + + return Arrays.asList(0.0, 0.0); + } +} diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/Consts.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/Consts.java new file mode 100644 index 0000000..bedd885 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/Consts.java @@ -0,0 +1,7 @@ +package com.uam.wmi.findmytutor.utils; + +public class Consts { + public final static Double presenceLatitude = 65.600244; + public final static Double presencelongitude = 480.032153; + public final static String presenceApproximatedName = "unknown"; +} 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 new file mode 100644 index 0000000..ab12f54 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/FeedbackUtils.java @@ -0,0 +1,121 @@ +package com.uam.wmi.findmytutor.utils; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.v7.app.AlertDialog; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; +import com.uam.wmi.findmytutor.R; +import com.uam.wmi.findmytutor.activity.BaseActivity; +import com.uam.wmi.findmytutor.model.Feedback; +import com.uam.wmi.findmytutor.network.ApiClient; +import com.uam.wmi.findmytutor.service.FeedbackService; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.ResponseBody; +import retrofit2.Response; + +public class FeedbackUtils { + private Context activityContext; + public FeedbackUtils(Context context){ + activityContext = context; + } + public void showNoteDialog(String subject) { + + 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(activityContext.getString(R.string.modal_feedback_send),null); + final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); + + EditText modalUserInput = view.findViewById(R.id.feedback_input); + CheckBox modalIsAnonymous = view.findViewById(R.id.feedback_is_anonymous); + TextView modalTitle = view.findViewById(R.id.feedback_modal_title); + TextView modalSubtitle = view.findViewById(R.id.feedback_modal_subtitle); + modalTitle.setText(subject); + 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 + public void onShow(DialogInterface dialogInterface) { + Button sendButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + sendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + String body = modalUserInput.getText().toString(); + if(TextUtils.isEmpty(body)){ + Toast.makeText(activityContext, activityContext.getString(R.string.modal_feedback_hint), Toast.LENGTH_SHORT).show(); + modalUserInput.requestFocus(); + }else{ + boolean mode = modalIsAnonymous.isChecked(); + sendFeedback(subject,body,mode); + alertDialog.dismiss(); + } + } + }); + } + }); + alertDialog.show(); + } + + private void sendFeedback(String header, String body, boolean mode) { + String appVersion = null; + String metadata = null; + try { + appVersion = activityContext.getPackageManager().getPackageInfo(activityContext.getPackageName(), 0).versionName; + if( !mode ){ + metadata = "\n-----------------------------\n" + + "User ID: " + PrefUtils.getUserId(activityContext) + "\n" + + "Device OS: Android\n" + + "Device OS version: " + Build.VERSION.RELEASE + "\n" + + "App Version: " + appVersion + "\n" + + "Device Model: " + Build.MODEL + "\n" + + "Device Manufacturer: " + Build.MANUFACTURER + "\n" + + "-----------------------------\n"; + body = metadata + body; + header = header + " - " + PrefUtils.getUserFirstName(activityContext) + " " + PrefUtils.getUserLastName(activityContext); + } + } catch (PackageManager.NameNotFoundException e) { + } + FeedbackService feedbackService = ApiClient.getClient(activityContext).create(FeedbackService.class); + Feedback userFeedback = new Feedback(mode,header,body); + CompositeDisposable disposable = new CompositeDisposable(); + disposable.add(feedbackService.postFeedback(userFeedback) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleResponse, this::handleError)); + } + private void handleResponse(Response resp) { + Toast.makeText(activityContext, activityContext.getString(R.string.modal_feedback_thankyou), Toast.LENGTH_SHORT).show(); + } + + private void handleError(Throwable error) { + if (error instanceof HttpException) { + + ResponseBody responseBody = ((HttpException) error).response().errorBody(); + Toast.makeText(activityContext, + RestApiHelper.getErrorMessage(responseBody), Toast.LENGTH_SHORT).show(); + + } else { + Toast.makeText(activityContext, + "Network error " + error.getMessage(), Toast.LENGTH_SHORT).show(); + Log.d("FEEDBACK",error.getMessage()); + } + } +} 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 0982f5a..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"); } @@ -134,7 +138,7 @@ public class PrefUtils { } public static String getLocale(Context context) { - return getSharedPreferences(context).getString("LOCALE", "pl"); + return getSharedPreferences(context).getString("LOCALE", "en"); } public static Boolean isBackgroundLocationServiceRunning(Context context) { 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/RxSearchObservable.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/RxSearchObservable.java new file mode 100644 index 0000000..33d4aee --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/RxSearchObservable.java @@ -0,0 +1,39 @@ +package com.uam.wmi.findmytutor.utils; + + +import android.support.v7.widget.SearchView; + +import io.reactivex.Observable; +import io.reactivex.subjects.PublishSubject; + + +public class RxSearchObservable { + + private RxSearchObservable() { + // no instance + } + + public static Observable fromView(SearchView searchView) { + + final PublishSubject subject = PublishSubject.create(); + + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + subject.onNext(s); + return false; + } + + @Override + public boolean onQueryTextChange(String text) { + subject.onNext(text); + return false; + } + + + }); + + + return subject; + } +} 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 new file mode 100644 index 0000000..b9b04f2 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/SharingLevel.java @@ -0,0 +1,19 @@ +package com.uam.wmi.findmytutor.utils; + +public enum SharingLevel { + PRESENCE("presence"), + APPROXIMATED("approximated"), + EXACT("exact"), + MANUAL("manual"); + + private final String text; + + SharingLevel(final String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/mapUtils.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/mapUtils.java index a58ca10..6d80d3e 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/mapUtils.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/mapUtils.java @@ -2,30 +2,61 @@ package com.uam.wmi.findmytutor.utils; import android.animation.TypeEvaluator; import android.content.Context; +import android.graphics.Color; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.content.res.AssetManager; +import com.mapbox.mapboxsdk.annotations.Polygon; +import com.mapbox.mapboxsdk.annotations.PolygonOptions; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.style.layers.FillLayer; +import com.mapbox.mapboxsdk.style.layers.Layer; import java.io.IOException; import java.io.InputStream; public class mapUtils { + // Boundires + private static final LatLngBounds WMI_BOUNDS = new LatLngBounds.Builder() + .include(new LatLng(52.46588041661952, 16.92543089389801)) + .include(new LatLng(52.467824943492374, 16.928574442863464)) + .build(); - public static class LatLngEvaluator implements TypeEvaluator { - // Method is used to interpolate the marker animation. + // Map Bounds Area + public static void setMapBoundsArea(Context context, MapboxMap mapboxMap, MapView mapView, Boolean check) { - private LatLng latLng = new LatLng(); - - @Override - public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { - latLng.setLatitude(startValue.getLatitude() - + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); - latLng.setLongitude(startValue.getLongitude() - + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); - return latLng; + if (check) { + // Set bounds to WMI + mapboxMap.setLatLngBoundsForCameraTarget(WMI_BOUNDS); + makeNewCamera(mapboxMap, 52.466799, 16.927002, 17, 0, 0, 4000); + mapboxMap.setMinZoomPreference(16); // TODO export to map config + } else { + mapboxMap.setLatLngBoundsForCameraTarget(null); + mapboxMap.setMinZoomPreference(2); } } + public static void makeNewCamera(MapboxMap mapboxMap, double lat, double lon, int zoomParam, int bearingParam, int tiltParam, int duration) { + CameraPosition position = new CameraPosition.Builder() + .target(new LatLng(lat, lon)) // Sets the new camera position + .zoom(zoomParam) // Sets the zoom + .bearing(bearingParam) // Rotate the camera + .tilt(tiltParam) // Set the camera tilt + .build(); // Creates a CameraPosition from the builder + + mapboxMap.animateCamera(CameraUpdateFactory + .newCameraPosition(position), duration); + } + + // read file to JSON public static String loadJsonFromAsset(Context context, String filename) { // Using this method to load in GeoJSON files from the assets folder. try { @@ -41,4 +72,21 @@ public class mapUtils { return null; } } + + // Function for marker animation + public static class LatLngEvaluator implements TypeEvaluator { + // Method is used to interpolate the marker animation. + + private LatLng latLng = new LatLng(); + + @Override + public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { + latLng.setLatitude(startValue.getLatitude() + + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); + latLng.setLongitude(startValue.getLongitude() + + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); + return latLng; + } + } + } diff --git a/app/src/main/res/drawable/blue_marker.png b/app/src/main/res/drawable/blue_marker.png index d7068f2..7bbbd9b 100644 Binary files a/app/src/main/res/drawable/blue_marker.png and b/app/src/main/res/drawable/blue_marker.png differ diff --git a/app/src/main/res/drawable/bug_icon.xml b/app/src/main/res/drawable/bug_icon.xml new file mode 100644 index 0000000..c3458e1 --- /dev/null +++ b/app/src/main/res/drawable/bug_icon.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/custom_marker.png b/app/src/main/res/drawable/custom_marker.png index 1df09fd..8b1f284 100644 Binary files a/app/src/main/res/drawable/custom_marker.png and b/app/src/main/res/drawable/custom_marker.png differ diff --git a/app/src/main/res/drawable/green_marker.png b/app/src/main/res/drawable/green_marker.png index b8f9abb..0babab0 100644 Binary files a/app/src/main/res/drawable/green_marker.png and b/app/src/main/res/drawable/green_marker.png differ diff --git a/app/src/main/res/drawable/red_marker.png b/app/src/main/res/drawable/red_marker.png index be782e1..6b72939 100644 Binary files a/app/src/main/res/drawable/red_marker.png and b/app/src/main/res/drawable/red_marker.png differ diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 0c0e1fe..3b298de 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -72,11 +72,6 @@ -