Tweak onboarding design to be more unified (#2979)

This commit is contained in:
Joris Pelgröm 2022-10-21 20:01:05 +02:00 committed by GitHub
parent e637b423f2
commit 760aca4fa1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 120 additions and 104 deletions

View file

@ -74,7 +74,8 @@ class SettingsWearMainView : AppCompatActivity() {
url = registerUrl,
defaultDeviceName = currentNodes.firstOrNull()?.displayName ?: "unknown",
locationTrackingPossible = false,
notificationsPossible = false
notificationsPossible = false,
isWatch = true
) // While notifications are technically possible, the app can't handle this for the Wear device
)
}

View file

@ -13,12 +13,14 @@ class OnboardApp : ActivityResultContract<OnboardApp.Input, OnboardApp.Output?>(
private const val EXTRA_DEFAULT_DEVICE_NAME = "extra_default_device_name"
private const val EXTRA_LOCATION_TRACKING_POSSIBLE = "location_tracking_possible"
private const val EXTRA_NOTIFICATIONS_POSSIBLE = "notifications_possible"
private const val EXTRA_IS_WATCH = "extra_is_watch"
fun parseInput(intent: Intent): Input = Input(
url = intent.getStringExtra(EXTRA_URL),
defaultDeviceName = intent.getStringExtra(EXTRA_DEFAULT_DEVICE_NAME) ?: Build.MODEL,
locationTrackingPossible = intent.getBooleanExtra(EXTRA_LOCATION_TRACKING_POSSIBLE, false),
notificationsPossible = intent.getBooleanExtra(EXTRA_NOTIFICATIONS_POSSIBLE, true)
notificationsPossible = intent.getBooleanExtra(EXTRA_NOTIFICATIONS_POSSIBLE, true),
isWatch = intent.getBooleanExtra(EXTRA_IS_WATCH, false)
)
}
@ -26,7 +28,8 @@ class OnboardApp : ActivityResultContract<OnboardApp.Input, OnboardApp.Output?>(
val url: String? = null,
val defaultDeviceName: String = Build.MODEL,
val locationTrackingPossible: Boolean = BuildConfig.FLAVOR == "full",
val notificationsPossible: Boolean = true
val notificationsPossible: Boolean = true,
val isWatch: Boolean = false
)
data class Output(
@ -53,6 +56,7 @@ class OnboardApp : ActivityResultContract<OnboardApp.Input, OnboardApp.Output?>(
putExtra(EXTRA_DEFAULT_DEVICE_NAME, input.defaultDeviceName)
putExtra(EXTRA_LOCATION_TRACKING_POSSIBLE, input.locationTrackingPossible)
putExtra(EXTRA_NOTIFICATIONS_POSSIBLE, input.notificationsPossible)
putExtra(EXTRA_IS_WATCH, input.isWatch)
}
}

View file

