2026-04-03-maplibra come next

This commit is contained in:
Hamza-Ayed
2026-04-03 16:23:14 +03:00
parent c6b27d06d4
commit e325405dff
13 changed files with 363 additions and 830 deletions

View File

@@ -30,6 +30,7 @@ android {
version "3.22.1"
}
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
@@ -47,8 +48,8 @@ android {
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdkVersion = 24
targetSdk = 36
versionCode = 60
versionName = '1.1.60'
versionCode = 63
versionName = '1.1.63'
multiDexEnabled = true
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"

View File

@@ -1,7 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.Intaleq.intaleq">
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
@@ -14,9 +13,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
@@ -30,7 +26,6 @@
android:usesCleartextTraffic="false"
android:networkSecurityConfig="@xml/network_security_config">
<!-- ✅ مهم جداً: تعريف أن المشروع يستخدم V2 Embedding -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
@@ -39,49 +34,37 @@
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:supportsPictureInPicture="true"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Flutter -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<!-- Launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 🔗 App Links -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="intaleqapp.com"
android:pathPrefix="/" />
<data
android:scheme="https"
android:host="www.intaleqapp.com"
<data android:scheme="https" android:host="intaleqapp.com" android:pathPrefix="/" />
<data android:scheme="https" android:host="www.intaleqapp.com"
android:pathPrefix="/" />
</intent-filter>
<!-- 🔗 Custom Scheme -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="intaleq" />
</intent-filter>
<!-- 🔗 Intercept Geo URIs (geo:lat,lng) -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
@@ -89,34 +72,16 @@
<data android:scheme="geo" />
</intent-filter>
<!-- 🔗 Intercept External Map URLs (Google/Apple) -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="maps.google.com" />
<data android:scheme="https" android:host="maps.google.com" />
<data android:scheme="https" android:host="maps.apple.com" />
<data android:scheme="https" android:host="goo.gl" />
<data android:scheme="http" android:host="goo.gl" />
<data android:scheme="https" android:host="maps.app.goo.gl" />
<data android:scheme="http" android:host="maps.app.goo.gl" />
</intent-filter>
</activity>
<!-- Google Maps API -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${mapsApiKey}" />
<!-- Firebase Notification Channel -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
<!-- Local Notifications Receivers -->
<receiver
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver"
android:exported="false" />
@@ -129,12 +94,7 @@
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<service
android:name=".RideTrackingService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location" />
<!-- UCrop -->
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"

View File

@@ -1,8 +1,12 @@
package com.Intaleq.intaleq
import android.app.AlertDialog
import android.app.PictureInPictureParams
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.Rational
import android.widget.LinearLayout
import android.widget.ProgressBar
import android.widget.TextView
@@ -21,8 +25,9 @@ class MainActivity : FlutterFragmentActivity() {
private val SECURITY_CHANNEL_NAME = "com.Intaleq.intaleq/security"
private lateinit var securityChannel: MethodChannel
// قناة تتبّع الرحلة (Live Activity على أندرويد)
private val RIDE_TRACKING_CHANNEL = "intaleq/ride_tracking"
// قناة PiP الجديدة
private val PIP_CHANNEL = "intaleq/pip"
private var pipEnabled = false // هل الرحلة نشطة ويجب تفعيل PiP عند الخروج؟
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
@@ -43,50 +48,24 @@ class MainActivity : FlutterFragmentActivity() {
}
}
// -------- 2) قناة تتبع الرحلة (Ride Tracking) --------
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, RIDE_TRACKING_CHANNEL)
// -------- 2) قناة PiP (Picture-in-Picture) --------
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, PIP_CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
"updateRideTracking" -> {
val driverName = call.argument<String>("driverName") ?: "السائق"
val driverPhone = call.argument<String>("driverPhone") ?: ""
val carDetails = call.argument<String>("carDetails") ?: ""
val driverLat = call.argument<Double>("driverLat") ?: 0.0
val driverLng = call.argument<Double>("driverLng") ?: 0.0
val passengerLat = call.argument<Double>("passengerLat") ?: 0.0
val passengerLng = call.argument<Double>("passengerLng") ?: 0.0
val destLat = call.argument<Double>("destLat") ?: 0.0
val destLng = call.argument<Double>("destLng") ?: 0.0
val rideState =
call.argument<String>("rideState")
?: "waiting" // "waiting" أو "inProgress"
val estimatedTime = call.argument<Int>("estimatedTime") ?: 5 // بالدقائق
val totalDistance =
call.argument<Double>("totalDistance") ?: 0.0 // بالمتر
RideTrackingService.startOrUpdate(
context = this,
driverName = driverName,
driverPhone = driverPhone,
carDetails = carDetails,
driverLat = driverLat,
driverLng = driverLng,
passengerLat = passengerLat,
passengerLng = passengerLng,
destLat = destLat,
destLng = destLng,
rideState = rideState,
estimatedTime = estimatedTime,
totalDistance = totalDistance
)
result.success(null)
"enablePip" -> {
pipEnabled = true
result.success(true)
}
"stopRideTracking" -> {
RideTrackingService.stop(this)
result.success(null)
"disablePip" -> {
pipEnabled = false
result.success(true)
}
"enterPip" -> {
val success = enterPipMode()
result.success(success)
}
"isPipSupported" -> {
result.success(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
}
else -> {
result.notImplemented()
@@ -95,6 +74,39 @@ class MainActivity : FlutterFragmentActivity() {
}
}
// -------- PiP Helper Methods --------
private fun enterPipMode(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val params = PictureInPictureParams.Builder()
.setAspectRatio(Rational(9, 16)) // نسبة عمودية مناسبة لعرض الخريطة
.build()
return enterPictureInPictureMode(params)
}
return false
}
// عند ضغط المستخدم على زر الرجوع للشاشة الرئيسية أثناء رحلة نشطة
override fun onUserLeaveHint() {
super.onUserLeaveHint()
if (pipEnabled) {
enterPipMode()
}
}
// إعلام Flutter بتغيير وضع PiP
override fun onPictureInPictureModeChanged(
isInPipMode: Boolean,
newConfig: Configuration
) {
super.onPictureInPictureModeChanged(isInPipMode, newConfig)
// يمكن لاحقاً إرسال حدث لـ Flutter لإخفاء/إظهار عناصر الواجهة
flutterEngine?.dartExecutor?.binaryMessenger?.let { messenger ->
MethodChannel(messenger, PIP_CHANNEL)
.invokeMethod("onPipChanged", isInPipMode)
}
}
// ---------------- أمن الجهاز (كما عندك تقريباً) ----------------
override fun onCreate(savedInstanceState: Bundle?) {

View File

@@ -1,373 +0,0 @@
package com.Intaleq.intaleq
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import kotlin.math.*
class RideTrackingService : Service() {
companion object {
private const val TAG = "RideTrackingService"
const val CHANNEL_ID = "TRIP_LIVE_ACTIVITY_CHANNEL"
const val NOTIFICATION_ID = 1001
fun startOrUpdate(
context: Context,
driverName: String,
driverPhone: String,
carDetails: String,
driverLat: Double,
driverLng: Double,
passengerLat: Double,
passengerLng: Double,
destLat: Double,
destLng: Double,
rideState: String,
estimatedTime: Int,
totalDistance: Double
) {
val intent =
Intent(context, RideTrackingService::class.java).apply {
putExtra("driverName", driverName)
putExtra("driverPhone", driverPhone)
putExtra("carDetails", carDetails)
putExtra("driverLat", driverLat)
putExtra("driverLng", driverLng)
putExtra("passengerLat", passengerLat)
putExtra("passengerLng", passengerLng)
putExtra("destLat", destLat)
putExtra("destLng", destLng)
putExtra("rideState", rideState)
putExtra("estimatedTime", estimatedTime)
putExtra("totalDistance", totalDistance)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
fun stop(context: Context) {
val intent = Intent(context, RideTrackingService::class.java)
context.stopService(intent)
}
}
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationCallback: LocationCallback
private lateinit var notificationManager: NotificationManager
private var driverLatitude = 0.0
private var driverLongitude = 0.0
private var passengerLatitude = 0.0
private var passengerLongitude = 0.0
private var destinationLatitude = 0.0
private var destinationLongitude = 0.0
private var rideState: String = "waiting"
private var driverName: String = "السائق"
private var driverPhone: String = ""
private var carDetails: String = ""
private var estimatedTimeMinutes: Int = 0
private var totalDistanceMeters: Double = 0.0
private var distanceCoveredMeters: Double = 0.0
private var initialDriverDistanceToPassenger: Double = -1.0
override fun onCreate() {
super.onCreate()
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
setupLocationCallback()
createNotificationChannel()
Log.d(TAG, "Service Created")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "Service Started")
intent?.let {
driverName = it.getStringExtra("driverName") ?: "السائق"
driverPhone = it.getStringExtra("driverPhone") ?: ""
carDetails = it.getStringExtra("carDetails") ?: ""
driverLatitude = it.getDoubleExtra("driverLat", 0.0)
driverLongitude = it.getDoubleExtra("driverLng", 0.0)
passengerLatitude = it.getDoubleExtra("passengerLat", 0.0)
passengerLongitude = it.getDoubleExtra("passengerLng", 0.0)
destinationLatitude = it.getDoubleExtra("destLat", 0.0)
destinationLongitude = it.getDoubleExtra("destLng", 0.0)
rideState = it.getStringExtra("rideState") ?: "waiting"
estimatedTimeMinutes = it.getIntExtra("estimatedTime", 5)
totalDistanceMeters = it.getDoubleExtra("totalDistance", 0.0)
}
if (rideState == "waiting" && initialDriverDistanceToPassenger < 0) {
val currentDist =
calculateDistance(
passengerLatitude,
passengerLongitude,
driverLatitude,
driverLongitude
)
initialDriverDistanceToPassenger =
if (totalDistanceMeters > currentDist) totalDistanceMeters else currentDist
}
startForeground(NOTIFICATION_ID, createNotification())
startLocationUpdates()
return START_STICKY
}
private fun setupLocationCallback() {
locationCallback =
object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
for (location in locationResult.locations) {
passengerLatitude = location.latitude
passengerLongitude = location.longitude
if (rideState == "inProgress" && totalDistanceMeters > 0) {
val remainingToDest =
calculateDistance(
passengerLatitude,
passengerLongitude,
destinationLatitude,
destinationLongitude
)
distanceCoveredMeters =
(totalDistanceMeters - remainingToDest).coerceAtLeast(0.0)
}
updateNotification()
}
}
}
}
private fun startLocationUpdates() {
val locationRequest =
LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 5000L)
.setMinUpdateIntervalMillis(2000L)
.build()
try {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
} catch (e: SecurityException) {
Log.e(TAG, "Location permission denied: ${e.message}")
}
}
private fun createNotification(): Notification {
val contentText = buildContentText()
// 1. جلب التصميم المخصص
val layoutId = resources.getIdentifier("notification_ride_live", "layout", packageName)
// إذا لم يجد الملف، سيطبع خطأ أحمر في اللوج
if (layoutId == 0) {
Log.e(TAG, "❌ خطأ فادح: ملف notification_ride_live.xml غير موجود!")
}
val remoteViews = RemoteViews(packageName, layoutId)
// 2. تعبئة النصوص
val subtitleId = resources.getIdentifier("tv_subtitle", "id", packageName)
val etaId = resources.getIdentifier("tv_eta", "id", packageName)
val titleId = resources.getIdentifier("tv_title", "id", packageName)
if (subtitleId != 0) remoteViews.setTextViewText(subtitleId, "$driverName$carDetails")
if (etaId != 0) remoteViews.setTextViewText(etaId, contentText)
if (titleId != 0)
remoteViews.setTextViewText(
titleId,
if (rideState == "waiting") "السائق في الطريق إليك"
else "رحلة Intaleq جارية"
)
// 3. حساب التقدم (موقع السيارة على الشارع)
var progressIndex = 0
if (rideState == "inProgress" && totalDistanceMeters > 0) {
val percent = (distanceCoveredMeters / totalDistanceMeters).coerceIn(0.0, 1.0)
progressIndex = (percent * 9).toInt()
} else if (rideState == "waiting") {
val remainingToPassenger =
calculateDistance(
passengerLatitude,
passengerLongitude,
driverLatitude,
driverLongitude
)
val total =
if (initialDriverDistanceToPassenger > 0) initialDriverDistanceToPassenger
else remainingToPassenger.coerceAtLeast(1.0)
val percent = 1.0 - (remainingToPassenger / total).coerceIn(0.0, 1.0)
progressIndex = (percent * 9).toInt()
}
// 4. إظهار السيارة في الموضع الصحيح وإخفائها من الباقي
for (i in 0..9) {
val resId = resources.getIdentifier("car_slot_$i", "id", packageName)
if (resId != 0) {
remoteViews.setViewVisibility(
resId,
if (i == progressIndex) View.VISIBLE else View.INVISIBLE
)
}
}
val intent = Intent(this, MainActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 5. بناء الإشعار (بدون استخدام setProgress نهائياً لكي لا يظهر الخط الأزرق)
val builder =
NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_map) // أيقونة التطبيق الصغيرة
.setStyle(
NotificationCompat.DecoratedCustomViewStyle()
) // إجباري للتصميم المخصص
.setCustomContentView(remoteViews) // التصميم عند طي الإشعار
.setCustomBigContentView(remoteViews) // التصميم عند سحب الإشعار للأسفل
.setContentIntent(pendingIntent)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
return builder.build()
}
private fun buildContentText(): String {
return when (rideState) {
"waiting" -> {
val distanceToPassenger =
calculateDistance(
passengerLatitude,
passengerLongitude,
driverLatitude,
driverLongitude
)
val etaMinutes =
if (distanceToPassenger > 0) {
(distanceToPassenger / 250.0).toInt().coerceAtLeast(1)
} else {
estimatedTimeMinutes
}
"وصول خلال $etaMinutes د • ${String.format("%.1f", distanceToPassenger / 1000)} كم"
}
"inProgress" -> {
if (totalDistanceMeters > 0) {
val remaining = (totalDistanceMeters - distanceCoveredMeters).coerceAtLeast(0.0)
val progressPercent =
((distanceCoveredMeters / totalDistanceMeters) * 100)
.toInt()
.coerceIn(0, 100)
val etaMinutes =
if (estimatedTimeMinutes > 0) {
((remaining / totalDistanceMeters) * estimatedTimeMinutes)
.toInt()
.coerceAtLeast(1)
} else {
5
}
"المتبقي: ${String.format("%.1f", remaining / 1000)} كم • ~$etaMinutes د"
} else {
"الرحلة قيد التنفيذ..."
}
}
else -> "جاري تحديث موقع الرحلة..."
}
}
private fun updateNotification() {
val notification = createNotification()
notificationManager.notify(NOTIFICATION_ID, notification)
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel =
NotificationChannel(
CHANNEL_ID,
"تتبع الرحلة",
NotificationManager.IMPORTANCE_HIGH
)
.apply {
description = "إخطارات حية لتقدم الرحلة"
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
setSound(null, null)
}
notificationManager.createNotificationChannel(channel)
}
}
private fun calculateDistance(lat1: Double, lng1: Double, lat2: Double, lng2: Double): Double {
val r = 6371000.0
val dLat = Math.toRadians(lat2 - lat1)
val dLng = Math.toRadians(lng2 - lng1)
val a =
sin(dLat / 2) * sin(dLat / 2) +
cos(Math.toRadians(lat1)) *
cos(Math.toRadians(lat2)) *
sin(dLng / 2) *
sin(dLng / 2)
val c = 2 * atan2(sqrt(a), sqrt(1 - a))
return r * c
}
override fun onDestroy() {
super.onDestroy()
try {
fusedLocationClient.removeLocationUpdates(locationCallback)
} catch (e: Exception) {
Log.e(TAG, "Error removing location updates: ${e.message}")
}
Log.d(TAG, "Service Destroyed")
}
override fun onBind(intent: Intent?): IBinder? = null
}

