diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 6806f5a..cde3e19 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -37,6 +37,10 @@
+
+
+
+
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..931b96c
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c83eb85..3ad9729 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -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 {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a274b7a..7b38436 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,8 @@
+
+
+
+
+
+
,
val customIndices: ArrayList,
val lessons: ArrayList
-)
\ No newline at end of file
+) : Parcelable {
+ fun getDistanceToNextByMinutes(from: Int): Map.Entry? {
+ 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 {
+ override val key: Int
+ get() = toIdx
+ override val value: Int
+ get() = lessons[toIdx]!!.time!!.start - from
+ }
+ }
+
+ fun getDistanceToNextByIdx(from: Int? = null): Map.Entry? {
+ 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? {
+ val minutes = Calendar.getInstance()
+ .get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
+ .get(Calendar.MINUTE)
+
+ for (lessonIdx in 0..= lesson.time.end
+ )
+ continue
+
+ return object : Map.Entry {
+ override val key: Int
+ get() = lessonIdx
+ override val value: Lesson
+ get() = lesson
+ }
+ }
+
+ return null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/model/Group.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/model/Group.kt
index 71542de..2ba4aa0 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/model/Group.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/model/Group.kt
@@ -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
-)
\ No newline at end of file
+) : Parcelable {
+ fun getCurrentDay(): Map.Entry? {
+ val currentDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2)
+
+ if (currentDay < 0 || currentDay > days.size - 1)
+ return null
+
+ return object : Map.Entry {
+ override val key: Int
+ get() = currentDay
+ override val value: Day?
+ get() = days[currentDay]
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/model/Lesson.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/model/Lesson.kt
index e942679..6ff32e5 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/model/Lesson.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/model/Lesson.kt
@@ -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,
val teacherNames: ArrayList
-)
\ No newline at end of file
+) : 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(", ")
+ )
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/model/LessonTime.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/model/LessonTime.kt
index 0dcb84b..e3513b5 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/model/LessonTime.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/model/LessonTime.kt
@@ -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)
\ No newline at end of file
+data class LessonTime(val start: Int, val end: Int) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/service/CurrentLessonViewService.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/service/CurrentLessonViewService.kt
new file mode 100644
index 0000000..e722e84
--- /dev/null
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/service/CurrentLessonViewService.kt
@@ -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()
+ .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
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/service/MyFirebaseMessagingService.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/service/MyFirebaseMessagingService.kt
index ed210a8..04de6bc 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/service/MyFirebaseMessagingService.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/service/MyFirebaseMessagingService.kt
@@ -78,6 +78,7 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
}
notify(id.hashCode(), notification)
+ CurrentLessonViewService.startService(applicationContext)
}
}
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/MainActivity.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/MainActivity.kt
index 37b2e5c..728a3e7 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/MainActivity.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/MainActivity.kt
@@ -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))) {
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayCard.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayCard.kt
index 60553b3..e5d7c0c 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayCard.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayCard.kt
@@ -67,8 +67,8 @@ fun calculateCurrentLessonIdx(lessons: ArrayList): 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())
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/LessonView.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/LessonView.kt
index faafdd1..5a9b7bc 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/LessonView.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/LessonView.kt
@@ -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 {
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 = arrayListOf("Хомченко Н.Е.", "Хомченко Н.Е."),
+ teacherNames: ArrayList = arrayListOf(
+ "Хомченко Н.Е. (1 подggggggggggggggggggggggggggggggggggggggгруппа)",
+ "Хомченко Н.Е. (2 подгруппа)"
+ ),
cabinets: ArrayList = 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.. 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("…")
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/work/LinkUpdateWorker.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/work/LinkUpdateWorker.kt
index bad1fb4..a6f43bc 100644
--- a/app/src/main/java/ru/n08i40k/polytechnic/next/work/LinkUpdateWorker.kt
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/work/LinkUpdateWorker.kt
@@ -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()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/work/StartClvService.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/work/StartClvService.kt
new file mode 100644
index 0000000..1610fff
--- /dev/null
+++ b/app/src/main/java/ru/n08i40k/polytechnic/next/work/StartClvService.kt
@@ -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()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 946186d..36d44b2 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -51,4 +51,18 @@
Информирует о выходе новой версии этого приложения
Вышла версия %1$s!
Нажмите что бы загрузить обновление.
+ Текущая пара
+ Отображает текущую пару или перемену в уведомлении
+ Загрузка расписания…
+ Это уведомление обновится в течении нескольких секунд!
+ До конца %1$d ч. %2$d мин.
+ %1$s\n| Далее в %2$s - %3$s
+ Конец пар
+ Пары закончились!
+ Ура, можно идти домой! Наверное :(
+ каб.
+ в %1$s каб.
+ в спорт-зале
+ Пары ещё не начались
+ До начала пар %1$d ч. %2$d мин.
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dcff827..e3a855b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -51,4 +51,18 @@
Inform about new version of this app has been released
Version %1$s released!
Click to download new version.
+ Current lesson
+ View current lesson and breaks in notification
+ Loading schedule…
+ This notification will be updated in several seconds!
+ To end %1$d h. %2$d min.
+ %1$s\n| After in %2$s - %3$s
+ Lessons end
+ Lessons finished!
+ TODO
+ cab.
+ in %1$s cab.
+ in gym
+ Lessons haven\'t started yet
+ %1$d h. %2$d min. before lessons start
\ No newline at end of file