diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
index 7920580..ee8e666 100644
Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
index 3e6884f..ca7b4ef 100644
Binary files a/.gradle/buildOutputCleanup/outputFiles.bin and b/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/.gradle/checksums/checksums.lock b/.gradle/checksums/checksums.lock
index fd7b750..cc802fa 100644
Binary files a/.gradle/checksums/checksums.lock and b/.gradle/checksums/checksums.lock differ
diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
new file mode 100644
index 0000000..c79a75b
--- /dev/null
+++ b/.idea/assetWizardSettings.xml
@@ -0,0 +1,328 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/app/app.iml b/.idea/modules/app/app.iml
index 48895a5..035bed8 100644
--- a/.idea/modules/app/app.iml
+++ b/.idea/modules/app/app.iml
@@ -31,7 +31,7 @@
-
+
@@ -70,21 +70,21 @@
-
-
+
-
+
+
+
-
-
+
@@ -134,11 +134,11 @@
-
-
+
+
@@ -161,19 +161,20 @@
+
-
+
-
+
-
+
@@ -193,6 +194,8 @@
+
+
@@ -201,10 +204,19 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index cdd6d98..180ef52 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -38,11 +38,11 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
- implementation "androidx.fragment:fragment-ktx:1.2.1"
+ implementation "androidx.fragment:fragment-ktx:1.2.2"
testImplementation 'junit:junit:4.12'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
- implementation 'com.google.android.material:material:1.2.0-alpha04'
+ implementation 'com.google.android.material:material:1.2.0-alpha05'
implementation 'androidx.preference:preference-ktx:1.1.0'
@@ -54,6 +54,8 @@ dependencies {
implementation "androidx.room:room-runtime:2.2.3"
kapt "androidx.room:room-compiler:$room_version"
+ implementation "androidx.work:work-runtime-ktx:2.3.3"
+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
index f25ef56..5c0fd1a 100644
Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/java/com/denizd/qwark/activity/MainActivity.kt b/app/src/main/java/com/denizd/qwark/activity/MainActivity.kt
index a42f245..b9820eb 100644
--- a/app/src/main/java/com/denizd/qwark/activity/MainActivity.kt
+++ b/app/src/main/java/com/denizd/qwark/activity/MainActivity.kt
@@ -1,27 +1,22 @@
package com.denizd.qwark.activity
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
import android.os.Bundle
-import android.os.Handler
-import android.util.Log
import android.view.View
-import android.view.ViewAnimationUtils
-import androidx.activity.viewModels
-import androidx.appcompat.app.AppCompatDelegate
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
+import androidx.work.*
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.database.QwarkRepository
import com.denizd.qwark.databinding.ActivityMainBinding
import com.denizd.qwark.fragment.*
import com.denizd.qwark.util.Dependencies
-import com.denizd.qwark.util.QwarkPreferences
+import com.denizd.qwark.util.ExamNotificationWorker
import com.denizd.qwark.viewmodel.MainViewModel
-import kotlin.math.hypot
+import java.util.concurrent.TimeUnit
import kotlin.random.Random
class MainActivity : FragmentActivity() {
@@ -68,25 +63,44 @@ class MainActivity : FragmentActivity() {
// TODO reselected listener for scrolling up
resources.getStringArray(R.array.greetings).also { array ->
- binding.greetingTextView.text = String.format(array[Random.nextInt(array.size)], "TODO")
+ binding.greetingTextView.text = String.format(
+ array[Random.nextInt(array.size)],
+ Dependencies.repo.prefs.getScoreProfileName()
+ )
}
- Handler().postDelayed({
- binding.splashScreen.apply {
- val cx = width / 2
- val cy = height / 2
- val initialRadius = hypot(cx.toDouble(), cy.toDouble()).toFloat()
+ // splash screen
+// Handler().postDelayed({
+// binding.splashScreen.apply {
+// val cx = width / 2
+// val cy = height / 2
+// val initialRadius = hypot(cx.toDouble(), cy.toDouble()).toFloat()
+//
+// ViewAnimationUtils.createCircularReveal(this, cx, cy, initialRadius, 0f).also { anim ->
+// anim.addListener(object : AnimatorListenerAdapter() {
+// override fun onAnimationEnd(animation: Animator) {
+// super.onAnimationEnd(animation)
+// visibility = View.GONE
+// }
+// })
+// anim.start()
+// }
+// }
+// }, 1200)
- ViewAnimationUtils.createCircularReveal(this, cx, cy, initialRadius, 0f).also { anim ->
- anim.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator) {
- super.onAnimationEnd(animation)
- visibility = View.GONE
- }
- })
- anim.start()
+ Dependencies.repo.allCoursesWithExams.observe(this, Observer { courses ->
+ with (WorkManager.getInstance(this)) {
+ for (course in courses) {
+ beginUniqueWork(
+ "${course.name}-${course.courseId}",
+ ExistingWorkPolicy.REPLACE,
+ OneTimeWorkRequestBuilder()
+ .setInitialDelay(getTimeUntil(course.examTime), TimeUnit.MILLISECONDS)
+ .setInputData(Data.Builder().putString("course", course.name).build())
+ .build()
+ ).enqueue()
}
}
- }, 1200)
+ })
}
override fun onResume() {
@@ -105,9 +119,9 @@ class MainActivity : FragmentActivity() {
}
supportFragmentManager.beginTransaction()
- .replace(R.id.fragment_container, fragment, type)
- .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
- .commit()
+ .replace(R.id.fragment_container, fragment, type)
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .commit()
// with (supportFragmentManager) {
// beginTransaction()
@@ -139,4 +153,7 @@ class MainActivity : FragmentActivity() {
}
}
}
+
+ // TODO add option to set time of notification (currently: 7 AM)
+ private fun getTimeUntil(examTime: Long): Long = examTime + viewModel.getExamNotificationTime() - System.currentTimeMillis()
}
diff --git a/app/src/main/java/com/denizd/qwark/database/QwarkDao.kt b/app/src/main/java/com/denizd/qwark/database/QwarkDao.kt
index ecd77e6..5fa91e0 100644
--- a/app/src/main/java/com/denizd/qwark/database/QwarkDao.kt
+++ b/app/src/main/java/com/denizd/qwark/database/QwarkDao.kt
@@ -20,6 +20,9 @@ interface QwarkDao {
@Query("SELECT course.*, (SELECT MIN(exam_time) FROM grade WHERE grade.course_id = course.course_id AND exam_time >= :time) AS exam_time FROM course GROUP BY course.course_id ORDER BY time")
fun getAllCourseExams(time: Long = QwarkUtil.timeAtMidnight): List
+ @Query("SELECT course.*, (SELECT MIN(exam_time) FROM grade WHERE grade.course_id = course.course_id AND exam_time >= :time) AS exam_time FROM course WHERE exam_time > :time GROUP BY course.course_id ORDER BY time")
+ fun getAllCoursesWithExams(time: Long = QwarkUtil.timeAtMidnight + 25200000L): LiveData>
+
@Query("SELECT *, -1 AS exam_time FROM course WHERE course_id != :u ORDER BY time")
fun getAllCourses(u: Int = -1): List // the u variable is an unnecessary workaround to return a list instead of LiveData
diff --git a/app/src/main/java/com/denizd/qwark/database/QwarkRepository.kt b/app/src/main/java/com/denizd/qwark/database/QwarkRepository.kt
index a04abea..077d3d7 100644
--- a/app/src/main/java/com/denizd/qwark/database/QwarkRepository.kt
+++ b/app/src/main/java/com/denizd/qwark/database/QwarkRepository.kt
@@ -83,7 +83,6 @@ class QwarkRepository(app: Application) {
prefs.setInt(PreferenceKey.SCORE_PROFILE_ID, scoreProfile.scoreProfileId)
.setString(PreferenceKey.SCORE_PROFILE_NAME, scoreProfile.name)
}
-
fun setCurrentSchoolYear(schoolYear: SchoolYear) {
prefs.setInt(PreferenceKey.SCHOOL_YEAR_ID, schoolYear.yearId)
.setString(PreferenceKey.SCHOOL_YEAR_NAME, schoolYear.year)
@@ -122,7 +121,6 @@ class QwarkRepository(app: Application) {
dao.update(SchoolYear(name, prefs.getCurrentSchoolYearId()))
setCurrentSchoolYear(SchoolYear(name, prefs.getCurrentSchoolYearId()))
}
-
fun updateScoreProfile(name: String) {
dao.update(ScoreProfile(name, prefs.getScoreProfileId()))
setCurrentScoreProfile(ScoreProfile(name, prefs.getScoreProfileId()))
@@ -137,7 +135,6 @@ class QwarkRepository(app: Application) {
dao.deleteSchoolYear(prefs.getCurrentSchoolYearId())
setCurrentSchoolYear(SchoolYear("", 0))
}
-
fun deleteScoreProfile() {
dao.deleteScoreProfile(prefs.getScoreProfileId())
setCurrentScoreProfile(ScoreProfile("", 0))
@@ -148,6 +145,7 @@ class QwarkRepository(app: Application) {
val allCoursesForToday: LiveData> = dao.getCoursesByDayType(getDayType(), prefs.getSchoolYear())
val allYears: LiveData> = dao.allYears
val allScoreProfiles: LiveData> = dao.allScoreProfiles
+ val allCoursesWithExams: LiveData> = dao.getAllCoursesWithExams()
// get
fun getCourse(courseId: Int): CourseExam = dao.getCourse(courseId)
@@ -166,7 +164,7 @@ class QwarkRepository(app: Application) {
(participations.map { it.timesSpoken }.sum())
)
}
- fun getDayType(): String = if (dayId in 1..5) days[dayId - 1] else days[1]
+ private fun getDayType(): String = if (dayId in 1..5) days[dayId - 1] else days[1]
private fun getMaxFinalScoreId(increment: Boolean): Int {
if (increment) {
prefs.setInt(PreferenceKey.MAX_SCORE_PROFILE_ID, getMaxFinalScoreId(false) + 1)
diff --git a/app/src/main/java/com/denizd/qwark/fragment/SettingsFragment.kt b/app/src/main/java/com/denizd/qwark/fragment/SettingsFragment.kt
index 82a092f..1608b90 100644
--- a/app/src/main/java/com/denizd/qwark/fragment/SettingsFragment.kt
+++ b/app/src/main/java/com/denizd/qwark/fragment/SettingsFragment.kt
@@ -1,8 +1,10 @@
package com.denizd.qwark.fragment
+import android.app.TimePickerDialog
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
+import android.widget.TimePicker
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.denizd.lawrence.util.viewBinding
@@ -13,10 +15,12 @@ import com.denizd.qwark.sheet.ScoreProfileCreateSheet
import com.denizd.qwark.sheet.YearCreateSheet
import com.denizd.qwark.databinding.SettingsFragmentBinding
import com.denizd.qwark.model.SchoolYear
+import com.denizd.qwark.util.toHourAndSecond
+import com.denizd.qwark.util.toMillis
import com.denizd.qwark.viewmodel.SettingsViewModel
import com.google.android.material.snackbar.Snackbar
-class SettingsFragment : QwarkFragment(R.layout.settings_fragment) {
+class SettingsFragment : QwarkFragment(R.layout.settings_fragment), TimePickerDialog.OnTimeSetListener {
private val binding: SettingsFragmentBinding by viewBinding(SettingsFragmentBinding::bind)
private val viewModel: SettingsViewModel by viewModels()
@@ -166,7 +170,7 @@ class SettingsFragment : QwarkFragment(R.layout.settings_fragment) {
viewModel.allScoreProfiles.observe(viewLifecycleOwner, Observer { scoreProfiles ->
binding.scoreProfileDropdown.apply {
setAdapter(
- ArrayAdapter(
+ ArrayAdapter(
context,
R.layout.dropdown_item,
scoreProfiles.map { s -> s.name }
@@ -203,6 +207,24 @@ class SettingsFragment : QwarkFragment(R.layout.settings_fragment) {
openBottomSheet(deleteScoreProfileSheet)
}
}
+ setExamNotificationTimeText()
+ binding.setExamNotificationTimeButton.setOnClickListener {
+ val time = viewModel.getExamNotificationTime().toHourAndSecond()
+ TimePickerDialog(context, this, time.first, time.second, true).show()
+ }
+ }
+
+ override fun onTimeSet(view: TimePicker?, hourOfDay: Int, minute: Int) {
+ viewModel.setExamNotificationTime(Pair(hourOfDay, minute).toMillis())
+ setExamNotificationTimeText()
+ }
+
+ private fun setExamNotificationTimeText() {
+ val time = viewModel.getExamNotificationTime().toHourAndSecond()
+ val examNotificationTime = with (time) {
+ "${first.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}"
+ }
+ binding.examNotificationTimeTextView.text = getString(R.string.exam_notification_time_placeholder, examNotificationTime)
}
fun copyCourses(yearId: Int) {
diff --git a/app/src/main/java/com/denizd/qwark/util/Converters.kt b/app/src/main/java/com/denizd/qwark/util/Converters.kt
new file mode 100644
index 0000000..bd9cc6b
--- /dev/null
+++ b/app/src/main/java/com/denizd/qwark/util/Converters.kt
@@ -0,0 +1,7 @@
+package com.denizd.qwark.util
+
+fun Pair.toMillis(): Long = (first.toLong() * 60 * 60 * 1000) + (second.toLong() * 60 * 1000)
+fun Long.toHourAndSecond(): Pair {
+ val minutes = (this / (1000 * 60)).toInt()
+ return Pair(minutes / 60, minutes % 60)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizd/qwark/util/ExamNotificationWorker.kt b/app/src/main/java/com/denizd/qwark/util/ExamNotificationWorker.kt
new file mode 100644
index 0000000..f18f3d7
--- /dev/null
+++ b/app/src/main/java/com/denizd/qwark/util/ExamNotificationWorker.kt
@@ -0,0 +1,66 @@
+package com.denizd.qwark.util
+
+import android.annotation.TargetApi
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.graphics.Color
+import android.os.Build
+import androidx.core.app.NotificationCompat
+import androidx.work.Worker
+import androidx.work.WorkerParameters
+import com.denizd.qwark.R
+import com.denizd.qwark.activity.MainActivity
+
+private const val notificationChannelId = "qwark_exam_notification"
+
+class ExamNotificationWorker(private val context: Context, workerParams: WorkerParameters) : Worker(context.applicationContext, workerParams) {
+
+ override fun doWork(): Result {
+ sendNotification(course = inputData.getString("course") ?: "error")
+ return Result.success()
+ }
+
+ // TODO launch fragment from intent and launch the fragment for the course
+ private fun sendNotification(course: String) {
+ val openAppPending = PendingIntent.getActivity(
+ context, 0,
+ Intent(context, MainActivity::class.java).also { intent ->
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + Intent.FLAG_ACTIVITY_CLEAR_TASK
+ }, 0
+ )
+
+ val notificationService = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ createNotificationChannel(context, notificationService)
+ }
+
+ val notification = NotificationCompat.Builder(context, notificationChannelId)
+// .setStyle(NotificationCompat.BigTextStyle())
+ .setContentTitle(context.getString(R.string.exam_reminder, course))
+ .setContentText(context.getString(R.string.writing_an_exam_today, course))
+ .setContentIntent(openAppPending)
+ .setAutoCancel(true)
+ .setColor(context.getColor(R.color.colorAccent))
+ .setSmallIcon(R.drawable.bolt)
+ .build()
+
+ notificationService.notify(42, notification)
+ }
+
+ @TargetApi(26)
+ private fun createNotificationChannel(context: Context, notificationManager: NotificationManager) {
+ if (!Dependencies.repo.prefs.getIsNotificationChannelCreated()) {
+ notificationManager.createNotificationChannel(NotificationChannel(
+ notificationChannelId, context.getString(R.string.exams), NotificationManager.IMPORTANCE_DEFAULT
+ ).also { channel ->
+ channel.enableLights(true)
+ channel.lightColor = Color.GREEN
+ })
+ Dependencies.repo.prefs.setIsNotificationChannelCreated(true)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizd/qwark/util/PreferenceKey.kt b/app/src/main/java/com/denizd/qwark/util/PreferenceKey.kt
index c763ae4..9fdf01b 100644
--- a/app/src/main/java/com/denizd/qwark/util/PreferenceKey.kt
+++ b/app/src/main/java/com/denizd/qwark/util/PreferenceKey.kt
@@ -18,5 +18,9 @@ enum class PreferenceKey(val value: String) {
// Bools
SHOW_GRADE_AVERAGE("show_grade_average"),
- FIRST_LAUNCH("first_launch")
+ FIRST_LAUNCH("first_launch"),
+ IS_NOTIFICATION_CHANNEL_CREATED("is_notification_channel_created"),
+
+ // Longs
+ EXAM_NOTIFICATION_TIME("exam_notification_time")
}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizd/qwark/util/QwarkPreferences.kt b/app/src/main/java/com/denizd/qwark/util/QwarkPreferences.kt
index 8a6f506..6f84f43 100644
--- a/app/src/main/java/com/denizd/qwark/util/QwarkPreferences.kt
+++ b/app/src/main/java/com/denizd/qwark/util/QwarkPreferences.kt
@@ -12,6 +12,7 @@ class QwarkPreferences(context: Context) {
fun getString(key: PreferenceKey, default: String = ""): String = prefs.getString(key.value, default) ?: default
fun getInt(key: PreferenceKey, default: Int = 0): Int = prefs.getInt(key.value, default)
fun getBool(key: PreferenceKey, default: Boolean = false): Boolean = prefs.getBoolean(key.value, default)
+ fun getLong(key: PreferenceKey, default: Long = 0L): Long = prefs.getLong(key.value, default)
fun setString(key: PreferenceKey, value: String): QwarkPreferences {
edit.putString(key.value, value).apply()
@@ -25,6 +26,10 @@ class QwarkPreferences(context: Context) {
edit.putBoolean(key.value, value).apply()
return this
}
+ fun setLong(key: PreferenceKey, value: Long): QwarkPreferences {
+ edit.putLong(key.value, value).apply()
+ return this
+ }
// TODO remove all of these
fun getShowGradeAverage(): Boolean = getBool(PreferenceKey.SHOW_GRADE_AVERAGE)
@@ -40,6 +45,8 @@ class QwarkPreferences(context: Context) {
fun getFinalScoreId(): Int = getInt(PreferenceKey.SCORE_PROFILE_ID)
fun getFirstLaunch(): Boolean = getBool(PreferenceKey.FIRST_LAUNCH)
fun getCurrentSchoolYearId(): Int = getInt(PreferenceKey.SCHOOL_YEAR_ID)
+ fun getIsNotificationChannelCreated(): Boolean = getBool(PreferenceKey.IS_NOTIFICATION_CHANNEL_CREATED)
+ fun getExamNotificationTime(): Long = getLong(PreferenceKey.EXAM_NOTIFICATION_TIME, 25200000L)
fun setCourseSortType(value: Int) { setInt(PreferenceKey.COURSE_SORT_TYPE, value) }
fun setParticipationDisplay(value: Int) { setInt(PreferenceKey.PARTICIPATION_DISPLAY, value) }
@@ -48,4 +55,6 @@ class QwarkPreferences(context: Context) {
fun setFirstLaunch(value: Boolean) { setBool(PreferenceKey.FIRST_LAUNCH, value) }
fun setShowGradeAverage(value: Boolean) { setBool(PreferenceKey.SHOW_GRADE_AVERAGE, value) }
fun setGradeType(value: Int) { setInt(PreferenceKey.GRADE_TYPE, value) }
+ fun setIsNotificationChannelCreated(value: Boolean) { setBool(PreferenceKey.IS_NOTIFICATION_CHANNEL_CREATED, value) }
+ fun setExamNotificationTime(value: Long) { setLong(PreferenceKey.EXAM_NOTIFICATION_TIME, value) }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizd/qwark/viewmodel/MainViewModel.kt b/app/src/main/java/com/denizd/qwark/viewmodel/MainViewModel.kt
index 1ed02f3..b6b899d 100644
--- a/app/src/main/java/com/denizd/qwark/viewmodel/MainViewModel.kt
+++ b/app/src/main/java/com/denizd/qwark/viewmodel/MainViewModel.kt
@@ -59,4 +59,6 @@ class MainViewModel(val app: Application) : QwarkViewModel(app) {
repo.prefs.setFirstLaunch(false)
}
}
+
+ fun getExamNotificationTime(): Long = repo.prefs.getExamNotificationTime()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizd/qwark/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/denizd/qwark/viewmodel/SettingsViewModel.kt
index 7bb8812..2d9891d 100644
--- a/app/src/main/java/com/denizd/qwark/viewmodel/SettingsViewModel.kt
+++ b/app/src/main/java/com/denizd/qwark/viewmodel/SettingsViewModel.kt
@@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData
import com.denizd.qwark.database.QwarkClient
import com.denizd.qwark.model.ScoreProfile
import com.denizd.qwark.model.SchoolYear
+import com.denizd.qwark.util.PreferenceKey
class SettingsViewModel(private val app: Application) : QwarkViewModel(app) {
@@ -21,6 +22,7 @@ class SettingsViewModel(private val app: Application) : QwarkViewModel(app) {
fun getCurrentSchoolYearId(): Int = repo.prefs.getCurrentSchoolYearId()
fun getParticipationDisplay(): Int = repo.prefs.getParticipationDisplay()
fun getParticipationDay(): Int = repo.prefs.getParticipationDay()
+ fun getExamNotificationTime(): Long = repo.prefs.getExamNotificationTime()
// Preference setters
fun setAppTheme(value: Int) { repo.prefs.setAppTheme(value) }
@@ -31,6 +33,7 @@ class SettingsViewModel(private val app: Application) : QwarkViewModel(app) {
fun updateSchoolYear(schoolYear: SchoolYear) { repo.setCurrentSchoolYear(schoolYear) }
fun setParticipationDisplay(value: Int) { repo.prefs.setParticipationDisplay(value) }
fun setParticipationDay(value: Int) { repo.prefs.setParticipationDay(value) }
+ fun setExamNotificationTime(value: Long) = repo.prefs.setExamNotificationTime(value)
// Database functions
fun insert(schoolYear: SchoolYear) = doAsync { repo.insert(schoolYear) }
diff --git a/app/src/main/res/drawable/bolt.xml b/app/src/main/res/drawable/bolt.xml
index 80ba978..c5d0a6d 100644
--- a/app/src/main/res/drawable/bolt.xml
+++ b/app/src/main/res/drawable/bolt.xml
@@ -1,5 +1,9 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
index 0d025f9..ca3826a 100644
--- a/app/src/main/res/drawable/ic_launcher_background.xml
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -1,170 +1,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/launch_screen.xml b/app/src/main/res/drawable/launch_screen.xml
index 3f0d793..852248d 100644
--- a/app/src/main/res/drawable/launch_screen.xml
+++ b/app/src/main/res/drawable/launch_screen.xml
@@ -8,7 +8,7 @@
-
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 9837f33..79df71a 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -128,7 +128,8 @@
+ android:animateLayoutChanges="false"
+ android:visibility="gone">
@@ -106,6 +106,34 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index 036d09b..c4a603d 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index 036d09b..c4a603d 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index 809a656..c88686c 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
index 8503a5b..236c0de 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 809a656..c88686c 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index ed4cc00..da83a41 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
index b5a1375..66b85a5 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index ed4cc00..da83a41 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index d644f07..cd25a6f 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
index f8b6e71..586681f 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index d644f07..cd25a6f 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index b384698..7337157 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
index b807043..c1ddea3 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index b384698..7337157 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 37bc130..79fc59b 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index 992972d..50b9299 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 37bc130..79fc59b 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index f414f3e..9b71135 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -16,6 +16,9 @@
Erstelle ein Schuljahr
Bevor du Kurse und Abschlussnoten hinzufügst, gehe in die Einstellungen und erstelle ein Schuljahr und ein Abschlussprofil!
Wird noch hinzugefügt
+ Klausuren
+ Klausurerinnerung: %s
+ Heute schreibst du eine Klausur in %s!
Kurs
@@ -145,6 +148,8 @@
Einstellungen
+ Stelle Zeit für Klausurbenachrichtigung
+ Derzeit eingestellt auf %s
Sortiere Kurse nach
- Zeit hinzugefügt (aufsteigend)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 434a08c..8011de7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -18,6 +18,9 @@
To be implemented
Powered by Qwark
Made by Deniz
+ Exams
+ Exam reminder: %s
+ You\'re writing an exam in %s today!
- Hello %s!
@@ -211,6 +214,8 @@
Settings
+ Set exam notification time
+ Currently set to %s
Sort courses by
- Time added (ascending)