Added announcement list screen
This commit is contained in:
@@ -8,6 +8,7 @@ import androidx.navigation.navArgument
|
|||||||
import de.sebse.fuplanner2.ui.courses.CoursesScreen
|
import de.sebse.fuplanner2.ui.courses.CoursesScreen
|
||||||
import de.sebse.fuplanner2.ui.details.CourseDetailsScreen
|
import de.sebse.fuplanner2.ui.details.CourseDetailsScreen
|
||||||
import de.sebse.fuplanner2.ui.details_announcements.CourseAnnouncementScreen
|
import de.sebse.fuplanner2.ui.details_announcements.CourseAnnouncementScreen
|
||||||
|
import de.sebse.fuplanner2.ui.details_announcements.CourseAnnouncementsScreen
|
||||||
import de.sebse.fuplanner2.ui.details_description.CourseDescriptionScreen
|
import de.sebse.fuplanner2.ui.details_description.CourseDescriptionScreen
|
||||||
|
|
||||||
sealed class MenuItem {
|
sealed class MenuItem {
|
||||||
@@ -53,6 +54,15 @@ fun MainActivityComposable() {
|
|||||||
val id = it.arguments!!.getLong("id")
|
val id = it.arguments!!.getLong("id")
|
||||||
CourseDescriptionScreen(tools, id)
|
CourseDescriptionScreen(tools, id)
|
||||||
}
|
}
|
||||||
|
composable(
|
||||||
|
arguments = listOf(
|
||||||
|
navArgument("id") { type = NavType.LongType }
|
||||||
|
),
|
||||||
|
route = "${MenuItem.Courses.route}/{id}/announcements"
|
||||||
|
) {
|
||||||
|
val id = it.arguments!!.getLong("id")
|
||||||
|
CourseAnnouncementsScreen(tools, id)
|
||||||
|
}
|
||||||
composable(
|
composable(
|
||||||
arguments = listOf(
|
arguments = listOf(
|
||||||
navArgument("id") { type = NavType.LongType },
|
navArgument("id") { type = NavType.LongType },
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.sebse.fuplanner2.ui.details
|
package de.sebse.fuplanner2.ui.details
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -91,7 +92,8 @@ fun CourseDetailsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview(showBackground = true)
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun CourseDetailsScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
fun CourseDetailsScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ import de.sebse.fuplanner2.ui.theme.AppTheme
|
|||||||
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
||||||
import de.sebse.fuplanner2.utils.toDateTimeString
|
import de.sebse.fuplanner2.utils.toDateTimeString
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AnnouncementItem(announcement: Announcement) {
|
|
||||||
AnnouncementItem(announcement) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AnnouncementItem(announcement: Announcement, click: () -> Unit) {
|
fun AnnouncementItem(announcement: Announcement, click: () -> Unit) {
|
||||||
FuCardColumn(
|
FuCardColumn(
|
||||||
@@ -40,6 +35,6 @@ fun AnnouncementItem(announcement: Announcement, click: () -> Unit) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun AnnouncementItemPreview(@PreviewParameter(AnnouncementPreviewProvider::class, 5) announcement: Announcement) {
|
fun AnnouncementItemPreview(@PreviewParameter(AnnouncementPreviewProvider::class, 5) announcement: Announcement) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
AnnouncementItem(announcement)
|
AnnouncementItem(announcement) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package de.sebse.fuplanner2.ui.details.components
|
package de.sebse.fuplanner2.ui.details.components
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.GridCells
|
import androidx.compose.foundation.lazy.GridCells
|
||||||
import androidx.compose.material.Card
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.ButtonDefaults.buttonColors
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -37,28 +38,28 @@ fun QuickLinks(courseId: Long, onClick: (String) -> Unit) {
|
|||||||
cells = GridCells.Adaptive(150.dp)
|
cells = GridCells.Adaptive(150.dp)
|
||||||
) {
|
) {
|
||||||
list.forEach {
|
list.forEach {
|
||||||
Card(
|
Button(
|
||||||
backgroundColor = MaterialTheme.colors.secondary,
|
colors = buttonColors(
|
||||||
|
backgroundColor = MaterialTheme.colors.secondary,
|
||||||
|
contentColor = MaterialTheme.colors.onSecondary,
|
||||||
|
),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(dimensionResource(R.dimen.card_view_margin))
|
.padding(dimensionResource(R.dimen.card_view_margin))
|
||||||
.fillMaxWidth()
|
.fillMaxWidth(),
|
||||||
.clickable { onClick(it.route) },
|
onClick = { onClick(it.route) }
|
||||||
elevation = dimensionResource(R.dimen.card_view_elevation),
|
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(it.name),
|
text = stringResource(it.name),
|
||||||
color = MaterialTheme.colors.onSecondary,
|
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = MaterialTheme.typography.h6,
|
style = MaterialTheme.typography.h6
|
||||||
modifier = Modifier
|
|
||||||
.padding(dimensionResource(R.dimen.card_view_padding))
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview(showBackground = true)
|
||||||
|
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun QuickLinksPreview() {
|
fun QuickLinksPreview() {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package de.sebse.fuplanner2.ui.details_announcements
|
|
||||||
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.paging.PagedListAdapter
|
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
|
||||||
import de.sebse.fuplanner2.database.Announcement
|
|
||||||
import de.sebse.fuplanner2.ui.ListItemHolder
|
|
||||||
import de.sebse.fuplanner2.utils.toDateTimeString
|
|
||||||
|
|
||||||
class AnnouncementsAdapter() : PagedListAdapter<Announcement, ListItemHolder>(EventDiffCallback()) {
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListItemHolder {
|
|
||||||
return ListItemHolder.invoke(parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ListItemHolder, position: Int) {
|
|
||||||
val event = getItem(position)
|
|
||||||
val actCtx = holder.itemView.context
|
|
||||||
|
|
||||||
event?.let {
|
|
||||||
holder.title.text = it.title
|
|
||||||
holder.subLeft.text = it.createdOn.toDateTimeString(actCtx)
|
|
||||||
holder.subRight.text = it.createdBy
|
|
||||||
} ?: run {
|
|
||||||
holder.clear()
|
|
||||||
holder.itemView.setOnClickListener(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EventDiffCallback : DiffUtil.ItemCallback<Announcement>() {
|
|
||||||
|
|
||||||
override fun areItemsTheSame(oldItem: Announcement, newItem: Announcement): Boolean {
|
|
||||||
return oldItem.uid == newItem.uid
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: Announcement, newItem: Announcement): Boolean {
|
|
||||||
return oldItem.getHash() == newItem.getHash()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package de.sebse.fuplanner2.ui.details_announcements
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import androidx.navigation.fragment.navArgs
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.work.workDataOf
|
|
||||||
import de.sebse.fuplanner2.R
|
|
||||||
import de.sebse.fuplanner2.auth.AppAccounts
|
|
||||||
import de.sebse.fuplanner2.databinding.FragmentRefreshRecyclerBinding
|
|
||||||
import de.sebse.fuplanner2.utils.console
|
|
||||||
import de.sebse.fuplanner2.utils.enqueueOneTimeWork
|
|
||||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_ACCOUNT_NAME
|
|
||||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker.Companion.KEY_COURSE_ID
|
|
||||||
import de.sebse.fuplanner2.worker.AnnouncementWorker
|
|
||||||
|
|
||||||
class AnnouncementsFragment : Fragment() {
|
|
||||||
|
|
||||||
private var title: String = ""
|
|
||||||
private val args: AnnouncementsFragmentArgs by navArgs()
|
|
||||||
private val announcementsViewModel: AnnouncementsViewModel by viewModels { AnnouncementsViewModelFactory(args.courseId) }
|
|
||||||
private lateinit var navController: NavController
|
|
||||||
private lateinit var binding: FragmentRefreshRecyclerBinding
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
val viewManager = LinearLayoutManager(context)
|
|
||||||
val viewAdapter = AnnouncementsAdapter()
|
|
||||||
return inflater.inflate(R.layout.fragment_refresh_recycler, container, false).apply {
|
|
||||||
console.log(findViewById(R.id.recycler_view), binding.recyclerView)
|
|
||||||
binding.recyclerView.apply {
|
|
||||||
setHasFixedSize(true)
|
|
||||||
|
|
||||||
layoutManager = viewManager
|
|
||||||
adapter = viewAdapter
|
|
||||||
}
|
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
|
||||||
enqueueOneTimeWork<AnnouncementWorker>(context.applicationContext) {
|
|
||||||
it.setInputData(workDataOf(
|
|
||||||
KEY_ACCOUNT_NAME to AppAccounts.getInstance().selectedAccount?.name,
|
|
||||||
KEY_COURSE_ID to args.courseId
|
|
||||||
))
|
|
||||||
}.observe(viewLifecycleOwner, Observer {
|
|
||||||
if (it.state.isFinished)
|
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
announcementsViewModel.events.observe(viewLifecycleOwner, Observer {
|
|
||||||
viewAdapter.submitList(it)
|
|
||||||
this@AnnouncementsFragment.title = args.title
|
|
||||||
})
|
|
||||||
navController = findNavController()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package de.sebse.fuplanner2.ui.details_announcements
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import androidx.paging.LivePagedListBuilder
|
|
||||||
import androidx.paging.PagedList
|
|
||||||
import de.sebse.fuplanner2.database.Announcement
|
|
||||||
import de.sebse.fuplanner2.database.AppDatabase
|
|
||||||
|
|
||||||
class AnnouncementsViewModelFactory(private val courseId: Long): ViewModelProvider.NewInstanceFactory() {
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = AnnouncementsViewModel(courseId) as T
|
|
||||||
}
|
|
||||||
|
|
||||||
class AnnouncementsViewModel(private val courseId: Long) : ViewModel() {
|
|
||||||
private val factory = AppDatabase.getInstance().announcementDao().getAll1(courseId)
|
|
||||||
|
|
||||||
val events: LiveData<PagedList<Announcement>> = LivePagedListBuilder(factory, 50).build()
|
|
||||||
}
|
|
||||||
@@ -16,11 +16,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import de.sebse.fuplanner2.R
|
import de.sebse.fuplanner2.R
|
||||||
import de.sebse.fuplanner2.Tools
|
import de.sebse.fuplanner2.Tools
|
||||||
import de.sebse.fuplanner2.database.Announcement
|
import de.sebse.fuplanner2.database.Announcement
|
||||||
import de.sebse.fuplanner2.database.Course
|
|
||||||
import de.sebse.fuplanner2.ui.shared.Heading
|
import de.sebse.fuplanner2.ui.shared.Heading
|
||||||
import de.sebse.fuplanner2.ui.shared.HtmlText
|
import de.sebse.fuplanner2.ui.shared.HtmlText
|
||||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||||
import de.sebse.fuplanner2.ui.tools.previews.CoursePreviewProvider
|
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
||||||
import de.sebse.fuplanner2.ui.tools.viewmodels.AnnouncementViewModel
|
import de.sebse.fuplanner2.ui.tools.viewmodels.AnnouncementViewModel
|
||||||
import de.sebse.fuplanner2.ui.tools.viewmodels.AnnouncementViewModelFactory
|
import de.sebse.fuplanner2.ui.tools.viewmodels.AnnouncementViewModelFactory
|
||||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||||
@@ -57,10 +56,8 @@ fun CourseAnnouncementScreen(announcement: Announcement) {
|
|||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun CourseAnnouncementScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
fun CourseAnnouncementScreenPreview(@PreviewParameter(AnnouncementPreviewProvider::class, 2) announcement: Announcement) {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
/*CourseAnnouncementScreen(
|
CourseAnnouncementScreen(announcement)
|
||||||
"scrip<b>fsdfsfg</b><br><a href='example.com'>ti</a>on"
|
|
||||||
)*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package de.sebse.fuplanner2.ui.details_announcements
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import de.sebse.fuplanner2.MenuItem
|
||||||
|
import de.sebse.fuplanner2.R
|
||||||
|
import de.sebse.fuplanner2.Tools
|
||||||
|
import de.sebse.fuplanner2.database.Announcement
|
||||||
|
import de.sebse.fuplanner2.ui.details.components.AnnouncementItem
|
||||||
|
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||||
|
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
||||||
|
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||||
|
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CourseAnnouncementsScreen(tools: Tools, id: Long) {
|
||||||
|
val coursesViewModel: DetailsViewModel =
|
||||||
|
viewModel(factory = DetailsViewModelFactory(id))
|
||||||
|
val course by coursesViewModel.course.observeAsState()
|
||||||
|
val announcements by coursesViewModel.announcements.observeAsState()
|
||||||
|
val title = course?.title ?: stringResource(id = R.string.description)
|
||||||
|
LaunchedEffect(title) {
|
||||||
|
tools.setTitle(title)
|
||||||
|
}
|
||||||
|
announcements?.let { CourseAnnouncementsScreen(it) { uid ->
|
||||||
|
tools.navTo("${MenuItem.Courses.route}/$id/announcements/${uid}")
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CourseAnnouncementsScreen(announcements: List<Announcement>, onClick: (Long) -> Unit) {
|
||||||
|
LazyColumn {
|
||||||
|
items(announcements) {
|
||||||
|
AnnouncementItem(it) {
|
||||||
|
it.uid?.let { uid -> onClick(uid) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun CourseAnnouncementsScreenPreview() {
|
||||||
|
AppTheme {
|
||||||
|
CourseAnnouncementsScreen(
|
||||||
|
AnnouncementPreviewProvider().values.take(10).toList()
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ fun Heading(text: String, onClick: (() -> Unit)? = null) {
|
|||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.h5,
|
style = MaterialTheme.typography.h5,
|
||||||
|
color = MaterialTheme.colors.onSurface,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = dimensionResource(id = R.dimen.header_padding))
|
.padding(top = dimensionResource(id = R.dimen.header_padding))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,18 +27,6 @@
|
|||||||
android:name="title"
|
android:name="title"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
|
||||||
android:id="@+id/course_announcements"
|
|
||||||
android:name="de.sebse.fuplanner2.ui.details_announcements.AnnouncementsFragment"
|
|
||||||
android:label="{title}"
|
|
||||||
tools:layout="@layout/fragment_refresh_recycler">
|
|
||||||
<argument
|
|
||||||
android:name="courseId"
|
|
||||||
app:argType="long" />
|
|
||||||
<argument
|
|
||||||
android:name="title"
|
|
||||||
app:argType="string" />
|
|
||||||
</fragment>
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/nav_notifications"
|
android:id="@+id/nav_notifications"
|
||||||
android:name="de.sebse.fuplanner2.ui.notification.NotificationFragment"
|
android:name="de.sebse.fuplanner2.ui.notification.NotificationFragment"
|
||||||
|
|||||||
Reference in New Issue
Block a user