@ -40,6 +40,7 @@ class OnboardingActivity : AppCompatActivity() {
NotificationManagerCompat.from(this).areNotificationsEnabled()
)
} else false
viewModel.deviceIsWatch = input.isWatch
if (savedInstanceState == null) {
supportFragmentManager.commit {

View file

@ -0,0 +1,46 @@
package io.homeassistant.companion.android.onboarding
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.mikepenz.iconics.compose.Image
import com.mikepenz.iconics.typeface.IIcon
import io.homeassistant.companion.android.common.R as commonR
@Composable
fun OnboardingHeaderView(
icon: IIcon,
title: String
) {
Column(modifier = Modifier.fillMaxWidth()) {
Spacer(modifier = Modifier.height(32.dp))
Image(
asset = icon,
colorFilter = ColorFilter.tint(colorResource(commonR.color.colorAccent)),
contentDescription = null,
modifier = Modifier
.size(48.dp)
.align(Alignment.CenterHorizontally)
)
Text(
text = title,
style = MaterialTheme.typography.h5,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(vertical = 16.dp)
.align(Alignment.CenterHorizontally)
)
}
}

View file

@ -49,6 +49,7 @@ class OnboardingViewModel @Inject constructor(
private set
var authCode by mutableStateOf("")
private set
var deviceIsWatch by mutableStateOf(false)
val deviceName = mutableStateOf("")
val locationTrackingPossible = mutableStateOf(false)
var locationTrackingEnabled by mutableStateOf(false)

View file

@ -1,13 +1,9 @@
package io.homeassistant.companion.android.onboarding.discovery
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@ -18,17 +14,10 @@ import io.homeassistant.companion.android.onboarding.OnboardingViewModel
import io.homeassistant.companion.android.onboarding.authentication.AuthenticationFragment
import io.homeassistant.companion.android.onboarding.manual.ManualSetupFragment
import javax.inject.Inject
import io.homeassistant.companion.android.common.R as commonR
@AndroidEntryPoint
class DiscoveryFragment @Inject constructor() : Fragment() {
companion object {
private const val TAG = "DiscoveryFragment"
private const val HOME_ASSISTANT = "https://www.home-assistant.io"
}
private val viewModel by activityViewModels<OnboardingViewModel>()
override fun onCreateView(
@ -43,7 +32,6 @@ class DiscoveryFragment @Inject constructor() : Fragment() {
MdcTheme {
DiscoveryView(
onboardingViewModel = viewModel,
whatIsThisClicked = { openHomeAssistantHomePage() },
manualSetupClicked = { navigateToManualSetup() },
instanceClicked = { onInstanceClicked(it) }
)
@ -52,18 +40,6 @@ class DiscoveryFragment @Inject constructor() : Fragment() {
}
}
private fun openHomeAssistantHomePage() {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(HOME_ASSISTANT)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
try {
startActivity(intent)
} catch (e: Exception) {
Log.e(TAG, "Unable to load Home Assistant home page", e)
Toast.makeText(context, commonR.string.what_is_this_crash, Toast.LENGTH_LONG).show()
}
}
private fun navigateToManualSetup() {
parentFragmentManager
.beginTransaction()

View file

@ -4,95 +4,89 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.onboarding.OnboardingHeaderView
import io.homeassistant.companion.android.onboarding.OnboardingViewModel
import io.homeassistant.companion.android.common.R as commonR
@Composable
fun DiscoveryView(
onboardingViewModel: OnboardingViewModel,
whatIsThisClicked: () -> Unit,
manualSetupClicked: () -> Unit,
instanceClicked: (instance: HomeAssistantInstance) -> Unit
) {
val scrollState = rememberScrollState()
Column(modifier = Modifier.fillMaxWidth()) {
TextButton(
onClick = whatIsThisClicked,
modifier = Modifier
.align(Alignment.CenterHorizontally)
) {
Text(
text = stringResource(commonR.string.what_is_this)
)
}
Text(
text = stringResource(id = commonR.string.select_instance),
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(20.dp)
Column(
modifier = Modifier.fillMaxWidth()
.padding(16.dp)
) {
OnboardingHeaderView(
icon = CommunityMaterial.Icon2.cmd_home_search,
title = stringResource(id = commonR.string.select_instance)
)
Column(
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth(0.25f)
.padding(vertical = 16.dp)
.height(2.dp)
.align(Alignment.CenterHorizontally)
)
LazyColumn(
modifier = Modifier
.weight(1f)
.verticalScroll(scrollState)
.fillMaxWidth()
.fillMaxHeight()
.padding(20.dp)
.weight(1f)
) {
onboardingViewModel.foundInstances.forEach { instance ->
items(onboardingViewModel.foundInstances.size, { onboardingViewModel.foundInstances[it].url }) { index ->
val instance = onboardingViewModel.foundInstances[index]
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
.clickable(onClick = { instanceClicked(instance) })
) {
Column {
Text(
text = instance.name,
style = TextStyle(
fontSize = 20.sp
Text(instance.name)
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
text = instance.url.toString(),
fontSize = 14.sp
)
)
Text(
text = instance.url.toString(),
style = TextStyle(
fontSize = 16.sp
)
)
}
}
Icon(
painter = painterResource(R.drawable.navigate_next),
contentDescription = null
)
}
Divider(Modifier.padding(10.dp))
Divider(Modifier.padding(8.dp))
}
}
TextButton(
onClick = manualSetupClicked,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(10.dp)
.padding(top = 16.dp)
) {
Text(text = stringResource(commonR.string.manual_setup))
}

View file

@ -17,12 +17,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import io.homeassistant.companion.android.onboarding.OnboardingHeaderView
import io.homeassistant.companion.android.onboarding.OnboardingViewModel
import io.homeassistant.companion.android.common.R as commonR
@ -42,10 +45,15 @@ fun MobileAppIntegrationView(
.padding(16.dp)
) {
Text(
text = stringResource(id = commonR.string.connect_to_home_assistant),
modifier = Modifier
.align(Alignment.CenterHorizontally)
OnboardingHeaderView(
icon = if (onboardingViewModel.deviceIsWatch) {
CommunityMaterial.Icon3.cmd_watch
} else if (LocalConfiguration.current.screenWidthDp.dp >= 600.dp) {
CommunityMaterial.Icon3.cmd_tablet
} else {
CommunityMaterial.Icon.cmd_cellphone
},
title = stringResource(id = commonR.string.connect_to_home_assistant)
)
TextField(

View file

@ -14,9 +14,11 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import io.homeassistant.companion.android.onboarding.OnboardingHeaderView
import io.homeassistant.companion.android.onboarding.OnboardingViewModel
import io.homeassistant.companion.android.common.R as commonR
@ -31,21 +33,20 @@ fun ManualSetupView(
Column(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp)
.padding(16.dp)
) {
Text(
text = stringResource(commonR.string.manual_title),
modifier = Modifier
.align(Alignment.CenterHorizontally)
OnboardingHeaderView(
icon = CommunityMaterial.Icon3.cmd_web,
title = stringResource(id = commonR.string.manual_title)
)
Text(
text = stringResource(id = commonR.string.manual_desc),
fontWeight = FontWeight.Light,
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(20.dp)
.padding(bottom = 16.dp)
)
TextField(
@ -68,7 +69,7 @@ fun ManualSetupView(
onClick = connectedClicked,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(10.dp)
.padding(16.dp)
) {
Text(stringResource(commonR.string.connect))
}

View file

@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
@ -14,13 +13,10 @@ import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Notifications
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -29,6 +25,7 @@ import com.google.android.material.composethemeadapter.MdcTheme
import com.mikepenz.iconics.compose.Image
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import io.homeassistant.companion.android.onboarding.OnboardingHeaderView
import io.homeassistant.companion.android.common.R as commonR
@Composable
@ -46,23 +43,11 @@ fun NotificationPermissionView(
modifier = Modifier
.verticalScroll(scrollState)
.fillMaxWidth()
.padding(top = 32.dp)
.weight(1f)
) {
Icon(
imageVector = Icons.Outlined.Notifications,
contentDescription = null,
tint = colorResource(id = commonR.color.colorAccent),
modifier = Modifier
.size(48.dp)
.align(Alignment.CenterHorizontally)
)
Text(
text = stringResource(id = commonR.string.notifications),
style = MaterialTheme.typography.h5,
modifier = Modifier
.padding(vertical = 16.dp)
.align(Alignment.CenterHorizontally)
OnboardingHeaderView(
icon = CommunityMaterial.Icon.cmd_bell_outline,
title = stringResource(id = commonR.string.notifications)
)
Text(
text = stringResource(id = commonR.string.onboarding_notifications_subtitle),

View file

@ -333,9 +333,9 @@
<string name="manage_wear_device">Manage device %1$s</string>
<string name="manage_widgets_summary">Edit your widgets, adding/deleting can only be done from the home screen</string>
<string name="manage_widgets">Manage Widgets</string>
<string name="manual_desc">Enter the URL of your Home Assistant server. Make sure the URL includes the protocol and port. For example:\n\nhttp://homeassistant.local:8123 or \nhttps://example.duckdns.org.</string>
<string name="manual_desc">Enter the URL of your Home Assistant server. Make sure it includes the protocol and port. For example:\n\nhttp://homeassistant.local:8123 or \nhttps://example.duckdns.org.</string>
<string name="manual_setup">Enter address manually</string>
<string name="manual_title">What is your Home Assistant URL?</string>
<string name="manual_title">What is your Home Assistant address?</string>
<string name="map">Map</string>
<string name="maximum">Maximum</string>
<string name="media_player">Media player</string>
@ -457,7 +457,7 @@
<string name="security">Security</string>
<string name="select">Select</string>
<string name="select_entity_to_display">Select Entity to display</string>
<string name="select_instance">Select the instance you would like to connect to:</string>
<string name="select_instance">Select your Home Assistant server</string>
<string name="sensor_description_active_notification_count">Total count of active notifications that are visible to the user including silent, persistent and the Sensor Worker notifications.</string>
<string name="sensor_description_app_importance">If the app is in the foreground, background or any other state it can be.</string>
<string name="sensor_description_app_inactive">Whether the app is currently considered inactive by the system</string>
@ -792,7 +792,6 @@
<string name="welcome_hass_desc">This app connects to your Home Assistant server and allows integrating data about you and your phone.\n\nHome Assistant is free and open source home automation software with a focus on local control and privacy.</string>
<string name="welcome_hass">Welcome to Home Assistant Companion!</string>
<string name="what_is_this_crash">Unable to load Home Assistant home page, do you have a browser installed?</string>
<string name="what_is_this">What is this?</string>
<string name="widget_attribute_separator_label">Separator between attributes:</string>
<string name="widget_background_type_label">Widget theme:</string>
<string name="widget_background_type_daynight">Light/dark theme</string>