migrate diagnosis screen to compose

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2025-02-14 13:34:49 +01:00
parent 773acf49e7
commit 84ce5df2d7
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
4 changed files with 326 additions and 222 deletions

View File

@ -0,0 +1,47 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.diagnose
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.nextcloud.talk.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppBar(title: String) {
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
TopAppBar(
title = { Text(text = title) },
navigationIcon = {
IconButton(
onClick = { backDispatcher?.onBackPressed() }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.back_button)
)
}
}
)
}
@Preview(showBackground = true)
@Composable
fun AppBarPreview() {
AppBar("title")
}

View File

@ -9,24 +9,27 @@ package com.nextcloud.talk.diagnose
import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Build.MANUFACTURER
import android.os.Build.MODEL
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.util.TypedValue
import android.view.Menu
import android.view.MenuItem
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.core.text.bold
import androidx.core.view.updateLayoutParams
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import autodagger.AutoInjector
import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R
@ -34,7 +37,6 @@ import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.databinding.ActivityDiagnoseBinding
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.BrandingUtils
import com.nextcloud.talk.utils.ClosedInterfaceImpl
@ -50,7 +52,6 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
@Suppress("TooManyFunctions")
class DiagnoseActivity : BaseActivity() {
private lateinit var binding: ActivityDiagnoseBinding
@Inject
lateinit var arbitraryStorageManager: ArbitraryStorageManager
@ -66,16 +67,44 @@ class DiagnoseActivity : BaseActivity() {
private var isGooglePlayServicesAvailable: Boolean = false
private val markdownText = SpannableStringBuilder()
sealed class DiagnoseElement {
data class DiagnoseHeadline(val headline: String) : DiagnoseElement()
data class DiagnoseEntry(val key: String, val value: String) : DiagnoseElement()
}
private val diagnoseData = mutableListOf<DiagnoseElement>()
private val diagnoseDataState = mutableStateOf(emptyList<DiagnoseElement>())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
binding = ActivityDiagnoseBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
val colorScheme = viewThemeUtils.getColorScheme(this)
setContent {
val backgroundColor = colorResource(id = R.color.bg_default)
MaterialTheme(
colorScheme = colorScheme
) {
Scaffold(
topBar = {
AppBar(
title = stringResource(R.string.nc_settings_diagnose_title)
)
},
content = {
Column(
Modifier
.padding(it)
.background(backgroundColor)
.fillMaxSize()
) {
DiagnoseContentComposable(diagnoseDataState)
}
}
)
}
}
}
override fun onResume() {
@ -84,25 +113,13 @@ class DiagnoseActivity : BaseActivity() {
isGooglePlayServicesAvailable = ClosedInterfaceImpl().isGooglePlayServicesAvailable
markdownText.clear()
diagnoseData.clear()
setupMetaValues()
setupPhoneValues()
setupAppValues()
setupAccountValues()
createLayoutFromMarkdown()
}
private fun setupActionBar() {
setSupportActionBar(binding.settingsToolbar)
binding.settingsToolbar.setNavigationOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(android.R.color.transparent, null)))
supportActionBar?.title = context.getString(R.string.nc_settings_diagnose_title)
viewThemeUtils.material.themeToolbar(binding.settingsToolbar)
diagnoseDataState.value = diagnoseData.toList()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -124,22 +141,22 @@ class DiagnoseActivity : BaseActivity() {
}
R.id.copy -> {
copyToClipboard(markdownText.toString())
copyToClipboard(diagnoseData.toMarkdownString())
true
}
R.id.share -> {
shareToOtherApps(markdownText.toString())
shareToOtherApps(diagnoseData.toMarkdownString())
true
}
R.id.send_mail -> {
composeEmail(markdownText.toString())
composeEmail(diagnoseData.toMarkdownString())
true
}
R.id.create_issue -> {
createGithubIssue(markdownText.toString())
createGithubIssue(diagnoseData.toMarkdownString())
true
}
@ -185,7 +202,7 @@ class DiagnoseActivity : BaseActivity() {
private fun copyToClipboard(text: String) {
val clipboardManager =
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText(
resources?.getString(R.string.nc_app_product_name),
text
@ -201,25 +218,35 @@ class DiagnoseActivity : BaseActivity() {
private fun setupMetaValues() {
addHeadline(context.resources.getString(R.string.nc_diagnose_meta_category_title))
addKey(context.resources.getString(R.string.nc_diagnose_meta_system_report_date))
addValue(DisplayUtils.unixTimeToHumanReadable(System.currentTimeMillis()))
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_meta_system_report_date),
value = DisplayUtils.unixTimeToHumanReadable(System.currentTimeMillis())
)
}
private fun setupPhoneValues() {
addHeadline(context.resources.getString(R.string.nc_diagnose_phone_category_title))
addKey(context.resources.getString(R.string.nc_diagnose_device_name_title))
addValue(getDeviceName())
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_device_name_title),
value = getDeviceName()
)
addKey(context.resources.getString(R.string.nc_diagnose_android_version_title))
addValue(Build.VERSION.SDK_INT.toString())
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_android_version_title),
value = Build.VERSION.SDK_INT.toString()
)
if (isGooglePlayServicesAvailable) {
addKey(context.resources.getString(R.string.nc_diagnose_gplay_available_title))
addValue(context.resources.getString(R.string.nc_diagnose_gplay_available_yes))
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_gplay_available_title),
value = context.resources.getString(R.string.nc_diagnose_gplay_available_yes)
)
} else {
addKey(context.resources.getString(R.string.nc_diagnose_gplay_available_title))
addValue(context.resources.getString(R.string.nc_diagnose_gplay_available_no))
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_gplay_available_title),
value = context.resources.getString(R.string.nc_diagnose_gplay_available_no)
)
}
}
@ -228,81 +255,101 @@ class DiagnoseActivity : BaseActivity() {
private fun setupAppValues() {
addHeadline(context.resources.getString(R.string.nc_diagnose_app_category_title))
addKey(context.resources.getString(R.string.nc_diagnose_app_name_title))
addValue(context.resources.getString(R.string.nc_app_product_name))
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_app_name_title),
value = context.resources.getString(R.string.nc_app_product_name)
)
addKey(context.resources.getString(R.string.nc_diagnose_app_version_title))
addValue(String.format("v" + BuildConfig.VERSION_NAME))
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_app_version_title),
value = String.format("v" + BuildConfig.VERSION_NAME)
)
addKey(context.resources.getString(R.string.nc_diagnose_flavor))
addValue(BuildConfig.FLAVOR)
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_flavor),
value = BuildConfig.FLAVOR
)
if (isGooglePlayServicesAvailable) {
setupAppValuesForGooglePlayServices()
}
addKey(context.resources.getString(R.string.nc_diagnose_app_users_amount))
addValue(userManager.users.blockingGet().size.toString())
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_app_users_amount),
value = userManager.users.blockingGet().size.toString()
)
}
@Suppress("Detekt.LongMethod")
private fun setupAppValuesForGooglePlayServices() {
addKey(context.resources.getString(R.string.nc_diagnose_battery_optimization_title))
if (PowerManagerUtils().isIgnoringBatteryOptimizations()) {
addValue(context.resources.getString(R.string.nc_diagnose_battery_optimization_ignored))
} else {
addValue(context.resources.getString(R.string.nc_diagnose_battery_optimization_not_ignored))
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_battery_optimization_title),
value = if (PowerManagerUtils().isIgnoringBatteryOptimizations()) {
context.resources.getString(R.string.nc_diagnose_battery_optimization_ignored)
} else {
context.resources.getString(R.string.nc_diagnose_battery_optimization_not_ignored)
}
)
// handle notification permission on API level >= 33
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
addKey(context.resources.getString(R.string.nc_diagnose_notification_permission))
if (platformPermissionUtil.isPostNotificationsPermissionGranted()) {
addValue(context.resources.getString(R.string.nc_settings_notifications_granted))
} else {
addValue(context.resources.getString(R.string.nc_settings_notifications_declined))
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_notification_permission),
value = if (platformPermissionUtil.isPostNotificationsPermissionGranted()) {
context.resources.getString(R.string.nc_settings_notifications_granted)
} else {
context.resources.getString(R.string.nc_settings_notifications_declined)
}
)
}
addKey(context.resources.getString(R.string.nc_diagnose_notification_calls_channel_permission))
addValue(
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_notification_calls_channel_permission),
value =
translateBoolean(
NotificationUtils.isCallsNotificationChannelEnabled(this)
)
)
addKey(context.resources.getString(R.string.nc_diagnose_notification_messages_channel_permission))
addValue(
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_notification_messages_channel_permission),
value =
translateBoolean(
NotificationUtils.isMessagesNotificationChannelEnabled(this)
)
)
addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_title))
if (appPreferences.pushToken.isNullOrEmpty()) {
addValue(context.resources.getString(R.string.nc_diagnose_firebase_push_token_missing))
} else {
addValue("${appPreferences.pushToken.substring(0, PUSH_TOKEN_PREFIX_END)}...")
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_firebase_push_token_title),
value = if (appPreferences.pushToken.isNullOrEmpty()) {
context.resources.getString(R.string.nc_diagnose_firebase_push_token_missing)
} else {
"${appPreferences.pushToken.substring(0, PUSH_TOKEN_PREFIX_END)}..."
}
)
addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_generated))
if (appPreferences.pushTokenLatestGeneration != null && appPreferences.pushTokenLatestGeneration != 0L) {
addValue(
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_generated),
value = if (appPreferences.pushTokenLatestGeneration != null &&
appPreferences.pushTokenLatestGeneration != 0L
) {
DisplayUtils.unixTimeToHumanReadable(
appPreferences
.pushTokenLatestGeneration
)
)
} else {
addValue(context.resources.getString(R.string.nc_common_unknown))
}
} else {
context.resources.getString(R.string.nc_common_unknown)
}
)
addKey(context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_fetch))
if (appPreferences.pushTokenLatestFetch != null && appPreferences.pushTokenLatestFetch != 0L) {
addValue(DisplayUtils.unixTimeToHumanReadable(appPreferences.pushTokenLatestFetch))
} else {
addValue(context.resources.getString(R.string.nc_common_unknown))
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_firebase_push_token_latest_fetch),
value = if (appPreferences.pushTokenLatestFetch != null && appPreferences.pushTokenLatestFetch != 0L) {
DisplayUtils.unixTimeToHumanReadable(appPreferences.pushTokenLatestFetch)
} else {
context.resources.getString(R.string.nc_common_unknown)
}
)
}
private fun setupAccountValues() {
@ -310,21 +357,29 @@ class DiagnoseActivity : BaseActivity() {
addHeadline(context.resources.getString(R.string.nc_diagnose_account_category_title))
addKey(context.resources.getString(R.string.nc_diagnose_account_server))
addValue(currentUser.baseUrl!!)
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_account_server),
value =
currentUser.baseUrl!!
)
addKey(context.resources.getString(R.string.nc_diagnose_account_user_name))
addValue(currentUser.displayName!!)
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_account_user_name),
value =
currentUser.displayName!!
)
addKey(context.resources.getString(R.string.nc_diagnose_account_user_status_enabled))
addValue(
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_account_user_status_enabled),
value =
translateBoolean(
(currentUser.capabilities?.userStatusCapability?.enabled)
)
)
addKey(context.resources.getString(R.string.nc_diagnose_account_server_notification_app))
addValue(
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_account_server_notification_app),
value =
translateBoolean(currentUser.capabilities?.notificationsCapability?.features?.isNotEmpty())
)
@ -332,19 +387,27 @@ class DiagnoseActivity : BaseActivity() {
setupPushRegistrationDiagnose()
}
addKey(context.resources.getString(R.string.nc_diagnose_server_version))
addValue(currentUser.serverVersion?.versionString!!)
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_server_version),
value =
currentUser.serverVersion?.versionString!!
)
addKey(context.resources.getString(R.string.nc_diagnose_server_talk_version))
addValue(currentUser.capabilities?.spreedCapability?.version!!)
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_server_talk_version),
value =
currentUser.capabilities?.spreedCapability?.version!!
)
addKey(context.resources.getString(R.string.nc_diagnose_signaling_mode_title))
if (currentUser.externalSignalingServer?.externalSignalingServer?.isNotEmpty() == true) {
addValue(context.resources.getString(R.string.nc_diagnose_signaling_mode_extern))
} else {
addValue(context.resources.getString(R.string.nc_diagnose_signaling_mode_intern))
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_signaling_mode_title),
value =
if (currentUser.externalSignalingServer?.externalSignalingServer?.isNotEmpty() == true) {
context.resources.getString(R.string.nc_diagnose_signaling_mode_extern)
} else {
context.resources.getString(R.string.nc_diagnose_signaling_mode_intern)
}
)
}
private fun setupPushRegistrationDiagnose() {
@ -356,12 +419,14 @@ class DiagnoseActivity : BaseActivity() {
""
).blockingGet()?.value
addKey(context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_server))
if (latestPushRegistrationAtServer.isNullOrEmpty()) {
addValue(context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_server_fail))
} else {
addValue(DisplayUtils.unixTimeToHumanReadable(latestPushRegistrationAtServer.toLong()))
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_server),
if (latestPushRegistrationAtServer.isNullOrEmpty()) {
context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_server_fail)
} else {
DisplayUtils.unixTimeToHumanReadable(latestPushRegistrationAtServer.toLong())
}
)
val latestPushRegistrationAtPushProxy = arbitraryStorageManager.getStorageSetting(
accountId,
@ -369,12 +434,14 @@ class DiagnoseActivity : BaseActivity() {
""
).blockingGet()?.value
addKey(context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_push_proxy))
if (latestPushRegistrationAtPushProxy.isNullOrEmpty()) {
addValue(context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_push_proxy_fail))
} else {
addValue(DisplayUtils.unixTimeToHumanReadable(latestPushRegistrationAtPushProxy.toLong()))
}
addDiagnosisEntry(
key = context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_push_proxy),
value = if (latestPushRegistrationAtPushProxy.isNullOrEmpty()) {
context.resources.getString(R.string.nc_diagnose_latest_push_registration_at_push_proxy_fail)
} else {
DisplayUtils.unixTimeToHumanReadable(latestPushRegistrationAtPushProxy.toLong())
}
)
}
private fun getDeviceName(): String =
@ -392,72 +459,32 @@ class DiagnoseActivity : BaseActivity() {
}
}
@Suppress("MagicNumber")
private fun createLayoutFromMarkdown() {
val standardMargin = 16
val halfMargin = 8
val standardPadding = 16
private fun List<DiagnoseElement>.toMarkdownString(): String {
val markdownText = SpannableStringBuilder()
binding.diagnoseContentWrapper.removeAllViews()
markdownText.lines().forEach {
if (it.startsWith(MARKDOWN_HEADLINE)) {
val headline = TextView(context, null, 0)
headline.textSize = 2.0f
headline.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
context.resources.getDimension(R.dimen.headline_text_size)
)
headline.setTypeface(null, Typeface.BOLD)
headline.text = it.removeRange(0, 4)
binding.diagnoseContentWrapper.addView(headline)
headline.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(0, standardMargin, 0, standardMargin)
this.forEach {
when (it) {
is DiagnoseElement.DiagnoseHeadline -> {
markdownText.append("$MARKDOWN_HEADLINE ${it.headline}")
markdownText.append("\n\n")
}
headline.setPadding(0, standardPadding, 0, standardPadding)
viewThemeUtils.platform.colorTextView(headline)
} else if (it.startsWith(MARKDOWN_BOLD)) {
val key = TextView(context, null, 0)
key.setTextColor(resources.getColor(R.color.high_emphasis_text, null))
key.setTypeface(null, Typeface.BOLD)
key.text = it.replace(MARKDOWN_BOLD, "")
binding.diagnoseContentWrapper.addView(key)
key.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(0, 0, 0, halfMargin)
is DiagnoseElement.DiagnoseEntry -> {
markdownText.append("$MARKDOWN_BOLD${it.key}$MARKDOWN_BOLD")
markdownText.append("\n\n")
markdownText.append(it.value)
markdownText.append("\n\n")
}
} else if (it.isNotEmpty()) {
val value = TextView(context, null, 0)
value.setTextColor(resources.getColor(R.color.high_emphasis_text, null))
value.text = it
binding.diagnoseContentWrapper.addView(value)
value.updateLayoutParams<ViewGroup.MarginLayoutParams> {
setMargins(0, 0, 0, standardMargin)
}
value.setPadding(0, 0, 0, standardPadding)
}
}
return markdownText.toString()
}
private fun addHeadline(text: String) {
markdownText.append("$MARKDOWN_HEADLINE $text")
markdownText.append("\n\n")
diagnoseData.add(DiagnoseElement.DiagnoseHeadline(text))
}
private fun addKey(text: String) {
markdownText.bold { append("$MARKDOWN_BOLD$text$MARKDOWN_BOLD") }
markdownText.append("\n\n")
}
private fun addValue(text: String) {
markdownText.append(text)
markdownText.append("\n\n")
private fun addDiagnosisEntry(key: String, value: String) {
diagnoseData.add(DiagnoseElement.DiagnoseEntry(key, value))
}
companion object {
@ -465,6 +492,5 @@ class DiagnoseActivity : BaseActivity() {
private const val MARKDOWN_HEADLINE = "###"
private const val MARKDOWN_BOLD = "**"
private const val PUSH_TOKEN_PREFIX_END: Int = 5
private const val ORIGINAL_NEXTCLOUD_TALK_APPLICATION_ID = "com.nextcloud.talk2"
}
}

View File

@ -0,0 +1,77 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.diagnose
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.nextcloud.talk.R
@Composable
fun DiagnoseContentComposable(data: State<List<DiagnoseActivity.DiagnoseElement>>) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
data.value.forEach { element ->
when (element) {
is DiagnoseActivity.DiagnoseElement.DiagnoseHeadline -> Text(
modifier = Modifier.padding(vertical = 16.dp),
text = element.headline,
color = MaterialTheme.colorScheme.primary,
fontSize = LocalDensity.current.run { dimensionResource(R.dimen.headline_text_size).toPx().toSp() },
fontWeight = FontWeight.Bold
)
is DiagnoseActivity.DiagnoseElement.DiagnoseEntry -> {
Text(
text = element.key,
color = colorResource(R.color.high_emphasis_text),
fontWeight = FontWeight.Bold
)
Text(
modifier = Modifier.padding(bottom = 16.dp),
text = element.value,
color = colorResource(R.color.high_emphasis_text)
)
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun DiagnoseContentPreview() {
val state = remember {
mutableStateOf(
listOf(
DiagnoseActivity.DiagnoseElement.DiagnoseHeadline("Headline"),
DiagnoseActivity.DiagnoseElement.DiagnoseEntry("Key", "Value")
)
)
}
DiagnoseContentComposable(state)
}

View File

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Nextcloud Talk - Android Client
~
~ SPDX-FileCopyrightText: 2024 Marcel Hibbe <dev@mhibbe.de>
~ SPDX-License-Identifier: GPL-3.0-or-later
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/settings_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/settings_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/appbar"
android:theme="?attr/actionBarPopupTheme"
app:layout_scrollFlags="scroll|enterAlways"
app:navigationIconTint="@color/fontAppbar"
app:popupTheme="@style/appActionBarPopupMenu"
app:titleTextColor="@color/fontAppbar"
tools:title="@string/nc_app_product_name" />
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/diagnose_content_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/standard_padding">
</LinearLayout>
</ScrollView>
</LinearLayout>