diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml
index 7a6ef64..c7cf8d3 100644
--- a/ln_jq_app/android/app/src/main/AndroidManifest.xml
+++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml
@@ -14,7 +14,12 @@
-
+
+
+
+
+
+
@@ -30,6 +35,11 @@
+
+
stationMarkers = new ArrayList<>();
public NativeMapView(Context context, int id, Object args) {
this.mContext = context;
- // 隐私合规接口,必须在创建MapView之前设置
+ // 尝试获取Activity引用
+ mActivity = getActivityFromContext(context);
+
MapsInitializer.updatePrivacyShow(context, true, true);
MapsInitializer.updatePrivacyAgree(context, true);
+ container = new FrameLayout(context);
+ container.setClickable(true);
+ container.setFocusable(true);
+
mapView = new MapView(context);
- // 在 Flutter PlatformView 中,savedInstanceState 通常为 null
- mapView.onCreate(null);
+ mapView.onCreate(null);
aMap = mapView.getMap();
- // 设置地图的 UI 选项
+ container.addView(mapView, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+ initServices(context);
+ initOverlays(context);
setupMapUi();
- // 注册到 MainActivity 以便同步生命周期
+ // 通知MainActivity
if (context instanceof MainActivity) {
((MainActivity) context).setMapView(this);
}
+
+ Log.d(TAG, "NativeMapView初始化完成");
+ }
+
+ /**
+ * 初始化服务
+ */
+ private void initServices(Context context) {
+ try {
+ geocoderSearch = new GeocodeSearch(context);
+ geocoderSearch.setOnGeocodeSearchListener(this);
+ routeSearch = new RouteSearch(context);
+ routeSearch.setRouteSearchListener(this);
+ } catch (AMapException e) {
+ Log.e(TAG, "服务初始化失败", e);
+ }
+ }
+
+ /**
+ * 初始化覆盖层UI
+ */
+ private void initOverlays(Context context) {
+ LinearLayout searchBox = new LinearLayout(context);
+ searchBox.setOrientation(LinearLayout.VERTICAL);
+ searchBox.setBackground(getRoundedDrawable(Color.WHITE, 12));
+ searchBox.setElevation(dp2px(8));
+ int p = dp2px(15);
+ searchBox.setPadding(p, p, p, p);
+ searchBox.setClickable(true);
+ searchBox.setFocusable(true);
+
+ startInput = createInput(context, "起点: 正在定位...");
+ searchBox.addView(startInput);
+
+ View vSpace = new View(context);
+ searchBox.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(10)));
+
+ LinearLayout endRow = new LinearLayout(context);
+ endRow.setOrientation(LinearLayout.HORIZONTAL);
+ endRow.setGravity(Gravity.CENTER_VERTICAL);
+
+ endInput = createInput(context, "终点: 请输入目的地");
+ endRow.addView(endInput, new LinearLayout.LayoutParams(0, dp2px(42), 1f));
+
+ Button routeBtn = new Button(context);
+ routeBtn.setText("路径规划");
+ routeBtn.setTextColor(Color.WHITE);
+ routeBtn.setAllCaps(false);
+ routeBtn.setTextSize(14);
+ routeBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 6));
+ routeBtn.setOnClickListener(v -> startRouteSearch());
+ endRow.addView(routeBtn, new LinearLayout.LayoutParams(dp2px(90), dp2px(42)));
+
+ searchBox.addView(endRow);
+
+ FrameLayout.LayoutParams searchParams = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ searchParams.setMargins(dp2px(15), dp2px(50), dp2px(15), 0);
+ container.addView(searchBox, searchParams);
+
+ ImageButton locBtn = new ImageButton(context);
+ locBtn.setImageResource(android.R.drawable.ic_menu_mylocation);
+ locBtn.setBackground(getRoundedDrawable(Color.WHITE, 30));
+ locBtn.setElevation(dp2px(4));
+ locBtn.setOnClickListener(v -> {
+ if (currentLatLng != null) {
+ aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f));
+ }
+ });
+ FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(50), dp2px(50));
+ locParams.setMargins(0, 0, dp2px(20), dp2px(120));
+ locParams.gravity = Gravity.BOTTOM | Gravity.END;
+ container.addView(locBtn, locParams);
+ }
+
+ private EditText createInput(Context context, String hint) {
+ EditText et = new EditText(context);
+ et.setHint(hint);
+ et.setTextSize(14f);
+ et.setTextColor(Color.BLACK);
+ et.setPadding(dp2px(12), dp2px(10), dp2px(12), dp2px(10));
+ et.setBackground(getRoundedDrawable(Color.parseColor("#F5F5F5"), 6));
+ et.setSingleLine(true);
+ et.setImeOptions(EditorInfo.IME_ACTION_DONE);
+ et.setFocusable(true);
+ et.setFocusableInTouchMode(true);
+ return et;
+ }
+
+ private GradientDrawable getRoundedDrawable(int color, int radiusDp) {
+ GradientDrawable shape = new GradientDrawable();
+ shape.setShape(GradientDrawable.RECTANGLE);
+ shape.setCornerRadius(dp2px(radiusDp));
+ shape.setColor(color);
+ return shape;
+ }
+
+ private int dp2px(float dp) {
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics());
}
private void setupMapUi() {
aMap.setLocationSource(this);
aMap.setMyLocationEnabled(true);
+ aMap.setOnMarkerClickListener(this);
MyLocationStyle myLocationStyle = new MyLocationStyle();
- myLocationStyle.interval(2000);
- // 连续定位并将视角移动到地图中心点,定位蓝点跟随设备移动
- myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE);
+
+ // --- 放大定位图标 ---
+ try {
+ Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car);
+ if (carBitmap != null) {
+ // 放大到 80dp
+ int iconSize = dp2px(25);
+ Bitmap scaledBitmap = Bitmap.createScaledBitmap(carBitmap, iconSize, iconSize, true);
+ myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "设置大图标失败", e);
+ }
+
+ myLocationStyle.anchor(0.5f, 0.5f);
+ myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);
myLocationStyle.showMyLocation(true);
myLocationStyle.strokeColor(Color.TRANSPARENT);
myLocationStyle.radiusFillColor(Color.TRANSPARENT);
aMap.setMyLocationStyle(myLocationStyle);
-
- // 显示缩放按钮
+
aMap.getUiSettings().setZoomControlsEnabled(true);
+ aMap.getUiSettings().setScaleControlsEnabled(true);
+ aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);
}
- @Override
- public View getView() {
- return mapView;
- }
-
+ // ==================== LocationSource 接口实现 ====================
@Override
public void activate(OnLocationChangedListener listener) {
mListener = listener;
@@ -88,56 +291,405 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation
public void startLocation() {
if (mlocationClient == null) {
try {
- AMapLocationClient.updatePrivacyShow(mContext, true, true);
- AMapLocationClient.updatePrivacyAgree(mContext, true);
mlocationClient = new AMapLocationClient(mContext);
- AMapLocationClientOption mLocationOption = new AMapLocationClientOption();
+ AMapLocationClientOption option = new AMapLocationClientOption();
mlocationClient.setLocationListener(this);
- mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
- mlocationClient.setLocationOption(mLocationOption);
+ option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
+ mlocationClient.setLocationOption(option);
mlocationClient.startLocation();
+ Log.d(TAG, "定位启动成功");
} catch (Exception e) {
- Log.e(TAG, "startLocation error", e);
+ Log.e(TAG, "定位启动失败", e);
}
}
}
@Override
- public void onLocationChanged(AMapLocation amapLocation) {
- if (mListener != null && amapLocation != null) {
- if (amapLocation.getErrorCode() == 0) {
- mListener.onLocationChanged(amapLocation);
- // 首次定位成功后缩放地图
- // aMap.moveCamera(CameraUpdateFactory.zoomTo(15));
- } else {
- Log.e(TAG, "定位失败," + amapLocation.getErrorCode() + ": " + amapLocation.getErrorInfo());
+ public void onLocationChanged(AMapLocation loc) {
+ if (loc != null) {
+ if (mListener != null) {
+ mListener.onLocationChanged(loc);
+ }
+ currentLatLng = new LatLng(loc.getLatitude(), loc.getLongitude());
+
+ if (loc.getErrorCode() == 0) {
+ if (isFirstLocation) {
+ isFirstLocation = false;
+ startPoint = currentLatLng;
+ aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f));
+ getAddressByLatlng(currentLatLng);
+ fetchRecommendStation(loc);
+ fetchNearbyStations(loc);
+ }
}
}
}
- public void onResume() {
- if (mapView != null) {
- mapView.onResume();
+ // ==================== 逆地理编码 ====================
+ private void getAddressByLatlng(LatLng latLng) {
+ LatLonPoint point = new LatLonPoint(latLng.latitude, latLng.longitude);
+ RegeocodeQuery query = new RegeocodeQuery(point, 200, GeocodeSearch.AMAP);
+ geocoderSearch.getFromLocationAsyn(query);
+ }
+
+ @Override
+ public void onRegeocodeSearched(RegeocodeResult result, int rCode) {
+ if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && result.getRegeocodeAddress() != null) {
+ RegeocodeAddress addr = result.getRegeocodeAddress();
+ String fullAddr = addr.getFormatAddress();
+
+ // 优化地址显示逻辑
+ startName = formatAddress(fullAddr,result);
+
+ new Handler(Looper.getMainLooper()).post(() -> {
+ startInput.setText(startName);
+ startInput.setSelection(startName.length()); // 光标移到末尾
+ });
+
+ Log.d(TAG, "逆地理编码成功: " + startName);
+ } else {
+ Log.e(TAG, "逆地理编码失败: code=" + rCode + ", result=" + (result != null ? "null" : "has data"));
}
}
+ /**
+ * 格式化地址显示,移除重复的前缀并限制长度
+ */
+ private String formatAddress(String fullAddress,RegeocodeResult result) {
+ if (fullAddress == null || fullAddress.isEmpty()) {
+ return "未知地点";
+ }
+
+ // 获取各级地址信息
+ String province = null;
+ String city = null;
+ String district = null;
+ String township = null;
+
+ try {
+ if (result.getRegeocodeAddress() != null) {
+ RegeocodeAddress addr = result.getRegeocodeAddress();
+ province = addr.getProvince();
+ city = addr.getCity();
+ district = addr.getDistrict();
+ township = addr.getTownship();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "获取地址信息失败", e);
+ }
+
+ String formattedAddr = fullAddress;
+
+ // 按优先级移除重复前缀(省、市、区、乡)
+ String[] prefixes = {province, city, district, township};
+ for (String prefix : prefixes) {
+ if (prefix != null && !prefix.isEmpty() && formattedAddr.startsWith(prefix)) {
+ formattedAddr = formattedAddr.substring(prefix.length());
+ Log.d(TAG, "移除前缀: " + prefix + " -> " + formattedAddr);
+ }
+ }
+
+ // 限制地址长度并添加省略号
+ if (formattedAddr.length() > 25) {
+ formattedAddr = formattedAddr.substring(0, 25) + "...";
+ Log.d(TAG, "地址长度截断: " + formattedAddr);
+ }
+
+ return formattedAddr;
+ }
+
+ @Override
+ public void onGeocodeSearched(GeocodeResult result, int rCode) {
+ }
+
+ // ==================== API请求 ====================
+
+ private void fetchRecommendStation(AMapLocation loc) {
+ try {
+ JSONObject json = new JSONObject();
+ json.put("province", loc.getProvince() != null ? loc.getProvince() : "");
+ json.put("city", loc.getCity() != null && !loc.getCity().isEmpty() ? loc.getCity() : "");
+ json.put("district", loc.getDistrict() != null ? loc.getDistrict() : "");
+ json.put("longitude", String.valueOf(loc.getLongitude()));
+ json.put("latitude", String.valueOf(loc.getLatitude()));
+
+ RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8"));
+ Request request = new Request.Builder()
+ .url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea")
+ .post(body)
+ .build();
+
+ httpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
+ }
+
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
+ if (response.isSuccessful() && response.body() != null) {
+ try {
+ JSONObject res = new JSONObject(response.body().string());
+ if (res.getInt("code") == 0 && !res.isNull("data")) {
+ JSONObject data = res.getJSONObject("data");
+ endPoint = new LatLng(data.getDouble("latitude"), data.getDouble("longitude"));
+ endName = data.getString("name");
+ String addr = data.optString("address", "");
+ new Handler(Looper.getMainLooper()).post(() -> {
+ endInput.setText(addr);
+ markStation(endPoint, endName, true);
+ });
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void fetchNearbyStations(AMapLocation loc) {
+ try {
+ JSONObject json = new JSONObject();
+ json.put("longitude", String.valueOf(loc.getLongitude()));
+ json.put("latitude", String.valueOf(loc.getLatitude()));
+
+ RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8"));
+ Request request = new Request.Builder()
+ .url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation")
+ .post(body)
+ .build();
+
+ httpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
+ }
+
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
+ if (response.isSuccessful() && response.body() != null) {
+ try {
+ JSONObject res = new JSONObject(response.body().string());
+ if (res.getInt("code") == 0 && !res.isNull("data")) {
+ JSONArray array = res.getJSONArray("data");
+ new Handler(Looper.getMainLooper()).post(() -> {
+ for (int i = 0; i < array.length(); i++) {
+ try {
+ JSONObject item = array.getJSONObject(i);
+ markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")),
+ item.getString("name"), false);
+ } catch (Exception ignored) {
+ }
+ }
+ });
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void markStation(LatLng latLng, String name, boolean isRecommend) {
+ MarkerOptions opt = new MarkerOptions()
+ .position(latLng).title(name)
+ .icon(BitmapDescriptorFactory.defaultMarker(isRecommend ? BitmapDescriptorFactory.HUE_RED : BitmapDescriptorFactory.HUE_GREEN));
+ Marker m = aMap.addMarker(opt);
+ m.setObject(latLng);
+ stationMarkers.add(m);
+ }
+
+ @Override
+ public boolean onMarkerClick(Marker marker) {
+ if (marker.getObject() instanceof LatLng) {
+ endPoint = (LatLng) marker.getObject();
+ endName = marker.getTitle();
+ endInput.setText(endName);
+ startRouteSearch();
+ }
+ return true;
+ }
+
+ // ==================== 路径规划 ====================
+
+ private void startRouteSearch() {
+ if (startPoint == null || endPoint == null) {
+ Toast.makeText(mContext, "正在定位中,请稍后...", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Poi start = new Poi(startName, startPoint, "");
+ Poi end = new Poi(endName, endPoint, "");
+
+ AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE);
+
+ try {
+ AMapNavi mAMapNavi = AMapNavi.getInstance(mContext);
+ AMapCarInfo carInfo = new AMapCarInfo();
+ carInfo.setCarNumber("沪AGK2267");
+ carInfo.setCarType("1");
+ carInfo.setVehicleAxis("6");
+ carInfo.setVehicleHeight("3.32");
+ carInfo.setVehicleLength("6.9");
+ carInfo.setVehicleWidth("2.26");
+ carInfo.setVehicleSize("2");
+ carInfo.setVehicleLoad("4.5");
+ carInfo.setVehicleWeight("4.5");
+ carInfo.setRestriction(true);
+ carInfo.setVehicleLoadSwitch(true);
+ mAMapNavi.setCarInfo(carInfo);
+ } catch (com.amap.api.maps.AMapException e) {
+ Log.e(TAG, "设置车辆信息失败", e);
+ }
+
+ params.setRouteStrategy(PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT);
+
+ if (mActivity != null) {
+ AmapNaviPage.getInstance().showRouteActivity(mActivity, params, new INaviInfoCallback() {
+ @Override
+ public void onInitNaviFailure() {
+ Log.e(TAG, "导航初始化失败");
+ }
+
+ @Override
+ public void onGetNavigationText(String s) {
+ }
+
+ @Override
+ public void onLocationChange(AMapNaviLocation location) {
+ }
+
+ @Override
+ public void onArriveDestination(boolean b) {
+ }
+
+ @Override
+ public void onStartNavi(int i) {
+ }
+
+ @Override
+ public void onCalculateRouteSuccess(int[] ints) {
+ }
+
+ @Override
+ public void onCalculateRouteFailure(int i) {
+ }
+
+ @Override
+ public void onStopSpeaking() {
+ }
+
+ @Override
+ public void onReCalculateRoute(int i) {
+
+ }
+
+ @Override
+ public void onArrivedWayPoint(int i) {
+ }
+
+ @Override
+ public void onExitPage(int i) {
+ }
+
+ @Override
+ public void onStrategyChanged(int i) {
+ }
+
+ @Override
+ public void onMapTypeChanged(int i) {
+ }
+
+ @Override
+ public void onNaviDirectionChanged(int i) {
+ }
+
+ @Override
+ public void onDayAndNightModeChanged(int i) {
+ }
+
+ @Override
+ public void onBroadcastModeChanged(int i) {
+ }
+
+ @Override
+ public void onScaleAutoChanged(boolean b) {
+ }
+
+ @Override
+ public View getCustomNaviBottomView() {
+ return null;
+ }
+
+ @Override
+ public View getCustomNaviView() {
+ return null;
+ }
+
+ @Override
+ public View getCustomMiddleView() {
+ return null;
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onDriveRouteSearched(DriveRouteResult result, int rCode) {
+ }
+
+ @Override
+ public void onBusRouteSearched(BusRouteResult r, int c) {
+ }
+
+ @Override
+ public void onWalkRouteSearched(WalkRouteResult r, int c) {
+ }
+
+ @Override
+ public void onRideRouteSearched(RideRouteResult r, int c) {
+ }
+
+ private Activity getActivityFromContext(Context context) {
+ if (context instanceof Activity)
+ return (Activity) context;
+ if (context instanceof android.content.ContextWrapper) {
+ Context base = ((android.content.ContextWrapper) context).getBaseContext();
+ if (base instanceof Activity)
+ return (Activity) base;
+ }
+ return null;
+ }
+
+ public void onResume() {
+ mapView.onResume();
+ }
+
public void onPause() {
- if (mapView != null) {
- mapView.onPause();
- }
+ mapView.onPause();
}
- public void onSaveInstanceState(Bundle outState) {
- if (mapView != null) {
- mapView.onSaveInstanceState(outState);
- }
+ public void onSaveInstanceState(Bundle out) {
+ mapView.onSaveInstanceState(out);
+ }
+
+ @Override
+ public View getView() {
+ return container;
}
@Override
public void dispose() {
- if (mapView != null) {
- mapView.onDestroy();
+ if (mlocationClient != null) {
+ mlocationClient.stopLocation();
+ mlocationClient.onDestroy();
}
- deactivate();
+ mapView.onDestroy();
}
}
diff --git a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml b/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml
deleted file mode 100644
index a58e47e..0000000
--- a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/ln_jq_app/android/app/src/main/res/drawable/car.png b/ln_jq_app/android/app/src/main/res/drawable/car.png
new file mode 100644
index 0000000..5f5ba0a
Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/car.png differ
diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml
deleted file mode 100644
index 58bb442..0000000
--- a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml
deleted file mode 100644
index 4e99139..0000000
--- a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml
deleted file mode 100644
index e16e2fe..0000000
--- a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml
deleted file mode 100644
index 0af42cf..0000000
--- a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml
deleted file mode 100644
index ef73731..0000000
--- a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png b/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png
new file mode 100644
index 0000000..dcae650
Binary files /dev/null and b/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png differ