Apply theme changes
This commit is contained in:
parent
93ccc6b1b3
commit
60bef86647
22 changed files with 147 additions and 29 deletions
BIN
OsmAnd/res/drawable-hdpi/box_top_trans.9.png
Normal file
BIN
OsmAnd/res/drawable-hdpi/box_top_trans.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 933 B |
BIN
OsmAnd/res/drawable-hdpi/box_top_trans_l.9.png
Normal file
BIN
OsmAnd/res/drawable-hdpi/box_top_trans_l.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 910 B |
BIN
OsmAnd/res/drawable-hdpi/box_top_trans_r.9.png
Normal file
BIN
OsmAnd/res/drawable-hdpi/box_top_trans_r.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 B |
6
OsmAnd/res/drawable/box_top_l.xml
Normal file
6
OsmAnd/res/drawable/box_top_l.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:drawable="@drawable/box_top_simple" />
|
||||
</selector>
|
6
OsmAnd/res/drawable/box_top_lt.xml
Normal file
6
OsmAnd/res/drawable/box_top_lt.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:drawable="@drawable/box_top_trans_l" />
|
||||
</selector>
|
6
OsmAnd/res/drawable/box_top_r.xml
Normal file
6
OsmAnd/res/drawable/box_top_r.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:drawable="@drawable/box_top_simple" />
|
||||
</selector>
|
6
OsmAnd/res/drawable/box_top_rt.xml
Normal file
6
OsmAnd/res/drawable/box_top_rt.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:drawable="@drawable/box_top_trans_r" />
|
||||
</selector>
|
6
OsmAnd/res/drawable/box_top_t.xml
Normal file
6
OsmAnd/res/drawable/box_top_t.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:state_focused="true" android:drawable="@drawable/box_top_pressed" />
|
||||
<item android:drawable="@drawable/box_top_trans" />
|
||||
</selector>
|
BIN
OsmAnd/res/drawable/box_top_trans.9.png
Normal file
BIN
OsmAnd/res/drawable/box_top_trans.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 933 B |
BIN
OsmAnd/res/drawable/box_top_trans_l.9.png
Normal file
BIN
OsmAnd/res/drawable/box_top_trans_l.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 910 B |
BIN
OsmAnd/res/drawable/box_top_trans_r.9.png
Normal file
BIN
OsmAnd/res/drawable/box_top_trans_r.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 B |
|
@ -1,5 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<resources>
|
||||
<string name="use_transparent_map_theme_descr">Use transparent map controls (requires application restart)</string>
|
||||
<string name="use_transparent_map_theme">Transparent theme</string>
|
||||
|
||||
<string name="appearance_settings_descr">Configure application look and feel</string>
|
||||
<string name="appearance_settings">Appearance</string>
|
||||
<string name="native_library_not_supported">Native library is not supported on this device.</string>
|
||||
<string name="init_native_library">Initializing native library...</string>
|
||||
<string name="choose_auto_follow_route">Map view auto follow</string>
|
||||
|
|
|
@ -87,6 +87,9 @@
|
|||
<EditTextPreference android:title="@string/application_dir" android:key="external_storage_dir"></EditTextPreference>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen android:key="appearance_settings" android:title="@string/appearance_settings" android:summary="@string/appearance_settings_descr">
|
||||
<CheckBoxPreference android:key="transparent_map_theme" android:title="@string/use_transparent_map_theme" android:summary="@string/use_transparent_map_theme_descr"></CheckBoxPreference>
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen android:key = "osm_settings" android:title="@string/osm_settings" android:summary="@string/osm_settings_descr">
|
||||
<!--
|
||||
|
|
|
@ -1050,6 +1050,15 @@ public class OsmandSettings {
|
|||
public final OsmandPreference<Boolean> SHOW_ARRIVAL_TIME_OTHERWISE_EXPECTED_TIME =
|
||||
new BooleanPreference("show_arrival_time", true, true);
|
||||
|
||||
// UI boxes
|
||||
public final CommonPreference<Boolean> TRANSPARENT_MAP_THEME =
|
||||
new BooleanPreference("transparent_map_theme", true, true);
|
||||
{
|
||||
TRANSPARENT_MAP_THEME.setModeDefaultValue(ApplicationMode.CAR, false);
|
||||
TRANSPARENT_MAP_THEME.setModeDefaultValue(ApplicationMode.BICYCLE, false);
|
||||
TRANSPARENT_MAP_THEME.setModeDefaultValue(ApplicationMode.PEDESTRIAN, true);
|
||||
}
|
||||
|
||||
public enum DayNightMode {
|
||||
AUTO(R.string.daynight_mode_auto),
|
||||
DAY(R.string.daynight_mode_day),
|
||||
|
|
|
@ -885,6 +885,7 @@ public class MapActivity extends Activity implements IMapLocationListener, Senso
|
|||
routingHelper.setAppMode(settings.getApplicationMode());
|
||||
mapView.setMapPosition(settings.POSITION_ON_MAP.get());
|
||||
registerUnregisterSensor(getLastKnownLocation());
|
||||
mapLayers.getMapInfoLayer().applyTheme();
|
||||
mapLayers.updateLayers(mapView);
|
||||
}
|
||||
|
||||
|
|
|
@ -174,10 +174,10 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
|
|||
registerBooleanPreference(osmandSettings.USE_OSMAND_ROUTING_SERVICE_ALWAYS,screen);
|
||||
registerBooleanPreference(osmandSettings.USE_INTERNET_TO_DOWNLOAD_TILES,screen);
|
||||
registerBooleanPreference(osmandSettings.MAP_VECTOR_DATA,screen);
|
||||
registerBooleanPreference(osmandSettings.TRANSPARENT_MAP_THEME,screen);
|
||||
registerBooleanPreference(osmandSettings.TEST_ANIMATE_ROUTING,screen);
|
||||
registerBooleanPreference(osmandSettings.NATIVE_RENDERING,screen);
|
||||
|
||||
|
||||
registerEditTextPreference(osmandSettings.USER_NAME, screen);
|
||||
registerEditTextPreference(osmandSettings.USER_PASSWORD, screen);
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@ package net.osmand.plus.views;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
|
@ -11,11 +14,14 @@ public abstract class MapInfoControl extends View {
|
|||
int height = 0;
|
||||
Rect padding = new Rect();
|
||||
|
||||
public MapInfoControl(Context ctx, int background) {
|
||||
public MapInfoControl(Context ctx) {
|
||||
super(ctx);
|
||||
Drawable drawable = ctx.getResources().getDrawable(background).mutate();
|
||||
drawable.getPadding(padding);
|
||||
setBackgroundDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundDrawable(Drawable d) {
|
||||
d.getPadding(padding);
|
||||
super.setBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,6 +47,19 @@ public abstract class MapInfoControl extends View {
|
|||
|
||||
}
|
||||
|
||||
protected void drawShadowText(Canvas cv, String text, float centerX, float centerY, Paint textPaint) {
|
||||
int c = textPaint.getColor();
|
||||
textPaint.setStyle(Style.STROKE);
|
||||
textPaint.setColor(Color.LTGRAY);
|
||||
textPaint.setStrokeWidth(4);
|
||||
cv.drawText(text, centerX, centerY, textPaint);
|
||||
// reset
|
||||
textPaint.setStrokeWidth(1);
|
||||
textPaint.setStyle(Style.FILL);
|
||||
textPaint.setColor(c);
|
||||
cv.drawText(text, centerX, centerY, textPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
|
|
@ -84,7 +84,7 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
paintSubText.setStyle(Style.FILL_AND_STROKE);
|
||||
paintSubText.setColor(Color.BLACK);
|
||||
paintSubText.setTextSize(15 * scaleCoefficient);
|
||||
paintSubText.setFakeBoldText(true);
|
||||
|
||||
paintSubText.setAntiAlias(true);
|
||||
|
||||
paintImg = new Paint();
|
||||
|
@ -93,14 +93,39 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
paintImg.setAntiAlias(true);
|
||||
|
||||
createTopBarElements();
|
||||
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
public void applyTheme() {
|
||||
int boxTop = R.drawable.box_top;
|
||||
int boxTopR = R.drawable.box_top_r;
|
||||
int boxTopL = R.drawable.box_top_l;
|
||||
int expand = R.drawable.box_expand;
|
||||
if(view.getSettings().TRANSPARENT_MAP_THEME.get()){
|
||||
boxTop = R.drawable.box_top_t;
|
||||
boxTopR = R.drawable.box_top_rt;
|
||||
boxTopL = R.drawable.box_top_lt;
|
||||
}
|
||||
int i = 0;
|
||||
for(MapInfoControl m : rightStack.getAllViews()){
|
||||
m.setBackgroundDrawable(view.getResources().getDrawable(i == 0 ? boxTopR : boxTop).mutate());
|
||||
i++;
|
||||
}
|
||||
rightStack.setExpandImageDrawable(view.getResources().getDrawable(expand).mutate());
|
||||
i = 0;
|
||||
for(MapInfoControl m : leftStack.getAllViews()){
|
||||
m.setBackgroundDrawable(view.getResources().getDrawable(i < 2 ? boxTopL : boxTop).mutate());
|
||||
i++;
|
||||
}
|
||||
leftStack.setExpandImageDrawable(view.getResources().getDrawable(expand).mutate());
|
||||
statusBar.setBackgroundDrawable(view.getResources().getDrawable(boxTop).mutate());
|
||||
}
|
||||
|
||||
public void createTopBarElements() {
|
||||
// 1. Create view groups and controls
|
||||
statusBar = createStatusBar();
|
||||
Rect topRectPadding = new Rect();
|
||||
view.getResources().getDrawable(R.drawable.box_top).getPadding(topRectPadding);
|
||||
statusBar.setBackgroundDrawable(view.getResources().getDrawable(R.drawable.box_top).mutate());
|
||||
|
||||
rightStack = new MapStackControl(view.getContext());
|
||||
rightStack.addStackView(createDistanceControl());
|
||||
|
@ -112,12 +137,13 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
leftStack.addStackView(createMiniMapControl());
|
||||
|
||||
// 2. Preparations
|
||||
Rect topRectPadding = new Rect();
|
||||
view.getResources().getDrawable(R.drawable.box_top).getPadding(topRectPadding);
|
||||
|
||||
STATUS_BAR_MARGIN_X = (int) (STATUS_BAR_MARGIN_X * scaleCoefficient);
|
||||
statusBar.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
|
||||
Rect statusBarPadding = new Rect();
|
||||
statusBar.getBackground().getPadding(statusBarPadding);
|
||||
|
||||
|
||||
// 3. put into frame parent layout controls
|
||||
FrameLayout parent = (FrameLayout) view.getParent();
|
||||
// status bar hides own top part
|
||||
|
@ -129,21 +155,25 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
android.view.ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.RIGHT);
|
||||
flp.rightMargin = STATUS_BAR_MARGIN_X;
|
||||
flp.topMargin = topMargin;
|
||||
parent.addView(rightStack, flp);
|
||||
rightStack.setLayoutParams(flp);
|
||||
|
||||
|
||||
flp = new FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT,
|
||||
android.view.ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.LEFT);
|
||||
flp.leftMargin = STATUS_BAR_MARGIN_X;
|
||||
flp.topMargin = topMargin;
|
||||
parent.addView(leftStack, flp);
|
||||
leftStack.setLayoutParams(flp);
|
||||
|
||||
flp = new FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT,
|
||||
android.view.ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.TOP);
|
||||
flp.leftMargin = STATUS_BAR_MARGIN_X;
|
||||
flp.rightMargin = STATUS_BAR_MARGIN_X;
|
||||
flp.topMargin = -topRectPadding.top;
|
||||
statusBar.setLayoutParams(flp);
|
||||
|
||||
parent.addView(statusBar, flp);
|
||||
parent.addView(rightStack);
|
||||
parent.addView(leftStack);
|
||||
parent.addView(statusBar);
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,7 +214,7 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
}
|
||||
|
||||
private TextInfoControl createSpeedControl(){
|
||||
final TextInfoControl speedControl = new TextInfoControl(map, R.drawable.box_top, 0, paintText, paintSubText) {
|
||||
final TextInfoControl speedControl = new TextInfoControl(map, 0, paintText, paintSubText) {
|
||||
private float cachedSpeed = 0;
|
||||
|
||||
@Override
|
||||
|
@ -218,7 +248,7 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
final Drawable time = view.getResources().getDrawable(R.drawable.info_time);
|
||||
final Drawable timeToGo = view.getResources().getDrawable(R.drawable.info_time_to_go);
|
||||
showArrivalTime = view.getSettings().SHOW_ARRIVAL_TIME_OTHERWISE_EXPECTED_TIME.get();
|
||||
final TextInfoControl leftTimeControl = new TextInfoControl(map, R.drawable.box_top, 0, paintText, paintSubText) {
|
||||
final TextInfoControl leftTimeControl = new TextInfoControl(map, 0, paintText, paintSubText) {
|
||||
private long cachedLeftTime = 0;
|
||||
|
||||
@Override
|
||||
|
@ -275,7 +305,7 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
}
|
||||
|
||||
private TextInfoControl createDistanceControl() {
|
||||
TextInfoControl distanceControl = new TextInfoControl(map, R.drawable.box_top, 0, paintText, paintSubText) {
|
||||
TextInfoControl distanceControl = new TextInfoControl(map, 0, paintText, paintSubText) {
|
||||
private float[] calculations = new float[1];
|
||||
private int cachedMeters = 0;
|
||||
|
||||
|
@ -332,7 +362,7 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
}
|
||||
|
||||
private MiniMapControl createMiniMapControl() {
|
||||
MiniMapControl miniMapControl = new MiniMapControl(map, view, R.drawable.box_top) {
|
||||
MiniMapControl miniMapControl = new MiniMapControl(map, view) {
|
||||
@Override
|
||||
public boolean updateInfo() {
|
||||
boolean visible = false;
|
||||
|
@ -358,7 +388,7 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
}
|
||||
|
||||
private NextTurnInfoControl createNextInfoControl() {
|
||||
NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, R.drawable.box_top, paintText, paintSubText) {
|
||||
NextTurnInfoControl nextTurnInfo = new NextTurnInfoControl(map, paintText, paintSubText) {
|
||||
|
||||
@Override
|
||||
public boolean updateInfo() {
|
||||
|
@ -407,7 +437,6 @@ public class MapInfoLayer extends OsmandMapLayer {
|
|||
|
||||
private ViewGroup createStatusBar() {
|
||||
LinearLayout statusBar = new LinearLayout(view.getContext());
|
||||
statusBar.setBackgroundDrawable(view.getResources().getDrawable(R.drawable.box_top).mutate());
|
||||
statusBar.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
// Compass icon
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
@ -52,6 +53,10 @@ public class MapStackControl extends ViewGroup {
|
|||
});
|
||||
MapStackControl.this.addView(expandView);
|
||||
}
|
||||
|
||||
public void setExpandImageDrawable(Drawable d) {
|
||||
expandView.setImageDrawable(d);
|
||||
}
|
||||
|
||||
public void updateInfo() {
|
||||
for (MapInfoControl v : stackViews) {
|
||||
|
@ -82,6 +87,21 @@ public class MapStackControl extends ViewGroup {
|
|||
collapsedViews.add(v);
|
||||
MapStackControl.this.addView(v);
|
||||
}
|
||||
|
||||
public List<MapInfoControl> getStackViews() {
|
||||
return stackViews;
|
||||
}
|
||||
|
||||
public List<MapInfoControl> getCollapsedViews() {
|
||||
return collapsedViews;
|
||||
}
|
||||
|
||||
public List<MapInfoControl> getAllViews(){
|
||||
List<MapInfoControl> l = new ArrayList<MapInfoControl>();
|
||||
l.addAll(stackViews);
|
||||
l.addAll(collapsedViews);
|
||||
return l;
|
||||
}
|
||||
|
||||
public boolean isCollapsed() {
|
||||
return isCollapsed;
|
||||
|
|
|
@ -22,8 +22,8 @@ public class MiniMapControl extends MapInfoControl {
|
|||
private Paint fillBlack;
|
||||
protected Path miniMapPath = null;
|
||||
|
||||
public MiniMapControl(Context ctx, OsmandMapTileView view, int background) {
|
||||
super(ctx, background);
|
||||
public MiniMapControl(Context ctx, OsmandMapTileView view) {
|
||||
super(ctx);
|
||||
this.view = view;
|
||||
|
||||
fillBlack = new Paint();
|
||||
|
|
|
@ -27,8 +27,8 @@ public class NextTurnInfoControl extends MapInfoControl {
|
|||
private Paint paintBlack;
|
||||
private Paint paintRouteDirection;
|
||||
|
||||
public NextTurnInfoControl(Context ctx, int background, Paint textPaint, Paint subtextPaint) {
|
||||
super(ctx, background);
|
||||
public NextTurnInfoControl(Context ctx, Paint textPaint, Paint subtextPaint) {
|
||||
super(ctx);
|
||||
this.textPaint = textPaint;
|
||||
this.subtextPaint = subtextPaint;
|
||||
|
||||
|
@ -75,9 +75,10 @@ public class NextTurnInfoControl extends MapInfoControl {
|
|||
st = textPaint.measureText(subtext);
|
||||
}
|
||||
float mt = textPaint.measureText(text);
|
||||
canvas.drawText(text, (getWWidth() - st - mt) / 2 - scaleCoefficient, getWHeight() - 3 * scaleCoefficient, textPaint);
|
||||
drawShadowText(canvas, text,
|
||||
(getWWidth() - st - mt) / 2 - scaleCoefficient, getWHeight() - 3 * scaleCoefficient, textPaint);
|
||||
if (subtext != null) {
|
||||
canvas.drawText(subtext, (getWWidth() - st - mt) / 2 + 2 * scaleCoefficient + mt, getWHeight() - 3
|
||||
drawShadowText(canvas, subtext, (getWWidth() - st - mt) / 2 + 2 * scaleCoefficient + mt, getWHeight() - 3
|
||||
* scaleCoefficient, subtextPaint);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ public class TextInfoControl extends MapInfoControl {
|
|||
private Drawable imageDrawable;
|
||||
private float scaleCoefficient;
|
||||
|
||||
public TextInfoControl(Context ctx, int background, int leftMargin, Paint textPaint, Paint subtextPaint) {
|
||||
super(ctx, background);
|
||||
public TextInfoControl(Context ctx, int leftMargin, Paint textPaint, Paint subtextPaint) {
|
||||
super(ctx);
|
||||
scaleCoefficient = MapInfoLayer.scaleCoefficient;
|
||||
this.leftMargin = leftMargin;
|
||||
this.textPaint = textPaint;
|
||||
|
@ -81,13 +81,14 @@ public class TextInfoControl extends MapInfoControl {
|
|||
margin = (int) (imageDrawable.getBounds().width() + 2 * scaleCoefficient);
|
||||
}
|
||||
margin += leftMargin;
|
||||
cv.drawText(text, margin, getWHeight() - 3 * scaleCoefficient, textPaint);
|
||||
drawShadowText(cv, text, margin, getWHeight() - 3 * scaleCoefficient, textPaint);
|
||||
if (subtext != null) {
|
||||
cv.drawText(subtext, margin + 2 * scaleCoefficient + textPaint.measureText(text), getWHeight() - 3
|
||||
drawShadowText(cv, subtext, margin + 2 * scaleCoefficient + textPaint.measureText(text), getWHeight() - 3
|
||||
* scaleCoefficient, subtextPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isVisible() {
|
||||
return text != null && text.length() > 0;
|
||||
|
|
Loading…
Reference in a new issue