Merge branch 'r3.9'
This commit is contained in:
commit
baa6e52908
8 changed files with 128 additions and 107 deletions
|
@ -38,6 +38,11 @@ public class ProfileSettingsParams extends AidlParams {
|
|||
this.silent = silent;
|
||||
}
|
||||
|
||||
public ProfileSettingsParams(Uri profileSettingsUri, List<AExportSettingsType> settingsTypeList,
|
||||
boolean replace, String latestChanges, int version) {
|
||||
this(profileSettingsUri, settingsTypeList, replace, false, latestChanges, version);
|
||||
}
|
||||
|
||||
public ProfileSettingsParams(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.osmand.plus.api;
|
||||
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public interface SQLiteAPI {
|
||||
|
||||
|
@ -55,8 +56,6 @@ public interface SQLiteAPI {
|
|||
|
||||
void close();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public interface SQLiteStatement {
|
||||
|
@ -81,7 +80,9 @@ public interface SQLiteAPI {
|
|||
|
||||
}
|
||||
|
||||
public SQLiteConnection getOrCreateDatabase(String name, boolean readOnly);
|
||||
@Nullable
|
||||
SQLiteConnection getOrCreateDatabase(String name, boolean readOnly);
|
||||
|
||||
public SQLiteConnection openByAbsolutePath(String path, boolean readOnly);
|
||||
@Nullable
|
||||
SQLiteConnection openByAbsolutePath(String path, boolean readOnly);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package net.osmand.plus.api;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
public class SQLiteAPIImpl implements SQLiteAPI {
|
||||
|
||||
private OsmandApplication app;
|
||||
|
@ -20,6 +22,7 @@ public class SQLiteAPIImpl implements SQLiteAPI {
|
|||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
@Nullable
|
||||
@Override
|
||||
public SQLiteConnection getOrCreateDatabase(String name, boolean readOnly) {
|
||||
android.database.sqlite.SQLiteDatabase db = null;
|
||||
|
@ -29,13 +32,12 @@ public class SQLiteAPIImpl implements SQLiteAPI {
|
|||
} catch (RuntimeException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
if(db == null) {
|
||||
if (db == null) {
|
||||
return null;
|
||||
}
|
||||
return new SQLiteDatabaseWrapper(db) ;
|
||||
return new SQLiteDatabaseWrapper(db);
|
||||
}
|
||||
|
||||
|
||||
public class SQLiteDatabaseWrapper implements SQLiteConnection {
|
||||
android.database.sqlite.SQLiteDatabase ds;
|
||||
|
||||
|
@ -206,15 +208,15 @@ public class SQLiteAPIImpl implements SQLiteAPI {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SQLiteConnection openByAbsolutePath(String path, boolean readOnly) {
|
||||
// fix http://stackoverflow.com/questions/26937152/workaround-for-nexus-9-sqlite-file-write-operations-on-external-dirs
|
||||
android.database.sqlite.SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null,
|
||||
readOnly? SQLiteDatabase.OPEN_READONLY : (SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING));
|
||||
if(db == null) {
|
||||
readOnly ? SQLiteDatabase.OPEN_READONLY : (SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING));
|
||||
if (db == null) {
|
||||
return null;
|
||||
}
|
||||
return new SQLiteDatabaseWrapper(db) ;
|
||||
return new SQLiteDatabaseWrapper(db);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.osmand.plus.importfiles;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
@ -9,13 +10,13 @@ import android.os.Build;
|
|||
import android.os.Bundle;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.provider.Settings;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.CallbackWithObject;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
|
@ -418,7 +419,7 @@ public class ImportHelper {
|
|||
final boolean useImportDir, boolean forceImportFavourites, boolean showInDetailsActivity) {
|
||||
if (result != null) {
|
||||
if (result.error != null) {
|
||||
Toast.makeText(activity, result.error.getMessage(), Toast.LENGTH_LONG).show();
|
||||
app.showToastMessage(result.error.getMessage());
|
||||
if (gpxImportCompleteListener != null) {
|
||||
gpxImportCompleteListener.onImportComplete(false);
|
||||
}
|
||||
|
@ -439,6 +440,7 @@ public class ImportHelper {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (AndroidUtils.isActivityNotDestroyed(activity)) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.shared_string_import2osmand)
|
||||
.setMessage(R.string.import_gpx_failed_descr)
|
||||
|
@ -465,8 +467,9 @@ public class ImportHelper {
|
|||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
if (forceImportFavourites) {
|
||||
final Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
|
||||
Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
|
||||
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
newIntent.putExtra(TAB_ID, GPX_TAB);
|
||||
activity.startActivity(newIntent);
|
||||
|
@ -577,7 +580,7 @@ public class ImportHelper {
|
|||
showPlanRouteFragment();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(activity, warning, Toast.LENGTH_LONG).show();
|
||||
app.showToastMessage(warning);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -619,7 +622,8 @@ public class ImportHelper {
|
|||
final boolean forceImportFavourites, final boolean forceImportGpx) {
|
||||
if (gpxFile == null || gpxFile.isPointsEmpty()) {
|
||||
if (forceImportFavourites) {
|
||||
final DialogInterface.OnClickListener importAsTrackListener = new DialogInterface.OnClickListener() {
|
||||
if (AndroidUtils.isActivityNotDestroyed(activity)) {
|
||||
OnClickListener importAsTrackListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which) {
|
||||
|
@ -632,13 +636,13 @@ public class ImportHelper {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.import_track)
|
||||
.setMessage(activity.getString(R.string.import_track_desc, fileName))
|
||||
.setPositiveButton(R.string.shared_string_import, importAsTrackListener)
|
||||
.setNegativeButton(R.string.shared_string_cancel, importAsTrackListener)
|
||||
.show();
|
||||
}
|
||||
} else {
|
||||
handleResult(gpxFile, fileName, fileSize, save, useImportDir, false);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import com.github.mikephil.charting.data.ChartData;
|
|||
import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||
|
||||
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
|
@ -30,10 +30,10 @@ import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
|
|||
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener;
|
||||
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
|
||||
import net.osmand.plus.measurementtool.MeasurementToolFragment.OnUpdateInfoListener;
|
||||
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter;
|
||||
import net.osmand.plus.measurementtool.graph.CommonGraphAdapter;
|
||||
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter;
|
||||
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType;
|
||||
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter;
|
||||
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper;
|
||||
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper.RefreshMapCallback;
|
||||
import net.osmand.plus.routepreparationmenu.RouteDetailsFragment;
|
||||
|
@ -422,7 +422,7 @@ public class GraphsCard extends BaseCard implements OnUpdateInfoListener {
|
|||
GpxUiHelper.setupGPXChart(commonGraphAdapter.getChart(), 4, 24f, 16f, !nightMode, true);
|
||||
List<ILineDataSet> dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(),
|
||||
app, analysis, firstType, secondType, false);
|
||||
return !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null;
|
||||
return new LineData(dataSets);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -447,12 +447,11 @@ public class GraphsCard extends BaseCard implements OnUpdateInfoListener {
|
|||
@Override
|
||||
public BarData getChartData() {
|
||||
GpxUiHelper.setupHorizontalGPXChart(app, customGraphAdapter.getChart(), 5, 9, 24, true, nightMode);
|
||||
BarData data = null;
|
||||
if (!Algorithms.isEmpty(statistics.elements)) {
|
||||
data = GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(),
|
||||
return GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(),
|
||||
statistics, analysis, true, nightMode);
|
||||
}
|
||||
return data;
|
||||
return new BarData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -192,9 +192,9 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
|
|||
}
|
||||
|
||||
private BaseBottomSheetItem createCopyToMarkersItem(final GPXFile gpxFile) {
|
||||
final MapMarkersGroup markersGroup = getOrCreateMarkersGroup(gpxFile);
|
||||
final Set<String> categories = markersGroup.getWptCategories();
|
||||
final boolean synced = categories != null && categories.contains(group.getName());
|
||||
MapMarkersGroup markersGroup = mapMarkersHelper.getMarkersGroup(gpxFile);
|
||||
final boolean synced = markersGroup != null && (Algorithms.isEmpty(markersGroup.getWptCategories())
|
||||
|| markersGroup.getWptCategories().contains(group.getName()));
|
||||
|
||||
return new SimpleBottomSheetItem.Builder()
|
||||
.setIcon(getContentIcon(synced ? R.drawable.ic_action_delete_dark : R.drawable.ic_action_copy))
|
||||
|
@ -203,18 +203,25 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
|
|||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
updateGroupWptCategory(gpxFile, markersGroup, categories, synced);
|
||||
updateGroupWptCategory(gpxFile, synced);
|
||||
dismiss();
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
|
||||
private void updateGroupWptCategory(GPXFile gpxFile, MapMarkersGroup markersGroup, Set<String> categories, boolean synced) {
|
||||
private void updateGroupWptCategory(GPXFile gpxFile, boolean synced) {
|
||||
SelectedGpxFile selectedGpxFile = selectedGpxHelper.getSelectedFileByPath(gpxFile.path);
|
||||
if (selectedGpxFile == null) {
|
||||
selectedGpxHelper.selectGpxFile(gpxFile, true, false, false, false, false);
|
||||
}
|
||||
boolean groupCreated = false;
|
||||
MapMarkersGroup markersGroup = mapMarkersHelper.getMarkersGroup(gpxFile);
|
||||
if (markersGroup == null) {
|
||||
groupCreated = true;
|
||||
markersGroup = mapMarkersHelper.addOrEnableGroup(gpxFile);
|
||||
}
|
||||
Set<String> categories = markersGroup.getWptCategories();
|
||||
Set<String> selectedCategories = new HashSet<>();
|
||||
if (categories != null) {
|
||||
selectedCategories.addAll(categories);
|
||||
|
@ -224,16 +231,14 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
|
|||
} else {
|
||||
selectedCategories.add(group.getName());
|
||||
}
|
||||
if (Algorithms.isEmpty(selectedCategories)) {
|
||||
mapMarkersHelper.removeMarkersGroup(markersGroup);
|
||||
} else {
|
||||
mapMarkersHelper.updateGroupWptCategories(markersGroup, selectedCategories);
|
||||
if (!groupCreated) {
|
||||
mapMarkersHelper.runSynchronization(markersGroup);
|
||||
}
|
||||
|
||||
private MapMarkersGroup getOrCreateMarkersGroup(GPXFile gpxFile) {
|
||||
MapMarkersGroup markersGroup = mapMarkersHelper.getMarkersGroup(gpxFile);
|
||||
if (markersGroup == null) {
|
||||
markersGroup = mapMarkersHelper.addOrEnableGroup(gpxFile);
|
||||
}
|
||||
return markersGroup;
|
||||
}
|
||||
|
||||
private BaseBottomSheetItem createCopyToFavoritesItem() {
|
||||
|
|
|
@ -663,11 +663,12 @@ public class PoiFiltersHelper {
|
|||
|
||||
private SQLiteConnection openConnection(boolean readonly) {
|
||||
conn = context.getSQLiteAPI().getOrCreateDatabase(DATABASE_NAME, readonly);
|
||||
if (conn.getVersion() < DATABASE_VERSION) {
|
||||
if (conn != null && conn.getVersion() < DATABASE_VERSION) {
|
||||
if (readonly) {
|
||||
conn.close();
|
||||
conn = context.getSQLiteAPI().getOrCreateDatabase(DATABASE_NAME, false);
|
||||
}
|
||||
if (conn != null) {
|
||||
int version = conn.getVersion();
|
||||
conn.setVersion(DATABASE_VERSION);
|
||||
if (version == 0) {
|
||||
|
@ -676,6 +677,7 @@ public class PoiFiltersHelper {
|
|||
onUpgrade(conn, version, DATABASE_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,26 +17,28 @@ import net.osmand.data.QuadTree;
|
|||
import net.osmand.data.RotatedTileBox;
|
||||
import net.osmand.plus.FavouritesDbHelper;
|
||||
import net.osmand.plus.FavouritesDbHelper.FavoriteGroup;
|
||||
import net.osmand.plus.mapmarkers.MapMarkersHelper;
|
||||
import net.osmand.plus.mapmarkers.MapMarker;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.PointImageDrawable;
|
||||
import net.osmand.plus.mapmarkers.MapMarker;
|
||||
import net.osmand.plus.mapmarkers.MapMarkersHelper;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.views.OsmandMapLayer;
|
||||
import net.osmand.plus.views.OsmandMapTileView;
|
||||
import net.osmand.plus.views.layers.ContextMenuLayer.ApplyMovedObjectCallback;
|
||||
import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProvider;
|
||||
import net.osmand.plus.views.layers.ContextMenuLayer.IMoveObjectProvider;
|
||||
import net.osmand.plus.views.layers.MapTextLayer.MapTextProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider,
|
||||
ContextMenuLayer.IMoveObjectProvider, MapTextProvider<FavouritePoint> {
|
||||
public class FavouritesLayer extends OsmandMapLayer implements IContextMenuProvider, IMoveObjectProvider,
|
||||
MapTextProvider<FavouritePoint> {
|
||||
|
||||
protected int startZoom = 6;
|
||||
|
||||
protected OsmandMapTileView view;
|
||||
private FavouritesDbHelper favorites;
|
||||
private FavouritesDbHelper favouritesDbHelper;
|
||||
private MapMarkersHelper mapMarkersHelper;
|
||||
protected List<FavouritePoint> cache = new ArrayList<>();
|
||||
private MapTextLayer textLayer;
|
||||
|
@ -54,7 +56,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
public void initLayer(OsmandMapTileView view) {
|
||||
this.view = view;
|
||||
settings = view.getApplication().getSettings();
|
||||
favorites = view.getApplication().getFavorites();
|
||||
favouritesDbHelper = view.getApplication().getFavorites();
|
||||
mapMarkersHelper = view.getApplication().getMapMarkersHelper();
|
||||
textLayer = view.getLayerByClass(MapTextLayer.class);
|
||||
defaultColor = ContextCompat.getColor(view.getContext(), R.color.color_favorite);
|
||||
|
@ -92,7 +94,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
@Override
|
||||
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||
cache.clear();
|
||||
if (this.settings.SHOW_FAVORITES.get() && favorites.isFavoritesLoaded()) {
|
||||
if (this.settings.SHOW_FAVORITES.get() && favouritesDbHelper.isFavoritesLoaded()) {
|
||||
if (tileBox.getZoom() >= startZoom) {
|
||||
float textScale = this.settings.TEXT_SCALE.get();
|
||||
float iconSize = getIconSize(view.getApplication());
|
||||
|
@ -102,7 +104,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
final QuadRect latLonBounds = tileBox.getLatLonBounds();
|
||||
List<LatLon> fullObjectsLatLon = new ArrayList<>();
|
||||
List<LatLon> smallObjectsLatLon = new ArrayList<>();
|
||||
for (FavoriteGroup group : favorites.getFavoriteGroups()) {
|
||||
for (FavoriteGroup group : favouritesDbHelper.getFavoriteGroups()) {
|
||||
List<Pair<FavouritePoint, MapMarker>> fullObjects = new ArrayList<>();
|
||||
boolean synced = mapMarkersHelper.getMarkersGroup(group) != null;
|
||||
for (FavouritePoint favoritePoint : group.getPoints()) {
|
||||
|
@ -127,7 +129,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
if (marker != null && marker.history) {
|
||||
color = grayColor;
|
||||
} else {
|
||||
color = favorites.getColorWithCategory(favoritePoint,defaultColor);
|
||||
color = favouritesDbHelper.getColorWithCategory(favoritePoint,defaultColor);
|
||||
}
|
||||
PointImageDrawable pointImageDrawable = PointImageDrawable.getFromFavorite(
|
||||
view.getContext(), color,true, favoritePoint);
|
||||
|
@ -162,11 +164,11 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
boolean history = false;
|
||||
if (marker != null) {
|
||||
pointImageDrawable = PointImageDrawable.getOrCreateSyncedIcon(view.getContext(),
|
||||
favorites.getColorWithCategory(favoritePoint,defaultColor), favoritePoint);
|
||||
favouritesDbHelper.getColorWithCategory(favoritePoint,defaultColor), favoritePoint);
|
||||
history = marker.history;
|
||||
} else {
|
||||
pointImageDrawable = PointImageDrawable.getFromFavorite(view.getContext(),
|
||||
favorites.getColorWithCategory(favoritePoint, defaultColor),true, favoritePoint);
|
||||
favouritesDbHelper.getColorWithCategory(favoritePoint, defaultColor),true, favoritePoint);
|
||||
}
|
||||
pointImageDrawable.drawPoint(canvas, x, y, textScale, history);
|
||||
}
|
||||
|
@ -180,7 +182,8 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
int r = getScaledTouchRadius(view.getApplication(), getDefaultRadiusPoi(tb));
|
||||
int ex = (int) point.x;
|
||||
int ey = (int) point.y;
|
||||
for (FavouritePoint n : favorites.getFavouritePoints()) {
|
||||
List<FavouritePoint> favouritePoints = new ArrayList<>(favouritesDbHelper.getFavouritePoints());
|
||||
for (FavouritePoint n : favouritePoints) {
|
||||
getFavFromPoint(tb, res, r, ex, ey, n);
|
||||
}
|
||||
}
|
||||
|
@ -275,8 +278,8 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
|
|||
@Nullable ApplyMovedObjectCallback callback) {
|
||||
boolean result = false;
|
||||
if (o instanceof FavouritePoint) {
|
||||
favorites.editFavourite((FavouritePoint) o, position.getLatitude(), position.getLongitude());
|
||||
favorites.lookupAddress((FavouritePoint) o);
|
||||
favouritesDbHelper.editFavourite((FavouritePoint) o, position.getLatitude(), position.getLongitude());
|
||||
favouritesDbHelper.lookupAddress((FavouritePoint) o);
|
||||
result = true;
|
||||
}
|
||||
if (callback != null) {
|
||||
|
|
Loading…
Reference in a new issue