Отображение текущей пары в уведомлении.

Мне на данный момент невероятно сложно написать код для запуска сервиса перед началом пар (мне лень), поэтому сервис будет запускаться каждые 7 утра с задежкой до 15 минут.
This commit is contained in:
2024-10-08 16:13:35 +04:00
parent dde7f3e254
commit 3da65a3327
20 changed files with 544 additions and 52 deletions

View File

@@ -37,6 +37,10 @@
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewDeviceShouldUseNewSpec" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />
</inspection_tool>
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
<option name="composableFile" value="true" />
<option name="previewFile" value="true" />

13
.idea/runConfigurations.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.compose.compiler)
kotlin("plugin.serialization") version "2.0.20"
id("kotlin-parcelize")
id("com.google.devtools.ksp")
@@ -32,8 +33,8 @@ android {
applicationId = "ru.n08i40k.polytechnic.next"
minSdk = 26
targetSdk = 35
versionCode = 11
versionName = "1.6.0"
versionCode = 12
versionName = "1.7.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@@ -4,6 +4,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<application
android:name=".PolytechnicApplication"
@@ -24,6 +26,15 @@
</intent-filter>
</service>
<service
android:name=".service.CurrentLessonViewService"
android:exported="false"
android:foregroundServiceType="specialUse">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Service for viewing current lesson in notification." />
</service>
<activity
android:name=".ui.MainActivity"
android:exported="true"

View File

@@ -1,6 +1,7 @@
package ru.n08i40k.polytechnic.next
object NotificationChannels {
const val LESSON_VIEW = "lesson-view"
const val SCHEDULE_UPDATE = "schedule-update"
const val APP_UPDATE = "app-update"
}

View File

@@ -1,6 +1,10 @@
package ru.n08i40k.polytechnic.next
import android.Manifest
import android.app.Application
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
import dagger.hilt.android.HiltAndroidApp
import ru.n08i40k.polytechnic.next.data.AppContainer
import ru.n08i40k.polytechnic.next.utils.or
@@ -17,4 +21,10 @@ class PolytechnicApplication : Application() {
.getPackageInfo(this.packageName, 0)
.versionName or "1.0.0"
}
fun hasNotificationPermission(): Boolean {
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
|| ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED)
}
}

View File

@@ -1,7 +1,11 @@
package ru.n08i40k.polytechnic.next.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import java.util.Calendar
@Parcelize
@Suppress("unused")
@Serializable
class Day(
@@ -10,4 +14,62 @@ class Day(
val defaultIndices: ArrayList<Int>,
val customIndices: ArrayList<Int>,
val lessons: ArrayList<Lesson?>
)
) : Parcelable {
fun getDistanceToNextByMinutes(from: Int): Map.Entry<Int, Int>? {
val toIdx = lessons
.map { if (it?.time == null) null else it.time.start }
.indexOfFirst { if (it == null) false else it > from }
if (toIdx == -1)
return null
return object : Map.Entry<Int, Int> {
override val key: Int
get() = toIdx
override val value: Int
get() = lessons[toIdx]!!.time!!.start - from
}
}
fun getDistanceToNextByIdx(from: Int? = null): Map.Entry<Int, Int>? {
val fromLesson = if (from != null) lessons[from] else null
if (from != null && fromLesson?.time == null)
throw NullPointerException("Lesson (by given index) and it's time should be non-null!")
val fromTime =
if (from != null)
fromLesson!!.time!!.end
else
Calendar.getInstance()
.get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
.get(Calendar.MINUTE)
return getDistanceToNextByMinutes(fromTime)
}
fun getCurrentLesson(): Map.Entry<Int, Lesson>? {
val minutes = Calendar.getInstance()
.get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
.get(Calendar.MINUTE)
for (lessonIdx in 0..<lessons.size) {
val lesson = lessons[lessonIdx] ?: continue
if (lesson.time == null
|| minutes < lesson.time.start
|| minutes >= lesson.time.end
)
continue
return object : Map.Entry<Int, Lesson> {
override val key: Int
get() = lessonIdx
override val value: Lesson
get() = lesson
}
}
return null
}
}

View File

@@ -1,9 +1,27 @@
package ru.n08i40k.polytechnic.next.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import java.util.Calendar
@Parcelize
@Serializable
class Group(
data class Group(
val name: String,
val days: ArrayList<Day?>
)
) : Parcelable {
fun getCurrentDay(): Map.Entry<Int, Day?>? {
val currentDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2)
if (currentDay < 0 || currentDay > days.size - 1)
return null
return object : Map.Entry<Int, Day?> {
override val key: Int
get() = currentDay
override val value: Day?
get() = days[currentDay]
}
}
}

View File

@@ -1,7 +1,13 @@
package ru.n08i40k.polytechnic.next.model
import android.content.Context
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.utils.limit
@Parcelize
@Serializable
data class Lesson(
val type: LessonType,
@@ -10,4 +16,37 @@ data class Lesson(
val time: LessonTime?,
val cabinets: ArrayList<String>,
val teacherNames: ArrayList<String>
)
) : Parcelable {
fun getDuration(): Int? {
if (this.time == null)
return null
return time.end - time.start
}
fun getNameAndCabinetsShort(context: Context): String {
val limitedName = name limit 15
if (cabinets.isEmpty())
return limitedName
if (cabinets.size == 1 && cabinets[0] == "с")
return buildString {
append(limitedName)
append(" ")
append(context.getString(R.string.in_gym_lc))
}
return buildString {
append(limitedName)
append(" ")
append(
context.getString(
R.string.in_cabinets_short_lc,
cabinets.joinToString(", ")
)
)
}
}
}

View File

@@ -1,6 +1,9 @@
package ru.n08i40k.polytechnic.next.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
@Parcelize
@Serializable
data class LessonTime(val start: Int, val end: Int)
data class LessonTime(val start: Int, val end: Int) : Parcelable

View File

