From 2a7e63dce48bc3d75a2fd21bc4a2c739e14c0be4 Mon Sep 17 00:00:00 2001 From: n08i40k Date: Thu, 10 Oct 2024 01:27:26 +0400 Subject: [PATCH] 1.7.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Фикс невозможности запуска службы переднего плана из LinkUpdateWorker. Небольшие визуальные изменения. --- app/build.gradle.kts | 4 +- app/src/main/AndroidManifest.xml | 19 ++++ .../polytechnic/next/IntentRequestCodes.kt | 5 ++ .../next/PolytechnicApplication.kt | 87 ++++++++++++++++++ .../ru/n08i40k/polytechnic/next/model/Day.kt | 89 ++++++++++++------- .../n08i40k/polytechnic/next/model/Group.kt | 28 +++--- .../n08i40k/polytechnic/next/model/Lesson.kt | 12 ++- .../next/receiver/AlarmReceiver.kt | 42 +++++++++ .../BootCompletedBroadcastReceiver.kt | 45 ++++++++++ .../next/service/CurrentLessonViewService.kt | 35 ++++---- .../service/MyFirebaseMessagingService.kt | 13 +++ .../polytechnic/next/ui/ExpandableCard.kt | 7 +- .../polytechnic/next/ui/MainActivity.kt | 16 +--- .../polytechnic/next/ui/main/MainScreen.kt | 19 ++-- .../next/ui/main/schedule/DayCard.kt | 16 ++-- .../next/ui/main/schedule/DayPager.kt | 6 +- .../next/ui/main/schedule/LessonView.kt | 6 +- .../next/ui/main/schedule/ScheduleScreen.kt | 4 + .../polytechnic/next/utils/Extensions.kt | 7 +- .../polytechnic/next/work/LinkUpdateWorker.kt | 2 +- .../polytechnic/next/work/ScheduleClvAlarm.kt | 29 ++++++ 21 files changed, 388 insertions(+), 103 deletions(-) create mode 100644 app/src/main/java/ru/n08i40k/polytechnic/next/IntentRequestCodes.kt create mode 100644 app/src/main/java/ru/n08i40k/polytechnic/next/receiver/AlarmReceiver.kt create mode 100644 app/src/main/java/ru/n08i40k/polytechnic/next/receiver/BootCompletedBroadcastReceiver.kt create mode 100644 app/src/main/java/ru/n08i40k/polytechnic/next/work/ScheduleClvAlarm.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3ad9729..9231046 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -33,8 +33,8 @@ android { applicationId = "ru.n08i40k.polytechnic.next" minSdk = 26 targetSdk = 35 - versionCode = 12 - versionName = "1.7.0" + versionCode = 13 + versionName = "1.7.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7b38436..737a600 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,11 +2,20 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/IntentRequestCodes.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/IntentRequestCodes.kt new file mode 100644 index 0000000..1ce37e8 --- /dev/null +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/IntentRequestCodes.kt @@ -0,0 +1,5 @@ +package ru.n08i40k.polytechnic.next + +object IntentRequestCodes { + const val ALARM_CLV = 1337 +} \ No newline at end of file diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/PolytechnicApplication.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/PolytechnicApplication.kt index e255faa..7fc259b 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/PolytechnicApplication.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/PolytechnicApplication.kt @@ -1,13 +1,20 @@ package ru.n08i40k.polytechnic.next import android.Manifest +import android.app.AlarmManager import android.app.Application +import android.app.PendingIntent +import android.content.Context +import android.content.Intent 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.model.Group +import ru.n08i40k.polytechnic.next.receiver.AlarmReceiver import ru.n08i40k.polytechnic.next.utils.or +import java.util.Calendar import javax.inject.Inject @HiltAndroidApp @@ -27,4 +34,84 @@ class PolytechnicApplication : Application() { || ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) } + + private fun getDate(group: Group): Calendar? { + val javaCalendar = Calendar.getInstance() + val currentMinutes = javaCalendar.get(Calendar.HOUR_OF_DAY) * 60 + + javaCalendar.get(Calendar.MINUTE) + var startDayIdx = javaCalendar.get(Calendar.DAY_OF_WEEK) - 2 + + println("Current day is $startDayIdx") + + val currentDay = group.days[startDayIdx] + if (currentDay != null) { + val firstLesson = currentDay.first + + if (firstLesson == null || firstLesson.time.start < currentMinutes) { + println("Current day already started or ended!") + ++startDayIdx + } + } + + for (dayIdx in startDayIdx..5) { + println("Trying $dayIdx day...") + val day = group.days[dayIdx] ?: continue + println("Day isn't null") + val firstLesson = day.first ?: continue + println("Day isn't empty") + + val executeMinutes = (firstLesson.time.start - 15).coerceAtLeast(0) + + println("Schedule minutes at $executeMinutes") + + return Calendar.getInstance().apply { + set(Calendar.DAY_OF_WEEK, dayIdx + 2) // sunday is first + index from 0 + set(Calendar.HOUR_OF_DAY, executeMinutes / 60) + set(Calendar.MINUTE, executeMinutes % 60) + set(Calendar.SECOND, 0) +// set(Calendar.MINUTE, get(Calendar.MINUTE) + 1) + } + } + + return null + } + + fun scheduleClvService(group: Group) { + // -1 = вс + // 0 = пн + // 1 = вт + // 2 = ср + // 3 = чт + // 4 = пт + // 5 = сб + + println("Getting date...") + + val date = getDate(group) ?: return + + println("Alarm on this week!") + + val alarmManager = applicationContext + .getSystemService(Context.ALARM_SERVICE) as? AlarmManager + + val pendingIntent = + Intent(applicationContext, AlarmReceiver::class.java).let { + PendingIntent.getBroadcast( + applicationContext, + IntentRequestCodes.ALARM_CLV, + it, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + } + + if (alarmManager != null) + println("Alarm manager isn't null.") + + alarmManager?.cancel(pendingIntent) + alarmManager?.set( + AlarmManager.RTC_WAKEUP, + date.timeInMillis, + pendingIntent + ) + } } \ No newline at end of file diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/model/Day.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/model/Day.kt index 2a540be..b031ea9 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/model/Day.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/model/Day.kt @@ -3,10 +3,11 @@ package ru.n08i40k.polytechnic.next.model import android.os.Parcelable import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable +import ru.n08i40k.polytechnic.next.utils.getDayMinutes import java.util.Calendar @Parcelize -@Suppress("unused") +@Suppress("unused", "MemberVisibilityCanBePrivate") @Serializable class Day( val name: String, @@ -15,7 +16,7 @@ class Day( val customIndices: ArrayList, val lessons: ArrayList ) : Parcelable { - fun getDistanceToNextByMinutes(from: Int): Map.Entry? { + fun distanceToNextByMinutes(from: Int): Pair? { val toIdx = lessons .map { if (it?.time == null) null else it.time.start } .indexOfFirst { if (it == null) false else it > from } @@ -23,53 +24,79 @@ class Day( 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 - } + return Pair(toIdx, lessons[toIdx]!!.time.start - from) } - fun getDistanceToNextByIdx(from: Int? = null): Map.Entry? { + fun distanceToNextByIdx(from: Int? = null): Pair? { val fromLesson = if (from != null) lessons[from] else null - if (from != null && fromLesson?.time == null) + if (from != null && fromLesson == null) throw NullPointerException("Lesson (by given index) and it's time should be non-null!") val fromTime = if (from != null) - fromLesson!!.time!!.end + fromLesson!!.time.end else Calendar.getInstance() .get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance() .get(Calendar.MINUTE) - return getDistanceToNextByMinutes(fromTime) + return distanceToNextByMinutes(fromTime) } - fun getCurrentLesson(): Map.Entry? { - val minutes = Calendar.getInstance() - .get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance() - .get(Calendar.MINUTE) + // current + val currentIdx: Int? + get() { + val minutes = Calendar.getInstance().getDayMinutes() - for (lessonIdx in 0..= lesson.time.end - ) - continue - - return object : Map.Entry { - override val key: Int - get() = lessonIdx - override val value: Lesson - get() = lesson + if (lesson.time.start <= minutes && minutes < lesson.time.end) + return lessonIdx } + + return null } - return null - } + val current: Lesson? + get() { + return lessons[currentIdx ?: return null] + } + + val currentKV: Pair? + get() { + val idx = currentIdx ?: return null + return Pair(idx, lessons[idx]!!) + } + + // first + val firstIdx: Int? + get() = nonNullIndices.getOrNull(0) + + val first: Lesson? + get() { + return lessons[firstIdx ?: return null]!! + } + + val firstKV: Pair? + get() { + val idx = firstIdx ?: return null + return Pair(idx, lessons[idx]!!) + } + + // last + val lastIdx: Int? + get() = nonNullIndices.getOrNull(nonNullIndices.size - 1) + + val last: Lesson? + get() { + return lessons[lastIdx ?: return null]!! + } + + val lastKV: Pair? + get() { + val idx = lastIdx ?: return null + return Pair(idx, lessons[idx]!!) + } } \ 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 2ba4aa0..9594035 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 @@ -5,23 +5,31 @@ import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable import java.util.Calendar +@Suppress("MemberVisibilityCanBePrivate") @Parcelize @Serializable data class Group( val name: String, val days: ArrayList ) : Parcelable { - fun getCurrentDay(): Map.Entry? { - val currentDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2) + val currentIdx: Int? + get() { + val currentDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2) - if (currentDay < 0 || currentDay > days.size - 1) - return null + 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] + return currentDay + } + + val current: Day? + get() { + return days.getOrNull(currentIdx ?: return null) + } + + val currentKV: Pair? + get() { + val idx = currentIdx ?: return null + return Pair(idx, days[idx]) } - } } \ 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 6ff32e5..3237c38 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 @@ -13,16 +13,14 @@ data class Lesson( val type: LessonType, val defaultIndex: Int, val name: String, - val time: LessonTime?, + val time: LessonTime, val cabinets: ArrayList, val teacherNames: ArrayList ) : Parcelable { - fun getDuration(): Int? { - if (this.time == null) - return null - - return time.end - time.start - } + val duration: Int + get() { + return time.end - time.start + } fun getNameAndCabinetsShort(context: Context): String { val limitedName = name limit 15 diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/receiver/AlarmReceiver.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/receiver/AlarmReceiver.kt new file mode 100644 index 0000000..5f1a394 --- /dev/null +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/receiver/AlarmReceiver.kt @@ -0,0 +1,42 @@ +package ru.n08i40k.polytechnic.next.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import androidx.work.Constraints +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import ru.n08i40k.polytechnic.next.service.CurrentLessonViewService +import ru.n08i40k.polytechnic.next.work.ScheduleClvAlarm + +class AlarmReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + println("Hi from AlarmReceiver") + + if (intent == null) { + println("No intend provided!") + return + } + + if (context == null) { + println("No context provided!") + return + } + println(intent.action) + + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + + val rescheduleRequest = OneTimeWorkRequestBuilder() + .setConstraints(constraints) + .build() + + WorkManager + .getInstance(context) + .enqueue(rescheduleRequest) + + CurrentLessonViewService.startService(context.applicationContext) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/receiver/BootCompletedBroadcastReceiver.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/receiver/BootCompletedBroadcastReceiver.kt new file mode 100644 index 0000000..823c6c4 --- /dev/null +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/receiver/BootCompletedBroadcastReceiver.kt @@ -0,0 +1,45 @@ +package ru.n08i40k.polytechnic.next.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import androidx.work.Constraints +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import ru.n08i40k.polytechnic.next.work.ScheduleClvAlarm +import java.util.logging.Logger + +class BootCompletedBroadcastReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val logger = Logger.getLogger("BootCompletedBroadcastReceiver") + + if (context == null) { + logger.warning("No context provided!") + return + } + + if (intent == null) { + logger.warning("No intend provided!") + return + } + + if (intent.action != "android.intent.action.BOOT_COMPLETED") { + logger.warning("Strange intent action passed!") + logger.warning(intent.action) + return + } + + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + + val request = OneTimeWorkRequestBuilder() + .setConstraints(constraints) + .build() + + WorkManager + .getInstance(context) + .enqueue(request) + } +} \ 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 index e722e84..2191488 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/service/CurrentLessonViewService.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/service/CurrentLessonViewService.kt @@ -19,9 +19,11 @@ 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.utils.getDayMinutes import ru.n08i40k.polytechnic.next.work.StartClvService import java.util.Calendar +@Suppress("UNNECESSARY_NOT_NULL_ASSERTION") class CurrentLessonViewService : Service() { companion object { private const val NOTIFICATION_STATUS_ID = 1337 @@ -58,16 +60,16 @@ class CurrentLessonViewService : Service() { .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 currentLessonEntry = day!!.currentKV + val currentLessonIdx: Int? = currentLessonEntry?.first + val currentLesson: Lesson? = currentLessonEntry?.second - val nextLessonEntry = day!!.getDistanceToNextByIdx(currentLessonIdx) + val nextLessonEntry = day!!.distanceToNextByIdx(currentLessonIdx) val nextLesson = if (nextLessonEntry == null) null else - day!!.lessons[nextLessonEntry.key] + day!!.lessons[nextLessonEntry.first] if (currentLesson == null && nextLesson == null) { val notification = NotificationCompat @@ -83,13 +85,13 @@ class CurrentLessonViewService : Service() { return } - val firstLessonIdx = day!!.getDistanceToNextByMinutes(0)?.key + val firstLessonIdx = day!!.distanceToNextByMinutes(0)?.first ?: throw NullPointerException("Is this even real?") val distanceToFirst = day!!.lessons[firstLessonIdx]!!.time!!.start - currentMinutes val currentLessonDelay = if (currentLesson == null) // Если эта пара - перемена, то конец перемены через (результат getDistanceToNext) - nextLessonEntry!!.value + nextLessonEntry!!.second else // Если эта пара - обычная пара, то конец пары через (конец этой пары - текущее кол-во минут) currentLesson.time!!.end - currentMinutes @@ -157,32 +159,29 @@ class CurrentLessonViewService : Service() { return getSystemService(NOTIFICATION_SERVICE) as NotificationManager } - fun updateSchedule(group: Group?): Boolean { + private fun updateSchedule(group: Group?): Boolean { if (group == null) { stopSelf() return false } - val day = group.getCurrentDay() - if (day?.value == null) { + val currentDay = group.current + if (currentDay == null || currentDay.nonNullIndices.isEmpty()) { 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) - ) { + val nowMinutes = Calendar.getInstance().getDayMinutes() + + if (currentDay.first!!.time.start - nowMinutes > 30 + || currentDay.last!!.time.end < nowMinutes) { stopSelf() return false } } - this.day = dayValue + this.day = currentDay this.handler.removeCallbacks(updateRunnable) updateRunnable.run() 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 04de6bc..70b5202 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 @@ -20,6 +20,7 @@ import com.google.firebase.messaging.RemoteMessage import ru.n08i40k.polytechnic.next.NotificationChannels import ru.n08i40k.polytechnic.next.R import ru.n08i40k.polytechnic.next.work.FcmSetTokenWorker +import ru.n08i40k.polytechnic.next.work.ScheduleClvAlarm import java.time.Duration class MyFirebaseMessagingService : FirebaseMessagingService() { @@ -100,6 +101,18 @@ class MyFirebaseMessagingService : FirebaseMessagingService() { NotificationCompat.PRIORITY_DEFAULT, message.data["etag"] ) + + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + + val request = OneTimeWorkRequestBuilder() + .setConstraints(constraints) + .build() + + WorkManager + .getInstance(applicationContext) + .enqueue(request) } "app-update" -> { diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt index 5e30cd4..f04c88e 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/ExpandableCard.kt @@ -10,6 +10,7 @@ import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -18,6 +19,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material3.Card +import androidx.compose.material3.CardColors +import androidx.compose.material3.CardDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -30,6 +33,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @Composable @@ -53,7 +57,8 @@ fun ExpandableCard( onExpandedChange() transitionState.targetState = expanded }, - shape = RectangleShape + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), + border = BorderStroke(Dp.Hairline, MaterialTheme.colorScheme.inverseSurface) ) { Column { ExpandableCardHeader(title, transition) 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 728a3e7..7a24bde 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,7 +3,6 @@ package ru.n08i40k.polytechnic.next.ui import android.Manifest import android.app.NotificationChannel import android.app.NotificationManager -import android.content.Intent import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -38,7 +37,6 @@ 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 @@ -103,10 +101,7 @@ class MainActivity : ComponentActivity() { requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) } - private fun startTestService() { - if (!(applicationContext as PolytechnicApplication).hasNotificationPermission()) - return - + private fun scheduleAlarm() { lifecycleScope.launch { val schedule = (applicationContext as PolytechnicApplication) .container @@ -116,11 +111,8 @@ class MainActivity : ComponentActivity() { 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) + (applicationContext as PolytechnicApplication) + .scheduleClvService((schedule as MyResult.Success).data) } } @@ -190,7 +182,7 @@ class MainActivity : ComponentActivity() { setupFirebaseConfig() handleUpdate() - startTestService() + scheduleAlarm() setContent { Box(Modifier.windowInsetsPadding(WindowInsets.safeContent.only(WindowInsetsSides.Top))) { diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt index 5881a17..983cf87 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/MainScreen.kt @@ -7,8 +7,9 @@ import androidx.activity.ComponentActivity import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.animation.slideIn -import androidx.compose.animation.slideOut import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -95,19 +96,25 @@ private fun NavHostContainer( enterTransition = { slideIn( animationSpec = tween( - 500, + 400, delayMillis = 250, easing = LinearOutSlowInEasing ) - ) { fullSize -> IntOffset(-fullSize.width, 0) } + ) { fullSize -> IntOffset(0, fullSize.height / 16) } + fadeIn( + animationSpec = tween( + 400, + delayMillis = 250, + easing = LinearOutSlowInEasing + ) + ) }, exitTransition = { - slideOut( + fadeOut( animationSpec = tween( - 500, + 250, easing = FastOutSlowInEasing ) - ) { fullSize -> IntOffset(fullSize.width, 0) } + ) }, builder = { composable("profile") { 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 e5d7c0c..db412e6 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 @@ -66,9 +66,7 @@ fun calculateCurrentLessonIdx(lessons: ArrayList): Int { val filteredLessons = lessons .filterNotNull() .filter { - it.time != null - && it.time.start <= currentMinutes - && it.time.end >= currentMinutes + it.time.start <= currentMinutes && it.time.end >= currentMinutes } if (filteredLessons.isEmpty()) @@ -101,16 +99,20 @@ fun DayCard( modifier = modifier, colors = CardDefaults.cardColors( containerColor = - if (current) MaterialTheme.colorScheme.surfaceContainerHighest - else MaterialTheme.colorScheme.surfaceContainerLowest - ) + if (current) MaterialTheme.colorScheme.inverseSurface + else MaterialTheme.colorScheme.surface + ), + border = BorderStroke(1.dp, MaterialTheme.colorScheme.inverseSurface) ) { if (day == null) { Text( modifier = Modifier.fillMaxWidth(), fontWeight = FontWeight.Bold, textAlign = TextAlign.Center, - text = stringResource(R.string.day_null) + text = stringResource(R.string.day_null), + color = + if (current) MaterialTheme.colorScheme.inverseOnSurface + else MaterialTheme.colorScheme.onSurface ) return@Card } diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt index 3e0c0af..dace29c 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/DayPager.kt @@ -37,10 +37,10 @@ fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) { val offset = pagerState.getOffsetDistanceInPages(page).absoluteValue lerp( - start = 0.95f, stop = 1f, fraction = 1f - offset.coerceIn(0f, 1f) + start = 1f, stop = 0.95f, fraction = 1f - offset.coerceIn(0f, 1f) ).also { scale -> - scaleX = 1F - scale + 0.95F - scaleY = 1F - scale + 0.95F + scaleX = scale + scaleY = scale } alpha = lerp( start = 0.5f, stop = 1f, fraction = 1f - offset.coerceIn(0f, 1f) 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 5a9b7bc..182a680 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 @@ -79,7 +79,7 @@ fun LessonExtraInfo( append(stringResource(R.string.lesson_duration)) append(" - ") val duration = - if (lesson.time != null) lesson.time.end - lesson.time.start else 0 + lesson.time.end - lesson.time.start append(duration / 60) append(stringResource(R.string.hours)) @@ -215,9 +215,7 @@ fun FreeLessonRow( ) { LessonViewRow( -1, - if (lesson.time != null && nextLesson.time != null) LessonTime( - lesson.time.end, nextLesson.time.start - ) else null, + LessonTime(lesson.time.end, nextLesson.time.start), LessonTimeFormat.ONLY_MINUTES_DURATION, stringResource(R.string.lesson_break), arrayListOf(), diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt index 73c23f0..416b44f 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/ui/main/schedule/ScheduleScreen.kt @@ -2,7 +2,9 @@ package ru.n08i40k.polytechnic.next.ui.main.schedule import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -15,6 +17,7 @@ import androidx.compose.ui.platform.LocalContext 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 androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner @@ -79,6 +82,7 @@ fun ScheduleScreen( val hasSchedule = uiState as ScheduleUiState.HasSchedule UpdateInfo(hasSchedule.lastUpdateAt, hasSchedule.updateDates) + Spacer(Modifier.height(10.dp)) DayPager(hasSchedule.group) } } diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/utils/Extensions.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/utils/Extensions.kt index a960bd8..5a8ae1a 100644 --- a/app/src/main/java/ru/n08i40k/polytechnic/next/utils/Extensions.kt +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/utils/Extensions.kt @@ -1,5 +1,7 @@ package ru.n08i40k.polytechnic.next.utils +import java.util.Calendar + infix fun T?.or(data: T): T { if (this == null) return data @@ -25,4 +27,7 @@ infix fun String.limit(count: Int): String { .substring(0, count - 1) .trimEnd() .plus("…") -} \ No newline at end of file +} + +fun Calendar.getDayMinutes(): Int = + this.get(Calendar.HOUR_OF_DAY) * 60 + this.get(Calendar.MINUTE) \ 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 a6f43bc..22decaf 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 @@ -17,7 +17,7 @@ class LinkUpdateWorker(context: Context, params: WorkerParameters) : .getGroup() } - CurrentLessonViewService.startService(applicationContext) +// CurrentLessonViewService.startService(applicationContext) return Result.success() } diff --git a/app/src/main/java/ru/n08i40k/polytechnic/next/work/ScheduleClvAlarm.kt b/app/src/main/java/ru/n08i40k/polytechnic/next/work/ScheduleClvAlarm.kt new file mode 100644 index 0000000..8056640 --- /dev/null +++ b/app/src/main/java/ru/n08i40k/polytechnic/next/work/ScheduleClvAlarm.kt @@ -0,0 +1,29 @@ +package ru.n08i40k.polytechnic.next.work + +import android.content.Context +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 + +class ScheduleClvAlarm(context: Context, workerParams: WorkerParameters) : + Worker(context, workerParams) { + override fun doWork(): Result { + val application = applicationContext as PolytechnicApplication + + val result = runBlocking { + application + .container + .scheduleRepository + .getGroup() + } + + if (result is MyResult.Failure) + return Result.failure() + + application.scheduleClvService((result as MyResult.Success).data) + + return Result.success() + } +} \ No newline at end of file