зеркало из https://github.com/nextcloud/android.git
Merge pull request #12880 from nextcloud/bugfix/assistant-ui-ux
Assistant Feature UI/UX Fixes
This commit is contained in:
Коммит
f050c340af
|
@ -42,8 +42,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.nextcloud.client.assistant.component.AddTaskAlertDialog
|
||||
import com.nextcloud.client.assistant.component.CenterText
|
||||
import com.nextcloud.client.assistant.component.TaskTypesRow
|
||||
import com.nextcloud.client.assistant.component.TaskView
|
||||
import com.nextcloud.client.assistant.taskTypes.TaskTypesRow
|
||||
import com.nextcloud.client.assistant.task.TaskView
|
||||
import com.nextcloud.client.assistant.repository.AssistantMockRepository
|
||||
import com.nextcloud.ui.composeActivity.ComposeActivity
|
||||
import com.nextcloud.ui.composeComponents.alertDialog.SimpleAlertDialog
|
||||
|
|
|
@ -35,3 +35,8 @@ fun Task.statusData(): Pair<Int, Int> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add
|
||||
fun Task.completionDateRepresentation(): String {
|
||||
return completionExpectedAt ?: "TODO IMPLEMENT IT"
|
||||
}
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
*/
|
||||
package com.nextcloud.client.assistant.repository
|
||||
|
||||
import com.nextcloud.utils.extensions.getRandomString
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.resources.assistant.model.Task
|
||||
import com.owncloud.android.lib.resources.assistant.model.TaskList
|
||||
import com.owncloud.android.lib.resources.assistant.model.TaskType
|
||||
import com.owncloud.android.lib.resources.assistant.model.TaskTypes
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
class AssistantMockRepository(private val giveEmptyTasks: Boolean = false) : AssistantRepositoryType {
|
||||
override fun getTaskTypes(): RemoteOperationResult<TaskTypes> {
|
||||
return RemoteOperationResult<TaskTypes>(RemoteOperationResult.ResultCode.OK).apply {
|
||||
|
@ -41,16 +43,8 @@ class AssistantMockRepository(private val giveEmptyTasks: Boolean = false) : Ass
|
|||
null,
|
||||
"12",
|
||||
"",
|
||||
"Give me some text",
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. " +
|
||||
"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s," +
|
||||
" when an unknown printer took a galley of type and scrambled it to make a type" +
|
||||
" specimen book. It has survived not only five centuries, " +
|
||||
"but also the leap into electronic typesetting, remaining essentially unchanged." +
|
||||
" It was popularised in the 1960s with the release of Letraset sheets containing " +
|
||||
"Lorem Ipsum passages, and more recently with desktop publishing software like Aldus" +
|
||||
" PageMaker including versions of Lorem Ipsum",
|
||||
"",
|
||||
"Give me some long text 1",
|
||||
"Lorem ipsum".getRandomString(100),
|
||||
""
|
||||
),
|
||||
Task(
|
||||
|
@ -60,7 +54,62 @@ class AssistantMockRepository(private val giveEmptyTasks: Boolean = false) : Ass
|
|||
"12",
|
||||
"",
|
||||
"Give me some text 2",
|
||||
"Lorem Ipsum is simply dummy text of the printing and typesetting industry.",
|
||||
"Lorem".getRandomString(100),
|
||||
"",
|
||||
""
|
||||
),
|
||||
Task(
|
||||
3,
|
||||
"FreePrompt",
|
||||
null,
|
||||
"12",
|
||||
"",
|
||||
"Give me some text 3",
|
||||
"Lorem".getRandomString(300),
|
||||
"",
|
||||
""
|
||||
),
|
||||
Task(
|
||||
4,
|
||||
"FreePrompt",
|
||||
null,
|
||||
"12",
|
||||
"",
|
||||
"Give me some text 4",
|
||||
"Lorem".getRandomString(300),
|
||||
"",
|
||||
""
|
||||
),
|
||||
Task(
|
||||
5,
|
||||
"FreePrompt",
|
||||
null,
|
||||
"12",
|
||||
"",
|
||||
"Give me some text 5",
|
||||
"Lorem".getRandomString(300),
|
||||
"",
|
||||
""
|
||||
),
|
||||
Task(
|
||||
6,
|
||||
"FreePrompt",
|
||||
null,
|
||||
"12",
|
||||
"",
|
||||
"Give me some text 6",
|
||||
"Lorem".getRandomString(300),
|
||||
"",
|
||||
""
|
||||
),
|
||||
Task(
|
||||
7,
|
||||
"FreePrompt",
|
||||
null,
|
||||
"12",
|
||||
"",
|
||||
"Give me some text 7",
|
||||
"Lorem".getRandomString(300),
|
||||
"",
|
||||
""
|
||||
)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.client.assistant.task
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.nextcloud.client.assistant.extensions.statusData
|
||||
import com.owncloud.android.lib.resources.assistant.model.Task
|
||||
|
||||
@Composable
|
||||
fun TaskStatus(task: Task, foregroundColor: Color) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val (iconId, descriptionId) = task.statusData()
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = iconId),
|
||||
modifier = Modifier.size(16.dp),
|
||||
colorFilter = ColorFilter.tint(foregroundColor),
|
||||
contentDescription = "status icon"
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
|
||||
Text(text = stringResource(id = descriptionId), color = foregroundColor)
|
||||
|
||||
/*
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Text(text = task.completionDateRepresentation(), color = foregroundColor)
|
||||
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -1,27 +1,22 @@
|
|||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper_ozturk@proton.me>
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH
|
||||
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.client.assistant.component
|
||||
package com.nextcloud.client.assistant.task
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -31,18 +26,15 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.nextcloud.client.assistant.extensions.statusData
|
||||
import com.nextcloud.client.assistant.taskDetail.TaskDetailBottomSheet
|
||||
import com.nextcloud.ui.composeComponents.bottomSheet.MoreActionsBottomSheet
|
||||
import com.nextcloud.utils.extensions.getRandomString
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.lib.resources.assistant.model.Task
|
||||
|
||||
|
@ -53,7 +45,7 @@ fun TaskView(
|
|||
task: Task,
|
||||
showDeleteTaskAlertDialog: (Long) -> Unit
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
var showTaskDetailBottomSheet by remember { mutableStateOf(false) }
|
||||
var showMoreActionsBottomSheet by remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
|
@ -62,7 +54,7 @@ fun TaskView(
|
|||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(MaterialTheme.colorScheme.primary)
|
||||
.combinedClickable(onClick = {
|
||||
expanded = !expanded
|
||||
showTaskDetailBottomSheet = true
|
||||
}, onLongClick = {
|
||||
showMoreActionsBottomSheet = true
|
||||
})
|
||||
|
@ -84,10 +76,11 @@ fun TaskView(
|
|||
HorizontalDivider(modifier = Modifier.padding(horizontal = 4.dp, vertical = 8.dp))
|
||||
|
||||
Text(
|
||||
text = if (expanded) it else it.take(100) + "...",
|
||||
text = it.take(100),
|
||||
fontSize = 12.sp,
|
||||
color = Color.White,
|
||||
modifier = Modifier
|
||||
.height(100.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioLowBouncy,
|
||||
|
@ -97,39 +90,7 @@ fun TaskView(
|
|||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val (iconId, descriptionId) = task.statusData()
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = iconId),
|
||||
modifier = Modifier.size(16.dp),
|
||||
colorFilter = ColorFilter.tint(Color.White),
|
||||
contentDescription = "status icon"
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
|
||||
Text(text = stringResource(id = descriptionId), color = Color.White)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
if ((task.output?.length ?: 0) >= 100) {
|
||||
Image(
|
||||
painter = painterResource(
|
||||
id = if (!expanded) R.drawable.ic_expand_more else R.drawable.ic_expand_less
|
||||
),
|
||||
contentDescription = "expand content icon",
|
||||
colorFilter = ColorFilter.tint(Color.White)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
TaskStatus(task, foregroundColor = Color.White)
|
||||
|
||||
if (showMoreActionsBottomSheet) {
|
||||
val bottomSheetAction = listOf(
|
||||
|
@ -147,27 +108,20 @@ fun TaskView(
|
|||
dismiss = { showMoreActionsBottomSheet = false }
|
||||
)
|
||||
}
|
||||
|
||||
if (showTaskDetailBottomSheet) {
|
||||
TaskDetailBottomSheet(task) {
|
||||
showTaskDetailBottomSheet = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TaskViewPreview() {
|
||||
val output =
|
||||
"Lorem Ipsum is simply dummy text of the printing and " +
|
||||
"typesetting industry. Lorem Ipsum has been the " +
|
||||
"industry's standard dummy text ever since the 1500s, " +
|
||||
"when an unknown printer took a galley of type and " +
|
||||
"scrambled it to make a type specimen book. " +
|
||||
"It has survived not only five centuries, but also " +
|
||||
"the leap into electronic typesetting, remaining" +
|
||||
" essentially unchanged. It wLorem Ipsum is simply dummy" +
|
||||
" text of the printing and typesetting industry. " +
|
||||
"Lorem Ipsum has been the industry's standard dummy " +
|
||||
"text ever since the 1500s, when an unknown printer took a" +
|
||||
" galley of type and scrambled it to make a type specimen book. " +
|
||||
"It has survived not only five centuries, but also the leap " +
|
||||
"into electronic typesetting, remaining essentially unchanged."
|
||||
val output = "Lorem".getRandomString(100)
|
||||
|
||||
TaskView(
|
||||
task = Task(
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.client.assistant.taskDetail
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.nextcloud.client.assistant.task.TaskStatus
|
||||
import com.nextcloud.utils.extensions.getRandomString
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.lib.resources.assistant.model.Task
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TaskDetailBottomSheet(task: Task, dismiss: () -> Unit) {
|
||||
var showInput by remember { mutableStateOf(true) }
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier.padding(top = 32.dp),
|
||||
containerColor = Color.White,
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
},
|
||||
sheetState = sheetState
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
stickyHeader {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = colorResource(id = R.color.light_grey), shape = RoundedCornerShape(8.dp))
|
||||
) {
|
||||
TextInputSelectButton(
|
||||
Modifier.weight(1f),
|
||||
R.string.assistant_task_detail_screen_input_button_title,
|
||||
showInput,
|
||||
onClick = {
|
||||
showInput = true
|
||||
}
|
||||
)
|
||||
|
||||
TextInputSelectButton(
|
||||
Modifier.weight(1f),
|
||||
R.string.assistant_task_detail_screen_output_button_title,
|
||||
!showInput,
|
||||
onClick = {
|
||||
showInput = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color = colorResource(id = R.color.light_grey), shape = RoundedCornerShape(8.dp))
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = if (showInput) {
|
||||
task.input ?: ""
|
||||
} else {
|
||||
task.output ?: ""
|
||||
},
|
||||
fontSize = 12.sp,
|
||||
color = Color.Black,
|
||||
modifier = Modifier
|
||||
.animateContentSize(
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioLowBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
TaskStatus(task, foregroundColor = Color.Black)
|
||||
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextInputSelectButton(modifier: Modifier, titleId: Int, highlightCondition: Boolean, onClick: () -> Unit) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = if (highlightCondition) {
|
||||
ButtonDefaults.buttonColors(containerColor = Color.White)
|
||||
} else {
|
||||
ButtonDefaults.buttonColors(containerColor = colorResource(id = R.color.light_grey))
|
||||
},
|
||||
modifier = modifier
|
||||
.widthIn(min = 0.dp, max = 200.dp)
|
||||
.padding(horizontal = 4.dp)
|
||||
) {
|
||||
Text(text = stringResource(id = titleId), color = Color.Black)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
@Preview
|
||||
@Composable
|
||||
private fun TaskDetailScreenPreview() {
|
||||
TaskDetailBottomSheet(
|
||||
task = Task(
|
||||
1,
|
||||
"Free Prompt",
|
||||
0,
|
||||
"1",
|
||||
"1",
|
||||
"Give me text".getRandomString(100),
|
||||
"output".getRandomString(300),
|
||||
"",
|
||||
""
|
||||
)
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.client.assistant.component
|
||||
package com.nextcloud.client.assistant.taskTypes
|
||||
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Row
|
|
@ -36,7 +36,7 @@ import java.lang.ref.WeakReference
|
|||
class ComposeActivity : DrawerActivity() {
|
||||
|
||||
lateinit var binding: ActivityComposeBinding
|
||||
private var menuItemId: Int? = null
|
||||
private var menuItemId: Int = R.id.nav_all_files
|
||||
|
||||
companion object {
|
||||
const val DESTINATION = "DESTINATION"
|
||||
|
@ -51,13 +51,12 @@ class ComposeActivity : DrawerActivity() {
|
|||
|
||||
val destination = intent.getSerializableArgument(DESTINATION, ComposeDestination::class.java)
|
||||
val titleId = intent.getIntExtra(TITLE, R.string.empty)
|
||||
menuItemId = intent.getIntExtra(MENU_ITEM, -1)
|
||||
menuItemId = intent.getIntExtra(MENU_ITEM, R.id.nav_all_files)
|
||||
|
||||
setupToolbar()
|
||||
updateActionBarTitleAndHomeButtonByString(getString(titleId))
|
||||
setupDrawer(menuItemId)
|
||||
|
||||
if (menuItemId != -1) {
|
||||
setupDrawer(menuItemId!!)
|
||||
setupToolbarShowOnlyMenuButtonAndTitle(getString(titleId)) {
|
||||
openDrawer()
|
||||
}
|
||||
|
||||
binding.composeView.setContent {
|
||||
|
@ -72,15 +71,13 @@ class ComposeActivity : DrawerActivity() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (menuItemId != -1) {
|
||||
setDrawerMenuItemChecked(R.id.nav_assistant)
|
||||
}
|
||||
setDrawerMenuItemChecked(menuItemId)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
if (isDrawerOpen) closeDrawer() else openDrawer()
|
||||
toggleDrawer()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Nextcloud - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.utils.extensions
|
||||
|
||||
fun String.getRandomString(length: Int): String {
|
||||
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
|
||||
val result = (1..length)
|
||||
.map { allowedChars.random() }
|
||||
.joinToString("")
|
||||
|
||||
return this + result
|
||||
}
|
|
@ -286,10 +286,10 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
|
||||
public void updateHeader() {
|
||||
int primaryColor = themeColorUtils.unchangedPrimaryColor(getAccount(), this);
|
||||
boolean isClientBranded = getResources().getBoolean(R.bool.is_branded_client);
|
||||
|
||||
if (getAccount() != null &&
|
||||
getCapabilities().getServerBackground() != null &&
|
||||
!getResources().getBoolean(R.bool.is_branded_client)) {
|
||||
getCapabilities().getServerBackground() != null && !isClientBranded) {
|
||||
|
||||
OCCapability capability = getCapabilities();
|
||||
String logo = capability.getServerLogo();
|
||||
|
@ -339,47 +339,57 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
}
|
||||
|
||||
// hide ecosystem apps according to user preference or in branded client
|
||||
LinearLayout ecosystemApps = mNavigationViewHeader.findViewById(R.id.drawer_ecosystem_apps);
|
||||
if (getResources().getBoolean(R.bool.is_branded_client) || !preferences.isShowEcosystemApps()) {
|
||||
ecosystemApps.setVisibility(View.GONE);
|
||||
LinearLayout banner = mNavigationViewHeader.findViewById(R.id.drawer_ecosystem_apps);
|
||||
boolean shouldHideTopBanner = isClientBranded || !preferences.isShowEcosystemApps();
|
||||
|
||||
if (shouldHideTopBanner) {
|
||||
hideTopBanner(banner);
|
||||
} else {
|
||||
LinearLayout notesView = ecosystemApps.findViewById(R.id.drawer_ecosystem_notes);
|
||||
LinearLayout talkView = ecosystemApps.findViewById(R.id.drawer_ecosystem_talk);
|
||||
LinearLayout moreView = ecosystemApps.findViewById(R.id.drawer_ecosystem_more);
|
||||
LinearLayout assistantView = ecosystemApps.findViewById(R.id.drawer_ecosystem_assistant);
|
||||
|
||||
notesView.setOnClickListener(v -> openAppOrStore("it.niedermann.owncloud.notes"));
|
||||
talkView.setOnClickListener(v -> openAppOrStore("com.nextcloud.talk2"));
|
||||
moreView.setOnClickListener(v -> openAppStore("Nextcloud", true));
|
||||
assistantView.setOnClickListener(v -> startComposeActivity(ComposeDestination.AssistantScreen, R.string.assistant_screen_top_bar_title, -1));
|
||||
if (getCapabilities() != null && getCapabilities().getAssistant().isTrue()) {
|
||||
assistantView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
assistantView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
List<LinearLayout> views = Arrays.asList(notesView, talkView, moreView, assistantView);
|
||||
|
||||
int iconColor;
|
||||
if (Hct.fromInt(primaryColor).getTone() < 80.0) {
|
||||
iconColor = Color.WHITE;
|
||||
} else {
|
||||
iconColor = getColor(R.color.grey_800_transparent);
|
||||
}
|
||||
|
||||
for (LinearLayout view : views) {
|
||||
ImageView imageView = (ImageView) view.getChildAt(0);
|
||||
imageView.setImageTintList(ColorStateList.valueOf(iconColor));
|
||||
GradientDrawable background = (GradientDrawable) imageView.getBackground();
|
||||
background.setStroke(DisplayUtils.convertDpToPixel(1, this), iconColor);
|
||||
TextView textView = (TextView) view.getChildAt(1);
|
||||
textView.setTextColor(iconColor);
|
||||
}
|
||||
|
||||
ecosystemApps.setVisibility(View.VISIBLE);
|
||||
showTopBanner(banner, primaryColor);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideTopBanner(LinearLayout banner) {
|
||||
banner.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void showTopBanner(LinearLayout banner, int primaryColor) {
|
||||
LinearLayout notesView = banner.findViewById(R.id.drawer_ecosystem_notes);
|
||||
LinearLayout talkView = banner.findViewById(R.id.drawer_ecosystem_talk);
|
||||
LinearLayout moreView = banner.findViewById(R.id.drawer_ecosystem_more);
|
||||
LinearLayout assistantView = banner.findViewById(R.id.drawer_ecosystem_assistant);
|
||||
|
||||
notesView.setOnClickListener(v -> openAppOrStore("it.niedermann.owncloud.notes"));
|
||||
talkView.setOnClickListener(v -> openAppOrStore("com.nextcloud.talk2"));
|
||||
moreView.setOnClickListener(v -> openAppStore("Nextcloud", true));
|
||||
assistantView.setOnClickListener(v -> startComposeActivity(ComposeDestination.AssistantScreen, R.string.assistant_screen_top_bar_title, -1));
|
||||
if (getCapabilities() != null && getCapabilities().getAssistant().isTrue()) {
|
||||
assistantView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
assistantView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
List<LinearLayout> views = Arrays.asList(notesView, talkView, moreView, assistantView);
|
||||
|
||||
int iconColor;
|
||||
if (Hct.fromInt(primaryColor).getTone() < 80.0) {
|
||||
iconColor = Color.WHITE;
|
||||
} else {
|
||||
iconColor = getColor(R.color.grey_800_transparent);
|
||||
}
|
||||
|
||||
for (LinearLayout view : views) {
|
||||
ImageView imageView = (ImageView) view.getChildAt(0);
|
||||
imageView.setImageTintList(ColorStateList.valueOf(iconColor));
|
||||
GradientDrawable background = (GradientDrawable) imageView.getBackground();
|
||||
background.setStroke(DisplayUtils.convertDpToPixel(1, this), iconColor);
|
||||
TextView textView = (TextView) view.getChildAt(1);
|
||||
textView.setTextColor(iconColor);
|
||||
}
|
||||
|
||||
banner.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open specified app and, if not installed redirect to corresponding download.
|
||||
*
|
||||
|
@ -463,9 +473,7 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
DrawerMenuUtil.filterGroupfoldersMenuItem(menu, capability);
|
||||
DrawerMenuUtil.filterAssistantMenuItem(menu, capability, getResources());
|
||||
DrawerMenuUtil.setupHomeMenuItem(menu, getResources());
|
||||
|
||||
DrawerMenuUtil.removeMenuItem(menu, R.id.nav_community,
|
||||
!getResources().getBoolean(R.bool.participate_enabled));
|
||||
DrawerMenuUtil.removeMenuItem(menu, R.id.nav_community, !getResources().getBoolean(R.bool.participate_enabled));
|
||||
DrawerMenuUtil.removeMenuItem(menu, R.id.nav_shared, !getResources().getBoolean(R.bool.shared_enabled));
|
||||
DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout));
|
||||
}
|
||||
|
@ -494,10 +502,17 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
MainApp.showOnlyPersonalFiles(itemId == R.id.nav_personal_files);
|
||||
Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
if (this instanceof ComposeActivity) {
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
}
|
||||
|
||||
intent.setAction(FileDisplayActivity.ALL_FILES);
|
||||
intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItem.getItemId());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
closeDrawer();
|
||||
} else if (itemId == R.id.nav_favorites) {
|
||||
handleSearchEvents(new SearchEvent("", SearchRemoteOperation.SearchType.FAVORITE_SEARCH),
|
||||
menuItem.getItemId());
|
||||
|
@ -520,7 +535,8 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
startActivity(CommunityActivity.class);
|
||||
} else if (itemId == R.id.nav_logout) {
|
||||
mCheckedMenuItem = -1;
|
||||
menuItem.setChecked(false);
|
||||
MenuItem isNewMenuItemChecked = menuItem.setChecked(false);
|
||||
Log_OC.d(TAG,"onNavigationItemClicked nav_logout setChecked " + isNewMenuItemChecked);
|
||||
final Optional<User> optionalUser = getUser();
|
||||
if (optionalUser.isPresent()) {
|
||||
UserInfoActivity.openAccountRemovalDialog(optionalUser.get(), getSupportFragmentManager());
|
||||
|
@ -627,6 +643,11 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
private void launchActivityForSearch(SearchEvent searchEvent, int menuItemId) {
|
||||
Intent intent = new Intent(getApplicationContext(), FileDisplayActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
if (this instanceof ComposeActivity) {
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
}
|
||||
|
||||
intent.setAction(Intent.ACTION_SEARCH);
|
||||
intent.putExtra(OCFileListFragment.SEARCH_EVENT, searchEvent);
|
||||
intent.putExtra(FileDisplayActivity.DRAWER_MENU_ID, menuItemId);
|
||||
|
@ -673,6 +694,14 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START);
|
||||
}
|
||||
|
||||
public void toggleDrawer() {
|
||||
if (isDrawerOpen()) {
|
||||
closeDrawer();
|
||||
} else {
|
||||
openDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* closes the drawer.
|
||||
*/
|
||||
|
@ -1115,6 +1144,11 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
MainApp.showOnlyPersonalFiles(onlyPersonalFiles);
|
||||
Intent fileDisplayActivity = new Intent(getApplicationContext(), FileDisplayActivity.class);
|
||||
fileDisplayActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
if (this instanceof ComposeActivity) {
|
||||
fileDisplayActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
}
|
||||
|
||||
fileDisplayActivity.setAction(FileDisplayActivity.ALL_FILES);
|
||||
startActivity(fileDisplayActivity);
|
||||
}
|
||||
|
@ -1122,7 +1156,8 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
@Override
|
||||
public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
|
||||
if (callContext instanceof MenuItem menuItem) {
|
||||
menuItem.setIcon(avatarDrawable);
|
||||
MenuItem newIcon = menuItem.setIcon(avatarDrawable);
|
||||
Log_OC.d(TAG,"avatarGenerated new icon: " + newIcon);
|
||||
} else if (callContext instanceof ImageView imageView) {
|
||||
imageView.setImageDrawable(avatarDrawable);
|
||||
} else if (callContext instanceof MaterialButton materialButton) {
|
||||
|
|
|
@ -104,6 +104,22 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable
|
|||
viewThemeUtils.material.colorMaterialTextButton(mSwitchAccountButton);
|
||||
}
|
||||
|
||||
public void setupToolbarShowOnlyMenuButtonAndTitle(String title, View.OnClickListener toggleDrawer) {
|
||||
setupToolbar(false, false);
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
}
|
||||
|
||||
LinearLayout toolbar = findViewById(R.id.toolbar_linear_layout);
|
||||
MaterialButton menuButton = findViewById(R.id.toolbar_menu_button);
|
||||
MaterialTextView titleTextView = findViewById(R.id.toolbar_title);
|
||||
titleTextView.setText(title);
|
||||
toolbar.setVisibility(View.VISIBLE);
|
||||
menuButton.setOnClickListener(toggleDrawer);
|
||||
}
|
||||
|
||||
public void setupToolbar() {
|
||||
setupToolbar(false, false);
|
||||
}
|
||||
|
@ -278,7 +294,7 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable
|
|||
|
||||
public void clearToolbarSubtitle() {
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if(actionBar != null){
|
||||
if (actionBar != null) {
|
||||
actionBar.setSubtitle(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public final class DrawerMenuUtil {
|
|||
User user,
|
||||
Resources resources) {
|
||||
if (user.isAnonymous()) {
|
||||
filterMenuItems(menu, R.id.nav_gallery, R.id.nav_favorites);
|
||||
removeMenuItem(menu, R.id.nav_gallery, R.id.nav_favorites);
|
||||
}
|
||||
|
||||
if (!resources.getBoolean(R.bool.recently_modified_enabled)) {
|
||||
|
@ -38,26 +38,29 @@ public final class DrawerMenuUtil {
|
|||
public static void filterTrashbinMenuItem(Menu menu, @Nullable OCCapability capability) {
|
||||
if (capability != null && capability.getFilesUndelete().isFalse() ||
|
||||
capability != null && capability.getFilesUndelete().isUnknown()) {
|
||||
filterMenuItems(menu, R.id.nav_trashbin);
|
||||
removeMenuItem(menu, R.id.nav_trashbin);
|
||||
}
|
||||
}
|
||||
|
||||
public static void filterActivityMenuItem(Menu menu, @Nullable OCCapability capability) {
|
||||
if (capability != null && capability.getActivity().isFalse()) {
|
||||
filterMenuItems(menu, R.id.nav_activity);
|
||||
removeMenuItem(menu, R.id.nav_activity);
|
||||
}
|
||||
}
|
||||
|
||||
public static void filterAssistantMenuItem(Menu menu, @Nullable OCCapability capability, Resources resources) {
|
||||
boolean showCondition = capability != null && capability.getAssistant().isTrue() && !resources.getBoolean(R.bool.is_branded_client);
|
||||
if (!showCondition) {
|
||||
filterMenuItems(menu, R.id.nav_assistant);
|
||||
if (resources.getBoolean(R.bool.is_branded_client)) {
|
||||
if (capability != null && capability.getAssistant().isFalse()) {
|
||||
removeMenuItem(menu, R.id.nav_assistant);
|
||||
}
|
||||
} else {
|
||||
removeMenuItem(menu, R.id.nav_assistant);
|
||||
}
|
||||
}
|
||||
|
||||
public static void filterGroupfoldersMenuItem(Menu menu, @Nullable OCCapability capability) {
|
||||
if (capability != null && !capability.getGroupfolders().isTrue()) {
|
||||
filterMenuItems(menu, R.id.nav_groupfolders);
|
||||
removeMenuItem(menu, R.id.nav_groupfolders);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +77,7 @@ public final class DrawerMenuUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private static void filterMenuItems(Menu menu, int... menuIds) {
|
||||
private static void removeMenuItem(Menu menu, int... menuIds) {
|
||||
if (menuIds != null) {
|
||||
for (int menuId : menuIds) {
|
||||
menu.removeItem(menuId);
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<!--
|
||||
~ Nextcloud - Android Client
|
||||
~
|
||||
~ SPDX-FileCopyrightText: 2018-2024 Google LLC
|
||||
~ SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m296,615 l-56,-56 240,-240 240,240 -56,56 -184,-184 -184,184Z" />
|
||||
</vector>
|
|
@ -114,6 +114,42 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/toolbar_linear_layout"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/toolbar_menu_button"
|
||||
style="@style/Widget.AppTheme.Button.IconButton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
app:cornerRadius="@dimen/button_corner_radius"
|
||||
app:icon="@drawable/ic_menu"
|
||||
app:iconTint="@color/black" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/toolbar_title"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/black"
|
||||
android:lines="1"
|
||||
android:textSize="16sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<!-- home/search toolbar -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/home_toolbar"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<color name="white">#ffffff</color>
|
||||
<color name="white_helper_text">#B3FFFFFF</color>
|
||||
<color name="text_color">#333333</color>
|
||||
<color name="light_grey">#F5F5F5</color>
|
||||
<color name="grid_file_features_icon_color">#303034</color>
|
||||
<color name="grid_file_features_background_color">#E9E8EB</color>
|
||||
<color name="drawer_text_color">@color/secondary_text_color</color>
|
||||
|
|
|
@ -52,6 +52,9 @@
|
|||
<string name="assistant_screen_failed_task_text">Failed</string>
|
||||
<string name="assistant_screen_running_task_text">In Progress</string>
|
||||
|
||||
<string name="assistant_task_detail_screen_input_button_title">Input</string>
|
||||
<string name="assistant_task_detail_screen_output_button_title">Output</string>
|
||||
|
||||
<string name="assistant_screen_all_task_type">All</string>
|
||||
|
||||
<string name="drawer_item_assistant">Assistant</string>
|
||||
|
|
Загрузка…
Ссылка в новой задаче