@@ -0,0 +1,222 @@
package ru.n08i40k.polytechnic.next.service
import android.app.Notification
import android.app.NotificationManager
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import androidx.core.app.NotificationCompat
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import ru.n08i40k.polytechnic.next.NotificationChannels
import ru.n08i40k.polytechnic.next.PolytechnicApplication
import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.model.Day
import ru.n08i40k.polytechnic.next.model.Group
import ru.n08i40k.polytechnic.next.model.Lesson
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
import ru.n08i40k.polytechnic.next.work.StartClvService
import java.util.Calendar
class CurrentLessonViewService : Service() {
companion object {
private const val NOTIFICATION_STATUS_ID = 1337
private const val NOTIFICATION_END_ID = NOTIFICATION_STATUS_ID + 1
private const val UPDATE_INTERVAL = 60_000L
fun startService(appContext: Context) {
if (!(appContext as PolytechnicApplication).hasNotificationPermission())
return
if (Calendar.getInstance()
.get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
.get(Calendar.MINUTE) < 420)
return
val request = OneTimeWorkRequestBuilder<StartClvService>()
.build()
WorkManager.getInstance(appContext).enqueue(request)
}
}
private var day: Day? = null
private val handler = Handler(Looper.getMainLooper())
private val updateRunnable = object : Runnable {
override fun run() {
if (day == null || day!!.nonNullIndices.isEmpty()) {
stopSelf()
return
}
val currentMinutes = Calendar.getInstance()
.get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
.get(Calendar.MINUTE)
val currentLessonEntry = day!!.getCurrentLesson()
val currentLessonIdx: Int? = currentLessonEntry?.key
val currentLesson: Lesson? = currentLessonEntry?.value
val nextLessonEntry = day!!.getDistanceToNextByIdx(currentLessonIdx)
val nextLesson =
if (nextLessonEntry == null)
null
else
day!!.lessons[nextLessonEntry.key]
if (currentLesson == null && nextLesson == null) {
val notification = NotificationCompat
.Builder(applicationContext, NotificationChannels.LESSON_VIEW)
.setSmallIcon(R.drawable.logo)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentTitle(getString(R.string.lessons_end_notification_title))
.setContentText(getString(R.string.lessons_end_notification_description))
.build()
getNotificationManager().notify(NOTIFICATION_END_ID, notification)
stopSelf()
return
}
val firstLessonIdx = day!!.getDistanceToNextByMinutes(0)?.key
?: throw NullPointerException("Is this even real?")
val distanceToFirst = day!!.lessons[firstLessonIdx]!!.time!!.start - currentMinutes
val currentLessonDelay =
if (currentLesson == null) // Если эта пара - перемена, то конец перемены через (результат getDistanceToNext)
nextLessonEntry!!.value
else // Если эта пара - обычная пара, то конец пары через (конец этой пары - текущее кол-во минут)
currentLesson.time!!.end - currentMinutes
val currentLessonName =
currentLesson?.getNameAndCabinetsShort(this@CurrentLessonViewService)
?: run {
if (distanceToFirst > 0)
getString(R.string.lessons_not_started)
else
getString(R.string.lesson_break)
}
val nextLessonName =
if (currentLesson == null) // Если текущая пара - перемена
nextLesson!!.getNameAndCabinetsShort(this@CurrentLessonViewService)
else if (nextLesson == null) // Если текущая пара - последняя
getString(R.string.lessons_end)
else // Если после текущей пары есть ещё пара(ы)
getString(R.string.lesson_break)
val nextLessonTotal =
if (currentLesson == null)
nextLesson!!.time!!.start
else
currentLesson.time!!.end
val notification = createNotification(
getString(
if (distanceToFirst > 0)
R.string.waiting_for_day_start_notification_title
else
R.string.lesson_going_notification_title,
currentLessonDelay / 60,
currentLessonDelay % 60
),
getString(
R.string.lesson_going_notification_description,
currentLessonName,
nextLessonTotal.fmtAsClock(),
nextLessonName,
)
)
getNotificationManager().notify(NOTIFICATION_STATUS_ID, notification)
handler.postDelayed(this, UPDATE_INTERVAL)
}
}
private fun createNotification(
title: String? = null,
description: String? = null
): Notification {
return NotificationCompat
.Builder(applicationContext, NotificationChannels.LESSON_VIEW)
.setSmallIcon(R.drawable.logo)
.setContentTitle(title ?: getString(R.string.lesson_notification_title))
.setContentText(description ?: getString(R.string.lesson_notification_description))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setOngoing(true)
.setSilent(true)
.build()
}
private fun getNotificationManager(): NotificationManager {
return getSystemService(NOTIFICATION_SERVICE) as NotificationManager
}
fun updateSchedule(group: Group?): Boolean {
if (group == null) {
stopSelf()
return false
}
val day = group.getCurrentDay()
if (day?.value == null) {
stopSelf()
return false
}
val dayValue = day.value!!
if (this.day == null) {
if (dayValue.lessons[dayValue.defaultIndices[dayValue.defaultIndices.lastIndex]]!!.time!!.end
<= Calendar.getInstance()
.get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
.get(Calendar.MINUTE)
) {
stopSelf()
return false
}
}
this.day = dayValue
this.handler.removeCallbacks(updateRunnable)
updateRunnable.run()
return true
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (!(applicationContext as PolytechnicApplication).hasNotificationPermission()) {
stopSelf()
return START_STICKY
}
if (intent == null)
throw NullPointerException("Intent shouldn't be null!")
val notification = createNotification()
startForeground(NOTIFICATION_STATUS_ID, notification)
if (!updateSchedule(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra("group", Group::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableExtra("group")
}
)
)
updateRunnable.run()
return START_STICKY
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
}

View File

@@ -78,6 +78,7 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
}
notify(id.hashCode(), notification)
CurrentLessonViewService.startService(applicationContext)
}
}

View File

