Updated parking card

This commit is contained in:
Denis 2015-03-11 18:09:05 +02:00
parent e8b434c53c
commit 3f5123c191
12 changed files with 140 additions and 75 deletions

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/dashboard_parking_dark_selected" android:state_enabled="false"/>
<item android:drawable="@color/dashboard_parking_dark_selected" android:state_pressed="true"/>
<item android:drawable="@color/dashboard_parking_dark_selected" android:state_focused="true"/>
<item android:drawable="@color/dashboard_parking_dark_color"/>
</selector>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@color/parking_card_selected" />
<item android:state_pressed="true" android:drawable="@color/parking_card_selected" />
<item android:state_focused="true" android:drawable="@color/parking_card_selected" />
<item android:drawable="@color/dashboard_blue" />
</selector>

View file

@ -7,6 +7,7 @@
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout
android:id="@+id/parking_header"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dash_parking_height" android:layout_height="@dimen/dash_parking_height"
android:background="?attr/dash_parking_bg" android:background="?attr/dash_parking_bg"

View file

@ -36,7 +36,7 @@
<attr name="expandable_list_background" format="color"/> <attr name="expandable_list_background" format="color"/>
<attr name="list_settings_icon" format="reference"/> <attr name="list_settings_icon" format="reference"/>
<attr name="size_progress_bar" format="reference"/> <attr name="size_progress_bar" format="reference"/>
<attr name="dash_parking_bg" format="color"/> <attr name="dash_parking_bg" format="reference"/>
</declare-styleable> </declare-styleable>
<declare-styleable name="PagerSlidingTabStrip"> <declare-styleable name="PagerSlidingTabStrip">

View file

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="parking_card_selected">#234DDE</color>
<color name="dashboard_parking_dark_color">#54778c</color>
<color name="dashboard_parking_dark_selected">#446072</color>
<color name="list_divider_dark">#1f2326</color> <color name="list_divider_dark">#1f2326</color>
<color name="list_divider_light">@color/color_white</color> <color name="list_divider_light">@color/color_white</color>
<color name="list_background_dark">#292f33</color> <color name="list_background_dark">#292f33</color>
@ -33,7 +37,7 @@
<color name="dashboard_subheader_text_light">#212121</color> <color name="dashboard_subheader_text_light">#212121</color>
<color name="dashboard_general_button_text_dark">#ff8f00</color> <color name="dashboard_general_button_text_dark">#ff8f00</color>
<color name="dashboard_general_button_text_light">#536DFE</color> <color name="dashboard_general_button_text_light">#536DFE</color>
<color name="dashboard_parking_dark">#54778c</color>
<color name="color_transparent">#00000000</color> <color name="color_transparent">#00000000</color>
<color name="widgettext_night">#ffC8C8C8</color> <color name="widgettext_night">#ffC8C8C8</color>

View file

@ -165,7 +165,7 @@
<item name="expandable_list_background">@color/color_white</item> <item name="expandable_list_background">@color/color_white</item>
<item name="list_settings_icon">@drawable/ic_overflow_menu_light</item> <item name="list_settings_icon">@drawable/ic_overflow_menu_light</item>
<item name="size_progress_bar">@drawable/size_progressbar_light</item> <item name="size_progress_bar">@drawable/size_progressbar_light</item>
<item name="dash_parking_bg">@color/dashboard_blue</item> <item name="dash_parking_bg">@drawable/dash_parking_light</item>
</style> </style>
<style name="OsmandDarkTheme" parent="Theme.AppCompat"> <style name="OsmandDarkTheme" parent="Theme.AppCompat">
@ -209,7 +209,7 @@
<item name="expandable_list_background">@color/list_background_dark</item> <item name="expandable_list_background">@color/list_background_dark</item>
<item name="list_settings_icon">@drawable/ic_overflow_menu_dark</item> <item name="list_settings_icon">@drawable/ic_overflow_menu_dark</item>
<item name="size_progress_bar">@drawable/size_progressbar_dark</item> <item name="size_progress_bar">@drawable/size_progressbar_dark</item>
<item name="dash_parking_bg">@color/dashboard_parking_dark</item> <item name="dash_parking_bg">@drawable/dash_parking_dark</item>
</style> </style>
<style name="Widget.Styled.ActionBarDark" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse"> <style name="Widget.Styled.ActionBarDark" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse">

View file

@ -39,7 +39,8 @@ public class IconsCache {
public Drawable getIcon(int id, int colorId) { public Drawable getIcon(int id, int colorId) {
return getDrawable(id, colorId); return getDrawable(id, colorId);
} }
public Drawable getContentIcon(int id) { public Drawable getContentIcon(int id) {
return getDrawable(id, app.getSettings().isLightContent() ? R.color.icon_color_light : 0); return getDrawable(id, app.getSettings().isLightContent() ? R.color.icon_color_light : 0);
} }

View file

@ -9,6 +9,7 @@ import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.views.DirectionDrawable; import net.osmand.plus.views.DirectionDrawable;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -31,34 +32,34 @@ public abstract class DashLocationFragment extends DashBaseFragment {
private static final int ORIENTATION_180 = 2; private static final int ORIENTATION_180 = 2;
protected List<DashLocationView> distances = new ArrayList<DashLocationFragment.DashLocationView>(); protected List<DashLocationView> distances = new ArrayList<DashLocationFragment.DashLocationView>();
private int screenOrientation; private int screenOrientation;
public static class DashLocationView { public static class DashLocationView {
public ImageView arrow; public ImageView arrow;
public TextView txt; public TextView txt;
public LatLon loc; public LatLon loc;
public int arrowResId; public int arrowResId;
public boolean paint = true;
public DashLocationView(ImageView arrow, TextView txt, LatLon loc) { public DashLocationView(ImageView arrow, TextView txt, LatLon loc) {
super(); super();
this.arrow = arrow; this.arrow = arrow;
this.txt = txt; this.txt = txt;
this.loc = loc; this.loc = loc;
} }
} }
@Override @Override
public void onOpenDash() { public void onOpenDash() {
//Hardy: getRotation() is the correction if device's screen orientation != the default display's standard orientation //Hardy: getRotation() is the correction if device's screen orientation != the default display's standard orientation
screenOrientation = getScreenOrientation(getActivity()); screenOrientation = getScreenOrientation(getActivity());
} }
public static int getScreenOrientation(Activity a) { public static int getScreenOrientation(Activity a) {
int screenOrientation = ((WindowManager) a.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); int screenOrientation = ((WindowManager) a.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
switch (screenOrientation) switch (screenOrientation) {
{
case ORIENTATION_0: // Device default (normally portrait) case ORIENTATION_0: // Device default (normally portrait)
screenOrientation = 0; screenOrientation = 0;
break; break;
@ -73,16 +74,16 @@ public abstract class DashLocationFragment extends DashBaseFragment {
break; break;
} }
//Looks like screenOrientation correction must not be applied for devices without compass? //Looks like screenOrientation correction must not be applied for devices without compass?
Sensor compass = ((SensorManager) a.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); Sensor compass = ((SensorManager) a.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
if (compass == null) { if (compass == null) {
screenOrientation = 0; screenOrientation = 0;
} }
return screenOrientation; return screenOrientation;
} }
public LatLon getDefaultLocation() { public LatLon getDefaultLocation() {
DashboardOnMap d = dashboard; DashboardOnMap d = dashboard;
if(d == null) { if (d == null) {
return null; return null;
} }
return d.getMapViewLocation(); return d.getMapViewLocation();
@ -90,7 +91,7 @@ public abstract class DashLocationFragment extends DashBaseFragment {
public void updateAllWidgets() { public void updateAllWidgets() {
DashboardOnMap d = dashboard; DashboardOnMap d = dashboard;
if(d == null) { if (d == null) {
return; return;
} }
float head = d.getHeading(); float head = d.getHeading();
@ -103,19 +104,20 @@ public abstract class DashLocationFragment extends DashBaseFragment {
LatLon loc = (useCenter ? mw : myLoc); LatLon loc = (useCenter ? mw : myLoc);
float h = useCenter ? -mapRotation : head; float h = useCenter ? -mapRotation : head;
for (DashLocationView lv : distances) { for (DashLocationView lv : distances) {
updateLocationView(useCenter, loc, h, lv.arrow, lv.arrowResId, lv.txt, lv.loc.getLatitude(), lv.loc.getLongitude(), updateLocationView(useCenter, loc, h, lv.arrow, lv.arrowResId, lv.txt, lv.loc.getLatitude(), lv.loc.getLongitude(),
screenOrientation, getMyApplication(), getActivity()); screenOrientation, getMyApplication(), getActivity(), lv.paint);
} }
} }
public static void updateLocationView(boolean useCenter, LatLon fromLoc, Float h, public static void updateLocationView(boolean useCenter, LatLon fromLoc, Float h,
ImageView arrow, TextView txt, double toLat, double toLon, ImageView arrow, TextView txt, double toLat, double toLon,
int screenOrientation, OsmandApplication app, Context ctx) { int screenOrientation, OsmandApplication app, Context ctx) {
updateLocationView(useCenter, fromLoc, h, arrow, 0, txt, toLat, toLon, screenOrientation, app, ctx); updateLocationView(useCenter, fromLoc, h, arrow, 0, txt, toLat, toLon, screenOrientation, app, ctx, true);
} }
public static void updateLocationView(boolean useCenter, LatLon fromLoc, Float h,
ImageView arrow, int arrowResId, TextView txt, double toLat, double toLon, public static void updateLocationView(boolean useCenter, LatLon fromLoc, Float h,
int screenOrientation, OsmandApplication app, Context ctx) { ImageView arrow, int arrowResId, TextView txt, double toLat, double toLon,
int screenOrientation, OsmandApplication app, Context ctx, boolean paint) {
float[] mes = new float[2]; float[] mes = new float[2];
if (fromLoc != null) { if (fromLoc != null) {
Location.distanceBetween(toLat, toLon, fromLoc.getLatitude(), fromLoc.getLongitude(), mes); Location.distanceBetween(toLat, toLon, fromLoc.getLatitude(), fromLoc.getLongitude(), mes);
@ -129,7 +131,11 @@ public abstract class DashLocationFragment extends DashBaseFragment {
arrowResId = R.drawable.ic_destination_arrow_white; arrowResId = R.drawable.ic_destination_arrow_white;
} }
DirectionDrawable dd = (DirectionDrawable) arrow.getDrawable(); DirectionDrawable dd = (DirectionDrawable) arrow.getDrawable();
dd.setImage(arrowResId, useCenter ? R.color.color_distance : R.color.color_myloc_distance); if (paint) {
dd.setImage(arrowResId, useCenter ? R.color.color_distance : R.color.color_myloc_distance);
} else {
dd.setImage(arrowResId);
}
if (fromLoc == null || h == null) { if (fromLoc == null || h == null) {
dd.setAngle(0); dd.setAngle(0);
} else { } else {
@ -139,8 +145,10 @@ public abstract class DashLocationFragment extends DashBaseFragment {
} }
if (txt != null) { if (txt != null) {
if (fromLoc != null) { if (fromLoc != null) {
txt.setTextColor(app.getResources().getColor( if (paint) {
useCenter ? R.color.color_distance : R.color.color_myloc_distance)); txt.setTextColor(app.getResources().getColor(
useCenter ? R.color.color_distance : R.color.color_myloc_distance));
}
txt.setText(OsmAndFormatter.getFormattedDistance(mes[0], app)); txt.setText(OsmAndFormatter.getFormattedDistance(mes[0], app));
} else { } else {
txt.setText(""); txt.setText("");
@ -149,7 +157,7 @@ public abstract class DashLocationFragment extends DashBaseFragment {
} }
public void updateLocation(boolean centerChanged, boolean locationChanged, boolean compassChanged) { public void updateLocation(boolean centerChanged, boolean locationChanged, boolean compassChanged) {
if(compassChanged && !dashboard.isMapLinkedToLocation()) { if (compassChanged && !dashboard.isMapLinkedToLocation()) {
return; return;
} }
updateAllWidgets(); updateAllWidgets();

View file

@ -2,6 +2,7 @@ package net.osmand.plus.parkingpoint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.util.TimeUtils; import android.support.v4.util.TimeUtils;
@ -14,11 +15,14 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import net.osmand.Location; import net.osmand.Location;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandPlugin; import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.dashboard.DashLocationFragment; import net.osmand.plus.dashboard.DashLocationFragment;
import net.osmand.plus.helpers.FontCache; import net.osmand.plus.helpers.FontCache;
import net.osmand.util.MapUtils; import net.osmand.util.MapUtils;
@ -52,6 +56,16 @@ public class DashParkingFragment extends DashLocationFragment {
}); });
remove.setTypeface(typeface); remove.setTypeface(typeface);
view.findViewById(R.id.parking_header).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LatLon point = plugin.getParkingPosition();
getMyApplication().getSettings().setMapLocationToShow(point.getLatitude(), point.getLongitude(),
15, new PointDescription(PointDescription.POINT_TYPE_FAVORITE, plugin.getParkingDescription(getActivity())), true,
point); //$NON-NLS-1$
MapActivity.launchMapActivityMoveToTop(getActivity());
}
});
return view; return view;
} }
@ -75,29 +89,36 @@ public class DashParkingFragment extends DashLocationFragment {
LatLon loc = getDefaultLocation(); LatLon loc = getDefaultLocation();
LatLon position = plugin.getParkingPosition(); LatLon position = plugin.getParkingPosition();
boolean limited = plugin.getParkingType(); boolean limited = plugin.getParkingType();
String parking_name = limited ? String parking_name = limited ?
getString(R.string.parking_place_limited) : getString(R.string.parking_place); getString(R.string.parking_place_limited) : getString(R.string.parking_place);
if (limited) { if (limited) {
long endtime = plugin.getParkingTime(); long endtime = plugin.getParkingTime();
long currTime = Calendar.getInstance().getTimeInMillis(); long currTime = Calendar.getInstance().getTimeInMillis();
String time = getFormattedTime(endtime - currTime); long timeDiff = endtime - currTime;
((TextView)mainView.findViewById(R.id.time_left)).setText(time); String time = getFormattedTime(timeDiff);
TextView time_left = ((TextView) mainView.findViewById(R.id.time_left));
time_left.setText(time);
if (timeDiff < 0) {
time_left.setTextColor(Color.RED);
} else {
time_left.setTextColor(Color.WHITE);
}
mainView.findViewById(R.id.left_lbl).setVisibility(View.VISIBLE); mainView.findViewById(R.id.left_lbl).setVisibility(View.VISIBLE);
} else { } else {
((TextView)mainView.findViewById(R.id.time_left)).setText(""); ((TextView) mainView.findViewById(R.id.time_left)).setText("");
mainView.findViewById(R.id.left_lbl).setVisibility(View.GONE); mainView.findViewById(R.id.left_lbl).setVisibility(View.GONE);
} }
((TextView) mainView.findViewById(R.id.name)).setText(parking_name); ((TextView) mainView.findViewById(R.id.name)).setText(parking_name);
ImageView direction = (ImageView) mainView.findViewById(R.id.direction_icon); ImageView direction = (ImageView) mainView.findViewById(R.id.direction_icon);
if (loc != null){ if (loc != null) {
DashLocationView dv = new DashLocationView(direction, (TextView) mainView.findViewById(R.id.distance), position); DashLocationView dv = new DashLocationView(direction, (TextView) mainView.findViewById(R.id.distance), position);
dv.paint = false;
dv.arrowResId = R.drawable.ic_parking_postion_arrow; dv.arrowResId = R.drawable.ic_parking_postion_arrow;
distances.add(dv); distances.add(dv);
} }
} }
String getFormattedTime(long timeInMillis) { String getFormattedTime(long timeInMillis) {
@ -106,16 +127,19 @@ public class DashParkingFragment extends DashLocationFragment {
} }
StringBuilder timeStringBuilder = new StringBuilder(); StringBuilder timeStringBuilder = new StringBuilder();
int hours = (int) timeInMillis / (1000 * 60 * 60); int hours = (int) timeInMillis / (1000 * 60 * 60);
int miutes = (int) timeInMillis / (1000 * 60 * 60 * 60); int minutes = (int) timeInMillis / (1000 * 60);
if (hours > 0) { if (hours > 0) {
timeStringBuilder.append(hours); timeStringBuilder.append(hours);
timeStringBuilder.append(" "); timeStringBuilder.append(" ");
timeStringBuilder.append(getResources().getString(R.string.osmand_parking_hour)); timeStringBuilder.append(getResources().getString(R.string.osmand_parking_hour));
} }
timeStringBuilder.append(" "); timeStringBuilder.append(" ");
timeStringBuilder.append(miutes); timeStringBuilder.append(minutes);
timeStringBuilder.append(" "); timeStringBuilder.append(" ");
timeStringBuilder.append(getResources().getString(R.string.osmand_parking_minute)); timeStringBuilder.append(getResources().getString(R.string.osmand_parking_minute));
return timeStringBuilder.toString(); return timeStringBuilder.toString();
} }
} }

View file

@ -136,45 +136,12 @@ public class ParkingPositionLayer extends OsmandMapLayer implements ContextMenuL
@Override @Override
public String getObjectDescription(Object o) { public String getObjectDescription(Object o) {
if (o instanceof LatLon) { return plugin.getParkingDescription(map);
StringBuilder timeLimitDesc = new StringBuilder();
timeLimitDesc.append(map.getString(R.string.osmand_parking_position_description_add_time) + " ");
timeLimitDesc.append(getFormattedTime(plugin.getStartParkingTime()) + ".");
if (plugin.getParkingType()) {
// long parkingTime = settings.getParkingTime();
// long parkingStartTime = settings.getStartParkingTime();
// Time time = new Time();
// time.set(parkingTime);
// timeLimitDesc.append(map.getString(R.string.osmand_parking_position_description_add) + " ");
// timeLimitDesc.append(time.hour);
// timeLimitDesc.append(":");
// int minute = time.minute;
// timeLimitDesc.append(minute<10 ? "0" + minute : minute);
// if (!DateFormat.is24HourFormat(map.getApplicationContext())) {
// timeLimitDesc.append(time.hour >= 12 ? map.getString(R.string.osmand_parking_pm) :
// map.getString(R.string.osmand_parking_am));
// }
timeLimitDesc.append(map.getString(R.string.osmand_parking_position_description_add) + " ");
timeLimitDesc.append(getFormattedTime(plugin.getParkingTime()));
}
return map.getString(R.string.osmand_parking_position_description, timeLimitDesc.toString());
}
return null;
} }
String getFormattedTime(long timeInMillis) { public String getFormattedTime(long time){
StringBuilder timeStringBuilder = new StringBuilder(); return plugin.getFormattedTime(time, map);
Time time = new Time();
time.set(timeInMillis);
timeStringBuilder.append(time.hour);
timeStringBuilder.append(":");
int minute = time.minute;
timeStringBuilder.append(minute < 10 ? "0" + minute : minute);
if (!DateFormat.is24HourFormat(map)) {
timeStringBuilder.append(time.hour >= 12 ? map.getString(R.string.osmand_parking_pm) : map
.getString(R.string.osmand_parking_am));
}
return timeStringBuilder.toString();
} }
@Override @Override

View file

@ -27,6 +27,8 @@ import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.graphics.Paint; import android.graphics.Paint;
import android.text.format.DateFormat;
import android.text.format.Time;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CheckBox; import android.widget.CheckBox;
@ -524,4 +526,43 @@ public class ParkingPositionPlugin extends OsmandPlugin {
public int getLogoResourceId() { public int getLogoResourceId() {
return R.drawable.ic_action_parking_dark; return R.drawable.ic_action_parking_dark;
} }
String getFormattedTime(long timeInMillis, Activity ctx) {
StringBuilder timeStringBuilder = new StringBuilder();
Time time = new Time();
time.set(timeInMillis);
timeStringBuilder.append(time.hour);
timeStringBuilder.append(":");
int minute = time.minute;
timeStringBuilder.append(minute < 10 ? "0" + minute : minute);
if (!DateFormat.is24HourFormat(ctx)) {
timeStringBuilder.append(time.hour >= 12 ? ctx.getString(R.string.osmand_parking_pm) : ctx
.getString(R.string.osmand_parking_am));
}
return timeStringBuilder.toString();
}
public String getParkingDescription(Activity ctx) {
StringBuilder timeLimitDesc = new StringBuilder();
timeLimitDesc.append(ctx.getString(R.string.osmand_parking_position_description_add_time) + " ");
timeLimitDesc.append(getFormattedTime(getStartParkingTime(), ctx) + ".");
if (getParkingType()) {
// long parkingTime = settings.getParkingTime();
// long parkingStartTime = settings.getStartParkingTime();
// Time time = new Time();
// time.set(parkingTime);
// timeLimitDesc.append(map.getString(R.string.osmand_parking_position_description_add) + " ");
// timeLimitDesc.append(time.hour);
// timeLimitDesc.append(":");
// int minute = time.minute;
// timeLimitDesc.append(minute<10 ? "0" + minute : minute);
// if (!DateFormat.is24HourFormat(map.getApplicationContext())) {
// timeLimitDesc.append(time.hour >= 12 ? map.getString(R.string.osmand_parking_pm) :
// map.getString(R.string.osmand_parking_am));
// }
timeLimitDesc.append(ctx.getString(R.string.osmand_parking_position_description_add) + " ");
timeLimitDesc.append(getFormattedTime(getParkingTime(),ctx));
}
return ctx.getString(R.string.osmand_parking_position_description, timeLimitDesc.toString());
}
} }

View file

@ -33,6 +33,11 @@ public class DirectionDrawable extends Drawable {
arrowImage = iconsCache.getIcon(resourceId, clrId); arrowImage = iconsCache.getIcon(resourceId, clrId);
} }
public void setImage(int resourceId){
IconsCache iconsCache = ((OsmandApplication) ctx.getApplicationContext()).getIconsCache();
arrowImage = iconsCache.getIcon(resourceId, 0);
}
public DirectionDrawable(Context ctx, float width, float height) { public DirectionDrawable(Context ctx, float width, float height) {
this.ctx = ctx; this.ctx = ctx;