View File

@@ -1,157 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- العنوان الرئيسي -->
<TextView
android:id="@+id/tv_title"
android:text="رحلة Intaleq"
android:textStyle="bold"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- سطر بيانات السائق / السيارة -->
<TextView
android:id="@+id/tv_subtitle"
android:text="أحمد محمد • أبيض • ABC 123"
android:textSize="12sp"
android:textColor="#DDDDDD"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="2dp" />
<!-- خط الطريق + سلوطات السيارة -->
<FrameLayout
android:layout_marginTop="6dp"
android:layout_marginBottom="4dp"
android:layout_width="match_parent"
android:layout_height="32dp">
<!-- خلفية الطريق -->
<ImageView
android:id="@+id/img_road"
android:src="@drawable/road_bg"
android:scaleType="fitXY"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- شريط سلوطات السيارة -->
<LinearLayout
android:id="@+id/ll_car_slots"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp">
<!-- 10 سلوطات للسيارة -->
<!-- كل Slot عبارة عن ImageView، نخلي واحد بس منهم ظاهر حسب الـ progress -->
<ImageView
android:id="@+id/car_slot_0"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_1"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_2"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_3"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_4"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_5"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_6"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_7"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_8"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
android:layout_gravity="center_vertical" />
<ImageView
android:id="@+id/car_slot_9"
android:src="@drawable/car_icon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="visible"
android:layout_gravity="center_vertical" />
</LinearLayout>
</FrameLayout>
<!-- سطر الوقت/المسافة المتبقية -->
<TextView
android:id="@+id/tv_eta"
android:text="المتبقي: 8 كم • 12 دقيقة"
android:textSize="12sp"
android:textColor="#CCCCCC"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -1,21 +1,4 @@
// allprojects {
// repositories {
// google()
// mavenCentral()
// }
// }
// rootProject.buildDir = "../build"
// subprojects {
// project.buildDir = "${rootProject.buildDir}/${project.name}"
// }
// subprojects {
// project.evaluationDependsOn(":app")
// }
// tasks.register("clean", Delete) {
// delete rootProject.buildDir
// }
buildscript {
ext.kotlin_version = '2.1.0'
repositories {