repo created
This commit is contained in:
commit
93184d21d1
1403 changed files with 189511 additions and 0 deletions
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.threadsoverview
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Log
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import autodagger.AutoInjector
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.BaseActivity
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.chat.ChatActivity
|
||||
import com.nextcloud.talk.chat.ChatActivity.Companion.TAG
|
||||
import com.nextcloud.talk.components.ColoredStatusBar
|
||||
import com.nextcloud.talk.components.StandardAppBar
|
||||
import com.nextcloud.talk.data.database.mappers.asModel
|
||||
import com.nextcloud.talk.models.json.threads.ThreadInfo
|
||||
import com.nextcloud.talk.threadsoverview.components.ThreadRow
|
||||
import com.nextcloud.talk.threadsoverview.viewmodels.ThreadsOverviewViewModel
|
||||
import com.nextcloud.talk.users.UserManager
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_THREAD_ID
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ThreadsOverviewActivity : BaseActivity() {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||
|
||||
@Inject
|
||||
lateinit var ncApi: NcApi
|
||||
|
||||
@Inject
|
||||
lateinit var userManager: UserManager
|
||||
|
||||
lateinit var threadsOverviewViewModel: ThreadsOverviewViewModel
|
||||
|
||||
var threadsSourceUrl: String = ""
|
||||
var appbarTitle: String = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
||||
threadsOverviewViewModel = ViewModelProvider(
|
||||
this,
|
||||
viewModelFactory
|
||||
)[ThreadsOverviewViewModel::class.java]
|
||||
|
||||
val colorScheme = viewThemeUtils.getColorScheme(this)
|
||||
|
||||
val extras: Bundle? = intent.extras
|
||||
threadsSourceUrl = extras?.getString(KEY_THREADS_SOURCE_URL).orEmpty()
|
||||
appbarTitle = extras?.getString(KEY_APPBAR_TITLE).orEmpty()
|
||||
|
||||
setContent {
|
||||
val backgroundColor = colorResource(id = R.color.bg_default)
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme
|
||||
) {
|
||||
ColoredStatusBar()
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.statusBarsPadding(),
|
||||
topBar = {
|
||||
StandardAppBar(
|
||||
title = appbarTitle,
|
||||
null
|
||||
)
|
||||
},
|
||||
content = { paddingValues ->
|
||||
val uiState by threadsOverviewViewModel.threadsListState.collectAsState()
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.padding(0.dp, paddingValues.calculateTopPadding(), 0.dp, 0.dp)
|
||||
.background(backgroundColor)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
ThreadsOverviewScreen(
|
||||
uiState,
|
||||
onThreadClick = { roomToken, threadId ->
|
||||
navigateToChatActivity(roomToken, threadId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun navigateToChatActivity(roomToken: String, threadId: Int) {
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ROOM_TOKEN, roomToken)
|
||||
bundle.putLong(KEY_THREAD_ID, threadId.toLong())
|
||||
val chatIntent = Intent(context, ChatActivity::class.java)
|
||||
chatIntent.putExtras(bundle)
|
||||
startActivity(chatIntent)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
supportActionBar?.show()
|
||||
threadsOverviewViewModel.init(threadsSourceUrl)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = ThreadsOverviewActivity::class.java.simpleName
|
||||
val KEY_APPBAR_TITLE = "KEY_APPBAR_TITLE"
|
||||
val KEY_THREADS_SOURCE_URL = "KEY_THREADS_SOURCE_URL"
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ThreadsOverviewScreen(
|
||||
uiState: ThreadsOverviewViewModel.ThreadsListUiState,
|
||||
onThreadClick: (roomToken: String, threadId: Int) -> Unit
|
||||
) {
|
||||
when (val state = uiState) {
|
||||
is ThreadsOverviewViewModel.ThreadsListUiState.None -> {
|
||||
LoadingIndicator()
|
||||
}
|
||||
|
||||
is ThreadsOverviewViewModel.ThreadsListUiState.Success -> {
|
||||
ThreadsList(
|
||||
threads = state.threadsList!!,
|
||||
onThreadClick = onThreadClick
|
||||
)
|
||||
}
|
||||
|
||||
is ThreadsOverviewViewModel.ThreadsListUiState.Error -> {
|
||||
Log.e(TAG, "Error when retrieving threads", uiState.exception)
|
||||
ErrorView(message = stringResource(R.string.nc_common_error_sorry))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ThreadsList(threads: List<ThreadInfo>, onThreadClick: (roomToken: String, threadId: Int) -> Unit) {
|
||||
val space = ' '
|
||||
if (threads.isEmpty()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(stringResource(R.string.threads_list_empty))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
items(
|
||||
items = threads,
|
||||
key = { threadInfo -> threadInfo.thread!!.id }
|
||||
) { threadInfo ->
|
||||
val messageJson = threadInfo.last ?: threadInfo.first
|
||||
val messageModel = messageJson?.asModel()
|
||||
|
||||
ThreadRow(
|
||||
roomToken = threadInfo.thread!!.roomToken,
|
||||
threadId = threadInfo.thread!!.id,
|
||||
title = threadInfo.thread?.title.orEmpty(),
|
||||
numReplies = pluralStringResource(
|
||||
R.plurals.thread_replies,
|
||||
threadInfo.thread?.numReplies ?: 0,
|
||||
threadInfo.thread?.numReplies ?: 0
|
||||
),
|
||||
secondLineTitle = messageModel?.actorDisplayName?.substringBefore(space)?.let { "$it:" }.orEmpty(),
|
||||
secondLine = messageModel?.text.orEmpty(),
|
||||
date = getLastActivityDate(threadInfo), // replace with value from api when available
|
||||
onClick = onThreadClick
|
||||
)
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun getLastActivityDate(threadInfo: ThreadInfo): String {
|
||||
val oneSecond = 1000L
|
||||
|
||||
val lastActivityTimestamp = threadInfo.thread?.lastActivity ?: 0
|
||||
|
||||
val lastActivityDate = DateUtils.getRelativeTimeSpanString(
|
||||
lastActivityTimestamp.times(oneSecond),
|
||||
System.currentTimeMillis(),
|
||||
0,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE
|
||||
).toString()
|
||||
return lastActivityDate
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadingIndicator() {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ErrorView(message: String) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(text = message, color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue