Added course detail screens
This commit is contained in:
@@ -6,18 +6,21 @@ import androidx.room.*
|
||||
|
||||
@Dao
|
||||
interface AnnouncementDao {
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn ASC")
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn DESC")
|
||||
fun getAll1(courseId: Long): DataSource.Factory<Int, Announcement>
|
||||
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn ASC")
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn DESC")
|
||||
fun getAll2(courseId: Long): List<Announcement>
|
||||
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn ASC")
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn DESC")
|
||||
fun getAll3(courseId: Long): LiveData<List<Announcement>>
|
||||
|
||||
@Query("SELECT * FROM announcement WHERE uid = :announcementId LIMIT 1")
|
||||
fun getAnnouncementById(announcementId: Long): Announcement
|
||||
|
||||
@Query("SELECT * FROM announcement WHERE uid = :announcementId LIMIT 1")
|
||||
fun getAnnouncementById2(announcementId: Long): LiveData<Announcement>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
fun insert(announcement: Announcement): Long
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ data class Course (
|
||||
actCtx: Context,
|
||||
type: Notifications.CourseUpdateType,
|
||||
data: JsonObject
|
||||
): CharSequence? = when (type) {
|
||||
): CharSequence = when (type) {
|
||||
Notifications.CourseUpdateType.REMOVED -> actCtx.getHtmlSpannedString(R.string.not_course_update_course_removed, data.string("title"))
|
||||
Notifications.CourseUpdateType.UPDATED -> actCtx.getHtmlSpannedString(R.string.not_course_update_course_updated, data.string("title"))
|
||||
Notifications.CourseUpdateType.ADDED -> actCtx.getHtmlSpannedString(R.string.not_course_update_course_added, data.string("title"))
|
||||
@@ -72,7 +72,7 @@ data class Course (
|
||||
actCtx: Context,
|
||||
type: Notifications.CourseUpdateType,
|
||||
data: JsonObject
|
||||
): CharSequence? = when (type) {
|
||||
): CharSequence = when (type) {
|
||||
Notifications.CourseUpdateType.REMOVED -> actCtx.getHtmlSpannedString(R.string.adapter_course_update_course_removed, data.string("title"))
|
||||
Notifications.CourseUpdateType.UPDATED -> actCtx.getHtmlSpannedString(R.string.adapter_course_update_course_updated, data.string("title"))
|
||||
Notifications.CourseUpdateType.ADDED -> actCtx.getHtmlSpannedString(R.string.adapter_course_update_course_added, data.string("title"))
|
||||
|
||||
@@ -7,6 +7,8 @@ import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import de.sebse.fuplanner2.ui.courses.CoursesScreen
|
||||
import de.sebse.fuplanner2.ui.details.CourseDetailsScreen
|
||||
import de.sebse.fuplanner2.ui.details_announcements.CourseAnnouncementScreen
|
||||
import de.sebse.fuplanner2.ui.details_description.CourseDescriptionScreen
|
||||
|
||||
sealed class MenuItem {
|
||||
object Courses : NavLinks(R.string.menu_courses, R.drawable.ic_menu_courses, "courses")
|
||||
@@ -42,5 +44,25 @@ fun MainActivityComposable() {
|
||||
val id = it.arguments!!.getLong("id")
|
||||
CourseDetailsScreen(tools, id)
|
||||
}
|
||||
composable(
|
||||
arguments = listOf(
|
||||
navArgument("id") { type = NavType.LongType }
|
||||
),
|
||||
route = "${MenuItem.Courses.route}/{id}/description"
|
||||
) {
|
||||
val id = it.arguments!!.getLong("id")
|
||||
CourseDescriptionScreen(tools, id)
|
||||
}
|
||||
composable(
|
||||
arguments = listOf(
|
||||
navArgument("id") { type = NavType.LongType },
|
||||
navArgument("announceId") { type = NavType.LongType }
|
||||
),
|
||||
route = "${MenuItem.Courses.route}/{id}/announcements/{announceId}"
|
||||
) {
|
||||
val id = it.arguments!!.getLong("id")
|
||||
val announceId = it.arguments!!.getLong("announceId")
|
||||
CourseAnnouncementScreen(tools, id, announceId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package de.sebse.fuplanner2.ui.courses
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.util.Log
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
@@ -57,7 +56,6 @@ fun CoursesScreen(tools: Tools) {
|
||||
AppTheme {
|
||||
GroupedCourseList(groups = groups) { course ->
|
||||
course.uid?.let {
|
||||
Log.d("WHERE TO GO", "${MenuItem.Courses.route}/$it")
|
||||
tools.navTo("${MenuItem.Courses.route}/$it")
|
||||
}
|
||||
}
|
||||
@@ -133,9 +131,11 @@ fun CourseItem(id: Long?, title: String, lecturers: String, type: String, onclic
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.height(1.5.dp)
|
||||
.background(Brush.horizontalGradient(
|
||||
colors = listOf(color, MaterialTheme.colors.surface)
|
||||
))
|
||||
.background(
|
||||
Brush.horizontalGradient(
|
||||
colors = listOf(color, MaterialTheme.colors.surface)
|
||||
)
|
||||
)
|
||||
) {}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -11,17 +11,22 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
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.database.Course
|
||||
import de.sebse.fuplanner2.database.Event
|
||||
import de.sebse.fuplanner2.database.Lecturer
|
||||
import de.sebse.fuplanner2.ui.details.components.AnnouncementItem
|
||||
import de.sebse.fuplanner2.ui.details.components.EventItem
|
||||
import de.sebse.fuplanner2.ui.details.components.LecturerItem
|
||||
import de.sebse.fuplanner2.ui.details.components.QuickLinks
|
||||
import de.sebse.fuplanner2.ui.shared.Heading
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
||||
import de.sebse.fuplanner2.ui.tools.previews.CoursePreviewProvider
|
||||
import de.sebse.fuplanner2.ui.tools.previews.EventPreviewProvider
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||
import kotlin.math.min
|
||||
@@ -31,6 +36,7 @@ fun CourseDetailsScreen(tools: Tools, id: Long) {
|
||||
val coursesViewModel: DetailsViewModel = viewModel(factory = DetailsViewModelFactory(id))
|
||||
val course by coursesViewModel.course.observeAsState()
|
||||
val announcements by coursesViewModel.announcements.observeAsState()
|
||||
val events by coursesViewModel.events.observeAsState()
|
||||
val title = course?.title
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(title) {
|
||||
@@ -39,25 +45,47 @@ fun CourseDetailsScreen(tools: Tools, id: Long) {
|
||||
LaunchedEffect(true) {
|
||||
coursesViewModel.refresh(context)
|
||||
}
|
||||
CourseDetailsScreen(course, announcements, id)
|
||||
CourseDetailsScreen(
|
||||
course?.lecturers ?: emptyList(),
|
||||
announcements ?: emptyList(),
|
||||
events ?: emptyList(),
|
||||
id,
|
||||
course?.title ?: ""
|
||||
) {
|
||||
tools.navTo(it)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CourseDetailsScreen(course: Course?, announcement: List<Announcement>?, id: Long) {
|
||||
val announcements = announcement?.subList(0, min(announcement.size, 3)) ?: listOf()
|
||||
fun CourseDetailsScreen(
|
||||
lecturers: List<Lecturer>,
|
||||
announcements: List<Announcement>,
|
||||
events: List<Event>,
|
||||
id: Long,
|
||||
title: String,
|
||||
onClick: (String) -> Unit
|
||||
) {
|
||||
LazyColumn {
|
||||
item {
|
||||
QuickLinks(courseId = id)
|
||||
Heading(stringResource(R.string.lecturers))
|
||||
QuickLinks(courseId = id, onClick)
|
||||
if (lecturers.isNotEmpty()) Heading(stringResource(R.string.lecturers))
|
||||
}
|
||||
items(course?.lecturers ?: listOf()) {
|
||||
LecturerItem(lecturer = it, courseTitle = course?.title ?: "")
|
||||
items(lecturers.sortedBy { (if (it.isResponsible) "AAAA" else "ZZZZ") + it.lastName }) {
|
||||
LecturerItem(lecturer = it, courseTitle = title)
|
||||
}
|
||||
item {
|
||||
Heading(stringResource(R.string.announcements))
|
||||
if (announcements.isNotEmpty()) Heading(stringResource(R.string.announcements))
|
||||
}
|
||||
items(items = announcements) {
|
||||
AnnouncementItem(it)
|
||||
items(items = announcements.subList(0, min(announcements.size, 3)) ?: listOf()) {
|
||||
AnnouncementItem(it) {
|
||||
onClick("${MenuItem.Courses.route}/$id/announcements/${it.uid}")
|
||||
}
|
||||
}
|
||||
item {
|
||||
if (events.isNotEmpty()) Heading(stringResource(R.string.events))
|
||||
}
|
||||
items(items = events.subList(0, min(events.size, 3))) {
|
||||
EventItem(it)
|
||||
}
|
||||
// TODO: Add current assignments, upcoming events
|
||||
}
|
||||
@@ -67,6 +95,12 @@ fun CourseDetailsScreen(course: Course?, announcement: List<Announcement>?, id:
|
||||
@Composable
|
||||
fun CourseDetailsScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
||||
AppTheme {
|
||||
CourseDetailsScreen(course, AnnouncementPreviewProvider().values.take(3).toList(), course.uid!!)
|
||||
CourseDetailsScreen(
|
||||
course.lecturers,
|
||||
AnnouncementPreviewProvider().values.take(3).toList(),
|
||||
EventPreviewProvider().values.take(3).toList(),
|
||||
course.uid!!,
|
||||
course.title
|
||||
) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ fun AnnouncementItem(announcement: Announcement, click: () -> Unit) {
|
||||
.clickable(true, onClick = click)
|
||||
) {
|
||||
Text(
|
||||
text = announcement.title ?: "Title",
|
||||
text = announcement.title,
|
||||
style = MaterialTheme.typography.h6
|
||||
)
|
||||
Text(
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package de.sebse.fuplanner2.ui.details.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import de.sebse.fuplanner2.database.Event
|
||||
import de.sebse.fuplanner2.ui.shared.FuCardColumn
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.EventPreviewProvider
|
||||
import de.sebse.fuplanner2.utils.toDateTimeString
|
||||
|
||||
@Composable
|
||||
fun EventItem(event: Event) {
|
||||
EventItem(event) { }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EventItem(event: Event, click: () -> Unit) {
|
||||
FuCardColumn(
|
||||
modifier = Modifier
|
||||
.clickable(true, onClick = click)
|
||||
) {
|
||||
Text(
|
||||
text = event.title,
|
||||
style = MaterialTheme.typography.h6
|
||||
)
|
||||
Text(
|
||||
text = event.startDateTime.toDateTimeString(LocalContext.current) ?: "",
|
||||
style = MaterialTheme.typography.subtitle1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun EventItemPreview(@PreviewParameter(EventPreviewProvider::class, 5) event: Event) {
|
||||
AppTheme {
|
||||
EventItem(event)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package de.sebse.fuplanner2.ui.details.components
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.GridCells
|
||||
@@ -24,7 +25,7 @@ data class QuickLinkProps(@StringRes val name: Int, val route: String)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun QuickLinks(courseId: Long) {
|
||||
fun QuickLinks(courseId: Long, onClick: (String) -> Unit) {
|
||||
val list = listOf(
|
||||
QuickLinkProps(R.string.description, "courses/$courseId/description"),
|
||||
QuickLinkProps(R.string.resources, "courses/$courseId/resources"),
|
||||
@@ -40,7 +41,8 @@ fun QuickLinks(courseId: Long) {
|
||||
backgroundColor = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.padding(dimensionResource(R.dimen.card_view_margin))
|
||||
.fillMaxWidth(),
|
||||
.fillMaxWidth()
|
||||
.clickable { onClick(it.route) },
|
||||
elevation = dimensionResource(R.dimen.card_view_elevation),
|
||||
) {
|
||||
Text(
|
||||
@@ -60,6 +62,6 @@ fun QuickLinks(courseId: Long) {
|
||||
@Composable
|
||||
fun QuickLinksPreview() {
|
||||
AppTheme {
|
||||
QuickLinks(3)
|
||||
QuickLinks(3) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package de.sebse.fuplanner2.ui.details_announcements
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
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.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.Tools
|
||||
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.HtmlText
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.CoursePreviewProvider
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.AnnouncementViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.AnnouncementViewModelFactory
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||
|
||||
@Composable
|
||||
fun CourseAnnouncementScreen(tools: Tools, id: Long, announcementId: Long) {
|
||||
val coursesViewModel: DetailsViewModel =
|
||||
viewModel(factory = DetailsViewModelFactory(id))
|
||||
val announcementViewModel: AnnouncementViewModel =
|
||||
viewModel(factory = AnnouncementViewModelFactory(announcementId))
|
||||
val course by coursesViewModel.course.observeAsState()
|
||||
val announcement by announcementViewModel.observeAsState()
|
||||
val title = course?.title ?: stringResource(id = R.string.description)
|
||||
LaunchedEffect(title) {
|
||||
tools.setTitle(title)
|
||||
}
|
||||
announcement?.let { CourseAnnouncementScreen(it) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CourseAnnouncementScreen(announcement: Announcement) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(scrollState)
|
||||
) {
|
||||
Heading(text = announcement.title)
|
||||
HtmlText(
|
||||
html = announcement.body,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CourseAnnouncementScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
||||
AppTheme {
|
||||
/*CourseAnnouncementScreen(
|
||||
"scrip<b>fsdfsfg</b><br><a href='example.com'>ti</a>on"
|
||||
)*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.sebse.fuplanner2.ui.details_description
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
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.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.Tools
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.ui.shared.Heading
|
||||
import de.sebse.fuplanner2.ui.shared.HtmlText
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.CoursePreviewProvider
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||
|
||||
@Composable
|
||||
fun CourseDescriptionScreen(tools: Tools, id: Long) {
|
||||
val coursesViewModel: DetailsViewModel = viewModel(factory = DetailsViewModelFactory(id))
|
||||
val course by coursesViewModel.course.observeAsState()
|
||||
val title = course?.title ?: stringResource(id = R.string.description)
|
||||
LaunchedEffect(title) {
|
||||
tools.setTitle(title)
|
||||
}
|
||||
CourseDescriptionScreen(course?.description ?: "")
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CourseDescriptionScreen(description: String) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(scrollState)
|
||||
) {
|
||||
Heading(text = stringResource(id = R.string.description))
|
||||
HtmlText(
|
||||
html = description,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CourseDescriptionScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
||||
AppTheme {
|
||||
CourseDescriptionScreen(
|
||||
"scrip<b>fsdfsfg</b><br><a href='example.com'>ti</a>on"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package de.sebse.fuplanner2.ui.details_description
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebSettings
|
||||
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 de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.databinding.FragmentDescriptionBinding
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||
|
||||
|
||||
class DescriptionFragment : Fragment() {
|
||||
|
||||
private var title: String = ""
|
||||
private val args: DescriptionFragmentArgs by navArgs()
|
||||
private val detailsViewModel: DetailsViewModel by viewModels { DetailsViewModelFactory(args.courseId) }
|
||||
private lateinit var navController: NavController
|
||||
private lateinit var binding: FragmentDescriptionBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_description, container, false).apply {
|
||||
val nightModeFlags = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
binding.description.settings.forceDark = WebSettings.FORCE_DARK_ON
|
||||
}
|
||||
detailsViewModel.course.observe(viewLifecycleOwner, Observer {
|
||||
binding.description.loadDataWithBaseURL("", it.description, "text/html", "UTF-8", "")
|
||||
})
|
||||
navController = findNavController()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,48 @@
|
||||
package de.sebse.fuplanner2.ui.shared
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.res.dimensionResource
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
|
||||
@Composable
|
||||
fun Heading(text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.h5,
|
||||
modifier = Modifier.padding(top = dimensionResource(id = R.dimen.header_padding))
|
||||
)
|
||||
fun Heading(text: String, onClick: (() -> Unit)? = null) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.h5,
|
||||
modifier = Modifier
|
||||
.padding(top = dimensionResource(id = R.dimen.header_padding))
|
||||
)
|
||||
if (onClick != null) Text(
|
||||
text = "More >>",
|
||||
style = MaterialTheme.typography.subtitle2,
|
||||
textDecoration = TextDecoration.Underline,
|
||||
color = MaterialTheme.colors.primary,
|
||||
modifier = Modifier
|
||||
.padding(top = dimensionResource(id = R.dimen.header_padding))
|
||||
.align(Alignment.BottomEnd)
|
||||
.clickable(onClick = onClick)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun HeadingPreview() {
|
||||
AppTheme {
|
||||
Text("Super Cool")
|
||||
Heading("Super cool") { }
|
||||
}
|
||||
}
|
||||
|
||||
21
app/src/main/java/de/sebse/fuplanner2/ui/shared/HtmlText.kt
Normal file
21
app/src/main/java/de/sebse/fuplanner2/ui/shared/HtmlText.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package de.sebse.fuplanner2.ui.shared
|
||||
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.widget.TextView
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.text.HtmlCompat
|
||||
|
||||
@Composable
|
||||
fun HtmlText(html: String, modifier: Modifier = Modifier) {
|
||||
AndroidView(
|
||||
modifier = modifier,
|
||||
factory = { context -> TextView(context) },
|
||||
update = {
|
||||
it.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_COMPACT)
|
||||
it.movementMethod = LinkMovementMethod.getInstance()
|
||||
it.setTextIsSelectable(true)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.sebse.fuplanner2.ui.tools.previews
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import de.sebse.fuplanner2.database.Event
|
||||
import de.sebse.fuplanner2.utils.Faker
|
||||
import de.sebse.fuplanner2.utils.getFaker
|
||||
import java.util.*
|
||||
|
||||
class EventPreviewProvider(private val faker: Faker = getFaker()) : PreviewParameterProvider<Event> {
|
||||
val title = faker.strings.title()
|
||||
override val values = generateSequence(0) { it + 1 }
|
||||
.map { getItem(it) }
|
||||
|
||||
private fun getItem(num: Int): Event {
|
||||
val isExam = num == 20
|
||||
val cal = Calendar.getInstance()
|
||||
cal.add(Calendar.DATE, num / 2 * 7 + num % 2 * 3)
|
||||
cal.set(Calendar.HOUR, 14 + (num % 2) * 2)
|
||||
cal.set(Calendar.MINUTE, 30)
|
||||
cal.set(Calendar.SECOND, 0)
|
||||
cal.set(Calendar.MILLISECOND, 0)
|
||||
|
||||
return Event(
|
||||
faker.primitive.long(0, 100),
|
||||
faker.primitive.long(0, 100),
|
||||
faker.other.lastRefreshed(),
|
||||
title,
|
||||
90*60*1000 + (if (isExam) 1L else 0),
|
||||
cal.timeInMillis,
|
||||
"Hörsaal T9",
|
||||
if (isExam) "Klausur" else "Vorlesung",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.sebse.fuplanner2.ui.tools.viewmodels
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
|
||||
|
||||
class AnnouncementViewModelFactory(private val announcementId: Long): ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = AnnouncementViewModel(announcementId) as T
|
||||
}
|
||||
|
||||
class AnnouncementViewModel(private val announcementId: Long) : ViewModel() {
|
||||
private val announcement: LiveData<Announcement> =
|
||||
AppDatabase.getInstance().announcementDao().getAnnouncementById2(announcementId)
|
||||
|
||||
@Composable
|
||||
fun observeAsState(): State<Announcement?> {
|
||||
return announcement.observeAsState()
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.database.Event
|
||||
import de.sebse.fuplanner2.utils.enqueueOneTimeWork
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker
|
||||
import de.sebse.fuplanner2.worker.CourseWorker
|
||||
@@ -37,4 +38,8 @@ class DetailsViewModel(private val courseId: Long) : ViewModel() {
|
||||
AppDatabase.getInstance().announcementDao().getAll1(courseId),
|
||||
50
|
||||
).build()
|
||||
val events: LiveData<PagedList<Event>> = LivePagedListBuilder(
|
||||
AppDatabase.getInstance().eventDao().getAll1(courseId),
|
||||
50
|
||||
).build()
|
||||
}
|
||||
|
||||
@@ -39,17 +39,6 @@
|
||||
android:name="title"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/course_description"
|
||||
android:name="de.sebse.fuplanner2.ui.details_description.DescriptionFragment"
|
||||
android:label="{title}">
|
||||
<argument
|
||||
android:name="courseId"
|
||||
app:argType="long" />
|
||||
<argument
|
||||
android:name="title"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/nav_notifications"
|
||||
android:name="de.sebse.fuplanner2.ui.notification.NotificationFragment"
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
<dimen name="card_view_margin">4dp</dimen>
|
||||
<dimen name="card_view_padding">5dp</dimen>
|
||||
<dimen name="card_view_elevation">4dp</dimen>
|
||||
<dimen name="header_padding">8dp</dimen>
|
||||
<dimen name="header_padding">16dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<string name="course_type">Course Type</string>
|
||||
<string name="description">Description</string>
|
||||
<string name="resources">Resources</string>
|
||||
<string name="announcement">Announcement</string>
|
||||
<plurals name="not_course_update_text">
|
||||
<item quantity="one">One course message</item>
|
||||
<item quantity="other">%1$d course messages</item>
|
||||
|
||||
Reference in New Issue
Block a user