diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 646dfea..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index ab8ae7e..87b98e5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -57,6 +57,7 @@ dependencies {
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.auth0.android:jwtdecode:1.1.1'
implementation 'com.annimon:stream:1.2.1'
+ implementation 'com.google.android.gms:play-services-location:16.0.0'
// FloatingBarMenu
implementation 'com.getbase:floatingactionbutton:1.10.1'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5b1bc92..bb4aa0c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -50,6 +50,10 @@
android:name=".activity.SettingsActivity"
android:label="@string/title_activity_settings" />
+
+
{
try {
fetchTopCoords();
@@ -131,8 +128,6 @@ public class MapActivity extends BaseActivity
//start background task
handleBackgroundTaskLifeCycle();
-
- currentLanguage = getIntent().getStringExtra(currentLang);
}
@@ -142,19 +137,68 @@ public class MapActivity extends BaseActivity
mStatusChecker.run();
enableLocationPlugin();
-// // TODO what should happend on click?
-// mapboxMap.setOnMarkerClickListener(marker1 -> {
-//
-// // Show a toast with the title of the selected marker
-//// Toast.makeText(MapActivity.this, marker.getTitle(), Toast.LENGTH_SHORT).show();
-// return true;
-// });
+ mapboxMap.setOnMarkerClickListener(marker -> {
+ createMarkerModal(marker.getTitle());
+ return true;
+ });
setOnMapLongClickListener();
// addStaticLayer();
}
+ private void createMarkerModal(String userId) {
+ disposable.add(userService.getUserById(userId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::createMarkerModal, this::handleError));
+ }
+
+ private void createMarkerModal(User user) {
+ String cordStatus = coordsMap.get(user.getId()).getLabel();
+
+ LayoutInflater layoutInflaterAndroid = LayoutInflater.from(getApplicationContext());
+ @SuppressLint("InflateParams") View view = layoutInflaterAndroid.inflate(R.layout.marker_modal, null);
+
+ AlertDialog.Builder alertDialogBuilderUserInput = new android.support.v7.app.AlertDialog.Builder(this);
+ alertDialogBuilderUserInput.setView(view);
+
+ alertDialogBuilderUserInput.setNegativeButton(R.string.cancel, (dialog, id) -> {
+ // User cancelled the dialog
+ });
+
+ TextView userName = view.findViewById(R.id.userName);
+ TextView status = view.findViewById(R.id.label);
+
+ userName.setText(String.format("%s %s", user.getFirstName(), user.getLastName()));
+ status.setText(String.format("%s ", cordStatus));
+
+ final AlertDialog alertDialog = alertDialogBuilderUserInput.create();
+
+ alertDialog.show();
+ }
+
+
+ private void handleError(Throwable error) {
+ showError(error);
+ }
+
+
+ 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(MapActivity.this, message, Toast.LENGTH_SHORT).show();
+ }
+
+
private void setOnMapLongClickListener() {
final boolean[] cancel = {false};
@@ -193,7 +237,8 @@ public class MapActivity extends BaseActivity
latLng.getLongitude(),
latLng.getAltitude(),
PrefUtils.getUserFirstName(getApplicationContext()) + " " + PrefUtils.getUserLastName(getApplicationContext()),
- PrefUtils.getUserId(getApplicationContext())
+ PrefUtils.getUserId(getApplicationContext()),
+ PrefUtils.getLocationLevel(getApplicationContext())
);
disposable.add(
@@ -330,6 +375,7 @@ public class MapActivity extends BaseActivity
for (Coordinate element : coordsList) {
String id = element.getUserId();
+ String newLabel = element.getLabel();
Coordinate coordinate = coordsMap.get(id);
Log.e(tag, "hashMapSize: " + coordsMap.size());
@@ -346,6 +392,7 @@ public class MapActivity extends BaseActivity
if (!statement) {
Log.e(tag, "replace and animate");
Marker marker = markerHash.get(id);
+
LatLng toDestination = new LatLng(element.getLatitude(), element.getLongitude());
// TODO fix flickiering markers
ValueAnimator markerAnimator = ObjectAnimator.ofObject(marker, "position",
@@ -356,23 +403,25 @@ public class MapActivity extends BaseActivity
markerAnimator.setInterpolator(new LinearInterpolator());
markerAnimator.start();
-
// chba niepotrzbene
mapboxMap.getMarkerViewManager().update();
-
coordsMap.put(id, element);
marker.setPosition(toDestination);
}
} else {
+
Log.e(tag, "Marker Added: " + id);
+
coordsMap.put(id, element);
Marker marker = mapboxMap.addMarker(new MarkerOptions()
- .title(element.getLabel())
+ .title(id)
.position(new LatLng(element.getLatitude(), element.getLongitude())));
markerHash.put(id, marker);
}
+
+ coordsMap.get(id).setLabel(newLabel);
}
// For next fetch
@@ -510,7 +559,7 @@ public class MapActivity extends BaseActivity
permissionsManager = new PermissionsManager(this);
permissionsManager.requestLocationPermissions(this);
- permissionsManager.onRequestPermissionsResult(0, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, new int[] {0});
+ permissionsManager.onRequestPermissionsResult(0, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new int[]{0});
}
}
diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/SettingsActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/SettingsActivity.java
index a188c9a..1758057 100644
--- a/app/src/main/java/com/uam/wmi/findmytutor/activity/SettingsActivity.java
+++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/SettingsActivity.java
@@ -52,6 +52,13 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
addPreferencesFromResource(R.layout.pref_main);
Preference languagesList = findPreference(getResources().getString(R.string.key_language));
+ languagesList.setDefaultValue(0);
+
+ if(PrefUtils.getLocale(getActivity()).equals("pl")){
+ languagesList.setDefaultValue(1);
+ }
+
+
languagesList.setOnPreferenceChangeListener((preference, newValue) -> {
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 e671a31..f8adab8 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
@@ -14,13 +14,17 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Toast;
import com.uam.wmi.findmytutor.R;
import com.uam.wmi.findmytutor.service.BackgroundLocalizationService;
import com.uam.wmi.findmytutor.utils.PrefUtils;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -28,25 +32,45 @@ import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext;
public class SharingFragment extends PreferenceFragment {
+ private HashMap locationLevelMapping;
+// private HashMap statusMapping;
@SuppressLint("ResourceType")
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ locationLevelMapping = new HashMap();
+ locationLevelMapping.put(0,"presence");
+ locationLevelMapping.put(1,"approximated");
+ locationLevelMapping.put(2,"exact");
+
addPreferencesFromResource(R.layout.pref_sharing);
Preference manualStatus = findPreference("key_manual_status");
Preference locationSharing = findPreference("key_sharing_enabled");
+ Preference locationMode = findPreference("key_location_level");
+ Preference statusList = findPreference("key_status_value");
+
manualStatus.setOnPreferenceChangeListener((preference, newValue) -> {
ListPreference lp = (ListPreference) findPreference("key_status_value");
updateListPreference(lp, newValue, "manual_statuses");
return true;
});
+ locationMode.setOnPreferenceChangeListener((preference, newValue) -> {
+ ListPreference lp = (ListPreference) preference;
+ PrefUtils.storeLocationMode(getApplicationContext(),locationLevelMapping.get(Integer.parseInt((String) newValue)));
+ return true;
+ });
+ statusList.setOnPreferenceChangeListener((preference, newValue) -> {
+ ListPreference lp = (ListPreference) preference;
+ CharSequence [] entries = lp.getEntries();
+ PrefUtils.storeStatus(getApplicationContext(),(String) entries[Integer.parseInt((String) newValue)]);
+ return true;
+ });
- locationSharing.setOnPreferenceChangeListener((buttonView, isChecked) -> {
- PrefUtils.storeEnableSharingLocalization(getApplicationContext(), (Boolean) isChecked);
+ locationSharing.setOnPreferenceChangeListener((buttonView, newValue) -> {
+ PrefUtils.storeEnableSharingLocalization(getApplicationContext(), (Boolean) newValue);
((MapActivity)getActivity()).handleBackgroundTaskLifeCycle();
-
return true;
});
}
@@ -64,15 +88,22 @@ public class SharingFragment extends PreferenceFragment {
return view;
}
+ public String getListPreferenceValue(String key){
+ ListPreference lp = (ListPreference) findPreference(key);
+ return (String)lp.getEntry();
+
+ }
protected void updateListPreference(ListPreference lp,Object newValue,String storageKey){
CharSequence [] entries = lp.getEntries();
Set defaultEntries = new HashSet(Arrays.asList(entries));
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
+
Set manualStatusSet = sharedPref.getStringSet(storageKey,defaultEntries);
manualStatusSet.add((String) newValue);
String [] manualStatusArr = manualStatusSet.toArray(new String[0]);
Arrays.sort(manualStatusArr);
setListPreferenceData(lp.getKey(),manualStatusArr);
+
SharedPreferences.Editor editor = sharedPref.edit();
editor.putStringSet(storageKey,manualStatusSet);
editor.apply();
@@ -84,7 +115,7 @@ public class SharingFragment extends PreferenceFragment {
CharSequence[] entryValues = new CharSequence [entries.length];
for (int i = 0; i < entries.length; i++){
- entryValues[i] = Integer.toString(i+1);
+ entryValues[i] = Integer.toString(i);
}
lp.setDefaultValue("1");
diff --git a/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java b/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java
index 430311b..d0fd9dc 100644
--- a/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java
+++ b/app/src/main/java/com/uam/wmi/findmytutor/activity/StartupActivity.java
@@ -46,8 +46,4 @@ public class StartupActivity extends AppCompatActivity {
finish();
}
-
-
-
-
}
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 ecc460a..82888b2 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
@@ -105,7 +105,6 @@ public class UsersListFragment extends Fragment {
}
}));
-
}
public void searchUser(String textToSearch) {
@@ -217,11 +216,13 @@ public class UsersListFragment extends Fragment {
}
private void showError(Throwable e) {
- String message = e.toString();
+ String message;
if (e instanceof HttpException) {
ResponseBody responseBody = ((HttpException) e).response().errorBody();
message = RestApiHelper.getErrorMessage(responseBody);
+ }else{
+ message = "Network Error !";
}
Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_LONG)
diff --git a/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java b/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java
index 2280dd4..5c23701 100644
--- a/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java
+++ b/app/src/main/java/com/uam/wmi/findmytutor/model/Coordinate.java
@@ -44,7 +44,7 @@ public class Coordinate extends BaseResponse {
@SerializedName("label")
private String label;
- public Coordinate (Double latitude, Double longitude, Double altitude, String label, String userId) {
+ public Coordinate (Double latitude, Double longitude, Double altitude, String label, String userId, String displayMode) {
//if (!latitudeRange.contains(latitude)) throw new IllegalArgumentException("Inappropriate latitude value" + latitude);
//if (!longtitudeRange.contains(longitude)) throw new IllegalArgumentException("Inappropriate longitude value" + longitude);
@@ -53,6 +53,7 @@ public class Coordinate extends BaseResponse {
this.altitude = altitude;
this.label = label;
this.userId = userId;
+ this.displayMode = displayMode;
}
public Coordinate (Double latitude) {
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 cc20051..2b3ca3c 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
@@ -23,6 +23,9 @@ import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
+import com.google.android.gms.location.FusedLocationProviderClient;
+import com.google.android.gms.location.LocationServices;
+import com.google.android.gms.tasks.OnSuccessListener;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.uam.wmi.findmytutor.model.Coordinate;
import com.uam.wmi.findmytutor.network.ApiClient;
@@ -31,6 +34,7 @@ import com.uam.wmi.findmytutor.utils.RestApiHelper;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
@@ -58,6 +62,7 @@ public class BackgroundLocalizationService extends Service {
private Handler mHandler = new Handler();
private HandlerThread mHandlerThread = null;
private Runnable mStatusChecker;
+ private FusedLocationProviderClient mFusedLocationClient;
public BackgroundLocalizationService() {
providers.add(LocationManager.GPS_PROVIDER);
@@ -107,6 +112,9 @@ public class BackgroundLocalizationService extends Service {
startForeground(1001, notification);
}
+ mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
+
+
initializeLocationManager();
Integer providerIndex = 0;
@@ -194,8 +202,21 @@ public class BackgroundLocalizationService extends Service {
Log.e("Best localization:", String.valueOf(bestLocation));
- if (bestLocation != null)
+ /* if (bestLocation != null)
fn_update(bestLocation);
+*/
+
+ mFusedLocationClient.getLastLocation().addOnSuccessListener(
+ new OnSuccessListener() {
+ @Override
+ public void onSuccess(Location location) {
+ if (location != null) {
+ mLastLocation = location;
+ fn_update(location);
+ }
+ }
+
+ });
}
private void fn_update(Location location) {
@@ -285,8 +306,9 @@ public class BackgroundLocalizationService extends Service {
latitude,
longitude,
altitude,
- PrefUtils.getUserFirstName(getApplicationContext()) + " " + PrefUtils.getUserLastName(getApplicationContext()),
- PrefUtils.getUserId(getApplicationContext())
+ PrefUtils.getUserStatus(getApplicationContext()),
+ PrefUtils.getUserId(getApplicationContext()),
+ PrefUtils.getLocationLevel(getApplicationContext())
);
disposable.add(
@@ -320,7 +342,5 @@ public class BackgroundLocalizationService extends Service {
return null;
}
-
}
-
}
\ No newline at end of file
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 e8f415f..aca16a4 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
@@ -40,7 +40,7 @@ public interface UserService {
Single getPagedStudents(@Path("pageNum") String pageNum);
@GET("api/users/{id}")
- Single getUserByID(@Path("id") String userID);
+ Single getUserById(@Path("id") String userID);
@PUT("api/users/{id}")
Completable updateUserByID(@Path("id") String userID, @Body User user);
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 39510c0..0982f5a 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
@@ -2,8 +2,10 @@ package com.uam.wmi.findmytutor.utils;
import android.content.Context;
import android.content.SharedPreferences;
+import android.preference.ListPreference;
+import android.preference.PreferenceFragment;
import android.util.Log;
-
+import com.uam.wmi.findmytutor.activity.SharingFragment;
import com.auth0.android.jwt.Claim;
import com.auth0.android.jwt.JWT;
@@ -15,10 +17,9 @@ public class PrefUtils {
}
public static SharedPreferences getSharedPreferences(Context context) {
- return context.getSharedPreferences("APP_PREF", Context.MODE_PRIVATE);
+ return context.getSharedPreferences("com.uam.wmi.findmytutor_preferences", Context.MODE_PRIVATE);
}
-
public static void getAllKeys(Context context){
Map keys = getSharedPreferences(context).getAll();
@@ -33,9 +34,6 @@ public class PrefUtils {
editor.clear().apply();
}
-
-
-
public static void storeApiKey(Context context, String apiKey) {
SharedPreferences.Editor editor = getSharedPreferences(context).edit();
editor.putString("API_KEY", apiKey);
@@ -56,9 +54,13 @@ public class PrefUtils {
return getSharedPreferences(context).getString("USER_ID", null);
}
-
public static String getUserStatus(Context context) {
- return getSharedPreferences(context).getString("USER_STATUS", "Android");
+ return getSharedPreferences(context).getString("status_entry", "Available");
+ }
+ public static void storeStatus(Context context, String status){
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.putString("status_entry", status);
+ editor.apply();
}
public static void storeIsTutor(Context applicationContext, boolean isTutor) {
@@ -82,12 +84,20 @@ public class PrefUtils {
}
public static boolean isEnableSharingLocalization(Context context) {
- return getSharedPreferences(context).getBoolean("IS_ENABLE_SHARING_LOCALIZATION", false);
+ return getSharedPreferences(context).getBoolean("key_sharing_enabled", false);
}
public static void storeEnableSharingLocalization(Context context,Boolean isChecked) {
SharedPreferences.Editor editor = getSharedPreferences(context).edit();
- editor.putBoolean("IS_ENABLE_SHARING_LOCALIZATION", isChecked);
+ editor.putBoolean("key_sharing_enabled", isChecked);
+ editor.apply();
+ }
+ public static String getLocationLevel(Context context){
+ return getSharedPreferences(context).getString("location_mode", "exact");
+ }
+ public static void storeLocationMode(Context context, String mode){
+ SharedPreferences.Editor editor = getSharedPreferences(context).edit();
+ editor.putString("location_mode", mode);
editor.apply();
}
@@ -136,5 +146,4 @@ public class PrefUtils {
editor.putBoolean("BACKGROUND_SERVICE_STATUS", status);
editor.apply();
}
-
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/custom_marker.png b/app/src/main/res/drawable-v21/custom_marker.png
new file mode 100644
index 0000000..1df09fd
Binary files /dev/null and b/app/src/main/res/drawable-v21/custom_marker.png differ
diff --git a/app/src/main/res/drawable-v24/custom_marker.png b/app/src/main/res/drawable-v24/custom_marker.png
new file mode 100644
index 0000000..1df09fd
Binary files /dev/null and b/app/src/main/res/drawable-v24/custom_marker.png differ
diff --git a/app/src/main/res/drawable/custom_marker.png b/app/src/main/res/drawable/custom_marker.png
new file mode 100644
index 0000000..1df09fd
Binary files /dev/null and b/app/src/main/res/drawable/custom_marker.png differ
diff --git a/app/src/main/res/drawable/ic_cancel.xml b/app/src/main/res/drawable/ic_cancel.xml
new file mode 100644
index 0000000..a8b409b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cancel.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launch.xml b/app/src/main/res/drawable/ic_launch.xml
new file mode 100644
index 0000000..a8b409b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launch.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/marker_modal.xml b/app/src/main/res/layout/marker_modal.xml
new file mode 100644
index 0000000..99643d1
--- /dev/null
+++ b/app/src/main/res/layout/marker_modal.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/pref_sharing.xml b/app/src/main/res/layout/pref_sharing.xml
index 4a75c7b..95817ac 100644
--- a/app/src/main/res/layout/pref_sharing.xml
+++ b/app/src/main/res/layout/pref_sharing.xml
@@ -5,6 +5,7 @@
tools:ignore="MissingDefaultResource"
android:layout_width="match_parent"
android:layout_height="match_parent">
+
-
+
+
+
-
+
+
+
-
-
-
+
\ 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 c8102e5..60d4559 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -123,6 +123,11 @@
Zaloguj!
Niepoprawny format loginu.
Lista użytkowników
+ Wybierz lokalizacje
+ Nie dodano uprawnień do lokalizacji.
+ Ta aplikacja potrzebuje uprawnień do lokalizacji.
+ Ustawienia statusu
+ Ręczny wybór lokalizacji
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index eb46a55..e4e9ea1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -47,6 +47,8 @@
Sharing
Location sharing
+ Status settings
+ Manual location override
Sharing level
Only presence
Approximated
@@ -166,9 +168,9 @@
Main2Activity
- Hotels
- Parks
- Attractions
+ TODO
+ THIS
+ TOO
Select a location
This app needs location permissions in order to show its functionality.
You didn\'t grant location permissions.
@@ -187,5 +189,10 @@
Log in
Users list
Invalid login format.
+ Locale utils
+ Permission denied
+ permission should be granted
+
+