diff --git a/app/build.gradle b/app/build.gradle index 4d7fcf2..f019038 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.uam.wmi.findmytutor" minSdkVersion 22 targetSdkVersion 27 - versionCode 21 - versionName "0.9.5-beta" + versionCode 37 + versionName "0.9.6-beta" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } @@ -72,4 +72,6 @@ dependencies { // FloatingBarMenu implementation 'com.getbase:floatingactionbutton:1.10.1' implementation 'org.apache.commons:commons-collections4:4.0' + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support:design:27.1.1' } diff --git a/app/release/release/app.aab b/app/release/release/app.aab index 0f22d91..0b58fd8 100644 Binary files a/app/release/release/app.aab and b/app/release/release/app.aab differ diff --git a/app/release/release/fmtBeta0.9.5v18.aab b/app/release/release/fmtBeta0.9.5v18.aab new file mode 100644 index 0000000..fb0edf9 Binary files /dev/null and b/app/release/release/fmtBeta0.9.5v18.aab differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5ccbfb9..d209b5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,10 +27,10 @@ tools:ignore="AllowBackup,GoogleAppIndexingWarning"> + android:theme="@style/AppTheme.NoActionBar"> @@ -38,33 +38,43 @@ + android:screenOrientation="portrait" /> + android:screenOrientation="portrait" /> + android:configChanges="keyboardHidden|orientation|screenSize" + android:screenOrientation="portrait" /> - + android:theme="@style/AppTheme" /> + + \ No newline at end of file diff --git a/app/src/main/assets/wmi1floor.geojson b/app/src/main/assets/wmi1floor.geojson new file mode 100644 index 0000000..f099ad5 --- /dev/null +++ b/app/src/main/assets/wmi1floor.geojson @@ -0,0 +1,727 @@ +{ + "features": [ + { + "type": "Feature", + "properties": { + "name": "Pokoje profesorskie" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926707, + 52.46657 + ], + [ + 16.92652, + 52.466244 + ], + [ + 16.926459, + 52.466255 + ], + [ + 16.926645, + 52.466582 + ], + [ + 16.926707, + 52.46657 + ] + ] + ], + "type": "Polygon" + }, + "id": "07f45cd94d45bb5ad0b6b285b0f6fbbb" + }, + { + "type": "Feature", + "properties": { + "name": "Skrzydło B" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926961, + 52.467026 + ], + [ + 16.92677, + 52.466682 + ], + [ + 16.92652, + 52.466244 + ], + [ + 16.926459, + 52.466255 + ], + [ + 16.926428, + 52.466203 + ], + [ + 16.926175, + 52.46625 + ], + [ + 16.92621, + 52.466306 + ], + [ + 16.926323, + 52.466282 + ], + [ + 16.926515, + 52.466632 + ], + [ + 16.926408, + 52.466654 + ], + [ + 16.92644, + 52.466712 + ], + [ + 16.926543, + 52.46669 + ], + [ + 16.926754, + 52.467067 + ], + [ + 16.926961, + 52.467026 + ] + ] + ], + "type": "Polygon" + }, + "id": "143facf35f322434cfc5776f70f1db36" + }, + { + "type": "Feature", + "properties": { + "name": "Winda" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92669, + 52.467141 + ], + [ + 16.92666, + 52.467089 + ], + [ + 16.926755, + 52.46707 + ], + [ + 16.926786, + 52.467121 + ], + [ + 16.92669, + 52.467141 + ] + ] + ], + "type": "Polygon" + }, + "id": "1a35bfafd619b80ffb8b36f03549e9e3" + }, + { + "type": "Feature", + "properties": { + "name": "D2" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926876, + 52.466659 + ], + [ + 16.926984, + 52.466635 + ], + [ + 16.92694, + 52.466557 + ], + [ + 16.926831, + 52.46658 + ], + [ + 16.926876, + 52.466659 + ] + ] + ], + "type": "Polygon" + }, + "id": "3e0a32a0583254e9e7c47fea1f402472" + }, + { + "type": "Feature", + "properties": { + "name": "Sale A" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92714, + 52.466489 + ], + [ + 16.926925, + 52.466127 + ], + [ + 16.927027, + 52.466106 + ], + [ + 16.927232, + 52.466472 + ], + [ + 16.92714, + 52.466489 + ] + ] + ], + "type": "Polygon" + }, + "id": "3e56cb54baf90049a3ce2f16577c2cd8" + }, + { + "type": "Feature", + "properties": { + "name": "D1" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926984, + 52.466635 + ], + [ + 16.927084, + 52.466614 + ], + [ + 16.92704, + 52.466536 + ], + [ + 16.92694, + 52.466557 + ], + [ + 16.926984, + 52.466635 + ] + ] + ], + "type": "Polygon" + }, + "id": "56c2a7ab4e4d2ac14a46448d523470dc" + }, + { + "type": "Feature", + "properties": { + "name": "Hol" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.927104, + 52.467081 + ], + [ + 16.927039, + 52.467095 + ], + [ + 16.9268, + 52.467145 + ], + [ + 16.926754, + 52.467067 + ], + [ + 16.926961, + 52.467026 + ], + [ + 16.927277, + 52.46696 + ], + [ + 16.927272, + 52.466951 + ], + [ + 16.927451, + 52.466918 + ], + [ + 16.927494, + 52.467002 + ], + [ + 16.927278, + 52.467047 + ], + [ + 16.927144, + 52.467073 + ], + [ + 16.927104, + 52.467081 + ] + ] + ], + "type": "Polygon" + }, + "id": "6f1db27a4df5a46f7a6913556b01effe" + }, + { + "type": "Feature", + "properties": { + "name": "Pokoje profesorskie" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92677, + 52.466683 + ], + [ + 16.926961, + 52.467026 + ], + [ + 16.926887, + 52.467041 + ], + [ + 16.926695, + 52.466699 + ], + [ + 16.92677, + 52.466683 + ] + ] + ], + "type": "Polygon" + }, + "id": "94f310dcaa6cee75d9e7800bf8d94155" + }, + { + "type": "Feature", + "properties": { + "name": "Biblioteka" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926801, + 52.467144 + ], + [ + 16.926971, + 52.467424 + ], + [ + 16.926956, + 52.46743 + ], + [ + 16.926944, + 52.467436 + ], + [ + 16.92693, + 52.467441 + ], + [ + 16.926903, + 52.467452 + ], + [ + 16.926861, + 52.467464 + ], + [ + 16.926778, + 52.467476 + ], + [ + 16.926731, + 52.467485 + ], + [ + 16.926567, + 52.467194 + ], + [ + 16.926801, + 52.467144 + ] + ] + ], + "type": "Polygon" + }, + "id": "aadab5775bdeb4eaf82c940255ddadd7" + }, + { + "type": "Feature", + "properties": { + "name": "Sale A" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.927082, + 52.466492 + ], + [ + 16.926999, + 52.466509 + ], + [ + 16.926771, + 52.466109 + ], + [ + 16.926857, + 52.466088 + ], + [ + 16.927082, + 52.466492 + ] + ] + ], + "type": "Polygon" + }, + "id": "b39857ed605e5794fa6c9cdee5d7d6cf" + }, + { + "type": "Feature", + "properties": { + "name": "Pokoje profesorskie" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926754, + 52.467066 + ], + [ + 16.926814, + 52.467054 + ], + [ + 16.926605, + 52.466676 + ], + [ + 16.926542, + 52.46669 + ], + [ + 16.926564, + 52.466728 + ], + [ + 16.926754, + 52.467066 + ] + ] + ], + "type": "Polygon" + }, + "id": "b754d867fde3826e72fe8c243399ff26" + }, + { + "type": "Feature", + "properties": { + "name": "Sale A" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.927272, + 52.46695 + ], + [ + 16.927083, + 52.466613 + ], + [ + 16.927167, + 52.466595 + ], + [ + 16.92735, + 52.466936 + ], + [ + 16.927272, + 52.46695 + ] + ] + ], + "type": "Polygon" + }, + "id": "c3726b2a2b3a589995fd3f17eecd1f53" + }, + { + "type": "Feature", + "properties": { + "name": "D3" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92677, + 52.466682 + ], + [ + 16.926876, + 52.466659 + ], + [ + 16.926832, + 52.46658 + ], + [ + 16.926725, + 52.466604 + ], + [ + 16.92677, + 52.466682 + ] + ] + ], + "type": "Polygon" + }, + "id": "c73d9bdbccc15d9907e24b8bb731118a" + }, + { + "type": "Feature", + "properties": { + "name": "Pokoje profesorskie" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.926324, + 52.466282 + ], + [ + 16.926503, + 52.46661 + ], + [ + 16.926579, + 52.466595 + ], + [ + 16.926398, + 52.466268 + ], + [ + 16.926324, + 52.466282 + ] + ] + ], + "type": "Polygon" + }, + "id": "d54475cedfa0a866e13933c56bf35d76" + }, + { + "type": "Feature", + "properties": { + "name": "Sale A" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.927607, + 52.466891 + ], + [ + 16.92734, + 52.466562 + ], + [ + 16.927242, + 52.466585 + ], + [ + 16.927451, + 52.466918 + ], + [ + 16.927607, + 52.466891 + ] + ] + ], + "type": "Polygon" + }, + "id": "d97989e446002de50bc8844d2d9cdf5c" + }, + { + "type": "Feature", + "properties": { + "name": "Winda" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.92669, + 52.467141 + ], + [ + 16.92666, + 52.467089 + ], + [ + 16.926755, + 52.46707 + ], + [ + 16.926786, + 52.467121 + ], + [ + 16.92669, + 52.467141 + ] + ] + ], + "type": "Polygon" + }, + "id": "dfdba4ee1ee0c55193b8dd04f8b00f6c" + }, + { + "type": "Feature", + "properties": { + "name": "Skrzydło A" + }, + "geometry": { + "coordinates": [ + [ + [ + 16.927606, + 52.466891 + ], + [ + 16.927339, + 52.466562 + ], + [ + 16.927242, + 52.466585 + ], + [ + 16.92718, + 52.466482 + ], + [ + 16.927232, + 52.466473 + ], + [ + 16.927025, + 52.466105 + ], + [ + 16.926924, + 52.466126 + ], + [ + 16.926896, + 52.466078 + ], + [ + 16.92677, + 52.466108 + ], + [ + 16.926998, + 52.466509 + ], + [ + 16.927041, + 52.466537 + ], + [ + 16.927075, + 52.466595 + ], + [ + 16.927082, + 52.466614 + ], + [ + 16.927277, + 52.46696 + ], + [ + 16.927358, + 52.466942 + ], + [ + 16.927354, + 52.466935 + ], + [ + 16.92745, + 52.466918 + ], + [ + 16.927606, + 52.466891 + ] + ] + ], + "type": "Polygon" + }, + "id": "faaa569e3642a741f70a77071f19f131" + } + ], + "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 3a5956e..31d11e0 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 @@ -53,6 +53,7 @@ import io.reactivex.schedulers.Schedulers; import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; import static com.uam.wmi.findmytutor.utils.Const.defaultMapZoom; +import static com.uam.wmi.findmytutor.utils.Const.onlineBackgroundLocationInterval; import static com.uam.wmi.findmytutor.utils.Const.searchMapZoom; import static com.uam.wmi.findmytutor.utils.PrefUtils.storeBackgroundLocationStatus; @@ -99,11 +100,11 @@ public abstract class BaseActivity String itemName = (String) item.getTitle(); Intent launchIntent; if (itemName.equals(getResources().getString(R.string.navigation_item_whitelist))) { - /* launchIntent = new Intent(getApplicationContext(), WhitelistActivity.class); - startActivity(launchIntent);*/ + launchIntent = new Intent(getApplicationContext(), WhiteList.class); + startActivity(launchIntent); } else if (itemName.equals(getResources().getString(R.string.navigation_item_blacklist))) { - /* launchIntent = new Intent(getApplicationContext(), BlacklistActivity.class); - startActivity(launchIntent);*/ + launchIntent = new Intent(getApplicationContext(),BlackList.class); + startActivity(launchIntent); } else if (itemName.equals(getResources().getString(R.string.navigation_item_profile))) { @@ -200,7 +201,6 @@ public abstract class BaseActivity public void stopBackgroundLocalizationTask() { Intent stopIntent = new Intent(getApplicationContext(), BackgroundLocalizationService.class); stopIntent.putExtra("request_stop", true); - Log.e("Localization", "JEstem w stop BG"); stopService(stopIntent); @@ -210,6 +210,7 @@ public abstract class BaseActivity checkPermissions(); Intent startIntent = new Intent(getApplicationContext(), BackgroundLocalizationService.class); + startIntent.putExtra("notify_interval", onlineBackgroundLocationInterval); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { startForegroundService(startIntent); @@ -219,17 +220,12 @@ public abstract class BaseActivity } public void handleBackgroundTaskLifeCycle() { - Log.e("Localization", String.valueOf(PrefUtils.isEnableSharingLocalization(getApplicationContext()))); Boolean shouldServiceRun = PrefUtils.isEnableSharingLocalization(getApplicationContext()) && isTutor; - Log.e("Localization", String.valueOf(shouldServiceRun)); if (shouldServiceRun) { startBackgroundLocalizationTask(); - Log.e("Localization", "JEstem i odpalam"); - } else { stopBackgroundLocalizationTask(); - Log.e("Localization", "JEstem i nie odpalam"); } } @@ -285,7 +281,6 @@ public abstract class BaseActivity getMenuInflater().inflate(R.menu.menu_main, menu); infoMenuItem = menu.findItem(R.id.action_info); - MenuItem myActionMenuItem = menu.findItem(R.id.action_search); searchView = (SearchView) myActionMenuItem.getActionView(); @@ -295,6 +290,10 @@ public abstract class BaseActivity adjustMapToSearch(defaultMapZoom); } + if (!hasFocus && activeFragment.equals(ActiveFragment.USER_LIST)) { + ((UsersListFragment) userListFragment).restoreUsersList(); + } + if(hasFocus && activeFragment.equals(ActiveFragment.NONE)){ adjustMapToSearch(searchMapZoom); } @@ -303,6 +302,7 @@ public abstract class BaseActivity RxSearchObservable.fromView(searchView) .skip(0) .map(String::toLowerCase) + .filter(t -> !t.isEmpty()) .debounce(250, TimeUnit.MILLISECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -389,11 +389,14 @@ public abstract class BaseActivity if (itemId == R.id.nav_map) { removeFragment(sharingFragment); removeFragment(userListFragment); - activeFragment = ActiveFragment.NONE; + activeFragment = ActiveFragment.NONE; + findViewById(R.id.action_search).setVisibility(View.VISIBLE); } else if (itemId == R.id.nav_profile) { loadUserSettingsFragment(); + findViewById(R.id.action_search).setVisibility(View.GONE); } else if (itemId == R.id.nav_user_list) { loadUserListFragment(); + findViewById(R.id.action_search).setVisibility(View.VISIBLE); } selectBottomNavigationBarItem(itemId); }, 300); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java new file mode 100644 index 0000000..ce91562 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/BlackList.java @@ -0,0 +1,363 @@ +package com.uam.wmi.findmytutor.activity; + +import android.annotation.SuppressLint; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ToggleButton; + +import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.uam.wmi.findmytutor.R; +import com.uam.wmi.findmytutor.adapters.BlackListAdapter; +import com.uam.wmi.findmytutor.model.IsUsingListBool; +import com.uam.wmi.findmytutor.model.PredefinedCoordViewModel; +import com.uam.wmi.findmytutor.model.StudentIdModel; +import com.uam.wmi.findmytutor.model.User; +import com.uam.wmi.findmytutor.model.UserResponseModel; +import com.uam.wmi.findmytutor.network.ApiClient; +import com.uam.wmi.findmytutor.service.PredefinedStatusesService; +import com.uam.wmi.findmytutor.service.UserService; +import com.uam.wmi.findmytutor.utils.MyDividerItemDecoration; +import com.uam.wmi.findmytutor.utils.PrefUtils; +import com.uam.wmi.findmytutor.utils.RecyclerTouchListener; +import com.uam.wmi.findmytutor.utils.RestApiHelper; +import com.uam.wmi.findmytutor.utils.SharingLevel; +import com.uam.wmi.findmytutor.utils.WrapContentLinearLayoutManager; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.Observable; +import io.reactivex.ObservableSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.functions.Function; +import io.reactivex.observers.DisposableObserver; +import io.reactivex.observers.DisposableSingleObserver; +import io.reactivex.schedulers.Schedulers; +import okhttp3.ResponseBody; + +public class BlackList extends AppCompatActivity { + + private CompositeDisposable disposable = new CompositeDisposable(); + private UserService userService; + private boolean didFetched = false; + private String tutorId; + + @BindView(R.id.recycler_view_blacklist) + RecyclerView recyclerView; + @BindView(R.id.black_list_empty_text_view) + TextView noNotesView; + @BindView(R.id.switch_blacklist_toggle) + Switch aSwitch; + @BindView(R.id.add_to_black_list_fab) + FloatingActionButton addToBlackListFab; + + private Integer prevSize; + private BlackListAdapter mAdapter; + private List blacklistedUsers = new ArrayList<>(); + private Collator plCollator = Collator.getInstance(Locale.forLanguageTag("pl-PL")); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + setContentView(R.layout.activity_black_list); + ButterKnife.bind(this); + + tutorId = PrefUtils.getUserId(getApplicationContext()); + userService = ApiClient.getClient(getApplicationContext()) + .create(UserService.class); + + if (PrefUtils.isBlackListing(this)){ + aSwitch.setText(getString(R.string.action_black_list) +" ON"); + aSwitch.setChecked(true); + handleChangeRequest(true); + }else{ + aSwitch.setText(getString(R.string.action_black_list) +" OFF"); + aSwitch.setChecked(false); + handleChangeRequest(false); + } + + Toolbar toolbar = findViewById(R.id.toolbar); + toolbar.setTitle(getString(R.string.activity_title_blacklist)); + setSupportActionBar(toolbar); + + mAdapter = new BlackListAdapter(this, blacklistedUsers); + recyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getApplicationContext())); + recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16)); + recyclerView.setAdapter(mAdapter); + + fetchBlackListedUsers(); + /** + * On long press on RecyclerView item, open alert dialog + * with options to choose + * Edit and Delete + * */ + recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, + recyclerView, new RecyclerTouchListener.ClickListener() { + @Override + public void onClick(View view, final int position) { + } + + @Override + public void onLongClick(View view, int position) { + } + })); + + addToBlackListFab.setOnClickListener(this::showFabDialog); + + handleSwitch(); + } + + private Observable> getListOfBlacklistedUsers(String userId) { + return userService.getTutorBlacklistedByID(userId) + .toObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + private Observable getUserObservable(String userId) { + return userService + .getUserById(userId) + .toObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + private void fetchBlackListedUsers() { + prevSize = blacklistedUsers.size(); + + blacklistedUsers.clear(); + + disposable.add(getListOfBlacklistedUsers(tutorId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap((Function, Observable>) Observable::fromIterable) + .flatMap((Function>) this::getUserObservable) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(User user) { + blacklistedUsers.add(user); + } + + @Override + public void onError(Throwable e) { + showError(e); + } + + @Override + public void onComplete() { + Collections.sort(blacklistedUsers, (a, b) -> sortByUserName(a,b)); + refreshUI(); + } + })); + } + + private void refreshUI(){ + toggleEmptyNotes(); + mAdapter.notifyItemRangeInserted(prevSize, blacklistedUsers.size() - prevSize); + mAdapter.notifyDataSetChanged(); + } + + private int sortByUserName(User t1, User t2) { + return plCollator.compare(t1.getLastName(), t2.getLastName()); + } + + private void showFabDialog(View v){ + LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext()); + @SuppressLint("InflateParams") View view = layoutInflaterAndroid.inflate(R.layout.black_list_fab_modal, null); + AlertDialog.Builder alertDialogBuilderUserInput = new android.support.v7.app.AlertDialog.Builder(this); + + alertDialogBuilderUserInput.setView(view).setPositiveButton(getApplicationContext().getString(R.string.modal_location_send), null); + + alertDialogBuilderUserInput + .setPositiveButton(R.string.add, null) + .setNegativeButton(R.string.cancel, null); + + final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); + alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + + EditText modalUserInput = view.findViewById(R.id.black_list_modal_input); + + alertDialog.setOnShowListener(dialogInterface -> { + Button sendButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + + Button dismissButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + + dismissButton.setOnClickListener(view1 -> alertDialog.dismiss()); + + sendButton.setOnClickListener(view1 -> { + String body = modalUserInput.getText().toString(); + + if (TextUtils.isEmpty(body)) { + Toast.makeText(getApplicationContext(), R.string.can_not_be_empty, Toast.LENGTH_SHORT).show(); + modalUserInput.requestFocus(); + } else { + sendUserToBlacklist(body); + alertDialog.dismiss(); + } + }); + }); + + alertDialog.show(); + } + + private void sendUserToBlacklist(String body) { + StudentIdModel studentIdModel = new StudentIdModel(body); + disposable.add( + userService.addStudentToBlacklist(PrefUtils.getUserId(getApplicationContext()), studentIdModel) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleAddUser,this::showError) + ); + } + + + private void handleAddUser(User user) { + Toast.makeText(this, R.string.add_user_to_list, Snackbar.LENGTH_LONG).show(); + + blacklistedUsers.clear(); + fetchBlackListedUsers(); + } + + private void showError(Throwable e) { + String message; + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + message = RestApiHelper.getErrorMessage(responseBody); + if (((HttpException) e).response().code() == 404) { + message = getString(R.string.no_such_a_user); + } + } else { + message = "Network Error !"; + } + + Toast.makeText(this, message, Snackbar.LENGTH_LONG).show(); + } + + private void toggleEmptyNotes() { + + if (didFetched && blacklistedUsers.size() == 0) { + noNotesView.setText(R.string.list_is_empty); + noNotesView.setVisibility(View.VISIBLE); + }else if (blacklistedUsers.size() > 0) { + noNotesView.setVisibility(View.GONE); + } else { + noNotesView.setText(getString(R.string.loading)); + noNotesView.setVisibility(View.VISIBLE); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_black_list, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + if (item.getItemId()==R.id.action_blacklist_info_popup){ + int layoutID = R.layout.info_popup_blacklist; + + View popupView = getLayoutInflater().inflate(layoutID,null); + + PopupWindow popupWindow = new PopupWindow(popupView, + LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + // If the PopupWindow should be focusable + popupWindow.setFocusable(true); + // If you need the PopupWindow to dismiss when when touched outside + popupWindow.setBackgroundDrawable(new ColorDrawable()); + // Get the View's(the one that was clicked in the Fragment) location + View anchorView= getWindow().getDecorView().findViewById(android.R.id.content); + popupWindow.showAtLocation(anchorView,Gravity.TOP|Gravity.END, 0, 0); + } + + return super.onOptionsItemSelected(item); + } + + private void handleSwitch(){ + aSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked){ + aSwitch.setText(getString(R.string.action_black_list) + " "+ getString(R.string.on)); + handleChangeRequest(true); + PrefUtils.useBlacklist(this,true); + }else { + aSwitch.setText(getString(R.string.action_black_list) + " "+getString(R.string.off)); + handleChangeRequest(false); + PrefUtils.useBlacklist(this,false); + } + }); + } + + private void handleChangeRequest(boolean value){ + IsUsingListBool isUsingListBool = new IsUsingListBool(); + isUsingListBool.setIsUsing(value); + disposable.add( + userService.setTutorBlacklist(tutorId, isUsingListBool) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(()->{ + },this::showError) + ); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + } + + @Override + public void onStop() { + super.onStop(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + disposable.dispose(); + } +} 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 189f28a..fda30bf 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 @@ -149,7 +149,7 @@ public class LoginActivity extends AppCompatActivity { private void loginProcess(String email, String password) { ValidateUser user = new ValidateUser(email, password); - //LdapUser fakeUser = new LdapUser(email, password,"wmi","tutor",email,"Fałszywy",email); + // LdapUser fakeUser = new LdapUser(email, password,"wmi","tutor",email,"Fałszywy",email); disposable.add(ldapService.validate(user) //disposable.add(ldapService.fakeValidate(fakeUser) .subscribeOn(Schedulers.io()) 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 b1e9a32..2822ed9 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 @@ -44,6 +44,7 @@ import com.uam.wmi.findmytutor.model.PredefinedCoordViewModel; import com.uam.wmi.findmytutor.model.User; import com.uam.wmi.findmytutor.network.ApiClient; import com.uam.wmi.findmytutor.service.CoordinateService; +import com.uam.wmi.findmytutor.service.PredefinedCoordinatesService; import com.uam.wmi.findmytutor.service.PredefinedStatusesService; import com.uam.wmi.findmytutor.service.UserService; import com.uam.wmi.findmytutor.utils.ApproximatedLocalization; @@ -70,6 +71,8 @@ import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; import timber.log.Timber; +import static com.uam.wmi.findmytutor.utils.Const.mapRefreshInterval; + public class MapActivity extends BaseActivity implements PermissionsListener, OnMapReadyCallback { @@ -80,7 +83,7 @@ public class MapActivity extends BaseActivity private UserService userService; private CompositeDisposable disposable = new CompositeDisposable(); - private int mInterval = 10000; + private int mInterval = mapRefreshInterval; private Handler mHandler = new Handler(); private Runnable mStatusChecker; private MapView mapView; @@ -91,7 +94,7 @@ public class MapActivity extends BaseActivity private Coordinate droppedMarkercoordinate; private HashMap coordsMap = new HashMap<>(); private HashMap markerHash = new HashMap<>(); - private HashMap markerUserHash = new HashMap<>(); + public HashMap markerUserHash = new HashMap<>(); private Set previousCoordsIds = new HashSet<>(); private ManualLocationUtils manualLocationUtils; // Camera Animation params @@ -148,22 +151,7 @@ public class MapActivity extends BaseActivity mapboxMap.setOnMarkerClickListener(marker -> { String id = markerUserHash.get(marker.getId()); - String locationLevel = PrefUtils.getLocationLevel(getApplicationContext()); - - /* if (id.equals(myId) && (locationLevel.equals(SharingLevel.MANUAL.toString()) || locationLevel.equals(SharingLevel.PREDEFINED.toString()))) { - selectLocationButton.setVisibility(View.GONE); - removeLocationButton.setVisibility(View.VISIBLE); - - removeLocationButton.setOnClickListener(view -> { - stopBackgroundLocalizationTask(); - - removeLocationButton.setVisibility(View.GONE); - Toast.makeText(MapActivity.this, R.string.manual_marker_info, Toast.LENGTH_SHORT).show(); - - }); - } else {*/ - createMarkerModal(id); - /* }*/ + createMarkerModal(id); return true; }); @@ -246,7 +234,11 @@ public class MapActivity extends BaseActivity } private void setOnMapClickListener() { - mapboxMap.addOnMapClickListener(e -> removeLocationButton.setVisibility(View.GONE)); + + mapboxMap.addOnMapClickListener(e -> { + removeLocationButton.setVisibility(View.GONE); + selectLocationButton.setVisibility(View.GONE); + }); } private void setOnMapLongClickListener() { @@ -333,7 +325,7 @@ public class MapActivity extends BaseActivity final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); - EditText modalUserInput = view.findViewById(R.id.feedback_input); + EditText modalUserInput = view.findViewById(R.id.manual_input); alertDialog.setOnShowListener(dialogInterface -> { Button sendButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); @@ -365,7 +357,7 @@ public class MapActivity extends BaseActivity private void sendLocation(String body, LatLng latLng) { - PredefinedStatusesService predefinedStatusesService = ApiClient.getClient(getApplicationContext()).create(PredefinedStatusesService.class); + PredefinedCoordinatesService predefinedCoordinatesService = ApiClient.getClient(getApplicationContext()).create(PredefinedCoordinatesService.class); PredefinedCoordViewModel droppedMarkercoordinate = new PredefinedCoordViewModel( latLng.getLatitude(), @@ -379,7 +371,7 @@ public class MapActivity extends BaseActivity CompositeDisposable disposable = new CompositeDisposable(); disposable.add( - predefinedStatusesService.postUserPredefinedCoord(PrefUtils.getUserId(getApplicationContext()), droppedMarkercoordinate) + predefinedCoordinatesService.postUserPredefinedCoord(PrefUtils.getUserId(getApplicationContext()), droppedMarkercoordinate) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::SaveCurrentManualLocation, this::handleError) @@ -603,7 +595,6 @@ public class MapActivity extends BaseActivity } } - // Add the mapView lifecycle to the activity's lifecycle methods @Override public void onResume() { super.onResume(); @@ -615,6 +606,7 @@ public class MapActivity extends BaseActivity protected void onStart() { super.onStart(); mapView.onStart(); + shouldFetchNewCoords = true; } @Override @@ -708,7 +700,7 @@ public class MapActivity extends BaseActivity })); } - private void filterMarkers(List users) { + public void filterMarkers(List users) { restoreMapMarkers(); Icon markedMarker = IconFactory.getInstance(MapActivity.this).fromResource(R.drawable.search_marker); 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 1eee441..8882bfd 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 @@ -1,7 +1,9 @@ package com.uam.wmi.findmytutor.activity; import android.annotation.SuppressLint; +import android.app.AlertDialog; import android.app.FragmentTransaction; +import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.ListPreference; @@ -9,6 +11,7 @@ import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.SwitchPreference; +import android.support.annotation.NonNull; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -19,17 +22,21 @@ import com.annimon.stream.IntPair; import com.annimon.stream.Stream; import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; import com.uam.wmi.findmytutor.R; +import com.uam.wmi.findmytutor.adapters.TutorsListAdapter; import com.uam.wmi.findmytutor.model.PredefinedCoordViewModel; import com.uam.wmi.findmytutor.network.ApiClient; +import com.uam.wmi.findmytutor.service.PredefinedCoordinatesService; import com.uam.wmi.findmytutor.service.PredefinedStatusesService; -import com.uam.wmi.findmytutor.utils.Const; import com.uam.wmi.findmytutor.utils.EnableSharingDialog; 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 org.apache.commons.collections4.BidiMap; + import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -39,25 +46,34 @@ import io.reactivex.disposables.CompositeDisposable; import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; import okhttp3.ResponseBody; - import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; public class SharingFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { protected SwitchPreference locationSharing; + protected SwitchPreference statusSwitch; protected Preference locationMode; protected ListPreference manualLocationList; protected PreferenceCategory preferenceCategory; protected RightButtonPreference manualLocationButton; + protected RightButtonPreference removeManualLocation; + protected RightButtonPreference removeManualStatus; protected Preference manualStatus; protected ListPreference statusList; + private HashMap locationMap; + private ArrayList locationUUIDs; protected List predefinedCoordsList = new ArrayList<>(); private HashMap locationLevelMapping; private HashMap statusMapping; private PredefinedStatusesService statusesService; + private PredefinedCoordinatesService locationService; private CompositeDisposable disposable; + private AlertDialog.Builder builder; + private String[] statusesArray; + private boolean statusSwitchFlag; + private ArrayList predefinedLocationsList; - public static SharingFragment newInstance() { + public static SharingFragment newInstance() { return new SharingFragment(); } @@ -69,7 +85,13 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere .subscribeWith(new DisposableSingleObserver>() { @Override public void onSuccess(List strings) { - String[] statusesArray = strings.toArray(new String[strings.size()]); + statusesArray = strings.toArray(new String[strings.size()]); + if(strings.isEmpty()){ + disableStatusPreferences(); + }else{ + enableStatusPreferences(); + } +// Log.d("STATUSES",Integer.toString(statusesArray.length )); setListPreferenceData(statusList, statusesArray, null); } @@ -82,20 +104,47 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere } void getLocations(CompositeDisposable disposable) { - disposable.add(statusesService.getUserPredefinedCoords(PrefUtils.getUserId(getApplicationContext())) + disposable.add(locationService.getUserPredefinedCoords(PrefUtils.getUserId(getApplicationContext())) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(new DisposableSingleObserver>() { @Override public void onSuccess(List coords) { - String currentCoordId = PrefUtils.getCurrentManualLocation(getApplicationContext()); - List predefinedLocationsNames = Stream.of(coords).map(PredefinedCoordViewModel::getName).toList(); + String currentCoordId = PrefUtils.getCurrentManualLocation(getApplicationContext()); + locationMap = new HashMap(); + locationUUIDs = new ArrayList(); + for (PredefinedCoordViewModel i : coords) locationMap.put(i.getPredefinedCoordinateId(),i.getName()); + for (PredefinedCoordViewModel i : coords) locationUUIDs.add(i.getPredefinedCoordinateId()); + List predefinedLocationsNames = Stream.of(coords).map(PredefinedCoordViewModel::getName).toList(); + List predefinedLocationsUUIDs = Stream.of(coords).map(PredefinedCoordViewModel::getPredefinedCoordinateId).toList(); predefinedCoordsList.addAll(coords); String[] stringnames = predefinedLocationsNames.toArray(new String[0]); + predefinedLocationsList = new ArrayList<>(Arrays.asList(stringnames)); + if (!PrefUtils.getLocationLevel(getApplicationContext()).equals("manual")) { + preferenceCategory.removePreference(manualLocationList); + preferenceCategory.removePreference(removeManualLocation); + preferenceCategory.removePreference(manualLocationButton); + }else{ + if(predefinedCoordsList.isEmpty()){ + locationSharing.setEnabled(false); + locationSharing.setChecked(false); + PrefUtils.disableSharing(getApplicationContext()); + ((MapActivity) getActivity()).handleBackgroundTaskLifeCycle(); + removeManualLocation.setEnabled(false); + manualLocationList.setEnabled(false); + manualLocationList.setSummary(""); + }else{ + manualLocationList.setEnabled(true); + manualLocationList.setSummary(PrefUtils.getCurrentManualLocationName(getApplicationContext())); + removeManualLocation.setEnabled(true); + locationSharing.setEnabled(true); + + } + } List activesId = Stream.of(coords).indexed() .filter(v -> v.getSecond().getPredefinedCoordinateId().equals(currentCoordId)).map(IntPair::getFirst).toList(); @@ -105,29 +154,39 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere else { setListPreferenceData(manualLocationList, stringnames, activesId.get(0)); } + } @Override public void onError(Throwable e) { Toast.makeText(getApplicationContext(), R.string.error_location_fetch, Toast.LENGTH_SHORT).show(); } + })); } + @SuppressLint("ResourceType") @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - addPreferencesFromResource(R.layout.pref_sharing); + addPreferencesFromResource(R.xml.pref_sharing); locationSharing = (SwitchPreference) findPreference("key_sharing_enabled"); + statusSwitch = (SwitchPreference) findPreference("key_status_enabled"); locationMode = findPreference("key_location_level"); preferenceCategory = (PreferenceCategory) findPreference("category_sharing"); manualLocationList = (ListPreference) findPreference("key_manual_location_value"); manualLocationButton = (RightButtonPreference) findPreference("manual_location_button"); + removeManualLocation = (RightButtonPreference) findPreference("remove_manual_location"); + builder = new AlertDialog.Builder(getActivity()); + removeManualStatus = (RightButtonPreference) findPreference("remove_manual_status"); manualStatus = findPreference("key_manual_status"); statusList = (ListPreference) findPreference("key_status_value"); - statusesService = ApiClient.getClient(getApplicationContext()).create(PredefinedStatusesService.class); + statusesService = ApiClient.getClient(getApplicationContext()).create(PredefinedStatusesService.class); + locationService = ApiClient.getClient(getApplicationContext()).create(PredefinedCoordinatesService.class); disposable = new CompositeDisposable(); + statusesArray = new String[0]; + predefinedLocationsList = new ArrayList(); getStatuses(disposable); getLocations(disposable); locationLevelMapping = new HashMap(); @@ -153,28 +212,33 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere /** Sharing level list **/ locationMode.setOnPreferenceChangeListener((preference, newValue) -> { + ((MapActivity) getActivity()).stopBackgroundLocalizationTask(); + ((MapActivity) getActivity()).startBackgroundLocalizationTask(); PrefUtils.storeLocationMode(getApplicationContext(), locationLevelMapping.get(Integer.parseInt((String) newValue))); - if (PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.MANUAL.toString())) { if (!predefinedCoordsList.isEmpty()) { - preferenceCategory.addPreference(manualLocationList); + preferenceCategory.addPreference(manualLocationList); + preferenceCategory.addPreference(removeManualLocation); + }else{ + locationSharing.setEnabled(false); + locationSharing.setChecked(false); + PrefUtils.disableSharing(getApplicationContext()); + ((MapActivity) getActivity()).handleBackgroundTaskLifeCycle(); + } - preferenceCategory.addPreference(manualLocationButton); - } else { + locationSharing.setEnabled(true); preferenceCategory.removePreference(manualLocationList); preferenceCategory.removePreference(manualLocationButton); + preferenceCategory.removePreference(removeManualLocation); } 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) -> { @@ -199,6 +263,7 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere + /** Button 'choose from map' button listener **/ manualLocationButton.setOnPreferenceChangeListener((preference, o) -> { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); @@ -206,7 +271,9 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere fragmentTransaction.commit(); return true; }); - + statusSwitch.setOnPreferenceChangeListener((preference, newValue) -> { + return true; + }); /** Status list change listener **/ statusList.setOnPreferenceChangeListener((preference, newValue) -> { ListPreference lp = (ListPreference) preference; @@ -216,7 +283,7 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere return true; }); - /** Custom status list change listener **/ + /** Custom status edittext change listener **/ manualStatus.setOnPreferenceChangeListener((preference, newValue) -> { disposable.add(statusesService.postUserPredefinedStatus(PrefUtils.getUserId(getApplicationContext()), (String) newValue) @@ -226,6 +293,40 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere return true; }); + removeManualStatus.setOnPreferenceChangeListener((preference, newValue) -> { + showRemoveDialog(statusList.getEntries(),"status"); + return true; + }); + + removeManualLocation.setOnPreferenceChangeListener(((preference, newValue) -> { + showRemoveDialog(manualLocationList.getEntries(),"location"); + return true; + + })); + } + public void showRemoveDialog(CharSequence[] entries, String service){ + boolean [] checked = new boolean[entries.length]; + ArrayList tobeDeleted = new ArrayList(); +// Log.d("sharingDialog", "no to siup"); + builder.setPositiveButton("DELETE", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + for (int i=0; i< entries.length; i++){ + if(checked[i] == true) { + tobeDeleted.add((String) entries[i]); + } + } + removeEntries(service,tobeDeleted); +// Log.d("MANAGE-PREF",tobeDeleted.toString()); + } + }); + builder.setMultiChoiceItems(entries, checked, new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + + } + }); + builder.create().show(); } @Override @@ -236,6 +337,36 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere return view; } + protected void removeEntries(String service, ArrayList toBeDeleted){ + +// Log.d("MANAGE-PREF", toBeDeleted.toString()); + if(service.equals("status")){ + for (String uuid:toBeDeleted) { + disposable.add(statusesService.deleteUserPredefinedStatus(PrefUtils.getUserId(getApplicationContext()), uuid) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleDeleteStatuses, this::handleError)); + } + }else { + ArrayList uuidsToBeDeleted = new ArrayList(); + for (String name:toBeDeleted) { + for (String uuid:locationUUIDs) { + if(locationMap.get(uuid).equals(name)){ + uuidsToBeDeleted.add(uuid); + } + } + } + for (String uuid : uuidsToBeDeleted) { +// predefinedCoordsList.removeIf(x -> x.getPredefinedCoordinateId().equals(uuid)); + predefinedCoordsList.removeAll(Stream.of(predefinedCoordsList).filter(x -> x.getPredefinedCoordinateId().equals(uuid)).toList()); + disposable.add(locationService.deleteUserPredefinedCoord(PrefUtils.getUserId(getApplicationContext()), uuid) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleDeleteLocations, this::handleError)); + } + } + } + protected void setListPreferenceData(ListPreference lp, String[] entries, Integer activeId) { try { @@ -261,10 +392,15 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere ; private void handleResponse(List resp) { + if(resp.size() == 1){ + enableStatusPreferences(); + if(PrefUtils.isStatusEnabled(getApplicationContext()) == false){ + PrefUtils.enableStatus(getApplicationContext()); + statusSwitch.setChecked(true); + } + } String[] statusesArray = resp.toArray(new String[resp.size()]); - setListPreferenceData(statusList, statusesArray, resp.size() - 1); - statusList.setValueIndex(resp.size() - 1); PrefUtils.storeStatus(getApplicationContext(), resp.get(resp.size() - 1)); statusList.setSummary(PrefUtils.getUserStatus(getApplicationContext())); @@ -281,6 +417,73 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere "Network error " + error.getMessage(), Toast.LENGTH_SHORT).show(); } } + private void handleDeleteStatuses(List resp){ + if(resp.isEmpty()){ + disableStatusPreferences(); + }else{ + String[] statusesArray = resp.toArray(new String[resp.size()]); + setListPreferenceData(statusList, statusesArray, null); + String currentEntry = PrefUtils.getUserStatus(getApplicationContext()); + if(resp.contains(currentEntry)){ + statusList.setValueIndex(resp.indexOf(currentEntry)); + }else{ + statusList.setValueIndex(0); + statusList.setSummary(resp.get(0)); + } + } + + } + private void handleDeleteLocations(List resp){ + getLocations(disposable); + String currentEntry = PrefUtils.getCurrentManualLocation(getApplicationContext()); + if(resp.isEmpty()){ + disableManualLocationPreferences(); + }else{ + if(!Stream.of(resp).filter(x -> x.getName().equals(currentEntry)).toList().isEmpty()) + { + for (PredefinedCoordViewModel location: resp) { + if(location.getName().equals(currentEntry)){ + manualLocationList.setValueIndex(resp.indexOf(location)); + break; + } + } + }else{ + manualLocationList.setValueIndex(0); + manualLocationList.setSummary(resp.get(0).getName()); + //todo czy na pewno w shared pref sa dobre wartosci + } + + } + } + private void disableStatusPreferences(){ + removeManualStatus.setEnabled(false); + statusList.setEnabled(false); + statusSwitch.setEnabled(false); + statusList.setSummary(""); + PrefUtils.disableStatus(getApplicationContext()); + + } + private void enableStatusPreferences(){ + removeManualStatus.setEnabled(true); + statusList.setEnabled(true); + statusSwitch.setEnabled(true); + statusList.setSummary(PrefUtils.getUserStatus(getApplicationContext())); + } + private void disableManualLocationPreferences(){ + removeManualLocation.setEnabled(false); + manualLocationList.setEnabled(false); + manualLocationList.setSummary(""); + locationSharing.setChecked(false); + locationSharing.setEnabled(false); + PrefUtils.disableSharing(getApplicationContext()); + ((MapActivity) getActivity()).handleBackgroundTaskLifeCycle(); + + } + private void enableManualLocationPreferences(){ + removeManualLocation.setEnabled(true); + manualLocationList.setEnabled(true); + + } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { @@ -300,4 +503,10 @@ public class SharingFragment extends PreferenceFragment implements SharedPrefere getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); super.onPause(); } + + @Override + public void onDestroy() { + super.onDestroy(); + disposable.dispose(); + } } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/SpecialList.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/SpecialList.java new file mode 100644 index 0000000..ec12a92 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/SpecialList.java @@ -0,0 +1,19 @@ +package com.uam.wmi.findmytutor.activity; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; + +import com.uam.wmi.findmytutor.R; + +public abstract class SpecialList extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + setContentView(getContentViewId()); + + } + + abstract int getContentViewId(); + + +} diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java index 4db2335..575ff5d 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorTab.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import butterknife.ButterKnife; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.observers.DisposableCompletableObserver; @@ -61,9 +62,10 @@ public class TutorTab extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); setContentView(R.layout.content_tutor_tab); + ButterKnife.bind(this); userName = findViewById(R.id.userName); userNote = (TextInputEditText) findViewById(R.id.userNote); @@ -134,7 +136,12 @@ public class TutorTab extends AppCompatActivity { @Override public void onError(Throwable e) { - int code = ((HttpException) e).response().code(); + int code = 0; + + if (e instanceof HttpException) { + code = ((HttpException) e).response().code(); + } + if( code == 404){ ifTutorTabExists = false; dutyHoursAdapter = new DutyHoursAdapter(getApplicationContext(),new ArrayList()); @@ -144,7 +151,6 @@ public class TutorTab extends AppCompatActivity { showError(e); } })); - } private void addEmptyDuty(DutyHoursAdapter adapter){ diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorsListTab.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorsListTab.java new file mode 100644 index 0000000..06e39cc --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/TutorsListTab.java @@ -0,0 +1,46 @@ +package com.uam.wmi.findmytutor.activity; + +//import android.app.Fragment; +import android.support.v4.app.Fragment; +import android.os.Bundle; +import android.support.v4.app.FragmentTabHost; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.uam.wmi.findmytutor.R; + +public class TutorsListTab extends Fragment { + private FragmentTabHost mTabHost; + + public TutorsListTab() { + } + + public static TutorsListTab newInstance() { + return new TutorsListTab(); + } + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + } + + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View rootView = inflater.inflate(R.layout.tutors_list_tabs, container, false); + + mTabHost = rootView.findViewById(android.R.id.tabhost); + mTabHost.setup(getActivity(), getFragmentManager(), R.id.realtabcontent); + + mTabHost.addTab(mTabHost.newTabSpec("fragmentb").setIndicator("Fragment B"), + UsersListFragment.class, null); + mTabHost.addTab(mTabHost.newTabSpec("fragmentc").setIndicator("Fragment C"), + UsersListFragment.class, null); + + + + return rootView; + } +} + 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 0ed27fc..c0f9ac0 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 @@ -1,6 +1,8 @@ package com.uam.wmi.findmytutor.activity; import android.app.Fragment; +import android.app.FragmentTransaction; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.CoordinatorLayout; @@ -9,27 +11,36 @@ import android.support.v7.app.AlertDialog; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SearchView; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ImageSpan; +import android.util.Log; +import android.view.Gravity; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; -import android.widget.Toast; import com.annimon.stream.Stream; import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; import com.uam.wmi.findmytutor.R; import com.uam.wmi.findmytutor.adapters.TutorsListAdapter; - import com.uam.wmi.findmytutor.model.DutyHourViewModel; import com.uam.wmi.findmytutor.model.TutorTabViewModel; import com.uam.wmi.findmytutor.model.User; import com.uam.wmi.findmytutor.network.ApiClient; import com.uam.wmi.findmytutor.service.TutorTabApi; import com.uam.wmi.findmytutor.service.UserService; -import com.uam.wmi.findmytutor.utils.InfoHelperUtils; import com.uam.wmi.findmytutor.utils.MyDividerItemDecoration; +import com.uam.wmi.findmytutor.utils.PrefUtils; import com.uam.wmi.findmytutor.utils.RecyclerTouchListener; import com.uam.wmi.findmytutor.utils.RestApiHelper; @@ -59,13 +70,14 @@ public class UsersListFragment extends Fragment { @BindView(R.id.txt_empty_notes_view) TextView noNotesView; + private SearchView searchView; private UserService userService; private TutorTabApi tutorTabService; private CompositeDisposable disposable = new CompositeDisposable(); private TutorsListAdapter mAdapter; private List tutorsList = new ArrayList<>(); - private List tutorsFiltered = new ArrayList<>(); private Collator plCollator = Collator.getInstance(Locale.forLanguageTag("pl-PL")); + private Boolean fetchOnlyOnlineUsers = PrefUtils.getShowOnlyOnlineUsers(getApplicationContext()); public UsersListFragment() { } @@ -75,10 +87,10 @@ public class UsersListFragment extends Fragment { } public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - mAdapter = new TutorsListAdapter(getActivity().getApplicationContext(), tutorsFiltered); + mAdapter = new TutorsListAdapter(getActivity().getApplicationContext(), tutorsList); View view = inflater.inflate(R.layout.users_list, container, false); view.setBackgroundColor(getResources().getColor(android.R.color.white)); - + setHasOptionsMenu(true); return view; } @@ -94,6 +106,7 @@ public class UsersListFragment extends Fragment { RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.setVerticalScrollBarEnabled(true); recyclerView.addItemDecoration(new MyDividerItemDecoration(getActivity(), LinearLayoutManager.VERTICAL, 16)); recyclerView.setAdapter(mAdapter); @@ -103,7 +116,7 @@ public class UsersListFragment extends Fragment { recyclerView, new RecyclerTouchListener.ClickListener() { @Override public void onClick(View view, final int position) { - showNoteDialog(tutorsFiltered.get(position)); + showNoteDialog(tutorsList.get(position)); } @Override @@ -113,12 +126,52 @@ public class UsersListFragment extends Fragment { } - public void searchUser(String textToSearch) { - tutorsFiltered.clear(); - tutorsFiltered.addAll(Stream.of(tutorsList).filter(t -> - t.toSearchAbleString().toLowerCase().contains(textToSearch.toLowerCase())).toList()); - mAdapter.notifyDataSetChanged(); + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + try { + menu.findItem(R.id.showOnlineUsersOnly).setChecked(fetchOnlyOnlineUsers); + } catch (Exception e) { + Log.e(TAG, "onPrepareOptionsMenu error"); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + //item.setChecked(fetchOnlyOnlineUsers); + switch (item.getItemId()) { + case R.id.showOnlineUsersOnly: + + if (item.isChecked()) { + fetchOnlyOnlineUsers = false; + item.setChecked(false); + } else { + item.setChecked(true); + fetchOnlyOnlineUsers = true; + } + + PrefUtils.putShowOnlyOnlineUsers(getApplicationContext(), fetchOnlyOnlineUsers); + fetchAllTutors(); + break; + } + + return false; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.users_list_menu, menu); + menu.getItem(0).setChecked(fetchOnlyOnlineUsers); + + MenuItem myActionMenuItem = menu.findItem(R.id.action_search); + searchView = (SearchView) myActionMenuItem.getActionView(); + + super.onCreateOptionsMenu(menu, inflater); + } + + public void searchUser(String textToSearch) { + searchTutorInBackend(textToSearch); } private void showNoteDialog(final User user) { @@ -132,6 +185,7 @@ public class UsersListFragment extends Fragment { // User cancelled the dialog }); + TextView userName = view.findViewById(R.id.userName); ListView userDutyHours = view.findViewById(R.id.userDutyHours); TextView userDutyHoursTitle = view.findViewById(R.id.userDutyHoursTitle); @@ -140,8 +194,26 @@ public class UsersListFragment extends Fragment { TextView userEmail = view.findViewById(R.id.userEmail); TextView department = view.findViewById(R.id.userDepartment); - userName.setText(String.format("%s %s", user.getFirstName(), user.getLastName())); + userName.setText(String.format("%s %s", user.getFirstName(), user.getLastName())); + Drawable image; + if (user.isIsOnline()) { + image = this.getResources().getDrawable(R.drawable.user_list_online); + } else { + image = this.getResources().getDrawable(R.drawable.user_list_offline); + } + + if (!user.isIsActive()) { + image = this.getResources().getDrawable(R.drawable.user_list_off); + } + + Spannable span = new SpannableString(" " + userName.getText()); // or set your text manually + image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight()); + ImageSpan imageSpan = new ImageSpan(image); + span.setSpan(imageSpan, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + userName.setText(span); + + UsersListFragment usersListFragment = this; disposable.add( tutorTabService.apiUsersTutorTabByTutorIdGet(user.getId()) .subscribeOn(Schedulers.io()) @@ -149,7 +221,20 @@ public class UsersListFragment extends Fragment { .subscribeWith(new DisposableSingleObserver() { @Override public void onSuccess(TutorTabViewModel tutorTabViewModel) { - final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); + final AlertDialog alertDialog; + if (((MapActivity) getActivity()).markerUserHash.containsValue(user.getId())) { + alertDialogBuilderUserInput.setPositiveButton(R.string.show_on_map, (dialog, id) -> { + // User cancelled the dialog + FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); + fragmentTransaction.hide(usersListFragment); + fragmentTransaction.commit(); + List list = new ArrayList(); + list.add(user); + ((MapActivity) getActivity()).filterMarkers(list); + }); + } + alertDialog = alertDialogBuilderUserInput.create(); + String userNoteText = tutorTabViewModel.getNote(); List dutyHoursList = Stream.of(tutorTabViewModel.getDutyHours()) .map(DutyHourViewModel::getSummary).toList(); @@ -185,17 +270,16 @@ public class UsersListFragment extends Fragment { private void fetchAllTutors() { disposable.add( - userService.getAllTutors() + (fetchOnlyOnlineUsers ? + userService.getAllActiveTutors() : + userService.getAllOfflineTutors()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map(tutors -> { List tutorsList = new ArrayList<>(tutors); - List onlineTutors = Stream.of(tutorsList).filter(User::isIsOnline).toList(); - List activeNotOnlineTutors = Stream.of(tutorsList) .filter(t -> t.isIsActive() && !onlineTutors.contains(t)).toList(); - List notActiveTutors = Stream.of(tutorsList) .filterNot(User::isIsActive).toList(); @@ -213,9 +297,7 @@ public class UsersListFragment extends Fragment { @Override public void onSuccess(List users) { tutorsList.clear(); - tutorsFiltered.clear(); tutorsList.addAll(users); - tutorsFiltered.addAll(users); mAdapter.notifyDataSetChanged(); toggleEmptyNotes(); } @@ -228,22 +310,70 @@ public class UsersListFragment extends Fragment { } + private void searchTutorInBackend(String searchString) { + disposable.add( + userService.searchUser(searchString) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeWith(new DisposableSingleObserver>() { + @Override + public void onSuccess(List users) { + tutorsList.clear(); + tutorsList.addAll(users); + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onError(Throwable e) { + showSearchError(e); + } + })); + } + + + public void restoreUsersList() { + fetchAllTutors(); + } + private int sortByUserName(User t1, User t2) { return plCollator.compare(t1.getLastName(), t2.getLastName()); } private void showError(Throwable e) { String message; + Log.e(TAG, String.valueOf(e)); if (e instanceof HttpException) { ResponseBody responseBody = ((HttpException) e).response().errorBody(); message = RestApiHelper.getErrorMessage(responseBody); } else { - message = "Network Error !"; + message = getString(R.string.network_err); } - Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_LONG) - .show(); + createSnackbar(message); + } + + private void showSearchError(Throwable e) { + String message; + Log.e(TAG, String.valueOf(e)); + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + message = RestApiHelper.getErrorMessage(responseBody); + } else { + message = getString(R.string.search_null); + } + + createSnackbar(message); + } + + private void createSnackbar(String msg) { + Snackbar snackbar = Snackbar.make(coordinatorLayout, msg, Snackbar.LENGTH_LONG); + View view = snackbar.getView(); + CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams(); + params.gravity = Gravity.TOP; + view.setLayoutParams(params); + snackbar.show(); } private void toggleEmptyNotes() { @@ -251,6 +381,11 @@ public class UsersListFragment extends Fragment { noNotesView.setVisibility(View.GONE); } else { noNotesView.setVisibility(View.VISIBLE); + if (fetchOnlyOnlineUsers) + noNotesView.setText(R.string.no_online_users); + else { + noNotesView.setText(R.string.no_offline_users); + } } } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java new file mode 100644 index 0000000..aad7e70 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/WhiteList.java @@ -0,0 +1,345 @@ +package com.uam.wmi.findmytutor.activity; + +import android.annotation.SuppressLint; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.Switch; +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.adapters.WhiteListAdapter; +import com.uam.wmi.findmytutor.model.IsUsingListBool; +import com.uam.wmi.findmytutor.model.StudentIdModel; +import com.uam.wmi.findmytutor.model.User; +import com.uam.wmi.findmytutor.network.ApiClient; +import com.uam.wmi.findmytutor.service.UserService; +import com.uam.wmi.findmytutor.utils.MyDividerItemDecoration; +import com.uam.wmi.findmytutor.utils.PrefUtils; +import com.uam.wmi.findmytutor.utils.RecyclerTouchListener; +import com.uam.wmi.findmytutor.utils.RestApiHelper; +import com.uam.wmi.findmytutor.utils.WrapContentLinearLayoutManager; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; + +import java.util.List; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.Observable; +import io.reactivex.ObservableSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.functions.Function; +import io.reactivex.observers.DisposableObserver; +import io.reactivex.schedulers.Schedulers; +import okhttp3.ResponseBody; + +public class WhiteList extends AppCompatActivity { + + private CompositeDisposable disposable = new CompositeDisposable(); + private UserService userService; + private boolean didFetched = false; + private String tutorId; + + @BindView(R.id.recycler_view_whitelist) + RecyclerView recyclerView; + @BindView(R.id.white_list_empty_text_view) + TextView noNotesView; + @BindView(R.id.switch_whitelist_toggle) + Switch aSwitch; + @BindView(R.id.add_to_white_list_fab) + FloatingActionButton addToWhiteListFab; + + private WhiteListAdapter mAdapter; + private Integer prevSize; + private List whitelistedUsers = new ArrayList<>(); + private Collator plCollator = Collator.getInstance(Locale.forLanguageTag("pl-PL")); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + setContentView(R.layout.activity_white_list); + ButterKnife.bind(this); + tutorId = PrefUtils.getUserId(getApplicationContext()); + userService = ApiClient.getClient(getApplicationContext()) + .create(UserService.class); + + if (PrefUtils.isWhiteListing(this)){ + aSwitch.setText(getString(R.string.action_white_list) +" ON"); + aSwitch.setChecked(true); + handleChangeRequest(true); + }else{ + aSwitch.setText(getString(R.string.action_white_list) +" OFF"); + aSwitch.setChecked(false); + handleChangeRequest(false); + } + + Toolbar toolbar = findViewById(R.id.toolbar); + toolbar.setTitle(getString(R.string.activity_title_whitelist)); + setSupportActionBar(toolbar); + + mAdapter = new WhiteListAdapter(this, whitelistedUsers); + recyclerView.setLayoutManager(new WrapContentLinearLayoutManager(getApplicationContext())); + recyclerView.setItemAnimator(new DefaultItemAnimator()); + recyclerView.addItemDecoration(new MyDividerItemDecoration(this, LinearLayoutManager.VERTICAL, 16)); + recyclerView.setAdapter(mAdapter); + + /** + * On long press on RecyclerView item, open alert dialog + * with options to choose + * Edit and Delete + * */ + recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, + recyclerView, new RecyclerTouchListener.ClickListener() { + @Override + public void onClick(View view, final int position) { + } + + @Override + public void onLongClick(View view, int position) { + } + })); + + addToWhiteListFab.setOnClickListener(this::showFabDialog); + fetchWhiteListedUsers(); + handleSwitch(); + } + + private Observable> getListOfWhitelistedUsers(String userId) { + return userService.getTutorWhitelistedByID(userId) + .toObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + private Observable getUserObservable(String userId) { + return userService + .getUserById(userId) + .toObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + private void fetchWhiteListedUsers() { + prevSize = whitelistedUsers.size(); + whitelistedUsers.clear(); + + disposable.add(getListOfWhitelistedUsers(tutorId) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap((Function, Observable>) Observable::fromIterable) + .flatMap((Function>) this::getUserObservable) + .subscribeWith(new DisposableObserver() { + @Override + public void onNext(User user) { + whitelistedUsers.add(user); + } + + @Override + public void onError(Throwable e) { + showError(e); + } + + @Override + public void onComplete() { + Collections.sort(whitelistedUsers, (a, b) -> sortByUserName(a,b)); + refreshUI(); + } + })); + } + + private void refreshUI(){ + toggleEmptyNotes(); + mAdapter.notifyItemRangeInserted(prevSize, whitelistedUsers.size() - prevSize); + mAdapter.notifyDataSetChanged(); + } + + private int sortByUserName(User t1, User t2) { + return plCollator.compare(t1.getLastName(), t2.getLastName()); + } + + private void showFabDialog(View v){ + LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext()); + @SuppressLint("InflateParams") View view = layoutInflaterAndroid.inflate(R.layout.white_list_fab_modal, null); + AlertDialog.Builder alertDialogBuilderUserInput = new AlertDialog.Builder(this); + + alertDialogBuilderUserInput.setView(view).setPositiveButton(getApplicationContext().getString(R.string.modal_location_send), null); + + alertDialogBuilderUserInput + .setPositiveButton(R.string.add, null) + .setNegativeButton(R.string.cancel, null); + + final AlertDialog alertDialog = alertDialogBuilderUserInput.create(); + alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + + EditText modalUserInput = view.findViewById(R.id.white_list_modal_input); + + alertDialog.setOnShowListener(dialogInterface -> { + Button sendButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + + Button dismissButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE); + + dismissButton.setOnClickListener(view1 -> alertDialog.dismiss()); + + sendButton.setOnClickListener(view1 -> { + String body = modalUserInput.getText().toString(); + + if (TextUtils.isEmpty(body)) { + Toast.makeText(getApplicationContext(), R.string.can_not_be_empty, Toast.LENGTH_SHORT).show(); + modalUserInput.requestFocus(); + } else { + sendUserToWhitelist(body); + alertDialog.dismiss(); + } + }); + }); + + alertDialog.show(); + } + + private void sendUserToWhitelist(String body) { + StudentIdModel studentIdModel = new StudentIdModel(body); + + disposable.add( + userService.addStudentToWhitelist(tutorId, studentIdModel) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::handleAddUser,this::showError) + ); + } + + private void handleAddUser(User user) { + Toast.makeText(this, R.string.add_user_to_list, Snackbar.LENGTH_LONG).show(); + fetchWhiteListedUsers(); + } + + private void showError(Throwable e) { + String message; + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + message = RestApiHelper.getErrorMessage(responseBody); + if (((HttpException) e).response().code() == 404) { + message = getString(R.string.no_such_a_user); + } + } else { + message = "Network Error !"; + } + Log.e("ERR",message); + Toast.makeText(this, message, Snackbar.LENGTH_LONG).show(); + } + + private void toggleEmptyNotes() { + if (didFetched && whitelistedUsers.size() == 0) { + noNotesView.setText(R.string.list_is_empty); + noNotesView.setVisibility(View.VISIBLE); + }else if (whitelistedUsers.size() > 0) { + noNotesView.setVisibility(View.GONE); + } else { + noNotesView.setText(getString(R.string.loading)); + noNotesView.setVisibility(View.VISIBLE); + } + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + if (item.getItemId()==R.id.action_whitelist_info_popup){ + int layoutID = R.layout.info_popup_whitelist; + + View popupView = getLayoutInflater().inflate(layoutID,null); + + PopupWindow popupWindow = new PopupWindow(popupView, + LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + // If the PopupWindow should be focusable + popupWindow.setFocusable(true); + // If you need the PopupWindow to dismiss when when touched outside + popupWindow.setBackgroundDrawable(new ColorDrawable()); + // Get the View's(the one that was clicked in the Fragment) location + View anchorView= getWindow().getDecorView().findViewById(android.R.id.content); + popupWindow.showAtLocation(anchorView,Gravity.TOP|Gravity.END, 0, 0); + } + + return super.onOptionsItemSelected(item); + } + + private void handleSwitch(){ + aSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked){ + aSwitch.setText(getString(R.string.action_white_list) + " "+ getString(R.string.on)); + handleChangeRequest(true); + PrefUtils.useWhitelist(this, true); + }else { + aSwitch.setText(getString(R.string.action_white_list) + " "+getString(R.string.off)); + handleChangeRequest(false); + PrefUtils.useWhitelist(this, false); + } + }); + } + + private void handleChangeRequest(boolean value){ + IsUsingListBool isUsingListBool = new IsUsingListBool(); + isUsingListBool.setIsUsing(value); + disposable.add( + userService.setTutorWhitelist(tutorId, isUsingListBool) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(()->{ + },this::showError) + ); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + } + + @Override + public void onStop() { + super.onStop(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + disposable.dispose(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_white_list, menu); + return true; + } +} diff --git a/app/src/main/java/com/uam/wmi/findmytutor/adapters/BlackListAdapter.java b/app/src/main/java/com/uam/wmi/findmytutor/adapters/BlackListAdapter.java new file mode 100644 index 0000000..f42c9a7 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/adapters/BlackListAdapter.java @@ -0,0 +1,119 @@ +package com.uam.wmi.findmytutor.adapters; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +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.model.StudentIdModel; +import com.uam.wmi.findmytutor.model.User; +import com.uam.wmi.findmytutor.network.ApiClient; +import com.uam.wmi.findmytutor.service.UserService; +import com.uam.wmi.findmytutor.utils.PrefUtils; +import com.uam.wmi.findmytutor.utils.RestApiHelper; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.schedulers.Schedulers; +import okhttp3.ResponseBody; + +import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext; + + +public class BlackListAdapter extends RecyclerView.Adapter { + + private Context context; + private List tutorsList; + private CompositeDisposable disposable = new CompositeDisposable(); + private UserService userService; + + public BlackListAdapter(Context context, List tutors) { + this.context = context; + this.tutorsList = tutors; + } + + @NonNull + @Override + public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + userService = ApiClient.getClient(getApplicationContext()) + .create(UserService.class); + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.black_list_row, parent, false); + + return new MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { + Drawable image = null; + User tutor = tutorsList.get(position); + + holder.firstName.setText(tutor.getFirstName() + " " + tutor.getLastName()); + holder.lastName.setText("Index: " + tutor.getLdapLogin() + " Email: " + tutor.getEmail()); +//"s416196" + holder.imageButton.setOnClickListener(l ->{ + StudentIdModel studentIdModel = new StudentIdModel(tutor.getLdapLogin()); + String tutorId = PrefUtils.getUserId(getApplicationContext()); + disposable.add( + userService.removeStudentFromBlacklist(tutorId, studentIdModel) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(()->{ + Toast.makeText(getApplicationContext(), R.string.user_removed, Toast.LENGTH_SHORT).show(); + tutorsList.remove(position); + notifyDataSetChanged(); + },this::showError) + ); + }); + } + + @Override + public int getItemCount() { + return tutorsList.size(); + } + + class MyViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.firstName) + TextView firstName; + + @BindView(R.id.lastName) + TextView lastName; + + @BindView(R.id.removeUserImageButton) + ImageButton imageButton; + + MyViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + + private void showError(Throwable e) { + String message; + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + message = RestApiHelper.getErrorMessage(responseBody); + } else { + message = "Network Error !"; + } + + Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/adapters/DutyHoursAdapter.java b/app/src/main/java/com/uam/wmi/findmytutor/adapters/DutyHoursAdapter.java index ae2d465..eaa95f1 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/adapters/DutyHoursAdapter.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/adapters/DutyHoursAdapter.java @@ -11,12 +11,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; - import com.annimon.stream.Collectors; import com.annimon.stream.Stream; import com.uam.wmi.findmytutor.R; import com.uam.wmi.findmytutor.model.DutyHourViewModel; - import java.util.ArrayList; import java.util.List; import butterknife.BindView; @@ -29,7 +27,7 @@ public class DutyHoursAdapter extends RecyclerView.Adapter hours) { this.context = context; - this.hours = new ArrayList(hours); + this.hours = new ArrayList<>(hours); } @@ -114,16 +112,16 @@ public class DutyHoursAdapter extends RecyclerView.Adapter { + + private Context context; + private List tutorsList; + private CompositeDisposable disposable = new CompositeDisposable(); + private UserService userService; + + public WhiteListAdapter(Context context, List tutors) { + this.context = context; + this.tutorsList = tutors; + } + @NonNull + @Override + public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + userService = ApiClient.getClient(getApplicationContext()) + .create(UserService.class); + View itemView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.white_list_row, parent, false); + + return new MyViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { + Drawable image = null; + User tutor = tutorsList.get(position); + + holder.firstName.setText(tutor.getFirstName() + " " + tutor.getLastName()); + holder.lastName.setText("Index: " + tutor.getLdapLogin() + " Email: " + tutor.getEmail()); +//"" + holder.imageButton.setOnClickListener(l ->{ + StudentIdModel studentIdModel = new StudentIdModel(tutor.getLdapLogin()); + String tutorId = PrefUtils.getUserId(getApplicationContext()); + disposable.add( + userService.removeStudentFromWhitelist(tutorId, studentIdModel) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(()->{ + Toast.makeText(getApplicationContext(), R.string.user_removed, Toast.LENGTH_SHORT).show(); + tutorsList.remove(position); + notifyDataSetChanged(); + },this::showError) + ); + }); + + } + + @Override + public int getItemCount() { + return tutorsList.size(); + } + + class MyViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.firstName) + TextView firstName; + + @BindView(R.id.lastName) + TextView lastName; + + @BindView(R.id.removeUserImageButton) + ImageButton imageButton; + + MyViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + } + } + + private void showError(Throwable e) { + String message; + + if (e instanceof HttpException) { + ResponseBody responseBody = ((HttpException) e).response().errorBody(); + message = RestApiHelper.getErrorMessage(responseBody); + } else { + message = "Network Error !"; + } + Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/uam/wmi/findmytutor/model/StudentIdModel.java b/app/src/main/java/com/uam/wmi/findmytutor/model/StudentIdModel.java index 3eea407..ab1f37c 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/model/StudentIdModel.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/model/StudentIdModel.java @@ -18,6 +18,15 @@ public class StudentIdModel extends BaseResponse{ @SerializedName("ldapLogin") private String ldapLogin = null; + /** + * + * @param str + */ + public StudentIdModel(String str){ +// this.studentId = str; + this.ldapLogin = str; + } + public StudentIdModel studentId(String studentId) { this.studentId = studentId; return this; 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 0417d17..81fecf3 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 @@ -11,12 +11,13 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Color; import android.location.Location; +import android.location.LocationListener; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Build; -import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.support.annotation.RequiresApi; import android.support.v4.app.ActivityCompat; import android.support.v4.app.NotificationCompat; @@ -24,8 +25,10 @@ import android.util.Log; import com.annimon.stream.Stream; import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; import com.google.android.gms.location.LocationServices; -import com.jakewharton.retrofit2.adapter.rxjava2.HttpException; import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.geometry.LatLng; import com.uam.wmi.findmytutor.model.Coordinate; @@ -33,21 +36,17 @@ import com.uam.wmi.findmytutor.network.ApiClient; import com.uam.wmi.findmytutor.utils.ApproximatedLocalization; import com.uam.wmi.findmytutor.utils.MapUtils; import com.uam.wmi.findmytutor.utils.PrefUtils; -import com.uam.wmi.findmytutor.utils.RestApiHelper; import com.uam.wmi.findmytutor.utils.SharingLevel; import org.apache.commons.collections4.queue.CircularFifoQueue; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicReference; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.observers.DisposableCompletableObserver; -import io.reactivex.observers.DisposableSingleObserver; import io.reactivex.schedulers.Schedulers; -import okhttp3.ResponseBody; import static com.uam.wmi.findmytutor.utils.Const.offlineBackgroundLocationInterval; import static com.uam.wmi.findmytutor.utils.Const.onlineBackgroundLocationInterval; @@ -60,32 +59,33 @@ import static java.lang.String.valueOf; public class BackgroundLocalizationService extends Service { private static final String TAG = "MyLocationService"; - private static final float LOCATION_DISTANCE = 1f; - private static long notify_interval = onlineBackgroundLocationInterval; - private static long notify_interval_inside_building = onlineBackgroundLocationInterval; - private static long notify_interval_outside_building = offlineBackgroundLocationInterval; - private static int coordinatesHistoryLength = 5; - private static final Long LOCATION_INTERVAL = notify_interval; + private static Integer notify_interval = onlineBackgroundLocationInterval; + private static Integer notify_interval_inside_building = onlineBackgroundLocationInterval; + private static Integer notify_interval_outside_building = offlineBackgroundLocationInterval; + private static int coordinatesHistoryLength = 10; + private Boolean highAccuracyMode; private Location mLastLocation; private Boolean stopService = false; private ArrayList providers = new ArrayList(); - private LocationListener[] mLocationListeners; private CircularFifoQueue coordinatesHistory = new CircularFifoQueue(coordinatesHistoryLength); - private LocationManager mLocationManager = null; private Handler mHandler = new Handler(); private Runnable mStatusChecker; private FusedLocationProviderClient mFusedLocationClient; + private Location fakeLoc = null; + private LocationRequest mLocationRequest; + private Location mCurrentLocation; + private LocationCallback mLocationCallback; + private LocationListener mLocationListener; public BackgroundLocalizationService() { providers.add(LocationManager.GPS_PROVIDER); providers.add(LocationManager.NETWORK_PROVIDER); providers.add(LocationManager.PASSIVE_PROVIDER); + fakeLoc = new Location(""); - mLocationListeners = new LocationListener[]{ - new LocationListener(LocationManager.GPS_PROVIDER), - new LocationListener(LocationManager.NETWORK_PROVIDER), - new LocationListener(LocationManager.PASSIVE_PROVIDER) - }; + fakeLoc.setLatitude(0); + fakeLoc.setLongitude(0); + fakeLoc.setAltitude(0); } @Override @@ -100,7 +100,9 @@ public class BackgroundLocalizationService extends Service { if (intent != null) { stopService = intent.getBooleanExtra("request_stop", false); + notify_interval = intent.getIntExtra("notify_interval", onlineBackgroundLocationInterval); } + if (stopService) { storeBackgroundLocationStatus(getApplication(), false); stopForeground(true); @@ -111,6 +113,20 @@ public class BackgroundLocalizationService extends Service { return START_STICKY; } + private void createLocationCallback() { + mLocationCallback = new LocationCallback() { + @Override + public void onLocationResult(LocationResult locationResult) { + super.onLocationResult(locationResult); + if (locationResult != null) { + mCurrentLocation = locationResult.getLastLocation(); + sendCoordinateToBackend(mCurrentLocation); + changeBackgroundMode(); + } + } + }; + } + @Override public void onCreate() { Log.e(TAG, "onCreate"); @@ -124,35 +140,13 @@ public class BackgroundLocalizationService extends Service { startForeground(1001, notification); } - mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); - - initializeLocationManager(); - - Integer providerIndex = 0; - - for (LocationListener listener : mLocationListeners) { - try { - mLocationManager.requestLocationUpdates( - providers.get(providerIndex), - LOCATION_INTERVAL, - LOCATION_DISTANCE, - listener - ); - - } catch (java.lang.SecurityException ex) { - Log.i(TAG, "fail to request location update, ignore", ex); - } catch (IllegalArgumentException ex) { - Log.d(TAG, "network provider does not exist, " + ex.getMessage()); - } - - providerIndex++; - } - - if (!stopService) { + if (!stopService && !PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.MANUAL.toString())) { + createFusedLocationClient(); + } else if (!stopService && + PrefUtils.getLocationLevel(getApplicationContext()).equals(SharingLevel.MANUAL.toString())) { mStatusChecker = () -> { try { - getLocalizationFromListeners(); - changeBackgroundMode(); + sendCoordinateToBackend(fakeLoc); } finally { mHandler.postDelayed(mStatusChecker, notify_interval); } @@ -162,19 +156,52 @@ public class BackgroundLocalizationService extends Service { } } + private void createFusedLocationClient() { + Integer saveMode = Long.valueOf(notify_interval).compareTo(Long.valueOf(offlineBackgroundLocationInterval)); + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return; + } + + mLocationRequest = new LocationRequest(); + + if (saveMode != 0) { + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + } else { + mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); + } + + mLocationRequest.setFastestInterval(notify_interval); + mLocationRequest.setInterval(notify_interval); + + createLocationCallback(); + + if (!stopService) { + mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); + mFusedLocationClient.requestLocationUpdates(mLocationRequest, + mLocationCallback, Looper.getMainLooper()); + } + } + private void changeBackgroundMode() { - if (coordinatesHistory.size() > 4) { - Boolean shouldExtendTimeInterval = Stream.of(coordinatesHistory) - .map(MapUtils::checkIfCoordinateIsValid).takeWhile(s -> !s).toList().size() == coordinatesHistory.size(); + Integer prevInterval = notify_interval; + Boolean shouldExtendTimeInterval = Stream.of(coordinatesHistory) + .map(MapUtils::checkIfCoordinateIsValid).takeWhile(s -> !s).toList().size() == coordinatesHistory.size(); - Boolean shouldAbbreviateTimeInterval = Stream.of(coordinatesHistory). - map(MapUtils::checkIfCoordinateIsValid).toList().get(coordinatesHistory.size() - 1); + Boolean shouldAbbreviateTimeInterval = Stream.of(coordinatesHistory). + map(MapUtils::checkIfCoordinateIsValid).filter(x -> x).toList().size() > 0; - if (shouldExtendTimeInterval) { - notify_interval = notify_interval_outside_building; - } else if (shouldAbbreviateTimeInterval) { - notify_interval = notify_interval_inside_building; - } + if (shouldAbbreviateTimeInterval) { + notify_interval = notify_interval_inside_building; + } + + if (coordinatesHistory.size() > coordinatesHistoryLength && shouldExtendTimeInterval) { + notify_interval = notify_interval_outside_building; + } + + Integer changedMode = Long.valueOf(prevInterval).compareTo(Long.valueOf(notify_interval)); + if (changedMode != 0) { + updateListeners(); } } @@ -198,50 +225,6 @@ public class BackgroundLocalizationService extends Service { startForeground(2, notification); } - private void getLocalizationFromListeners() { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - // TODO: Consider calling - // ActivityCompat#requestPermissions - // here to request the missing permissions, and then overriding - // public void onRequestPermissionsResult(int requestCode, String[] permissions, - // int[] grantResults) - // to handle the case where the user grants the permission. See the documentation - // for ActivityCompat#requestPermissions for more details. - return; - } - - List providers1 = mLocationManager.getProviders(true); - Location bestLocation = null; - AtomicReference triggerAnotherLocationListener = new AtomicReference<>(false); - - mFusedLocationClient.getLastLocation().addOnSuccessListener( - location -> { - if (location != null) { - mLastLocation = location; - coordinatesHistory.add(location); - sendCoordinateToBackend(location); - } - - triggerAnotherLocationListener.set(true); - }); - - if (triggerAnotherLocationListener.get()) { - for (String provider : providers1) { - Location location = mLocationManager.getLastKnownLocation(provider); - - if (location == null) { - continue; - } - if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) { - bestLocation = location; - } - } - - coordinatesHistory.add(bestLocation); - } - - } - private void sendCoordinateToBackend(Location location) { new Task(location).execute(); } @@ -252,59 +235,49 @@ public class BackgroundLocalizationService extends Service { super.onDestroy(); mHandler.removeCallbacks(mStatusChecker); + destroyLocationListeners(); + } - if (mLocationManager != null) { - for (LocationListener listener : mLocationListeners) { - try { - if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - return; - } - mLocationManager.removeUpdates(listener); - - } catch (Exception ex) { - Log.i(TAG, "fail to remove location listener, ignore", ex); - } - } + private void destroyLocationListeners() { + if (mFusedLocationClient != null) { + mFusedLocationClient.removeLocationUpdates(mLocationCallback); + mFusedLocationClient = null; + mLocationCallback = null; + mLocationRequest = null; } } - private void initializeLocationManager() { - Log.e(TAG, "initializeLocationManager - LOCATION_INTERVAL: " + LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE); - - if (mLocationManager == null) { - mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE); + private void updateListeners() { + if (mFusedLocationClient != null) { + mFusedLocationClient.removeLocationUpdates(mLocationCallback) + .addOnCompleteListener(task -> { + restartService(); + mFusedLocationClient = null; + mLocationCallback = null; + mLocationRequest = null; + }); } } - - private class LocationListener implements android.location.LocationListener { - LocationListener(String provider) { - Log.e(TAG, "LocationListener " + provider); - mLastLocation = new Location(provider); + private void restartService() { + + Intent stopIntent = new Intent(getApplicationContext(), BackgroundLocalizationService.class); + stopIntent.putExtra("request_stop", true); + + stopService(stopIntent); + + Intent startIntent = new Intent(getApplicationContext(), BackgroundLocalizationService.class); + startIntent.putExtra("notify_interval", notify_interval); + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { + startForegroundService(startIntent); + } else { + startService(startIntent); } - @Override - public void onLocationChanged(Location location) { - Log.e(TAG, "onLocationChanged: " + location); - mLastLocation.set(location); - } - - @Override - public void onProviderDisabled(String provider) { - Log.e(TAG, "onProviderDisabled: " + provider); - } - - @Override - public void onProviderEnabled(String provider) { - Log.e(TAG, "onProviderEnabled: " + provider); - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - Log.e(TAG, "onStatusChanged: " + provider); - } } + @SuppressLint("StaticFieldLeak") private class Task extends AsyncTask { private ApproximatedLocalization approximatedLocalization; @@ -320,6 +293,7 @@ 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)); } @@ -330,9 +304,8 @@ public class BackgroundLocalizationService extends Service { String locationLevel = PrefUtils.getLocationLevel(getApplicationContext()); String status = (PrefUtils.isStatusEnabled(getApplicationContext())) ? PrefUtils.getUserStatus(getApplicationContext()) : ""; - if (locationLevel.equals(SharingLevel.PRESENCE.toString())) { - if(!MapUtils.checkIfCoordinateIsValid(latitude,longitude)){ + if (!MapUtils.checkIfCoordinateIsValid(latitude, longitude)) { return null; } @@ -350,6 +323,12 @@ public class BackgroundLocalizationService extends Service { approximatedBuildingPart = PrefUtils.getManualLocationApproximation(getApplicationContext()); } + Location fakeLoc = new Location(""); + + fakeLoc.setLatitude(latitude); + fakeLoc.setLongitude(longitude); + coordinatesHistory.add(fakeLoc); + try { Coordinate coordinate = new Coordinate( latitude, @@ -367,7 +346,6 @@ public class BackgroundLocalizationService extends Service { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribeWith(new DisposableCompletableObserver() { - @Override public void onComplete() { Log.e(TAG, "CoordinateSuccess"); @@ -375,9 +353,7 @@ public class BackgroundLocalizationService extends Service { @Override public void onError(Throwable e) { - - Log.e(TAG,"onErr" + valueOf(e)); - + Log.e(TAG, "onErr" + valueOf(e)); } })); } catch (IllegalArgumentException e) { diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedCoordinatesService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedCoordinatesService.java new file mode 100644 index 0000000..0ea2b7b --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedCoordinatesService.java @@ -0,0 +1,24 @@ +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.HTTP; +import retrofit2.http.POST; +import retrofit2.http.Path; + +public interface PredefinedCoordinatesService { + @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); + + @HTTP(method = "DELETE", path = "api/users/predefined/coordinate/{tutorId}", hasBody = true) + Single> deleteUserPredefinedCoord(@Path("tutorId") String tutorId, @Body String uuid); +} 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 index 5af0c22..2a3e8cf 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedStatusesService.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/PredefinedStatusesService.java @@ -5,25 +5,27 @@ import io.reactivex.Single; import retrofit2.http.Body; import retrofit2.http.DELETE; import retrofit2.http.GET; +import retrofit2.http.HTTP; import retrofit2.http.POST; import retrofit2.http.Path; -public interface PredefinedStatusesService { +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}") +// @DELETE("api/users/predefined/status/{tutorId}") + @HTTP(method = "DELETE", path = "api/users/predefined/status/{tutorId}", hasBody = true) Single> deleteUserPredefinedStatus(@Path("tutorId") String tutorId, @Body String status); - @GET("api/users/predefined/coordinate/{tutorId}") +/* @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); + 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 75671ed..f4092b4 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 @@ -10,14 +10,17 @@ import java.util.List; import io.reactivex.Completable; import io.reactivex.Observable; +import io.reactivex.ObservableEmitter; import io.reactivex.Single; import retrofit2.Response; import retrofit2.http.Body; import retrofit2.http.DELETE; import retrofit2.http.GET; +import retrofit2.http.HTTP; import retrofit2.http.POST; import retrofit2.http.PUT; import retrofit2.http.Path; +import retrofit2.http.Query; public interface UserService { @@ -30,6 +33,18 @@ public interface UserService { @GET("api/users/tutors") Single > getAllTutors(); + @GET("api/users/tutors/online") + Single > getAllOnlineTutors(); + + @GET("api/users/tutors/active") + Single > getAllActiveTutors(); + + @GET("api/users/tutors/offline") + Single > getAllOfflineTutors(); + + @GET("api/users/tutors/search") + Single > searchUser(@Query(value = "searchString", encoded = true) String searchString); + @POST("api/users") Completable createUser(@Body User user); @@ -61,26 +76,28 @@ public interface UserService { Completable setUserInActive(@Path("userID") String userID); @GET("api/users/blacklist/{tutorID}") - Single> getTutorBlacklistedByID(@Path("tutorID") String tutorID); + Single > getTutorBlacklistedByID(@Path("tutorID") String tutorID); @PUT("api/users/blacklist/{tutorID}") Completable setTutorBlacklist(@Path("tutorID") String tutorID, @Body IsUsingListBool isUsing); @POST("api/users/blacklist/{tutorID}") - Completable addStudentToBlacklist(@Path("tutorID") String tutorID, @Body StudentIdModel student); + Observable addStudentToBlacklist(@Path("tutorID") String tutorID, @Body StudentIdModel student); - @DELETE("api/users/blacklist/{tutorID}") +// @DELETE("api/users/blacklist/{tutorID}") + @HTTP(method = "DELETE", path = "api/users/blacklist/{tutorID}", hasBody = true) Completable removeStudentFromBlacklist(@Path("tutorID") String tutorID, @Body StudentIdModel student); @GET("api/users/whitelist/{tutorID}") - Single> getTutorwhitelistedByID(@Path("tutorID") String tutorID); + Single> getTutorWhitelistedByID(@Path("tutorID") String tutorID); @PUT("api/users/whitelist/{tutorID}") Completable setTutorWhitelist(@Path("tutorID") String tutorID, @Body IsUsingListBool isUsing); @POST("api/users/whitelist/{tutorID}") - Completable addStudentTowhitelist(@Path("tutorID") String tutorID, @Body StudentIdModel student); + Observable addStudentToWhitelist(@Path("tutorID") String tutorID, @Body StudentIdModel student); - @DELETE("api/users/whitelist/{tutorID}") +// @DELETE("api/users/whitelist/{tutorID}") + @HTTP(method = "DELETE", path = "api/users/whitelist/{tutorID}", hasBody = true) Completable removeStudentFromWhitelist(@Path("tutorID") String tutorID, @Body StudentIdModel student); } diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java index 48fd35f..b6c0dab 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/Const.java @@ -7,8 +7,9 @@ import java.util.List; public class Const { public final static String BASE_URL = "https://s416084.projektstudencki.pl/master/"; + public final static Integer mapRefreshInterval = 6000; public final static Integer onlineBackgroundLocationInterval = 7000; - public final static Integer offlineBackgroundLocationInterval = 36000; + public final static Integer offlineBackgroundLocationInterval = 360000; public final static Integer defaultMapZoom = 17; public final static Integer searchMapZoom = 13; public final static Double presenceLatitude = 52.466365; 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 5d45d85..2ae7c57 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 @@ -60,6 +60,16 @@ public class PrefUtils { return getSharedPreferences(context).getBoolean("key_status_enabled", false); } + public static void enableStatus(Context context){ + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("key_status_enabled", true); + editor.apply(); + } + public static void disableStatus(Context context) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("key_status_enabled", false); + editor.apply(); + } public static String getUserStatus(Context context) { return getSharedPreferences(context).getString("status_entry", "Dostępny"); @@ -94,6 +104,11 @@ public class PrefUtils { public static boolean isEnableSharingLocalization(Context context) { return getSharedPreferences(context).getBoolean("key_sharing_enabled", false); } + public static void disableSharing(Context context){ + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("key_sharing_enabled", false); + editor.apply(); + } public static void storeEnableSharingLocalization(Context context, Boolean isChecked) { SharedPreferences.Editor editor = getSharedPreferences(context).edit(); @@ -197,4 +212,35 @@ public class PrefUtils { return getSharedPreferences(context).getString("current_manual_location_name", null); } + public static void putShowOnlyOnlineUsers(Context context, Boolean flag) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("show_only_online_users_in_list", flag); + editor.apply(); + } + + public static Boolean getShowOnlyOnlineUsers(Context context) { + return getSharedPreferences(context).getBoolean("show_only_online_users_in_list", true); + } + + public static void useBlacklist(Context context, Boolean flag) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("blacklisting", flag); + editor.putBoolean("whitelisting", false); + editor.apply(); + } + + public static void useWhitelist(Context context, Boolean flag) { + SharedPreferences.Editor editor = getSharedPreferences(context).edit(); + editor.putBoolean("whitelisting", flag); + editor.putBoolean("blacklisting", false); + editor.apply(); + } + + public static Boolean isBlackListing(Context context) { + return getSharedPreferences(context).getBoolean("blacklisting", false); + } + public static Boolean isWhiteListing(Context context) { + return getSharedPreferences(context).getBoolean("whitelisting", false); + } + } \ No newline at end of file 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 index 5fdf137..3814e03 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/RightButtonPreference.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/RightButtonPreference.java @@ -2,6 +2,8 @@ package com.uam.wmi.findmytutor.utils; import android.content.Context; import android.preference.Preference; import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -9,31 +11,40 @@ import com.uam.wmi.findmytutor.R; public class RightButtonPreference extends Preference { + private Button prefButton; + private String buttonText; + public RightButtonPreference(Context context, AttributeSet attrs) { super(context, attrs); setWidgetLayoutResource(R.layout.preference_button_widget); + for (int i=0;i { + 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 index 33d4aee..5d0d5b4 100644 --- a/app/src/main/java/com/uam/wmi/findmytutor/utils/RxSearchObservable.java +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/RxSearchObservable.java @@ -21,6 +21,7 @@ public class RxSearchObservable { @Override public boolean onQueryTextSubmit(String s) { subject.onNext(s); + searchView.clearFocus(); return false; } @@ -31,6 +32,8 @@ public class RxSearchObservable { } + + }); diff --git a/app/src/main/java/com/uam/wmi/findmytutor/utils/WrapContentLinearLayoutManager.java b/app/src/main/java/com/uam/wmi/findmytutor/utils/WrapContentLinearLayoutManager.java new file mode 100644 index 0000000..e289bda --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/utils/WrapContentLinearLayoutManager.java @@ -0,0 +1,22 @@ +package com.uam.wmi.findmytutor.utils; + +import android.content.Context; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.util.Log; + +public class WrapContentLinearLayoutManager extends LinearLayoutManager { + public WrapContentLinearLayoutManager(Context context) { + super(context); + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + try { + super.onLayoutChildren(recycler, state); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/res/drawable/ic_add_person.xml b/app/src/main/res/drawable/ic_add_person.xml new file mode 100644 index 0000000..cc6dd3f --- /dev/null +++ b/app/src/main/res/drawable/ic_add_person.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/trip_orgin.xml b/app/src/main/res/drawable/trip_orgin.xml new file mode 100644 index 0000000..110d9dc --- /dev/null +++ b/app/src/main/res/drawable/trip_orgin.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_black_list.xml b/app/src/main/res/layout/activity_black_list.xml new file mode 100644 index 0000000..b4c9188 --- /dev/null +++ b/app/src/main/res/layout/activity_black_list.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_white_list.xml b/app/src/main/res/layout/activity_white_list.xml new file mode 100644 index 0000000..7c196c5 --- /dev/null +++ b/app/src/main/res/layout/activity_white_list.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/black_list_fab_modal.xml b/app/src/main/res/layout/black_list_fab_modal.xml new file mode 100644 index 0000000..5d49f4f --- /dev/null +++ b/app/src/main/res/layout/black_list_fab_modal.xml @@ -0,0 +1,42 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/black_list_row.xml b/app/src/main/res/layout/black_list_row.xml new file mode 100644 index 0000000..ded676c --- /dev/null +++ b/app/src/main/res/layout/black_list_row.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/content_black_list.xml b/app/src/main/res/layout/content_black_list.xml new file mode 100644 index 0000000..e7cc148 --- /dev/null +++ b/app/src/main/res/layout/content_black_list.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/content_tutor_tab.xml b/app/src/main/res/layout/content_tutor_tab.xml index 3862c1f..f22e5e7 100644 --- a/app/src/main/res/layout/content_tutor_tab.xml +++ b/app/src/main/res/layout/content_tutor_tab.xml @@ -7,8 +7,6 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + + + + + + + + + + + + diff --git a/app/src/main/res/layout/home_layout.xml b/app/src/main/res/layout/home_layout.xml new file mode 100644 index 0000000..d26e4eb --- /dev/null +++ b/app/src/main/res/layout/home_layout.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/info_popup_blacklist.xml b/app/src/main/res/layout/info_popup_blacklist.xml new file mode 100644 index 0000000..d014fd3 --- /dev/null +++ b/app/src/main/res/layout/info_popup_blacklist.xml @@ -0,0 +1,39 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/info_popup_userlist.xml b/app/src/main/res/layout/info_popup_userlist.xml index afd1c17..19761d7 100644 --- a/app/src/main/res/layout/info_popup_userlist.xml +++ b/app/src/main/res/layout/info_popup_userlist.xml @@ -72,4 +72,6 @@ android:text="@string/info_icon_userlist_summary" android:textColor="@color/half_black"/> + + \ No newline at end of file diff --git a/app/src/main/res/layout/info_popup_whitelist.xml b/app/src/main/res/layout/info_popup_whitelist.xml new file mode 100644 index 0000000..b61cb8f --- /dev/null +++ b/app/src/main/res/layout/info_popup_whitelist.xml @@ -0,0 +1,39 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/location_modal.xml b/app/src/main/res/layout/location_modal.xml index 51949bd..a4af220 100644 --- a/app/src/main/res/layout/location_modal.xml +++ b/app/src/main/res/layout/location_modal.xml @@ -24,14 +24,14 @@ android:textStyle="normal" /> diff --git a/app/src/main/res/layout/tutors_list_tabs.xml b/app/src/main/res/layout/tutors_list_tabs.xml new file mode 100644 index 0000000..c09a3b2 --- /dev/null +++ b/app/src/main/res/layout/tutors_list_tabs.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/user_list_modal.xml b/app/src/main/res/layout/user_list_modal.xml index c95e45e..b92f8eb 100644 --- a/app/src/main/res/layout/user_list_modal.xml +++ b/app/src/main/res/layout/user_list_modal.xml @@ -27,17 +27,19 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - + + @@ -158,25 +160,25 @@ + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:orientation="horizontal" + android:paddingLeft="20dp"> - - - + + + diff --git a/app/src/main/res/layout/users_list.xml b/app/src/main/res/layout/users_list.xml index daed3cd..6618359 100644 --- a/app/src/main/res/layout/users_list.xml +++ b/app/src/main/res/layout/users_list.xml @@ -10,6 +10,7 @@ + diff --git a/app/src/main/res/layout/users_list_main.xml b/app/src/main/res/layout/users_list_main.xml index 7e767f0..651b942 100644 --- a/app/src/main/res/layout/users_list_main.xml +++ b/app/src/main/res/layout/users_list_main.xml @@ -12,6 +12,7 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/white_list_fab_modal.xml b/app/src/main/res/layout/white_list_fab_modal.xml new file mode 100644 index 0000000..f0380e6 --- /dev/null +++ b/app/src/main/res/layout/white_list_fab_modal.xml @@ -0,0 +1,42 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/white_list_row.xml b/app/src/main/res/layout/white_list_row.xml new file mode 100644 index 0000000..35dad88 --- /dev/null +++ b/app/src/main/res/layout/white_list_row.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index c6e0307..90a85ef 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -1,14 +1,14 @@ - + android:title="@string/navigation_item_blacklist" /> + + diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 96cd955..985b8dd 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -6,6 +6,8 @@ android:id="@+id/action_search" android:icon="@drawable/ic_menu_search" app:showAsAction="always" + android:focusable="true" + android:focusableInTouchMode="true" app:actionViewClass="android.support.v7.widget.SearchView" android:title="@string/search"/> + + diff --git a/app/src/main/res/menu/users_list_menu.xml b/app/src/main/res/menu/users_list_menu.xml new file mode 100644 index 0000000..6e6a220 --- /dev/null +++ b/app/src/main/res/menu/users_list_menu.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index ac53573..ba3c288 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -132,7 +132,7 @@ Bounds OFF Find My Tutor - feedback Find My Tutor - zgłoszenie błędu - Proszę opisz swoje spostrzeżnia. + Opisz proszę swoje spostrzeżenia. Wyślij anonimowo Manualna Wybierz z mapy @@ -205,12 +205,16 @@ Dodatkowo, do Twojej lokalizacji możesz dodać status opisowy (będzie on widoczny dla użytkowników po kliknięciu w marker). Zarówno manualne lokalizacje jak i statusy możesz dodać do listy, z której możesz potem je wybrać w wygodny sposób. - W tym panelu znajduje się listę profesorów. + W tym panelu znajduje się lista profesorów. Ich status symbolizowany jest przez kolorowe kropki: - użytkownik jest obecnie online - użytkownik jest obecnie offline - użytkownik jest nieaktywny (nie udostępnił żadnych danych o lokalizacji od conajmniej tygodnia) + Dodaj + Index użytkownika + Dodaj użytkownika do Blacklsi + Po kliknięciu w imię i nazwisko, wyświetli się karta zawierająca dokładne informacje o profesorze. @@ -239,9 +243,39 @@ Nie Aby skorzystać z tej funkcji musisz pozwolić na udostępnianie lokalizacji. Zgadzasz sie? Udostępnianie + Zarządzaj zapisanymi + Zarządzaj zapisanymi + + Czarna lista + Pole nie może być puste + Użytkownik dodany + Lista jest pusta + WŁĄCZONA + WYŁĄCZONA + Czarna lista Pobierz dane z WMI Dane zostały zaktualizwane! + + Brak aktywnych użytkowników. + Brak użytkowników offline. + Czarna lista + Biała lista + Biała lista + Dodaj użytkownika do białej listy + Nie ma takiego użytkownika + Tylko aktywni użytkownicy + Błąd sieci! + Brak wyników! + Nadaj nazwę tej lokalizacji. + Dostępny + Niedostępny + Nieaktywny + POKAŻ NA MAPIE + + + Użytkownik został dodany! + Użytkownik usunięty! + - diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index 5de90b6..2f967d2 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -55,23 +55,15 @@ @string/description_available - @string/description_busy - @string/description_consultation 0 - 1 - 2 @string/assembly_c - @string/assembly_a - @string/passage_d 0 - 1 - 2 @string/lang_eng @@ -81,4 +73,19 @@ 0 1 + + + + Item 1 + Item 2 + Item 3 + Item 4 + + + + 0 + 1 + 2 + 3 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index bcc07bd..5bc97f5 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -19,4 +19,6 @@ 13sp 12dp 10dp + 180dp + 16dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 32686d4..52f5d89 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,7 +32,8 @@ Settings - Notes + Blacklist + Whitelist Password Sign in or register Sign out @@ -53,12 +54,10 @@ - Sharing - Sharing Location sharing Status settings @@ -69,6 +68,9 @@ Exact Manual Choose from map + Manage saved + Manage saved + Location level key_location_level @@ -86,14 +88,10 @@ Add custom status - Descrition + Description Save Edit your note. It will be shown in the users list. - - key_description - - Manual location Choose manual location Add custom location @@ -254,7 +252,7 @@ App issues reporting - On the map there are markers which represents tutors sharing their location right now. + On the map there are markers which represent tutors sharing their location right now. After clicking on a marker, you can check who is sharing it and the descriptive status (if the tutor have set one). In the app there are 3 possible types of localization, represented by various colors. exact localization (from mobile GPS) @@ -288,7 +286,7 @@ Each level, except from manual, will be automatically turned on when entering, and turn off when leaving the faculty. You only need to make sure that sharing is on, and the localization will be shared only when on the faculty. Sharing can be turned off at any time with the switch. Additionally, you can add descriptive status to your localization (visible for users after clicking on a marker). - Both manual localizations and statuses can be added to a list, and then used them in a convenient way. + Both manual localizations and statuses can be added to a list, and then used in a convenient way. This panel contains the list of tutors. @@ -297,10 +295,18 @@ - user is currently offline - user is inactive (didn’t share any localization data since 7 days) - After clicking on a name, the tutor tab will pop up, containing details about selected tutor. + BlackList + Whitelist + Add user to Whitelist + + After clicking on a name, the tutor tab will pop up, containing details about selected tutor.\n\nYou can search for any tutor on the map by entering his name and surname in the search field.\n\nBy default, only active users are shown. You can change that in menu (three dots icon).\n\nYou can also search for a tutor directly, by entering name and surname of person that you look for. + + + User index + Add user to blacklist + Add Yes - App issues reporting @@ -319,7 +325,31 @@ In order to use this function, you have to enable localization sharing. May I do it for you? Sharing The user hasn\'t defined a status. + Field can not be empty + User added + The list is empty + Map + ON + OFF Scrap! - Thank you for scraping your tab! + Data updated! + + + Currently, there are no\nactive users. + Currently, there are no\noffline users. + Only online users + No such a user + + Network Error ! + Search response is empty! + Insert a name for this localization. + Online + Offline + Inactive + SHOW ON MAP + + + User has been added! + User removed! diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ad4f49e..703fa27 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -22,4 +22,5 @@ @drawable/fab_label_background @color/mapboxWhite + diff --git a/app/src/main/res/layout/pref_sharing.xml b/app/src/main/res/xml/pref_sharing.xml similarity index 73% rename from app/src/main/res/layout/pref_sharing.xml rename to app/src/main/res/xml/pref_sharing.xml index 3e952df..4a6cee4 100644 --- a/app/src/main/res/layout/pref_sharing.xml +++ b/app/src/main/res/xml/pref_sharing.xml @@ -1,8 +1,8 @@ @@ -16,7 +16,7 @@ android:persistent="true" android:title="@string/title_sharing"/> + @@ -41,9 +48,11 @@ android:persistent="true" android:title="@string/status_switch_title"/> + + - - - \ No newline at end of file