mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-19 04:53:36 +00:00
Indicate when location sharing is active
Signed-off-by: zyphlar <zyphlar@gmail.com>
This commit is contained in:
@@ -425,20 +425,61 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
|
||||
private void shareMyLocation()
|
||||
{
|
||||
final Location loc = MwmApplication.from(this).getLocationHelper().getSavedLocation();
|
||||
if (loc != null)
|
||||
// Check if location sharing is already active
|
||||
if (app.organicmaps.location.LocationSharingManager.getInstance().isSharing())
|
||||
{
|
||||
SharingUtils.shareLocation(this, loc);
|
||||
// Stop sharing
|
||||
app.organicmaps.location.LocationSharingManager.getInstance().stopSharing();
|
||||
mMapButtonsViewModel.setLocationSharingState(false);
|
||||
return;
|
||||
}
|
||||
|
||||
dismissLocationErrorDialog();
|
||||
mLocationErrorDialog = new MaterialAlertDialogBuilder(MwmActivity.this, R.style.MwmTheme_AlertDialog)
|
||||
.setMessage(R.string.unknown_current_position)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setOnDismissListener(dialog -> mLocationErrorDialog = null)
|
||||
.show();
|
||||
final Location loc = MwmApplication.from(this).getLocationHelper().getSavedLocation();
|
||||
if (loc == null)
|
||||
{
|
||||
dismissLocationErrorDialog();
|
||||
mLocationErrorDialog = new MaterialAlertDialogBuilder(MwmActivity.this, R.style.MwmTheme_AlertDialog)
|
||||
.setMessage(R.string.unknown_current_position)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setOnDismissListener(dialog -> mLocationErrorDialog = null)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Show dialog with two options: share current coordinates or start live sharing
|
||||
new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
|
||||
.setTitle(R.string.share_my_location)
|
||||
.setItems(new CharSequence[] {
|
||||
getString(R.string.share_location_coordinates),
|
||||
getString(R.string.share_location_live)
|
||||
}, (dialog, which) -> {
|
||||
if (which == 0)
|
||||
{
|
||||
// Share current coordinates
|
||||
SharingUtils.shareLocation(this, loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start live location sharing
|
||||
app.organicmaps.location.LocationSharingDialog.show(getSupportFragmentManager());
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
public void onLocationSharingStateChanged(boolean isSharing)
|
||||
{
|
||||
mMapButtonsViewModel.setLocationSharingState(isSharing);
|
||||
MapButtonsController mapButtonsController =
|
||||
(MapButtonsController) getSupportFragmentManager().findFragmentById(R.id.map_buttons);
|
||||
if (mapButtonsController != null)
|
||||
mapButtonsController.updateMenuBadge();
|
||||
|
||||
// Update share location button color in navigation menu
|
||||
if (mNavigationController != null)
|
||||
mNavigationController.refreshShareLocationColor();
|
||||
}
|
||||
|
||||
private void showDownloader(boolean openDownloaded)
|
||||
@@ -2496,7 +2537,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
|
||||
items.add(new MenuBottomSheetItem(R.string.start_track_recording, R.drawable.ic_track_recording_off, -1,
|
||||
this::onTrackRecordingOptionSelected));
|
||||
|
||||
items.add(new MenuBottomSheetItem(R.string.share_my_location, R.drawable.ic_share,
|
||||
final boolean isLocationSharingActive = app.organicmaps.location.LocationSharingManager.getInstance().isSharing();
|
||||
final int locationSharingTitleRes = isLocationSharingActive ? R.string.stop_sharing_my_location : R.string.share_my_location;
|
||||
final int locationSharingBadge = isLocationSharingActive ? -1 : 0;
|
||||
items.add(new MenuBottomSheetItem(locationSharingTitleRes, R.drawable.ic_share, locationSharingBadge,
|
||||
this::onShareLocationOptionSelected));
|
||||
|
||||
if (!BUTTON_HELP_CODE.equals(activeLeftButton))
|
||||
|
||||
@@ -147,6 +147,12 @@ public class LocationSharingDialog extends DialogFragment
|
||||
|
||||
updateUI();
|
||||
|
||||
// Notify the activity
|
||||
if (getActivity() instanceof app.organicmaps.MwmActivity)
|
||||
{
|
||||
((app.organicmaps.MwmActivity) getActivity()).onLocationSharingStateChanged(true);
|
||||
}
|
||||
|
||||
// Auto-copy URL to clipboard
|
||||
copyUrlToClipboard(shareUrl);
|
||||
}
|
||||
@@ -167,6 +173,12 @@ public class LocationSharingDialog extends DialogFragment
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
||||
updateUI();
|
||||
|
||||
// Notify the activity
|
||||
if (getActivity() instanceof app.organicmaps.MwmActivity)
|
||||
{
|
||||
((app.organicmaps.MwmActivity) getActivity()).onLocationSharingStateChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyUrl()
|
||||
|
||||
@@ -66,21 +66,19 @@ public class LocationSharingNotification
|
||||
@NonNull
|
||||
public Notification buildNotification(@NonNull PendingIntent stopIntent)
|
||||
{
|
||||
return buildNotification(stopIntent, null, null);
|
||||
return buildNotification(stopIntent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build notification with current location and routing info.
|
||||
* Build notification with copy URL action.
|
||||
* @param stopIntent PendingIntent to stop sharing
|
||||
* @param location Current location (optional)
|
||||
* @param routingInfo Navigation info (optional)
|
||||
* @param copyUrlIntent PendingIntent to copy URL (optional)
|
||||
* @return Notification object
|
||||
*/
|
||||
@NonNull
|
||||
public Notification buildNotification(
|
||||
@NonNull PendingIntent stopIntent,
|
||||
@Nullable Location location,
|
||||
@Nullable RoutingInfo routingInfo)
|
||||
@Nullable PendingIntent copyUrlIntent)
|
||||
{
|
||||
Intent notificationIntent = new Intent(mContext, MwmActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
@@ -90,7 +88,7 @@ public class LocationSharingNotification
|
||||
PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_location_sharing)
|
||||
.setSmallIcon(R.drawable.ic_share)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
@@ -101,17 +99,15 @@ public class LocationSharingNotification
|
||||
// Title
|
||||
builder.setContentTitle(mContext.getString(R.string.location_sharing_active));
|
||||
|
||||
// Content text
|
||||
String contentText = buildContentText(location, routingInfo);
|
||||
builder.setContentText(contentText);
|
||||
// No subtitle - keep it simple
|
||||
|
||||
// Big text style for more details
|
||||
if (routingInfo != null)
|
||||
// Copy URL action button (if provided)
|
||||
if (copyUrlIntent != null)
|
||||
{
|
||||
NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle()
|
||||
.bigText(contentText)
|
||||
.setSummaryText(mContext.getString(R.string.location_sharing_tap_to_view));
|
||||
builder.setStyle(bigTextStyle);
|
||||
builder.addAction(
|
||||
R.drawable.ic_share,
|
||||
mContext.getString(R.string.location_sharing_copy_url),
|
||||
copyUrlIntent);
|
||||
}
|
||||
|
||||
// Stop action button
|
||||
@@ -129,71 +125,6 @@ public class LocationSharingNotification
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String buildContentText(@Nullable Location location, @Nullable RoutingInfo routingInfo)
|
||||
{
|
||||
StringBuilder text = new StringBuilder();
|
||||
|
||||
// If navigating, show ETA and distance
|
||||
if (routingInfo != null && routingInfo.distToTarget != null)
|
||||
{
|
||||
if (routingInfo.totalTimeInSeconds > 0)
|
||||
{
|
||||
String eta = formatTime(routingInfo.totalTimeInSeconds);
|
||||
text.append(mContext.getString(R.string.location_sharing_eta, eta));
|
||||
}
|
||||
|
||||
if (routingInfo.distToTarget != null && routingInfo.distToTarget.isValid())
|
||||
{
|
||||
if (text.length() > 0)
|
||||
text.append(" • ");
|
||||
text.append(routingInfo.distToTarget.toString(mContext));
|
||||
text.append(" ").append(mContext.getString(R.string.location_sharing_remaining));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Standalone mode - show accuracy if available
|
||||
if (location != null)
|
||||
{
|
||||
text.append(mContext.getString(R.string.location_sharing_accuracy,
|
||||
formatAccuracy(location.getAccuracy())));
|
||||
}
|
||||
else
|
||||
{
|
||||
text.append(mContext.getString(R.string.location_sharing_waiting_for_location));
|
||||
}
|
||||
}
|
||||
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String formatTime(int seconds)
|
||||
{
|
||||
if (seconds < 60)
|
||||
return String.format(Locale.US, "%ds", seconds);
|
||||
|
||||
int minutes = seconds / 60;
|
||||
if (minutes < 60)
|
||||
return String.format(Locale.US, "%d min", minutes);
|
||||
|
||||
int hours = minutes / 60;
|
||||
int remainingMinutes = minutes % 60;
|
||||
return String.format(Locale.US, "%dh %dm", hours, remainingMinutes);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String formatAccuracy(float accuracyMeters)
|
||||
{
|
||||
if (accuracyMeters < 10)
|
||||
return mContext.getString(R.string.location_sharing_accuracy_high);
|
||||
else if (accuracyMeters < 50)
|
||||
return mContext.getString(R.string.location_sharing_accuracy_medium);
|
||||
else
|
||||
return mContext.getString(R.string.location_sharing_accuracy_low);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update existing notification.
|
||||
* @param notificationId Notification ID
|
||||
|
||||
@@ -44,8 +44,9 @@ public class LocationSharingService extends Service implements LocationListener
|
||||
public static final String EXTRA_SERVER_URL = "server_url";
|
||||
public static final String EXTRA_UPDATE_INTERVAL = "update_interval";
|
||||
|
||||
// Action for notification stop button
|
||||
// Actions for notification buttons
|
||||
private static final String ACTION_STOP = "app.organicmaps.ACTION_STOP_LOCATION_SHARING";
|
||||
private static final String ACTION_COPY_URL = "app.organicmaps.ACTION_COPY_LOCATION_URL";
|
||||
|
||||
@Nullable
|
||||
private String mSessionId;
|
||||
@@ -95,6 +96,21 @@ public class LocationSharingService extends Service implements LocationListener
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
// Handle copy URL action from notification
|
||||
if (ACTION_COPY_URL.equals(intent.getAction()))
|
||||
{
|
||||
Logger.i(TAG, "Copy URL action received from notification");
|
||||
String shareUrl = LocationSharingManager.getInstance().getShareUrl();
|
||||
if (shareUrl != null)
|
||||
{
|
||||
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||
android.content.ClipData clip = android.content.ClipData.newPlainText("Location Share URL", shareUrl);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
android.widget.Toast.makeText(this, R.string.location_sharing_url_copied, android.widget.Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
// Extract session info
|
||||
mSessionId = intent.getStringExtra(EXTRA_SESSION_ID);
|
||||
mEncryptionKey = intent.getStringExtra(EXTRA_ENCRYPTION_KEY);
|
||||
@@ -129,7 +145,7 @@ public class LocationSharingService extends Service implements LocationListener
|
||||
|
||||
// Start foreground with notification
|
||||
Notification notification = mNotificationHelper != null
|
||||
? mNotificationHelper.buildNotification(getStopIntent())
|
||||
? mNotificationHelper.buildNotification(getStopIntent(), getCopyUrlIntent())
|
||||
: buildFallbackNotification();
|
||||
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
@@ -176,15 +192,7 @@ public class LocationSharingService extends Service implements LocationListener
|
||||
{
|
||||
mLastLocation = location;
|
||||
|
||||
// Update notification with location info
|
||||
if (mNotificationHelper != null)
|
||||
{
|
||||
Notification notification = mNotificationHelper.buildNotification(
|
||||
getStopIntent(),
|
||||
location,
|
||||
getNavigationInfo());
|
||||
mNotificationHelper.updateNotification(NOTIFICATION_ID, notification);
|
||||
}
|
||||
// No need to update notification - it's simple and static now
|
||||
|
||||
// Schedule update if needed
|
||||
scheduleUpdate();
|
||||
@@ -332,6 +340,15 @@ public class LocationSharingService extends Service implements LocationListener
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private PendingIntent getCopyUrlIntent()
|
||||
{
|
||||
Intent copyIntent = new Intent(this, LocationSharingService.class);
|
||||
copyIntent.setAction(ACTION_COPY_URL);
|
||||
return PendingIntent.getService(this, 1, copyIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Notification buildFallbackNotification()
|
||||
{
|
||||
@@ -341,8 +358,7 @@ public class LocationSharingService extends Service implements LocationListener
|
||||
|
||||
return new NotificationCompat.Builder(this, LocationSharingNotification.CHANNEL_ID)
|
||||
.setContentTitle(getString(R.string.location_sharing_active))
|
||||
.setContentText(getString(R.string.location_sharing_notification_text))
|
||||
.setSmallIcon(R.drawable.ic_location_sharing)
|
||||
.setSmallIcon(R.drawable.ic_share)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
.build();
|
||||
|
||||
@@ -322,7 +322,9 @@ public class MapButtonsController extends Fragment
|
||||
mBadgeDrawable.setVisible(count > 0);
|
||||
BadgeUtils.attachBadgeDrawable(mBadgeDrawable, menuButton);
|
||||
|
||||
updateMenuBadge(TrackRecorder.nativeIsTrackRecordingEnabled());
|
||||
final boolean isTrackRecording = TrackRecorder.nativeIsTrackRecordingEnabled();
|
||||
final boolean isLocationSharing = app.organicmaps.location.LocationSharingManager.getInstance().isSharing();
|
||||
updateMenuBadge(isTrackRecording || isLocationSharing);
|
||||
}
|
||||
|
||||
public void updateLayerButton()
|
||||
|
||||
@@ -16,6 +16,7 @@ public class MapButtonsViewModel extends ViewModel
|
||||
private final MutableLiveData<SearchWheel.SearchOption> mSearchOption = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> mTrackRecorderState =
|
||||
new MutableLiveData<>(TrackRecorder.nativeIsTrackRecordingEnabled());
|
||||
private final MutableLiveData<Boolean> mLocationSharingState = new MutableLiveData<>(false);
|
||||
|
||||
public MutableLiveData<Boolean> getButtonsHidden()
|
||||
{
|
||||
@@ -86,4 +87,14 @@ public class MapButtonsViewModel extends ViewModel
|
||||
{
|
||||
return mTrackRecorderState;
|
||||
}
|
||||
|
||||
public void setLocationSharingState(boolean state)
|
||||
{
|
||||
mLocationSharingState.setValue(state);
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> getLocationSharingState()
|
||||
{
|
||||
return mLocationSharingState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +205,11 @@ public class NavigationController implements TrafficManager.TrafficCallback, Nav
|
||||
mNavMenu.refreshTts();
|
||||
}
|
||||
|
||||
public void refreshShareLocationColor()
|
||||
{
|
||||
mNavMenu.updateShareLocationColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled()
|
||||
{
|
||||
|
||||
@@ -68,6 +68,16 @@ public class MenuAdapter extends RecyclerView.Adapter<MenuAdapter.ViewHolder>
|
||||
badge.setBackgroundResource(R.drawable.track_recorder_badge);
|
||||
badge.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (item.iconRes == R.drawable.ic_share && app.organicmaps.location.LocationSharingManager.getInstance().isSharing())
|
||||
{
|
||||
// Set icon tint to orange
|
||||
iv.setImageTintList(android.content.res.ColorStateList.valueOf(
|
||||
androidx.core.content.ContextCompat.getColor(viewHolder.itemView.getContext(), R.color.active_location_sharing)));
|
||||
// Show badge
|
||||
badge.setBackgroundResource(R.drawable.location_sharing_badge);
|
||||
badge.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,6 +27,7 @@ public class NavMenu
|
||||
private final View mHeaderFrame;
|
||||
|
||||
private final ShapeableImageView mTts;
|
||||
private final ShapeableImageView mShareLocation;
|
||||
private final MaterialTextView mEtaValue;
|
||||
private final MaterialTextView mEtaAmPm;
|
||||
private final MaterialTextView mTimeHourValue;
|
||||
@@ -98,14 +99,16 @@ public class NavMenu
|
||||
mRouteProgress = bottomFrame.findViewById(R.id.navigation_progress);
|
||||
|
||||
// Bottom frame buttons
|
||||
ShapeableImageView shareLocation = bottomFrame.findViewById(R.id.share_location);
|
||||
shareLocation.setOnClickListener(v -> onShareLocationClicked());
|
||||
mShareLocation = bottomFrame.findViewById(R.id.share_location);
|
||||
mShareLocation.setOnClickListener(v -> onShareLocationClicked());
|
||||
ShapeableImageView mSettings = bottomFrame.findViewById(R.id.settings);
|
||||
mSettings.setOnClickListener(v -> onSettingsClicked());
|
||||
mTts = bottomFrame.findViewById(R.id.tts_volume);
|
||||
mTts.setOnClickListener(v -> onTtsClicked());
|
||||
MaterialButton stop = bottomFrame.findViewById(R.id.stop);
|
||||
stop.setOnClickListener(v -> onStopClicked());
|
||||
|
||||
updateShareLocationColor();
|
||||
}
|
||||
|
||||
private void onStopClicked()
|
||||
@@ -116,6 +119,17 @@ public class NavMenu
|
||||
private void onShareLocationClicked()
|
||||
{
|
||||
LocationSharingDialog.show(mActivity.getSupportFragmentManager());
|
||||
// Update color after dialog is shown (in case state changes)
|
||||
mShareLocation.postDelayed(this::updateShareLocationColor, 500);
|
||||
}
|
||||
|
||||
public void updateShareLocationColor()
|
||||
{
|
||||
final boolean isLocationSharing = app.organicmaps.location.LocationSharingManager.getInstance().isSharing();
|
||||
final int color = isLocationSharing
|
||||
? androidx.core.content.ContextCompat.getColor(mActivity, R.color.active_location_sharing)
|
||||
: app.organicmaps.util.ThemeUtils.getColor(mActivity, R.attr.iconTint);
|
||||
mShareLocation.setImageTintList(android.content.res.ColorStateList.valueOf(color));
|
||||
}
|
||||
|
||||
private void onSettingsClicked()
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="12dp" />
|
||||
<solid android:color="@color/active_location_sharing" />
|
||||
</shape>
|
||||
@@ -51,7 +51,7 @@
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:scaleType="center"
|
||||
android:contentDescription="@string/location_sharing_title"
|
||||
app:srcCompat="@drawable/ic_location_sharing"
|
||||
app:srcCompat="@drawable/ic_share"
|
||||
app:tint="?iconTint" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/margin_base"
|
||||
app:srcCompat="@drawable/ic_location_sharing"
|
||||
app:srcCompat="@drawable/ic_share"
|
||||
app:tint="?colorSecondary"
|
||||
android:contentDescription="@string/location_sharing_title"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
<color name="elevation_profile">@color/base_accent</color>
|
||||
|
||||
<color name="active_track_recording">#0057ff</color>
|
||||
<color name="active_location_sharing">#FF9500</color>
|
||||
|
||||
<color name="material_calendar_surface_dark">#929292</color>
|
||||
<color name="notification_warning">#FFC22219</color>
|
||||
|
||||
@@ -210,6 +210,9 @@
|
||||
<!-- Length of track in cell that describes route -->
|
||||
<string name="length">Length</string>
|
||||
<string name="share_my_location">Share My Location</string>
|
||||
<string name="stop_sharing_my_location">Stop Sharing My Location</string>
|
||||
<string name="share_location_coordinates">Share Current Coordinates</string>
|
||||
<string name="share_location_live">Start Live Location Sharing</string>
|
||||
<!-- Settings general group in settings screen -->
|
||||
<string name="prefs_group_general">General settings</string>
|
||||
<!-- Settings information group in settings screen -->
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<string name="location_sharing_title">Live Location Sharing</string>
|
||||
<string name="location_sharing_start">Start Sharing</string>
|
||||
<string name="location_sharing_stop">Stop Sharing</string>
|
||||
<string name="location_sharing_active">Sharing location</string>
|
||||
<string name="location_sharing_active">Sharing live location</string>
|
||||
<string name="location_sharing_status_active">Your location is being shared</string>
|
||||
<string name="location_sharing_status_inactive">Location sharing is not active</string>
|
||||
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
#define TRAFFIC_DATA_BASE_URL ""
|
||||
#define USER_BINDING_PKCS12 ""
|
||||
#define USER_BINDING_PKCS12_PASSWORD ""
|
||||
#define LOCATION_SHARING_SERVER_URL "https://ec1e1096-e991-4cb1-ac21-30fbad2bd406.mock.pstmn.io"
|
||||
#define LOCATION_SHARING_SERVER_URL "https://live.comaps.app"
|
||||
|
||||
Reference in New Issue
Block a user