Add announcements to compose
This commit is contained in:
@@ -9,11 +9,11 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.google.android.material.composethemeadapter.MdcTheme
|
||||
import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.database.User
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -25,7 +25,7 @@ class MainActivity() : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
activityViewModel = ViewModelProvider(this)[MainActivityViewModel::class.java]
|
||||
setContent {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
MainActivityComposable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package de.sebse.fuplanner2.database
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.paging.DataSource
|
||||
import androidx.room.*
|
||||
import de.sebse.fuplanner2.utils.console
|
||||
|
||||
@Dao
|
||||
interface AnnouncementDao {
|
||||
@@ -12,6 +12,9 @@ interface AnnouncementDao {
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn ASC")
|
||||
fun getAll2(courseId: Long): List<Announcement>
|
||||
|
||||
@Query("SELECT * FROM announcement WHERE courseId = :courseId ORDER BY createdOn ASC")
|
||||
fun getAll3(courseId: Long): LiveData<List<Announcement>>
|
||||
|
||||
@Query("SELECT * FROM announcement WHERE uid = :announcementId LIMIT 1")
|
||||
fun getAnnouncementById(announcementId: Long): Announcement
|
||||
|
||||
@@ -43,4 +46,4 @@ interface AnnouncementDao {
|
||||
|
||||
@Delete
|
||||
fun delete(announcements: List<Announcement>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.google.android.material.composethemeadapter.MdcTheme
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ fun DrawerItems(currentRoute: String?, menu: List<NavLinks>, onItemClick: (route
|
||||
@Preview
|
||||
@Composable
|
||||
fun TopBarPreview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
TopBar(
|
||||
title = "A title"
|
||||
) { }
|
||||
@@ -150,7 +150,7 @@ fun TopBarPreview() {
|
||||
@Preview
|
||||
@Composable
|
||||
fun DrawerPreview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
Drawer(currentRoute = "courses", menu = screens) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
|
||||
import com.google.android.material.composethemeadapter.MdcTheme
|
||||
import de.sebse.fuplanner2.MenuItem
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.Tools
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.ui.details.CoursePreviewProvider
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.CoursePreviewProvider
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.CoursesViewModel
|
||||
import de.sebse.fuplanner2.utils.color.getColor
|
||||
import de.sebse.fuplanner2.viewmodels.CoursesViewModel
|
||||
|
||||
@Composable
|
||||
fun CoursesScreen(tools: Tools) {
|
||||
@@ -54,7 +54,7 @@ fun CoursesScreen(tools: Tools) {
|
||||
LaunchedEffect(title) {
|
||||
tools.setTitle(title)
|
||||
}
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
GroupedCourseList(groups = groups) { course ->
|
||||
course.uid?.let {
|
||||
Log.d("WHERE TO GO", "${MenuItem.Courses.route}/$it")
|
||||
@@ -163,7 +163,7 @@ fun CourseItemHint(icon: ImageVector, @StringRes imageAltRes: Int, text: String)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
fun CourseListPreview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
CourseList(
|
||||
CoursePreviewProvider().values.take(3).toList()
|
||||
) { }
|
||||
@@ -174,7 +174,7 @@ fun CourseListPreview() {
|
||||
@Preview
|
||||
@Composable
|
||||
fun CourseItemPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
CourseItem(course) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,27 +12,34 @@ 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 com.google.android.material.composethemeadapter.MdcTheme
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.Tools
|
||||
import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.ui.details.components.AnnouncementItem
|
||||
import de.sebse.fuplanner2.ui.details.components.LecturerItem
|
||||
import de.sebse.fuplanner2.ui.details.components.QuickLinks
|
||||
import de.sebse.fuplanner2.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.viewmodels.DetailsViewModelFactory
|
||||
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.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||
|
||||
@Composable
|
||||
fun CourseDetailsScreen(tools: Tools, id: Long) {
|
||||
val coursesViewModel: DetailsViewModel = viewModel(factory = DetailsViewModelFactory(id))
|
||||
val state = coursesViewModel.course.observeAsState()
|
||||
val announce = AppDatabase.getInstance().announcementDao().getAll3(id).observeAsState()
|
||||
val title = state.value?.title
|
||||
LaunchedEffect(title) {
|
||||
title?.let { tools.setTitle(it) }
|
||||
}
|
||||
CourseDetailsScreen(state.value, id)
|
||||
CourseDetailsScreen(state.value, announce.value, id)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CourseDetailsScreen(course: Course?, id: Long) {
|
||||
fun CourseDetailsScreen(course: Course?, announcement: List<Announcement>?, id: Long) {
|
||||
Column {
|
||||
QuickLinks(courseId = id)
|
||||
Text(
|
||||
@@ -44,6 +51,15 @@ fun CourseDetailsScreen(course: Course?, id: Long) {
|
||||
LecturerItem(lecturer = it, courseTitle = course?.title ?: "")
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.announcements),
|
||||
style = MaterialTheme.typography.h5
|
||||
)
|
||||
LazyColumn {
|
||||
items(announcement ?: listOf()) {
|
||||
AnnouncementItem(it)
|
||||
}
|
||||
}
|
||||
// TODO: Add latest announcements, current assignments, upcoming events
|
||||
}
|
||||
}
|
||||
@@ -51,7 +67,7 @@ fun CourseDetailsScreen(course: Course?, id: Long) {
|
||||
@Preview
|
||||
@Composable
|
||||
fun CourseDetailsScreenPreview(@PreviewParameter(CoursePreviewProvider::class, 1) course: Course) {
|
||||
MdcTheme {
|
||||
CourseDetailsScreen(course, course.uid!!)
|
||||
AppTheme {
|
||||
CourseDetailsScreen(course, AnnouncementPreviewProvider().values.take(3).toList(), course.uid!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package de.sebse.fuplanner2.ui.details.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Card
|
||||
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.res.dimensionResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
||||
import de.sebse.fuplanner2.utils.toDateTimeString
|
||||
|
||||
@Composable
|
||||
fun AnnouncementItem(announcement: Announcement) {
|
||||
AnnouncementItem(announcement) { }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AnnouncementItem(announcement: Announcement, click: () -> Unit) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(dimensionResource(R.dimen.card_view_margin)),
|
||||
elevation = dimensionResource(R.dimen.card_view_elevation)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clickable(true, onClick = click)
|
||||
.padding(dimensionResource(R.dimen.card_view_padding))
|
||||
) {
|
||||
Text(
|
||||
text = announcement.title ?: "Title",
|
||||
style = MaterialTheme.typography.h6
|
||||
)
|
||||
Text(
|
||||
text = announcement.createdOn.toDateTimeString(LocalContext.current) ?: "",
|
||||
style = MaterialTheme.typography.subtitle1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AnnouncementItemPreview(@PreviewParameter(AnnouncementPreviewProvider::class, 5) announcement: Announcement) {
|
||||
AppTheme {
|
||||
AnnouncementItem(announcement)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.sebse.fuplanner2.ui.details
|
||||
package de.sebse.fuplanner2.ui.details.components
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -21,9 +21,10 @@ import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.android.material.composethemeadapter.MdcTheme
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.database.Lecturer
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
import de.sebse.fuplanner2.ui.tools.previews.LecturerPreviewProvider
|
||||
|
||||
@Composable
|
||||
fun LecturerItem(lecturer: Lecturer, courseTitle: String) {
|
||||
@@ -84,8 +85,8 @@ fun LecturerItem(lecturer: Lecturer, click: () -> Unit) {
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun LecturerItemPreview(@PreviewParameter(LecturerPreviewProvider::class, 2) lecturer: Lecturer) {
|
||||
MdcTheme {
|
||||
fun LecturerItemPreview(@PreviewParameter(LecturerPreviewProvider::class, 3) lecturer: Lecturer) {
|
||||
AppTheme {
|
||||
LecturerItem(lecturer, "Course Name")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.android.material.composethemeadapter.MdcTheme
|
||||
import de.sebse.fuplanner2.R
|
||||
import de.sebse.fuplanner2.ui.theme.AppTheme
|
||||
|
||||
|
||||
data class QuickLinkProps(@StringRes val name: Int, val route: String)
|
||||
@@ -64,7 +64,7 @@ fun QuickLinks(courseId: Long) {
|
||||
@Preview
|
||||
@Composable
|
||||
fun QuickLinksPreview() {
|
||||
MdcTheme {
|
||||
AppTheme {
|
||||
QuickLinks(3)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
package de.sebse.fuplanner2.ui.details_announcements
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.paging.LivePagedListBuilder
|
||||
import androidx.paging.PagedList
|
||||
import androidx.work.workDataOf
|
||||
import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.utils.enqueueOneTimeWork
|
||||
import de.sebse.fuplanner2.worker.AbstractAccountWorker
|
||||
import de.sebse.fuplanner2.worker.AnnouncementWorker
|
||||
|
||||
class AnnouncementsViewModelFactory(private val courseId: Long): ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T = AnnouncementsViewModel(courseId) as T
|
||||
}
|
||||
|
||||
class AnnouncementsViewModel(courseId: Long) : ViewModel() {
|
||||
class AnnouncementsViewModel(private val courseId: Long) : ViewModel() {
|
||||
private val factory = AppDatabase.getInstance().announcementDao().getAll1(courseId)
|
||||
|
||||
fun refresh(ctx: Context) {
|
||||
enqueueOneTimeWork<AnnouncementWorker>(ctx) {
|
||||
it.setInputData(workDataOf(
|
||||
AbstractAccountWorker.KEY_ACCOUNT_NAME to AppAccounts.getInstance().selectedAccount?.name,
|
||||
AbstractAccountWorker.KEY_COURSE_ID to courseId
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
val events: LiveData<PagedList<Announcement>> = LivePagedListBuilder(factory, 50).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ 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.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.viewmodels.DetailsViewModelFactory
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModel
|
||||
import de.sebse.fuplanner2.ui.tools.viewmodels.DetailsViewModelFactory
|
||||
|
||||
|
||||
class DescriptionFragment : Fragment() {
|
||||
|
||||
58
app/src/main/java/de/sebse/fuplanner2/ui/theme/Color.kt
Normal file
58
app/src/main/java/de/sebse/fuplanner2/ui/theme/Color.kt
Normal file
@@ -0,0 +1,58 @@
|
||||
package de.sebse.fuplanner2.ui.theme
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
|
||||
val md_theme_light_primary = Color(0xFF245fa7)
|
||||
val md_theme_light_onPrimary = Color(0xFFffffff)
|
||||
val md_theme_light_primaryContainer = Color(0xFFd4e3ff)
|
||||
val md_theme_light_onPrimaryContainer = Color(0xFF001b3d)
|
||||
val md_theme_light_secondary = Color(0xFF4a6800)
|
||||
val md_theme_light_onSecondary = Color(0xFFffffff)
|
||||
val md_theme_light_secondaryContainer = Color(0xFFbef43c)
|
||||
val md_theme_light_onSecondaryContainer = Color(0xFF131f00)
|
||||
val md_theme_light_tertiary = Color(0xFF8b5000)
|
||||
val md_theme_light_onTertiary = Color(0xFFffffff)
|
||||
val md_theme_light_tertiaryContainer = Color(0xFFffdcba)
|
||||
val md_theme_light_onTertiaryContainer = Color(0xFF2d1600)
|
||||
val md_theme_light_error = Color(0xFFba1b1b)
|
||||
val md_theme_light_errorContainer = Color(0xFFffdad4)
|
||||
val md_theme_light_onError = Color(0xFFffffff)
|
||||
val md_theme_light_onErrorContainer = Color(0xFF410001)
|
||||
val md_theme_light_background = Color(0xFFfdfbff)
|
||||
val md_theme_light_onBackground = Color(0xFF1b1b1d)
|
||||
val md_theme_light_surface = Color(0xFFfdfbff)
|
||||
val md_theme_light_onSurface = Color(0xFF1b1b1d)
|
||||
val md_theme_light_surfaceVariant = Color(0xFFe0e2eb)
|
||||
val md_theme_light_onSurfaceVariant = Color(0xFF44474f)
|
||||
val md_theme_light_outline = Color(0xFF74777f)
|
||||
val md_theme_light_inverseOnSurface = Color(0xFFf1f0f4)
|
||||
val md_theme_light_inverseSurface = Color(0xFF2f3033)
|
||||
|
||||
val md_theme_dark_primary = Color(0xFFa6c8ff)
|
||||
val md_theme_dark_onPrimary = Color(0xFF003063)
|
||||
val md_theme_dark_primaryContainer = Color(0xFF00468b)
|
||||
val md_theme_dark_onPrimaryContainer = Color(0xFFd4e3ff)
|
||||
val md_theme_dark_secondary = Color(0xFFa3d719)
|
||||
val md_theme_dark_onSecondary = Color(0xFF253600)
|
||||
val md_theme_dark_secondaryContainer = Color(0xFF374e00)
|
||||
val md_theme_dark_onSecondaryContainer = Color(0xFFbef43c)
|
||||
val md_theme_dark_tertiary = Color(0xFFffb86b)
|
||||
val md_theme_dark_onTertiary = Color(0xFF4a2800)
|
||||
val md_theme_dark_tertiaryContainer = Color(0xFF6a3c00)
|
||||
val md_theme_dark_onTertiaryContainer = Color(0xFFffdcba)
|
||||
val md_theme_dark_error = Color(0xFFffb4a9)
|
||||
val md_theme_dark_errorContainer = Color(0xFF930006)
|
||||
val md_theme_dark_onError = Color(0xFF680003)
|
||||
val md_theme_dark_onErrorContainer = Color(0xFFffdad4)
|
||||
val md_theme_dark_background = Color(0xFF1b1b1d)
|
||||
val md_theme_dark_onBackground = Color(0xFFe3e2e6)
|
||||
val md_theme_dark_surface = Color(0xFF1b1b1d)
|
||||
val md_theme_dark_onSurface = Color(0xFFe3e2e6)
|
||||
val md_theme_dark_surfaceVariant = Color(0xFF44474f)
|
||||
val md_theme_dark_onSurfaceVariant = Color(0xFFc3c6cf)
|
||||
val md_theme_dark_outline = Color(0xFF8e919a)
|
||||
val md_theme_dark_inverseOnSurface = Color(0xFF1b1b1d)
|
||||
val md_theme_dark_inverseSurface = Color(0xFFe3e2e6)
|
||||
|
||||
val seed = Color(0xFF003366)
|
||||
val error = Color(0xFFba1b1b)
|
||||
102
app/src/main/java/de/sebse/fuplanner2/ui/theme/Theme.kt
Normal file
102
app/src/main/java/de/sebse/fuplanner2/ui/theme/Theme.kt
Normal file
@@ -0,0 +1,102 @@
|
||||
package de.sebse.fuplanner2.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.darkColors
|
||||
import androidx.compose.material.lightColors
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
// Comments are changes in Material 3 (Material You)
|
||||
|
||||
//private val LightThemeColors = lightColorScheme(
|
||||
private val LightThemeColors = lightColors(
|
||||
primary = md_theme_light_primary,
|
||||
onPrimary = md_theme_light_onPrimary,
|
||||
//primaryContainer = md_theme_light_primaryContainer,
|
||||
//onPrimaryContainer = md_theme_light_onPrimaryContainer,
|
||||
primaryVariant = md_theme_light_onPrimaryContainer,
|
||||
|
||||
secondary = md_theme_light_secondary,
|
||||
onSecondary = md_theme_light_onSecondary,
|
||||
//secondaryContainer = md_theme_light_secondaryContainer,
|
||||
//onSecondaryContainer = md_theme_light_onSecondaryContainer,
|
||||
secondaryVariant = md_theme_light_onSecondaryContainer,
|
||||
|
||||
//tertiary = md_theme_light_tertiary,
|
||||
//onTertiary = md_theme_light_onTertiary,
|
||||
//tertiaryContainer = md_theme_light_tertiaryContainer,
|
||||
//onTertiaryContainer = md_theme_light_onTertiaryContainer,
|
||||
|
||||
error = md_theme_light_error,
|
||||
onError = md_theme_light_onError,
|
||||
//errorContainer = md_theme_light_errorContainer,
|
||||
//onErrorContainer = md_theme_light_onErrorContainer,
|
||||
|
||||
background = md_theme_light_background,
|
||||
onBackground = md_theme_light_onBackground,
|
||||
|
||||
surface = md_theme_light_surface,
|
||||
onSurface = md_theme_light_onSurface,
|
||||
//surfaceVariant = md_theme_light_surfaceVariant,
|
||||
//onSurfaceVariant = md_theme_light_onSurfaceVariant,
|
||||
|
||||
//outline = md_theme_light_outline,
|
||||
//inverseOnSurface = md_theme_light_inverseOnSurface,
|
||||
//inverseSurface = md_theme_light_inverseSurface,
|
||||
)
|
||||
|
||||
//private val DarkThemeColors = darkColorScheme(
|
||||
private val DarkThemeColors = darkColors(
|
||||
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
//primaryContainer = md_theme_dark_primaryContainer,
|
||||
//onPrimaryContainer = md_theme_dark_onPrimaryContainer,
|
||||
primaryVariant = md_theme_dark_onPrimaryContainer,
|
||||
|
||||
secondary = md_theme_dark_secondary,
|
||||
onSecondary = md_theme_dark_onSecondary,
|
||||
//secondaryContainer = md_theme_dark_secondaryContainer,
|
||||
//onSecondaryContainer = md_theme_dark_onSecondaryContainer,
|
||||
secondaryVariant = md_theme_dark_onSecondaryContainer,
|
||||
|
||||
//tertiary = md_theme_dark_tertiary,
|
||||
//onTertiary = md_theme_dark_onTertiary,
|
||||
//tertiaryContainer = md_theme_dark_tertiaryContainer,
|
||||
//onTertiaryContainer = md_theme_dark_onTertiaryContainer,
|
||||
|
||||
error = md_theme_dark_error,
|
||||
onError = md_theme_dark_onError,
|
||||
//errorContainer = md_theme_dark_errorContainer,
|
||||
//onErrorContainer = md_theme_dark_onErrorContainer,
|
||||
|
||||
background = md_theme_dark_background,
|
||||
onBackground = md_theme_dark_onBackground,
|
||||
|
||||
surface = md_theme_dark_surface,
|
||||
onSurface = md_theme_dark_onSurface,
|
||||
//surfaceVariant = md_theme_dark_surfaceVariant,
|
||||
//onSurfaceVariant = md_theme_dark_onSurfaceVariant,
|
||||
|
||||
//outline = md_theme_dark_outline,
|
||||
//inverseOnSurface = md_theme_dark_inverseOnSurface,
|
||||
//inverseSurface = md_theme_dark_inverseSurface,
|
||||
)
|
||||
@Composable
|
||||
fun AppTheme(
|
||||
useDarkTheme: Boolean = isSystemInDarkTheme(),
|
||||
content: @Composable() () -> Unit
|
||||
) {
|
||||
val colors = if (!useDarkTheme) {
|
||||
LightThemeColors
|
||||
} else {
|
||||
DarkThemeColors
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
//colorScheme = colors,
|
||||
colors = colors,
|
||||
// typography = AppTypography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
117
app/src/main/java/de/sebse/fuplanner2/ui/theme/Type.kt
Normal file
117
app/src/main/java/de/sebse/fuplanner2/ui/theme/Type.kt
Normal file
@@ -0,0 +1,117 @@
|
||||
package de.sebse.fuplanner2.ui.theme
|
||||
|
||||
// Comments are changes in Material 3 (Material You)
|
||||
// Use default instead
|
||||
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
|
||||
//Replace with your font locations
|
||||
val Roboto = FontFamily.Default
|
||||
|
||||
/*val AppTypography = Typography(
|
||||
displayLarge = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 57.sp,
|
||||
lineHeight = 64.sp,
|
||||
letterSpacing = -0.25.sp,
|
||||
),
|
||||
displayMedium = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 45.sp,
|
||||
lineHeight = 52.sp,
|
||||
letterSpacing = 0.sp,
|
||||
),
|
||||
displaySmall = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 36.sp,
|
||||
lineHeight = 44.sp,
|
||||
letterSpacing = 0.sp,
|
||||
),
|
||||
headlineLarge = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 40.sp,
|
||||
letterSpacing = 0.sp,
|
||||
),
|
||||
headlineMedium = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 36.sp,
|
||||
letterSpacing = 0.sp,
|
||||
),
|
||||
headlineSmall = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 24.sp,
|
||||
lineHeight = 32.sp,
|
||||
letterSpacing = 0.sp,
|
||||
),
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp,
|
||||
),
|
||||
titleMedium = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.1.sp,
|
||||
),
|
||||
titleSmall = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.1.sp,
|
||||
),
|
||||
labelLarge = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.1.sp,
|
||||
),
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp,
|
||||
),
|
||||
bodyMedium = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp,
|
||||
letterSpacing = 0.25.sp,
|
||||
),
|
||||
bodySmall = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.W400,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.4.sp,
|
||||
),
|
||||
labelMedium = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp,
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = Roboto,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp,
|
||||
),
|
||||
)*/
|
||||
@@ -0,0 +1,40 @@
|
||||
package de.sebse.fuplanner2.ui.tools.previews
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import de.sebse.fuplanner2.database.Announcement
|
||||
import de.sebse.fuplanner2.database.Attachment
|
||||
import de.sebse.fuplanner2.utils.Faker
|
||||
import de.sebse.fuplanner2.utils.getFaker
|
||||
|
||||
class AnnouncementPreviewProvider(private val faker: Faker = getFaker()) : PreviewParameterProvider<Announcement> {
|
||||
override val values = generateSequence { getItem() }
|
||||
|
||||
private fun getItem(): Announcement {
|
||||
val title = faker.strings.title()
|
||||
return Announcement(
|
||||
faker.primitive.long(0, 100),
|
||||
faker.primitive.long(0, 100),
|
||||
faker.other.lastRefreshed(),
|
||||
faker.strings.uuid(title),
|
||||
title,
|
||||
faker.strings.lorem(100, 1000),
|
||||
faker.other.date(-20, -2),
|
||||
"${faker.name.firstName()} ${faker.name.lastName()}",
|
||||
AttachmentPreviewProvider(faker).values
|
||||
.take(faker.primitive.int(1, 4))
|
||||
.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class AttachmentPreviewProvider(private val faker: Faker = getFaker()) : PreviewParameterProvider<Attachment> {
|
||||
override val values = generateSequence { getItem() }
|
||||
|
||||
private fun getItem(): Attachment {
|
||||
return Attachment(
|
||||
faker.internet.url(),
|
||||
faker.strings.title(),
|
||||
faker.internet.mime()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.sebse.fuplanner2.ui.details
|
||||
package de.sebse.fuplanner2.ui.tools.previews
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
@@ -7,12 +7,13 @@ import de.sebse.fuplanner2.utils.Faker
|
||||
import de.sebse.fuplanner2.utils.getFaker
|
||||
|
||||
class LecturerPreviewProvider(private val faker: Faker = getFaker()) : PreviewParameterProvider<Lecturer> {
|
||||
private val resp = faker.primitive.int(1, 2)
|
||||
override val values = (0..10).map {
|
||||
getLecturer(it < resp)
|
||||
}.asSequence()
|
||||
override val values = sequence {
|
||||
yield(getItem(true))
|
||||
yield(getItem(faker.primitive.bool(.5f)))
|
||||
yieldAll(generateSequence { getItem(false) })
|
||||
}
|
||||
|
||||
private fun getLecturer(isResponsible: Boolean): Lecturer {
|
||||
private fun getItem(isResponsible: Boolean): Lecturer {
|
||||
val firstName = faker.name.firstName()
|
||||
val lastName = faker.name.lastName()
|
||||
return Lecturer(
|
||||
@@ -25,17 +26,16 @@ class LecturerPreviewProvider(private val faker: Faker = getFaker()) : PreviewPa
|
||||
}
|
||||
|
||||
class CoursePreviewProvider(private val faker: Faker = getFaker()) : PreviewParameterProvider<Course> {
|
||||
var isSummer = false
|
||||
var year = 21
|
||||
override val values = (0..10).map {
|
||||
val res = getCourse()
|
||||
private var isSummer = false
|
||||
private var year = 21
|
||||
override val values = sequence {
|
||||
yield(getItem())
|
||||
val reduce = faker.primitive.bool(.3f)
|
||||
year = if (reduce && isSummer) year-1 else year
|
||||
isSummer = if (reduce) !isSummer else isSummer
|
||||
res
|
||||
}.asSequence()
|
||||
}
|
||||
|
||||
private fun getCourse(): Course {
|
||||
private fun getItem(): Course {
|
||||
val diff = 1000L*60*60*24*5
|
||||
val title =
|
||||
"${faker.strings.title()} ${if (isSummer) "S" else "W"} ${if (isSummer) year else "$year/${year + 1}"}"
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.sebse.fuplanner2.viewmodels
|
||||
package de.sebse.fuplanner2.ui.tools.viewmodels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.sebse.fuplanner2.viewmodels
|
||||
package de.sebse.fuplanner2.ui.tools.viewmodels
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -21,6 +21,9 @@ class Faker(randomSeed: Int) {
|
||||
val primitive: FakerPrimitive
|
||||
get() = FakerPrimitive(random)
|
||||
|
||||
val other: FakerOther
|
||||
get() = FakerOther(random)
|
||||
|
||||
val strings: FakerStrings
|
||||
get() = FakerStrings(random)
|
||||
}
|
||||
@@ -29,6 +32,7 @@ class FakerName(private val random: Random) {
|
||||
fun lastName(): String {
|
||||
return LASTNAMES.random(random)
|
||||
}
|
||||
|
||||
fun firstName(): String {
|
||||
return FIRSTNAMES.random(random)
|
||||
}
|
||||
@@ -60,6 +64,19 @@ class FakerInternet(private val random: Random) {
|
||||
.replace(Regex("[^a-z0-9.]"), "")
|
||||
return "$user@fu-berlin.de"
|
||||
}
|
||||
|
||||
fun mime(): String {
|
||||
return MIME_TYPES.random(random)
|
||||
}
|
||||
|
||||
fun url(): String {
|
||||
return "https://example.de/file"
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MIME_TYPES = listOf("application/pdf", "text/plain", "text/csv",
|
||||
"application/msword")
|
||||
}
|
||||
}
|
||||
|
||||
class FakerPrimitive(private val random: Random) {
|
||||
@@ -76,11 +93,31 @@ class FakerPrimitive(private val random: Random) {
|
||||
}
|
||||
}
|
||||
|
||||
class FakerOther(private val random: Random) {
|
||||
fun lastRefreshed(): Long {
|
||||
return FakerPrimitive(random).long(
|
||||
System.currentTimeMillis() - DIFF,
|
||||
System.currentTimeMillis() + DIFF
|
||||
)
|
||||
}
|
||||
fun date(startDay: Int, endDay: Int): Long {
|
||||
return FakerPrimitive(random).long(
|
||||
System.currentTimeMillis() + DAY * startDay,
|
||||
System.currentTimeMillis() + DAY * endDay
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DAY = 1000L*60*60*24
|
||||
const val DIFF = DAY*5
|
||||
}
|
||||
}
|
||||
|
||||
class FakerStrings(private val random: Random) {
|
||||
fun lorem(min: Int, max: Int): String {
|
||||
val length = (min..max).random(random)
|
||||
val loremArray = LOREM.split(" ").size
|
||||
val n = ceil(length.toFloat() / loremArray).toInt()
|
||||
val n = ceil(length.toFloat() / loremArray).toInt() + 1
|
||||
val repeatedArray = ("$LOREM ")
|
||||
.repeat(n)
|
||||
.trim()
|
||||
@@ -109,7 +146,7 @@ class FakerStrings(private val random: Random) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOREM = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy "+
|
||||
const val LOREM = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy "+
|
||||
"eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam "+
|
||||
"voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita "+
|
||||
"kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem "+
|
||||
|
||||
@@ -12,7 +12,6 @@ import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.database.User
|
||||
import de.sebse.fuplanner2.utils.Notifications
|
||||
import de.sebse.fuplanner2.utils.UpdateResult
|
||||
import de.sebse.fuplanner2.utils.console
|
||||
import de.sebse.fuplanner2.whiteboard.Whiteboard
|
||||
import de.sebse.fuplanner2.whiteboard.getCourse
|
||||
import de.sebse.fuplanner2.whiteboard.getCourses
|
||||
@@ -39,6 +38,7 @@ class CourseWorker(context: Context, params: WorkerParameters) : AbstractAccount
|
||||
updates.added.forEach {
|
||||
if (it.isSummerSemester == latestSemester.semester && it.year == latestSemester.year) {
|
||||
EventWorker.work(applicationContext, database, user, it)
|
||||
AnnouncementWorker.work(applicationContext, database, user, it)
|
||||
}
|
||||
}
|
||||
Notifications.courseUpdates(updates, database, applicationContext)
|
||||
|
||||
@@ -7,7 +7,6 @@ import de.sebse.fuplanner2.auth.AppAccounts
|
||||
import de.sebse.fuplanner2.database.AppDatabase
|
||||
import de.sebse.fuplanner2.database.Course
|
||||
import de.sebse.fuplanner2.utils.Notifications
|
||||
import de.sebse.fuplanner2.utils.Updatable
|
||||
import de.sebse.fuplanner2.utils.UpdateResult
|
||||
import de.sebse.fuplanner2.utils.mergeUpdatable
|
||||
|
||||
@@ -52,6 +51,7 @@ class SyncWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
|
||||
courseCreations.forEach { course ->
|
||||
if (course.isSummerSemester == latestSemester.semester && course.year == latestSemester.year) {
|
||||
EventWorker.work(applicationContext, database, it, course)
|
||||
AnnouncementWorker.work(applicationContext, database, it, course)
|
||||
}
|
||||
}
|
||||
Notifications.courseUpdates(notifications, database, applicationContext)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package de.sebse.fuplanner2
|
||||
|
||||
import de.sebse.fuplanner2.ui.tools.previews.AnnouncementPreviewProvider
|
||||
import de.sebse.fuplanner2.utils.getFaker
|
||||
import org.junit.Test
|
||||
|
||||
@@ -17,4 +18,9 @@ class FakerTest {
|
||||
getFaker().strings.lorem(100, 1000)
|
||||
getFaker().strings.lorem(100, 1000)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun announcement() {
|
||||
AnnouncementPreviewProvider().values.take(10)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user