@@ -3,8 +3,7 @@ package ru.n08i40k.polytechnic.next.ui
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.pm.PackageManager
import android.os.Build
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
@@ -18,7 +17,6 @@ import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.safeContent
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.ui.Modifier
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope
import androidx.work.BackoffPolicy
@@ -39,6 +37,8 @@ import kotlinx.coroutines.launch
import ru.n08i40k.polytechnic.next.NotificationChannels
import ru.n08i40k.polytechnic.next.PolytechnicApplication
import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.data.MyResult
import ru.n08i40k.polytechnic.next.service.CurrentLessonViewService
import ru.n08i40k.polytechnic.next.settings.settingsDataStore
import ru.n08i40k.polytechnic.next.work.FcmUpdateCallbackWorker
import ru.n08i40k.polytechnic.next.work.LinkUpdateWorker
@@ -66,7 +66,7 @@ class MainActivity : ComponentActivity() {
}
private fun createNotificationChannels() {
if (!hasNotificationPermission())
if (!(applicationContext as PolytechnicApplication).hasNotificationPermission())
return
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
@@ -84,6 +84,13 @@ class MainActivity : ComponentActivity() {
getString(R.string.app_update_channel_description),
NotificationChannels.APP_UPDATE
)
createNotificationChannel(
notificationManager,
getString(R.string.lesson_view_channel_name),
getString(R.string.lesson_view_channel_description),
NotificationChannels.LESSON_VIEW
)
}
private val requestPermissionLauncher =
@@ -91,15 +98,30 @@ class MainActivity : ComponentActivity() {
if (it) createNotificationChannels()
}
private fun hasNotificationPermission(): Boolean {
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
|| ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED)
private fun askNotificationPermission() {
if (!(applicationContext as PolytechnicApplication).hasNotificationPermission())
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
private fun askNotificationPermission() {
if (!hasNotificationPermission())
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
private fun startTestService() {
if (!(applicationContext as PolytechnicApplication).hasNotificationPermission())
return
lifecycleScope.launch {
val schedule = (applicationContext as PolytechnicApplication)
.container
.scheduleRepository
.getGroup()
if (schedule is MyResult.Failure)
return@launch
val intent = Intent(this@MainActivity, CurrentLessonViewService::class.java)
.apply {
putExtra("group", (schedule as MyResult.Success).data)
}
startForegroundService(intent)
}
}
@@ -168,6 +190,7 @@ class MainActivity : ComponentActivity() {
setupFirebaseConfig()
handleUpdate()
startTestService()
setContent {
Box(Modifier.windowInsetsPadding(WindowInsets.safeContent.only(WindowInsetsSides.Top))) {

View File

@@ -67,8 +67,8 @@ fun calculateCurrentLessonIdx(lessons: ArrayList<Lesson?>): Int {
.filterNotNull()
.filter {
it.time != null
&& it.time.start >= currentMinutes
&& it.time.end <= currentMinutes
&& it.time.start <= currentMinutes
&& it.time.end >= currentMinutes
}
if (filteredLessons.isEmpty())

View File

@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material3.Card
import androidx.compose.material3.CardColors
import androidx.compose.material3.CardDefaults
@@ -30,26 +31,20 @@ import ru.n08i40k.polytechnic.next.data.schedule.impl.FakeScheduleRepository
import ru.n08i40k.polytechnic.next.model.Day
import ru.n08i40k.polytechnic.next.model.Lesson
import ru.n08i40k.polytechnic.next.model.LessonTime
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
private enum class LessonTimeFormat {
FROM_TO, ONLY_MINUTES_DURATION
}
private fun numWithZero(num: Int): String {
return "0".repeat(if (num <= 9) 1 else 0) + num.toString()
}
@Composable
private fun fmtTime(start: Int, end: Int, format: LessonTimeFormat): ArrayList<String> {
return when (format) {
LessonTimeFormat.FROM_TO -> {
val startHour = numWithZero(start / 60)
val startMinute = numWithZero(start % 60)
val startClock = start.fmtAsClock()
val endClock = end.fmtAsClock()
val endHour = numWithZero(end / 60)
val endMinute = numWithZero(end % 60)
arrayListOf("$startHour:$startMinute", "$endHour:$endMinute")
arrayListOf(startClock, endClock)
}
LessonTimeFormat.ONLY_MINUTES_DURATION -> {
@@ -86,13 +81,10 @@ fun LessonExtraInfo(
val duration =
if (lesson.time != null) lesson.time.end - lesson.time.start else 0
val hours = duration / 60
val minutes = duration % 60
append(hours)
append(duration / 60)
append(stringResource(R.string.hours))
append(" ")
append(minutes)
append(duration % 60)
append(stringResource(R.string.minutes))
}
Text(duration)
@@ -117,7 +109,10 @@ private fun LessonViewRow(
time: LessonTime? = LessonTime(0, 60),
timeFormat: LessonTimeFormat = LessonTimeFormat.FROM_TO,
name: String = "Test",
teacherNames: ArrayList<String> = arrayListOf("Хомченко Н.Е.", "Хомченко Н.Е."),
teacherNames: ArrayList<String> = arrayListOf(
"Хомченко Н.Е. (1 подggggggggggggggggggggggggggggggggggggggгруппа)",
"Хомченко Н.Е. (2 подгруппа)"
),
cabinets: ArrayList<String> = arrayListOf("14", "31"),
cardColors: CardColors = CardDefaults.cardColors(),
verticalPadding: Dp = 10.dp
@@ -125,6 +120,8 @@ private fun LessonViewRow(
val contentColor =
if (timeFormat == LessonTimeFormat.FROM_TO) cardColors.contentColor else cardColors.disabledContentColor
val teacherNamesRepl = teacherNames.map { it.replace("подгруппа", "подгр.") }
Row(
modifier = Modifier.padding(10.dp, verticalPadding),
verticalAlignment = Alignment.CenterVertically,
@@ -164,15 +161,12 @@ private fun LessonViewRow(
Column(
verticalArrangement = Arrangement.Center
) {
val fraction = if (cabinets.size == 0) 1F
else if (cabinets.any { it.contains("/") }) 0.9F
else 0.925F
Row {
Column {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(modifier = Modifier.weight(1f)) {
Text(
modifier = Modifier.fillMaxWidth(fraction),
text = name,
fontWeight = FontWeight.Medium,
maxLines = 1,
@@ -180,10 +174,9 @@ private fun LessonViewRow(
color = contentColor
)
for (listIdx: Int in 0..<teacherNames.size) {
for (teacherName in teacherNamesRepl) {
Text(
modifier = Modifier.fillMaxWidth(fraction),
text = teacherNames[listIdx],
text = teacherName,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = contentColor
@@ -191,18 +184,15 @@ private fun LessonViewRow(
}
}
Column {
if (cabinets.size <= teacherNames.size) {
Column(modifier = Modifier.wrapContentWidth()) {
if (cabinets.size <= teacherNamesRepl.size) {
Text(
modifier = Modifier.fillMaxWidth(),
text = "",
maxLines = 1
)
}
for (listIdx: Int in 0..<cabinets.size) {
Text(
modifier = Modifier.fillMaxWidth(),
text = cabinets[listIdx],
maxLines = 1,
overflow = TextOverflow.Ellipsis,

View File

@@ -4,4 +4,25 @@ infix fun <T> T?.or(data: T): T {
if (this == null)
return data
return this
}
fun Int.fmtAsClockEntry(): String {
return "0".repeat(if (this <= 9) 1 else 0) + this.toString()
}
fun Int.fmtAsClock(): String {
val hours = this / 60
val minutes = this % 60
return hours.fmtAsClockEntry() + ":" + minutes.fmtAsClockEntry()
}
infix fun String.limit(count: Int): String {
if (this.length <= count)
return this
return this
.substring(0, count - 1)
.trimEnd()
.plus("")
}

View File

@@ -5,6 +5,7 @@ import androidx.work.Worker
import androidx.work.WorkerParameters
import kotlinx.coroutines.runBlocking
import ru.n08i40k.polytechnic.next.PolytechnicApplication
import ru.n08i40k.polytechnic.next.service.CurrentLessonViewService
class LinkUpdateWorker(context: Context, params: WorkerParameters) :
Worker(context, params) {
@@ -15,6 +16,9 @@ class LinkUpdateWorker(context: Context, params: WorkerParameters) :
.scheduleRepository
.getGroup()
}
CurrentLessonViewService.startService(applicationContext)
return Result.success()
}
}

View File

@@ -0,0 +1,41 @@
package ru.n08i40k.polytechnic.next.work
import android.content.Context
import android.content.Intent
import androidx.core.content.ContextCompat.startForegroundService
import androidx.work.Worker
import androidx.work.WorkerParameters
import kotlinx.coroutines.runBlocking
import ru.n08i40k.polytechnic.next.PolytechnicApplication
import ru.n08i40k.polytechnic.next.data.MyResult
import ru.n08i40k.polytechnic.next.service.CurrentLessonViewService
class StartClvService(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
val schedule = runBlocking {
(applicationContext as PolytechnicApplication)
.container
.scheduleRepository
.getGroup()
}
if (schedule is MyResult.Failure)
return Result.success()
val intent = Intent(applicationContext, CurrentLessonViewService::class.java)
.apply {
putExtra("group", (schedule as MyResult.Success).data)
}
applicationContext.stopService(
Intent(
applicationContext,
CurrentLessonViewService::class.java
)
)
startForegroundService(applicationContext, intent)
return Result.success()
}
}

View File

@@ -51,4 +51,18 @@
<string name="app_update_channel_description">Информирует о выходе новой версии этого приложения</string>
<string name="app_update_title">Вышла версия %1$s!</string>
<string name="app_update_description">Нажмите что бы загрузить обновление.</string>
<string name="lesson_view_channel_name">Текущая пара</string>
<string name="lesson_view_channel_description">Отображает текущую пару или перемену в уведомлении</string>
<string name="lesson_notification_title">Загрузка расписания…</string>
<string name="lesson_notification_description">Это уведомление обновится в течении нескольких секунд!</string>
<string name="lesson_going_notification_title">До конца %1$d ч. %2$d мин.</string>
<string name="lesson_going_notification_description">%1$s\n| Далее в %2$s - %3$s</string>
<string name="lessons_end">Конец пар</string>
<string name="lessons_end_notification_title">Пары закончились!</string>
<string name="lessons_end_notification_description">Ура, можно идти домой! Наверное :(</string>
<string name="cabinets_short_lc">каб.</string>
<string name="in_cabinets_short_lc">в %1$s каб.</string>
<string name="in_gym_lc">в спорт-зале</string>
<string name="lessons_not_started">Пары ещё не начались</string>
<string name="waiting_for_day_start_notification_title">До начала пар %1$d ч. %2$d мин.</string>
</resources>

View File

@@ -51,4 +51,18 @@
<string name="app_update_channel_description">Inform about new version of this app has been released</string>
<string name="app_update_title">Version %1$s released!</string>
<string name="app_update_description">Click to download new version.</string>
<string name="lesson_view_channel_name">Current lesson</string>
<string name="lesson_view_channel_description">View current lesson and breaks in notification</string>
<string name="lesson_notification_title">Loading schedule…</string>
<string name="lesson_notification_description">This notification will be updated in several seconds!</string>
<string name="lesson_going_notification_title">To end %1$d h. %2$d min.</string>
<string name="lesson_going_notification_description">%1$s\n| After in %2$s - %3$s</string>
<string name="lessons_end">Lessons end</string>
<string name="lessons_end_notification_title">Lessons finished!</string>
<string name="lessons_end_notification_description">TODO</string>
<string name="cabinets_short_lc">cab.</string>
<string name="in_cabinets_short_lc">in %1$s cab.</string>
<string name="in_gym_lc">in gym</string>
<string name="lessons_not_started">Lessons haven\'t started yet</string>
<string name="waiting_for_day_start_notification_title">%1$d h. %2$d min. before lessons start</string>
</resources>