feat(manage): rework Manage screen layout and device list
- Match device item design to reference (ic_chip, status chips, trailing icon) - Add header (Your devices) and footer to device list - CTA at bottom, centered 46% width, same style for Sign in/Add device - Window background #FAFAFA, LegacyBackground on list area - No spacing between device items, no horizontal margin on list - Add DeviceItem.extra, ic_go_to_location drawable - Replace personal data with User/user@example.com - Strengthen app-recreation-core rule: path check before edits - Restore real auth logic in ManageViewModel Made-with: Cursor
This commit is contained in:
@@ -5,13 +5,22 @@ alwaysApply: true
|
||||
|
||||
# AIRMQ Recreation Core Rules
|
||||
|
||||
## CRITICAL: Path check before any edit
|
||||
|
||||
**BEFORE editing any file, verify its path.**
|
||||
|
||||
- Path contains `airmq-android` but **NOT** `airmq-android-2026` → **NEVER EDIT.** Read-only reference.
|
||||
- Path contains `airmq-android-2026` → OK to edit.
|
||||
|
||||
Example: `C:\Users\sysop\Desktop\airmq-android\app\...` → **DO NOT MODIFY.**
|
||||
|
||||
## Hard repository constraint
|
||||
|
||||
ALL CHANGES ONLY IN `airmq-android-2026` REPO; NO CHANGES EVER IN `airmq-android`.
|
||||
|
||||
## Repository boundaries
|
||||
|
||||
1. Do not modify anything under `C:\Users\sysop\Desktop\airmq-android`.
|
||||
1. **NEVER** modify anything under `C:\Users\sysop\Desktop\airmq-android`.
|
||||
2. Treat `airmq-android` as read-only reference only.
|
||||
3. Create and apply all code/config/build changes only under `C:\Users\sysop\Desktop\airmq-android-2026`.
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.db3.airmq.features.manage
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -17,9 +18,6 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -38,6 +36,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import org.db3.airmq.R
|
||||
@@ -48,6 +47,7 @@ import org.db3.airmq.features.manage.ManageScreenContract.DeviceItem
|
||||
import org.db3.airmq.features.manage.ManageScreenContract.Event
|
||||
import org.db3.airmq.features.manage.ManageScreenContract.State
|
||||
import org.db3.airmq.ui.theme.AirMQTheme
|
||||
import org.db3.airmq.ui.theme.LegacyBackground
|
||||
import org.db3.airmq.ui.theme.LegacyNavGradientEnd
|
||||
import org.db3.airmq.ui.theme.LegacyNavGradientStart
|
||||
|
||||
@@ -58,8 +58,7 @@ fun ManageScreen(
|
||||
onOpenSettings: () -> Unit,
|
||||
onOpenLogin: () -> Unit,
|
||||
onOpenLocation: () -> Unit,
|
||||
onOpenWidgetConstructor: () -> Unit,
|
||||
onBackToDashboard: () -> Unit,
|
||||
onOpenAddLocation: () -> Unit,
|
||||
viewModel: ManageViewModel = hiltViewModel()
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
@@ -71,23 +70,20 @@ fun ManageScreen(
|
||||
Action.OpenSetup -> onOpenSetup()
|
||||
is Action.OpenDevice -> onOpenDevice()
|
||||
is Action.OpenLocation -> onOpenLocation()
|
||||
is Action.OpenAddLocation -> onOpenAddLocation()
|
||||
}
|
||||
}
|
||||
}
|
||||
ManageScreenContent(
|
||||
uiState = uiState,
|
||||
onEvent = viewModel::onEvent,
|
||||
onOpenWidgetConstructor = onOpenWidgetConstructor,
|
||||
onBackToDashboard = onBackToDashboard
|
||||
onEvent = viewModel::onEvent
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ManageScreenContent(
|
||||
uiState: State,
|
||||
onEvent: (Event) -> Unit,
|
||||
onOpenWidgetConstructor: () -> Unit,
|
||||
onBackToDashboard: () -> Unit
|
||||
onEvent: (Event) -> Unit
|
||||
) {
|
||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||
Column(
|
||||
@@ -104,33 +100,31 @@ private fun ManageScreenContent(
|
||||
when (uiState.isAuthorized) {
|
||||
false -> AnonymousContent(
|
||||
modifier = Modifier.weight(1f),
|
||||
devicesLabel = uiState.devicesLabel,
|
||||
onSignIn = { onEvent(Event.SignInClicked) }
|
||||
devicesLabel = uiState.devicesLabel
|
||||
)
|
||||
true -> AuthorizedContent(
|
||||
devicesLabel = uiState.devicesLabel,
|
||||
modifier = Modifier.weight(1f),
|
||||
devices = uiState.devices,
|
||||
onOpenSetup = { onEvent(Event.SetupClicked) },
|
||||
onOpenDevice = { onEvent(Event.DeviceClicked(it)) },
|
||||
onOpenLocation = { onEvent(Event.DeviceLocationClicked(it)) }
|
||||
onOpenLocation = { onEvent(Event.DeviceLocationClicked(it)) },
|
||||
onAddLocation = { onEvent.invoke(Event.AddDeviceLocationClicked(it))}
|
||||
)
|
||||
}
|
||||
if (uiState.isAuthorized) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
AirMQButton(
|
||||
text = stringResource(id = R.string.manage_open_widget_constructor),
|
||||
onClick = onOpenWidgetConstructor,
|
||||
text = if (uiState.isAuthorized) stringResource(id = R.string.button_setup)
|
||||
else stringResource(id = R.string.button_sign_in),
|
||||
onClick = if (uiState.isAuthorized) { { onEvent(Event.SetupClicked) } }
|
||||
else { { onEvent(Event.SignInClicked) } },
|
||||
style = AirMQButtonStyle.Gradient,
|
||||
leadingIconRes = if (uiState.isAuthorized) null else R.drawable.ic_account,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
)
|
||||
AirMQButton(
|
||||
text = stringResource(id = R.string.back_to_dashboard),
|
||||
onClick = onBackToDashboard,
|
||||
style = AirMQButtonStyle.Outlined,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.fillMaxWidth(0.46f)
|
||||
.padding(bottom = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -222,8 +216,7 @@ private fun ProfileHeader(
|
||||
@Composable
|
||||
private fun AnonymousContent(
|
||||
modifier: Modifier = Modifier,
|
||||
devicesLabel: String,
|
||||
onSignIn: () -> Unit
|
||||
devicesLabel: String
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
@@ -236,94 +229,143 @@ private fun AnonymousContent(
|
||||
color = Color(0xFFBDBDBD),
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
AirMQButton(
|
||||
text = stringResource(id = R.string.button_sign_in),
|
||||
onClick = onSignIn,
|
||||
style = AirMQButtonStyle.Gradient,
|
||||
leadingIconRes = R.drawable.ic_account,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.fillMaxWidth(0.46f)
|
||||
.padding(bottom = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AuthorizedContent(
|
||||
devicesLabel: String,
|
||||
modifier: Modifier = Modifier,
|
||||
devices: List<DeviceItem>,
|
||||
onOpenSetup: () -> Unit,
|
||||
onOpenDevice: (String) -> Unit,
|
||||
onOpenLocation: (String) -> Unit
|
||||
onOpenLocation: (String) -> Unit,
|
||||
onAddLocation: (String) -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
.background(LegacyBackground)
|
||||
) {
|
||||
Text(text = devicesLabel, style = MaterialTheme.typography.titleMedium)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
AirMQButton(
|
||||
text = stringResource(id = R.string.button_setup),
|
||||
onClick = onOpenSetup,
|
||||
style = AirMQButtonStyle.Gradient,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
items(devices, key = { it.id }) { device ->
|
||||
DeviceRow(
|
||||
item = device,
|
||||
onOpenDevice = { onOpenDevice(device.id) },
|
||||
onOpenLocation = { onOpenLocation(device.id) }
|
||||
if (devices.isEmpty()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.text_nothing_to_show),
|
||||
style = MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.Light),
|
||||
color = Color(0xFF757575),
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(top = 8.dp),
|
||||
verticalArrangement = Arrangement.Top
|
||||
) {
|
||||
item(key = "header") {
|
||||
DeviceListHeader()
|
||||
}
|
||||
items(devices, key = { it.id }) { device ->
|
||||
DeviceRow(
|
||||
item = device,
|
||||
onOpenDevice = { onOpenDevice(device.id) },
|
||||
onOpenLocation = { onOpenLocation(device.id) },
|
||||
onAddLocation = { onAddLocation(device.id) }
|
||||
)
|
||||
}
|
||||
item(key = "footer") {
|
||||
DeviceListFooter()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val Black38 = Color(0x61000000)
|
||||
|
||||
@Composable
|
||||
private fun DeviceListHeader() {
|
||||
Text(
|
||||
text = stringResource(id = R.string.text_your_devices),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 22.dp),
|
||||
fontSize = 14.sp,
|
||||
color = Black38,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeviceListFooter() {
|
||||
Spacer(modifier = Modifier.height(72.dp))
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeviceRow(
|
||||
item: DeviceItem,
|
||||
onOpenDevice: () -> Unit,
|
||||
onOpenLocation: () -> Unit
|
||||
onOpenLocation: () -> Unit,
|
||||
onAddLocation: () -> Unit
|
||||
) {
|
||||
Card(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||
val isOnline = item.status.equals(stringResource(id = R.string.map_status_online), ignoreCase = true)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(72.dp)
|
||||
.clickable(onClick = onOpenDevice)
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(text = item.name, style = MaterialTheme.typography.titleMedium)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_chip),
|
||||
contentDescription = stringResource(id = R.string.content_device_icon),
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Column(modifier = Modifier.weight(1f, fill = true)) {
|
||||
Text(
|
||||
text = item.status,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color.Gray
|
||||
text = item.name,
|
||||
fontSize = 16.sp,
|
||||
color = Color.Black
|
||||
)
|
||||
Text(
|
||||
text = item.extra,
|
||||
fontSize = 14.sp,
|
||||
color = Black38
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Image(
|
||||
painter = painterResource(
|
||||
id = if (isOnline) R.drawable.device_chip_online else R.drawable.device_chip_offline
|
||||
),
|
||||
contentDescription = item.status,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Top)
|
||||
.padding(top = 18.dp)
|
||||
)
|
||||
val trailingIcon = if (item.hasLocation) R.drawable.ic_go_to_location else R.drawable.ic_warning
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (item.hasLocation) {
|
||||
onOpenLocation.invoke()
|
||||
} else {
|
||||
onAddLocation.invoke()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.size(48.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = trailingIcon),
|
||||
contentDescription = null,
|
||||
tint = Black38
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
AirMQButton(
|
||||
text = stringResource(id = R.string.button_open),
|
||||
onClick = onOpenDevice,
|
||||
style = AirMQButtonStyle.Contained,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
AirMQButton(
|
||||
text = if (item.hasLocation) {
|
||||
stringResource(id = R.string.button_view_on_map)
|
||||
} else {
|
||||
stringResource(id = R.string.manage_set_location)
|
||||
},
|
||||
onClick = onOpenLocation,
|
||||
style = AirMQButtonStyle.Outlined,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,9 +381,7 @@ private fun ManageScreenAnonymousPreview() {
|
||||
userEmail = "Your preferences are not being synced, please sign in",
|
||||
devicesLabel = "Sign in to add devices"
|
||||
),
|
||||
onEvent = {},
|
||||
onOpenWidgetConstructor = {},
|
||||
onBackToDashboard = {}
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -353,17 +393,14 @@ private fun ManageScreenAuthorizedPreview() {
|
||||
ManageScreenContent(
|
||||
uiState = State(
|
||||
isAuthorized = true,
|
||||
userName = "Anton Betsun",
|
||||
userEmail = "messbees@gmail.com",
|
||||
devicesLabel = "My devices",
|
||||
userName = "User",
|
||||
userEmail = "user@example.com",
|
||||
devices = listOf(
|
||||
DeviceItem("1", "AirMQ #1", "Online", true),
|
||||
DeviceItem("2", "AirMQ #2", "Offline", false)
|
||||
DeviceItem("1", "AirMQ #1", "mobile", "Online", true),
|
||||
DeviceItem("2", "AirMQ #2", "mobile", "Offline", false)
|
||||
)
|
||||
),
|
||||
onEvent = {},
|
||||
onOpenWidgetConstructor = {},
|
||||
onBackToDashboard = {}
|
||||
onEvent = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ object ManageScreenContract {
|
||||
data class DeviceItem(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val extra: String,
|
||||
val status: String,
|
||||
val hasLocation: Boolean
|
||||
)
|
||||
@@ -22,6 +23,7 @@ object ManageScreenContract {
|
||||
data object OpenLogin : Action
|
||||
data class OpenDevice(val deviceId: String) : Action
|
||||
data class OpenLocation(val deviceId: String) : Action
|
||||
data class OpenAddLocation(val deviceId: String) : Action
|
||||
}
|
||||
|
||||
sealed interface Event {
|
||||
@@ -30,5 +32,6 @@ object ManageScreenContract {
|
||||
data object SignInClicked : Event
|
||||
data class DeviceClicked(val deviceId: String) : Event
|
||||
data class DeviceLocationClicked(val deviceId: String) : Event
|
||||
data class AddDeviceLocationClicked(val deviceId: String) : Event
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ class ManageViewModel @Inject constructor(
|
||||
Event.SignInClicked -> _actions.tryEmit(Action.OpenLogin)
|
||||
is Event.DeviceClicked -> _actions.tryEmit(Action.OpenDevice(event.deviceId))
|
||||
is Event.DeviceLocationClicked -> _actions.tryEmit(Action.OpenLocation(event.deviceId))
|
||||
is Event.AddDeviceLocationClicked -> _actions.tryEmit(Action.OpenAddLocation(event.deviceId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,17 +72,19 @@ class ManageViewModel @Inject constructor(
|
||||
isAuthorized = true,
|
||||
userName = user.displayName ?: appContext.getString(R.string.text_anonymous_user),
|
||||
userEmail = user.email ?: "",
|
||||
devicesLabel = appContext.getString(R.string.text_your_devices),
|
||||
devicesLabel = "",
|
||||
devices = listOf(
|
||||
DeviceItem(
|
||||
id = "device-1",
|
||||
name = appContext.getString(R.string.mock_device_name_42),
|
||||
extra = "mobile",
|
||||
status = appContext.getString(R.string.map_status_online),
|
||||
hasLocation = true
|
||||
),
|
||||
DeviceItem(
|
||||
id = "device-2",
|
||||
name = appContext.getString(R.string.mock_device_name_17),
|
||||
extra = "mobile",
|
||||
status = appContext.getString(R.string.map_status_offline),
|
||||
hasLocation = false
|
||||
)
|
||||
|
||||
@@ -152,8 +152,7 @@ fun AirMQNavGraph(modifier: Modifier = Modifier) {
|
||||
onOpenSettings = { navController.navigate(AirMqRoutes.SETTINGS) },
|
||||
onOpenLogin = { navController.navigate(AirMqRoutes.LOGIN) },
|
||||
onOpenLocation = { navController.navigate(AirMqRoutes.LOCATION) },
|
||||
onOpenWidgetConstructor = { navController.navigate(AirMqRoutes.WIDGET_CONSTRUCTOR) },
|
||||
onBackToDashboard = { navController.navigate(AirMqRoutes.DASHBOARD) }
|
||||
onOpenAddLocation = { /* TODO */ }
|
||||
)
|
||||
}
|
||||
composable(
|
||||
|
||||
30
app/src/main/res/drawable/device_chip_offline.xml
Normal file
30
app/src/main/res/drawable/device_chip_offline.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="52dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="52"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M43,18H9c-4.97,0 -9,-4.03 -9,-9v0c0,-4.97 4.03,-9 9,-9l34,0c4.95,0 9,4.05 9,9v0C52,13.97 47.97,18 43,18z"
|
||||
android:fillColor="#F1AF00"/>
|
||||
<path
|
||||
android:pathData="M10.4,9.51c0,-0.62 0.12,-1.18 0.37,-1.68s0.58,-0.88 1.02,-1.15s0.93,-0.4 1.49,-0.4c0.86,0 1.56,0.3 2.09,0.9s0.8,1.39 0.8,2.38v0.08c0,0.62 -0.12,1.17 -0.35,1.66s-0.57,0.87 -1.01,1.15s-0.94,0.41 -1.51,0.41c-0.86,0 -1.56,-0.3 -2.09,-0.9s-0.8,-1.39 -0.8,-2.37V9.51zM11.49,9.64c0,0.7 0.16,1.27 0.49,1.69s0.76,0.64 1.31,0.64c0.55,0 0.99,-0.22 1.31,-0.65s0.49,-1.04 0.49,-1.81c0,-0.7 -0.17,-1.26 -0.5,-1.69s-0.77,-0.65 -1.32,-0.65c-0.54,0 -0.97,0.21 -1.29,0.64S11.49,8.85 11.49,9.64z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M18.06,12.74v-5.5h-1V6.4h1V5.75c0,-0.68 0.18,-1.21 0.54,-1.58s0.88,-0.56 1.54,-0.56c0.25,0 0.5,0.03 0.74,0.1l-0.06,0.87c-0.18,-0.04 -0.38,-0.05 -0.59,-0.05c-0.35,0 -0.62,0.1 -0.81,0.31s-0.29,0.5 -0.29,0.88V6.4h1.35v0.84h-1.35v5.5H18.06z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M22.23,12.74v-5.5h-1V6.4h1V5.75c0,-0.68 0.18,-1.21 0.54,-1.58s0.88,-0.56 1.54,-0.56c0.25,0 0.5,0.03 0.74,0.1L25,4.59c-0.18,-0.04 -0.38,-0.05 -0.59,-0.05c-0.35,0 -0.62,0.1 -0.81,0.31s-0.29,0.5 -0.29,0.88V6.4h1.35v0.84h-1.35v5.5H22.23z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M27.04,12.74h-1.08v-9h1.08V12.74z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M28.78,4.72c0,-0.18 0.05,-0.32 0.16,-0.45s0.27,-0.18 0.48,-0.18s0.37,0.06 0.48,0.18s0.16,0.27 0.16,0.45s-0.05,0.32 -0.16,0.44s-0.27,0.18 -0.48,0.18s-0.37,-0.06 -0.48,-0.18S28.78,4.89 28.78,4.72zM29.95,12.74h-1.08V6.4h1.08V12.74z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M32.71,6.4l0.04,0.8c0.48,-0.61 1.12,-0.91 1.9,-0.91c1.34,0 2.02,0.76 2.03,2.27v4.19h-1.08v-4.2c0,-0.46 -0.11,-0.79 -0.31,-1.01S34.75,7.2 34.32,7.2c-0.35,0 -0.66,0.09 -0.93,0.28s-0.47,0.43 -0.62,0.74v4.52h-1.08V6.4H32.71z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M40.94,12.85c-0.86,0 -1.56,-0.28 -2.1,-0.85s-0.81,-1.32 -0.81,-2.26v-0.2c0,-0.63 0.12,-1.19 0.36,-1.68s0.58,-0.88 1.01,-1.16s0.9,-0.42 1.4,-0.42c0.82,0 1.46,0.27 1.92,0.81s0.69,1.32 0.69,2.33v0.45h-4.29c0.02,0.63 0.2,1.13 0.55,1.51s0.79,0.58 1.33,0.58c0.38,0 0.71,-0.08 0.97,-0.23s0.5,-0.36 0.7,-0.62l0.66,0.52C42.8,12.45 42,12.85 40.94,12.85zM40.8,7.17c-0.44,0 -0.8,0.16 -1.1,0.48s-0.48,0.76 -0.55,1.34h3.18V8.91c-0.03,-0.55 -0.18,-0.98 -0.45,-1.28S41.26,7.17 40.8,7.17z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
||||
41
app/src/main/res/drawable/device_chip_online.xml
Normal file
41
app/src/main/res/drawable/device_chip_online.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="52dp"
|
||||
android:height="18dp"
|
||||
android:viewportWidth="52"
|
||||
android:viewportHeight="18">
|
||||
<path
|
||||
android:pathData="M43.05,18H8.95C4.01,18 0,13.99 0,9.05l0,-0.09C0,4.01 4.01,0 8.95,0l34.09,0C47.97,0 52,4.03 52,8.95v0.09C52,13.99 47.99,18 43.05,18z"
|
||||
android:strokeAlpha="0"
|
||||
android:fillColor="#F1AF00"
|
||||
android:fillAlpha="0"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10.4,9.51c0,-0.62 0.12,-1.18 0.37,-1.68s0.58,-0.88 1.02,-1.15s0.93,-0.4 1.49,-0.4c0.86,0 1.56,0.3 2.09,0.9s0.8,1.39 0.8,2.38v0.08c0,0.62 -0.12,1.17 -0.35,1.66s-0.57,0.87 -1.01,1.15s-0.94,0.41 -1.51,0.41c-0.86,0 -1.56,-0.3 -2.09,-0.9s-0.8,-1.39 -0.8,-2.37V9.51zM11.49,9.64c0,0.7 0.16,1.27 0.49,1.69s0.76,0.64 1.31,0.64c0.55,0 0.99,-0.22 1.31,-0.65s0.49,-1.04 0.49,-1.81c0,-0.7 -0.17,-1.26 -0.5,-1.69s-0.77,-0.65 -1.32,-0.65c-0.54,0 -0.97,0.21 -1.29,0.64S11.49,8.85 11.49,9.64z"
|
||||
android:strokeAlpha="0.38"
|
||||
android:fillAlpha="0.38"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18.56,6.4l0.04,0.8c0.48,-0.61 1.12,-0.91 1.9,-0.91c1.34,0 2.02,0.76 2.03,2.27v4.19h-1.08v-4.2c0,-0.46 -0.11,-0.79 -0.31,-1.01S20.59,7.2 20.16,7.2c-0.35,0 -0.66,0.09 -0.93,0.28s-0.47,0.43 -0.62,0.74v4.52h-1.08V6.4H18.56z"
|
||||
android:strokeAlpha="0.38"
|
||||
android:fillAlpha="0.38"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M25.33,12.74h-1.08v-9h1.08V12.74z"
|
||||
android:strokeAlpha="0.38"
|
||||
android:fillAlpha="0.38"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M27.07,4.72c0,-0.18 0.05,-0.32 0.16,-0.45s0.27,-0.18 0.48,-0.18s0.37,0.06 0.48,0.18s0.16,0.27 0.16,0.45s-0.05,0.32 -0.16,0.44s-0.27,0.18 -0.48,0.18s-0.37,-0.06 -0.48,-0.18S27.07,4.89 27.07,4.72zM28.24,12.74h-1.08V6.4h1.08V12.74z"
|
||||
android:strokeAlpha="0.38"
|
||||
android:fillAlpha="0.38"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M31,6.4l0.04,0.8c0.48,-0.61 1.12,-0.91 1.9,-0.91c1.34,0 2.02,0.76 2.03,2.27v4.19h-1.08v-4.2c0,-0.46 -0.11,-0.79 -0.31,-1.01S33.04,7.2 32.61,7.2c-0.35,0 -0.66,0.09 -0.93,0.28s-0.47,0.43 -0.62,0.74v4.52h-1.08V6.4H31z"
|
||||
android:strokeAlpha="0.38"
|
||||
android:fillAlpha="0.38"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M39.23,12.86c-0.86,0 -1.56,-0.28 -2.1,-0.85s-0.81,-1.32 -0.81,-2.26v-0.2c0,-0.63 0.12,-1.19 0.36,-1.68s0.58,-0.88 1.01,-1.16s0.9,-0.42 1.4,-0.42c0.82,0 1.46,0.27 1.92,0.81s0.69,1.32 0.69,2.33v0.45h-4.29c0.02,0.63 0.2,1.13 0.55,1.51s0.79,0.58 1.33,0.58c0.38,0 0.71,-0.08 0.97,-0.23s0.5,-0.36 0.7,-0.62l0.66,0.52C41.09,12.45 40.29,12.86 39.23,12.86zM39.09,7.17c-0.44,0 -0.8,0.16 -1.1,0.48s-0.48,0.76 -0.55,1.34h3.18V8.91c-0.03,-0.55 -0.18,-0.98 -0.45,-1.28S39.55,7.17 39.09,7.17z"
|
||||
android:strokeAlpha="0.38"
|
||||
android:fillAlpha="0.38"/>
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_chip.xml
Normal file
11
app/src/main/res/drawable/ic_chip.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#333333"
|
||||
android:alpha="0.6">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M14,9h-4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1zM13,13h-2v-2h2v2zM21,10c0,-0.55 -0.45,-1 -1,-1h-1L19,7c0,-1.1 -0.9,-2 -2,-2h-2L15,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1h-2L11,4c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1L7,5c-1.1,0 -2,0.9 -2,2v2L4,9c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v2L4,13c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h1v2c0,1.1 0.9,2 2,2h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2v1c0,0.55 0.45,1 1,1s1,-0.45 1,-1v-1h2c1.1,0 2,-0.9 2,-2v-2h1c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-1v-2h1c0.55,0 1,-0.45 1,-1zM16,17L8,17c-0.55,0 -1,-0.45 -1,-1L7,8c0,-0.55 0.45,-1 1,-1h8c0.55,0 1,0.45 1,1v8c0,0.55 -0.45,1 -1,1z"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/ic_go_to_location.xml
Normal file
9
app/src/main/res/drawable/ic_go_to_location.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12.01,0C7.24,0 3.38,3.86 3.38,8.63c0,5.14 5.45,12.23 7.69,14.93c0.49,0.59 1.39,0.59 1.89,0c2.23,-2.7 7.67,-9.79 7.67,-14.93C20.62,3.86 16.77,0 12.01,0zM15.45,9.43l-2.74,2.74c-0.28,0.28 -0.75,0.32 -1.06,0.07c-0.37,-0.32 -0.37,-0.84 -0.05,-1.15l1.44,-1.44h-4.2c-0.45,0 -0.82,-0.37 -0.82,-0.82C8.03,8.37 8.39,8 8.85,8h4.19l-1.4,-1.43c-0.3,-0.29 -0.29,-0.8 0,-1.1c0.3,-0.31 0.79,-0.3 1.09,0.01l2.74,2.8C15.75,8.58 15.75,9.11 15.45,9.43zM18.57,8.68c0,3.63 -2.94,6.57 -6.57,6.57S5.43,12.3 5.43,8.68S8.37,2.11 12,2.11S18.57,5.05 18.57,8.68z"/>
|
||||
</vector>
|
||||
11
app/src/main/res/drawable/ic_warning.xml
Normal file
11
app/src/main/res/drawable/ic_warning.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13.69,2.14C6.85,1.01 1.01,6.85 2.14,13.69c0.68,4.14 4.02,7.48 8.17,8.17c6.84,1.12 12.68,-4.71 11.55,-11.55C21.18,6.16 17.84,2.82 13.69,2.14zM12,13.21c-0.73,0 -1.33,-0.52 -1.33,-1.16V7.39c0,-0.64 0.6,-1.16 1.33,-1.16s1.33,0.52 1.33,1.16v4.66C13.33,12.69 12.73,13.21 12,13.21zM12,17.49L12,17.49c-0.73,0 -1.33,-0.59 -1.33,-1.33v0c0,-0.73 0.59,-1.33 1.33,-1.33h0c0.73,0 1.33,0.59 1.33,1.33v0C13.33,16.9 12.73,17.49 12,17.49z"
|
||||
android:strokeAlpha="0.54"
|
||||
android:fillAlpha="0.54"/>
|
||||
</vector>
|
||||
@@ -270,8 +270,8 @@
|
||||
<string name="widget_chart_constructor_title">Канструктар графіка</string>
|
||||
<string name="widget_news_constructor_title">Канструктар навін</string>
|
||||
<string name="back_to_news">Назад да навін</string>
|
||||
<string name="mock_user_name">Anton Betsun</string>
|
||||
<string name="mock_user_email">messbees@gmail.com</string>
|
||||
<string name="mock_user_name">User</string>
|
||||
<string name="mock_user_email">user@example.com</string>
|
||||
<string name="mock_device_name_42">AirMQ #42</string>
|
||||
<string name="mock_device_name_17">AirMQ #17</string>
|
||||
</resources>
|
||||
@@ -270,8 +270,8 @@
|
||||
<string name="widget_chart_constructor_title">Конструктор графика</string>
|
||||
<string name="widget_news_constructor_title">Конструктор новостей</string>
|
||||
<string name="back_to_news">Назад к новостям</string>
|
||||
<string name="mock_user_name">Anton Betsun</string>
|
||||
<string name="mock_user_email">messbees@gmail.com</string>
|
||||
<string name="mock_user_name">User</string>
|
||||
<string name="mock_user_email">user@example.com</string>
|
||||
<string name="mock_device_name_42">AirMQ #42</string>
|
||||
<string name="mock_device_name_17">AirMQ #17</string>
|
||||
</resources>
|
||||
@@ -14,4 +14,6 @@
|
||||
<color name="sensorRed">#FFF44336</color>
|
||||
<color name="sensorPink">#FFEC407A</color>
|
||||
<color name="sensorPurple">#FF8E24AA</color>
|
||||
<color name="black38">#61000000</color>
|
||||
<color name="windowBackground">#FAFAFA</color>
|
||||
</resources>
|
||||
@@ -18,7 +18,7 @@
|
||||
<string name="dialog_enable_wifi_title">Enable WiFi</string>
|
||||
<string name="dialog_are_you_sure">Are you sure?</string>
|
||||
<string name="dialog_about_title">About</string>
|
||||
<string name="dialog_about_text" translatable="false">App by Anton Betsun \nDesign by Alexander Prokhorov</string>
|
||||
<string name="dialog_about_text" translatable="false">App by AirMQ\nDesign by Alexander Prokhorov</string>
|
||||
<string name="dialog_anonym_title">Continue anonymously?</string>
|
||||
<string name="dialog_anonym_mesage">You will not be able to back up your preferences and add new AirMQ devices</string>
|
||||
<string name="dialog_select_device_title">Select device</string>
|
||||
@@ -326,8 +326,8 @@
|
||||
<string name="widget_chart_constructor_title">Chart Constructor</string>
|
||||
<string name="widget_news_constructor_title">News Constructor</string>
|
||||
<string name="back_to_news">Back to News</string>
|
||||
<string name="mock_user_name">Anton Betsun</string>
|
||||
<string name="mock_user_email">messbees@gmail.com</string>
|
||||
<string name="mock_user_name">User</string>
|
||||
<string name="mock_user_email">user@example.com</string>
|
||||
<string name="mock_device_name_42">AirMQ #42</string>
|
||||
<string name="mock_device_name_17">AirMQ #17</string>
|
||||
</resources>
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Theme.AirMQ" parent="android:Theme.Material.Light.NoActionBar" />
|
||||
<style name="Theme.AirMQ" parent="android:Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@color/windowBackground</item>
|
||||
<item name="android:colorBackground">@color/windowBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user