1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-11-22 11:06:05 -06:00
This commit is contained in:
Rafał Borcz 2024-06-11 20:37:31 +02:00 committed by GitHub
parent fc549309d8
commit 3e106d5af0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 192 additions and 7 deletions

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data
import io.github.wulkanowy.data.repositories.isEndDateReached
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
@ -267,7 +268,8 @@ inline fun <DatabaseType, ApiType, OutputType> networkBoundResource(
emit(Resource.Loading())
val data = query().first()
if (shouldFetch(data)) {
val updatedShouldFetch = if (isEndDateReached) false else shouldFetch(data)
if (updatedShouldFetch) {
emit(Resource.Intermediate(data))
try {

View File

@ -12,9 +12,13 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.sync.Mutex
import timber.log.Timber
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
private val endDate = LocalDate.of(2024, 6, 25)
val isEndDateReached = LocalDate.now() >= endDate
@Singleton
class WulkanowyRepository @Inject constructor(
private val wulkanowyService: WulkanowyService,
@ -24,7 +28,6 @@ class WulkanowyRepository @Inject constructor(
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "mapping_refresh_key"
fun getAdminMessages(): Flow<Resource<List<AdminMessage>>> =

View File

@ -4,19 +4,27 @@ import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.O
import androidx.core.app.NotificationManagerCompat
import androidx.lifecycle.asFlow
import androidx.work.*
import androidx.work.BackoffPolicy.EXPONENTIAL
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType.CONNECTED
import androidx.work.NetworkType.UNMETERED
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.isEndDateReached
import io.github.wulkanowy.services.sync.channels.Channel
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.isHolidays
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import timber.log.Timber
import java.time.LocalDate.now
import java.util.concurrent.TimeUnit.MINUTES
@ -34,7 +42,9 @@ class SyncManager @Inject constructor(
) {
init {
if (now().isHolidays) stopSyncWorker()
if (now().isHolidays || isEndDateReached) {
stopSyncWorker()
}
if (SDK_INT >= O) {
channels.forEach { it.create() }
@ -50,7 +60,7 @@ class SyncManager @Inject constructor(
}
fun startPeriodicSyncWorker(restart: Boolean = false) {
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
if (preferencesRepository.isServiceEnabled && !now().isHolidays && isEndDateReached) {
val serviceInterval = preferencesRepository.servicesInterval
workManager.enqueueUniquePeriodicWork(
@ -70,6 +80,10 @@ class SyncManager @Inject constructor(
// if quiet, no notifications will be sent
fun startOneTimeSyncWorker(quiet: Boolean = false): Flow<WorkInfo?> {
if (isEndDateReached) {
return flowOf(null)
}
val work = OneTimeWorkRequestBuilder<SyncWorker>()
.setInputData(
Data.Builder()

View File

@ -15,6 +15,7 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.isEndDateReached
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureUnavailableException
@ -42,7 +43,9 @@ class SyncWorker @AssistedInject constructor(
override suspend fun doWork(): Result = withContext(dispatchersProvider.io) {
Timber.i("SyncWorker is starting")
if (!studentRepository.isCurrentStudentSet()) return@withContext Result.failure()
if (!studentRepository.isCurrentStudentSet() || isEndDateReached) {
return@withContext Result.failure()
}
val (student, semester) = try {
val student = studentRepository.getCurrentStudent()
@ -91,6 +94,7 @@ class SyncWorker @AssistedInject constructor(
.build()
)
}
errors.isNotEmpty() -> Result.retry()
else -> {
preferencesRepository.lasSyncDate = Instant.now()

View File

@ -0,0 +1,31 @@
package io.github.wulkanowy.ui.modules.end
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.View
import androidx.activity.addCallback
import androidx.core.text.HtmlCompat
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.databinding.FragmentEndBinding
import io.github.wulkanowy.ui.base.BaseFragment
@AndroidEntryPoint
class EndFragment : BaseFragment<FragmentEndBinding>(R.layout.fragment_end), EndView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentEndBinding.bind(view)
requireActivity().onBackPressedDispatcher.addCallback {
requireActivity().finishAffinity()
}
binding.endClose.setOnClickListener { requireActivity().finishAffinity() }
val message = getString(R.string.end_message)
binding.endDescription.movementMethod = LinkMovementMethod.getInstance()
binding.endDescription.text =
HtmlCompat.fromHtml(message, HtmlCompat.FROM_HTML_MODE_COMPACT)
}
}

View File

@ -0,0 +1,5 @@
package io.github.wulkanowy.ui.modules.end
import io.github.wulkanowy.ui.base.BaseView
interface EndView : BaseView

View File

@ -15,6 +15,7 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.databinding.ActivityLoginBinding
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.modules.end.EndFragment
import io.github.wulkanowy.ui.modules.login.advanced.LoginAdvancedFragment
import io.github.wulkanowy.ui.modules.login.form.LoginFormFragment
import io.github.wulkanowy.ui.modules.login.recover.LoginRecoverFragment
@ -115,9 +116,14 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
}
}
override fun navigateToEnd() {
openFragment(EndFragment(), clearBackStack = true)
}
override fun onResume() {
super.onResume()
inAppUpdateHelper.onResume()
presenter.updateSdkMappings()
presenter.checkIfEnd()
}
}

View File

@ -2,6 +2,8 @@ package io.github.wulkanowy.ui.modules.login
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.WulkanowyRepository
import io.github.wulkanowy.data.repositories.isEndDateReached
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import kotlinx.coroutines.launch
@ -11,7 +13,8 @@ import javax.inject.Inject
class LoginPresenter @Inject constructor(
private val wulkanowyRepository: WulkanowyRepository,
errorHandler: ErrorHandler,
studentRepository: StudentRepository
studentRepository: StudentRepository,
private val syncManager: SyncManager
) : BasePresenter<LoginView>(errorHandler, studentRepository) {
override fun onAttachView(view: LoginView) {
@ -26,4 +29,11 @@ class LoginPresenter @Inject constructor(
.onFailure { Timber.e(it) }
}
}
fun checkIfEnd() {
if (isEndDateReached) {
syncManager.stopSyncWorker()
view?.navigateToEnd()
}
}
}

View File

@ -5,4 +5,6 @@ import io.github.wulkanowy.ui.base.BaseView
interface LoginView : BaseView {
fun initView()
fun navigateToEnd()
}

View File

@ -14,7 +14,9 @@ import io.github.wulkanowy.R
import io.github.wulkanowy.data.dataOrThrow
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.LuckyNumberRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.isEndDateReached
import io.github.wulkanowy.data.toFirstResult
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
@ -35,6 +37,9 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
@Inject
lateinit var sharedPref: SharedPrefProvider
@Inject
lateinit var preferencesRepository: PreferencesRepository
companion object {
private const val LUCKY_NUMBER_WIDGET_MAX_SIZE = 196
@ -130,6 +135,10 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
}
private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking {
if (isEndDateReached) {
return@runBlocking null
}
try {
val students = studentRepository.getSavedStudents()
val student = students.singleOrNull { it.student.id == studentId }?.student

View File

@ -33,6 +33,7 @@ import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.captcha.CaptchaDialog
import io.github.wulkanowy.ui.modules.end.EndFragment
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
@ -139,6 +140,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
super.onResume()
inAppUpdateHelper.onResume()
presenter.updateSdkMappings()
presenter.checkIfEnd()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -362,4 +364,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
super.onSaveInstanceState(outState)
navController.onSaveInstanceState(outState)
}
override fun navigateToEnd() {
binding.mainToolbar.isVisible = false
pushView(EndFragment())
onBackCallback?.isEnabled = false
}
}

View File

@ -7,6 +7,7 @@ import io.github.wulkanowy.data.onResourceSuccess
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.WulkanowyRepository
import io.github.wulkanowy.data.repositories.isEndDateReached
import io.github.wulkanowy.data.resourceFlow
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
@ -15,6 +16,7 @@ import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.account.AccountView
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsView
import io.github.wulkanowy.ui.modules.end.EndView
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
import io.github.wulkanowy.utils.AdsHelper
import io.github.wulkanowy.utils.AnalyticsHelper
@ -110,6 +112,7 @@ class MainPresenter @Inject constructor(
}
private fun shouldShowBottomNavigation(destination: BaseView) = when (destination) {
is EndView,
is AccountView,
is StudentInfoView,
is AccountDetailsView -> false
@ -208,4 +211,11 @@ class MainPresenter @Inject constructor(
.onFailure { Timber.e(it) }
}
}
fun checkIfEnd() {
if (isEndDateReached) {
syncManager.stopSyncWorker()
view?.navigateToEnd()
}
}
}

View File

@ -48,6 +48,8 @@ interface MainView : BaseView {
fun openMoreDestination(destination: Destination)
fun navigateToEnd()
interface MainChildView {
fun onFragmentReselected()

View File

@ -22,6 +22,7 @@ import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.data.repositories.TimetableRepository
import io.github.wulkanowy.data.repositories.isEndDateReached
import io.github.wulkanowy.data.toFirstResult
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getDateWidgetKey
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
@ -71,6 +72,8 @@ class TimetableWidgetFactory(
items = emptyList()
if (isEndDateReached) return
runBlocking {
runCatching {
val student = getStudent(studentId) ?: return@runBlocking

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/endIcon"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_marginTop="32dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toTopOf="@id/endText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/endText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="16dp"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:text="@string/end_title"
android:textSize="28sp"
app:layout_constraintBottom_toTopOf="@id/endDescription"
app:layout_constraintTop_toBottomOf="@id/endIcon" />
<TextView
android:id="@+id/endDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@id/endClose"
app:layout_constraintTop_toBottomOf="@id/endText"
tools:maxLines="15"
tools:text="@string/end_message" />
<com.google.android.material.button.MaterialButton
android:id="@+id/endClose"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="32dp"
android:text="ZAMKNIJ APLIKACJĘ"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/endDescription"
app:layout_constraintVertical_bias="0" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string-array name="app_theme_entries" tools:ignore="InconsistentArrays">
<item>Motiw systemu</item>
<item>Jôsny</item>
<item>Cemny</item>
<item>Cemny (AMOLED)</item>
</string-array>
</resources>

View File

@ -895,4 +895,8 @@
<string name="message_unmute">Unmute</string>
<string name="message_mute_success">You have muted this user</string>
<string name="message_unmute_success">You have unmuted this user</string>
<!--End-->
<string name="end_title">Koniec Wulkanowego</string>
<string name="end_message">Jak zapewne niektórzy z Was się domyślali zbliża się ten moment, aby zakończyć pewien etap. Wraz z końcem tego roku szkolnego zamykamy projekt Wulkanowy. Stworzenie apki było ekscytującym wyzwaniem, ale skala projektu jest tak duża, że nie jesteśmy w stanie odpowiedzialnie utrzymywać aplikacji. Wulkanowy był fajną przygodą, ale sytuacja wymknęła się nam spod kontroli zarówno pod względem technicznym, jak i społecznym. Nie akceptujemy pojawiającego się hejtu wobec nas ani wobec innych, także Vulcana. Nie chcemy brać udziału w tych działaniach i być z nimi utożsamiani. Prosimy Was o powściągliwość i rozwagę w publikowanych komentarzach i nieprzekraczanie dopuszczalnych granic.&lt;br />&lt;br />Prosimy Was też o uszanowanie naszej decyzji, jest ona przemyślana i ostateczna. Wszystkim dotychczasowym użytkownikom Wulkanowego rekomendujemy użycie oficjalnej aplikacji &lt;a href="https://play.google.com/store/apps/details?id=pl.edu.vulcan.hebe&amp;hl=pl">Dzienniczek VULCAN&lt;/a>. Jeszcze raz dziękujemy wszystkim użytkownikom za lata wsparcia, pomoc i miłe słowa!</string>
</resources>