Unified repository layer into a single class; added splash screen (WIP); using delegate classes by Zhuinden for view binding; changed UI to more so resemble "Material Design 2"

This commit is contained in:
Deniz Düzgören
2020-03-09 07:43:43 +01:00
parent 9ed5d7bb5f
commit 31b1bc5d4e
78 changed files with 764 additions and 855 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -1,2 +1,2 @@
#Wed Feb 12 10:01:56 CET 2020
gradle.version=6.1-rc-1
#Mon Mar 02 18:08:17 CET 2020
gradle.version=6.1.1
Binary file not shown.
Binary file not shown.
+11 -11
View File
File diff suppressed because one or more lines are too long
@@ -1,58 +1,46 @@
package com.denizd.qwark.activity
import android.graphics.Color
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.ViewGroup
import android.view.WindowManager
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.ViewModelProvider
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.viewmodel.MainViewModel
import kotlin.math.hypot
import kotlin.random.Random
class MainActivity : FragmentActivity() {
private lateinit var viewModel: MainViewModel
private var _binding: ActivityMainBinding? = null
private val binding: ActivityMainBinding get() = _binding!!
private val binding: ActivityMainBinding by viewBinding(ActivityMainBinding::inflate)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(R.style.AppTheme)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 42)
Dependencies.repo = QwarkRepository(application)
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
viewModel.applyTheme(window, this)
viewModel.checkForFirstTimeYearNotice(this)
binding.appBarLayout.also { appBarLayout ->
appBarLayout.setOnApplyWindowInsetsListener { _, insets ->
(appBarLayout.layoutParams as ViewGroup.MarginLayoutParams)
.topMargin = insets.systemWindowInsetTop
insets
}
}
// TODO remove this translucent app bar layout stuff, it's hard to maintain
window.decorView.systemUiVisibility = if (resources.getBoolean(R.bool.isLight)) {
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
window.attributes = window.attributes.apply {
flags and WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS.inv()
}
window.statusBarColor = Color.TRANSPARENT
binding.bottomNav.setOnNavigationItemSelectedListener { item ->
binding.appBarLayout.setExpanded(true)
loadFragment(viewModel.getFragmentType(item.itemId))
@@ -78,6 +66,27 @@ 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")
}
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)
}
override fun onResume() {
@@ -88,11 +97,6 @@ class MainActivity : FragmentActivity() {
}
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
private fun loadFragment(type: String): Boolean {
val fragment = supportFragmentManager.findFragmentByTag(type) ?: viewModel.getFragment(type)
@@ -53,7 +53,7 @@ class CourseAdapter(private var courses: List<CourseExam>,
val context = holder.averageTextView.context
holder.backgroundView.setBackgroundColor(
context.getColor(if (currentItem.advanced) R.color.colorAccent else R.color.colorCardBackground)
context.getColor(if (currentItem.advanced) R.color.colorAccent else R.color.colorBackground)
)
val textColour = context.getColor(if (currentItem.advanced) R.color.colorTextInverted else R.color.colorText)
@@ -1,39 +1,39 @@
package com.denizd.qwark.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.denizd.qwark.R
import com.denizd.qwark.databinding.AverageCardBinding
import com.denizd.qwark.util.QwarkUtil
import com.denizd.qwark.model.HistoricalAvg
import com.denizd.qwark.util.getUserDefinedAverage
import java.util.*
internal class HistoricalAverageAdapter(private var averages: List<HistoricalAvg>?) : RecyclerView.Adapter<HistoricalAverageAdapter.AverageViewHolder>() {
class HistoricalAverageAdapter(private val averages: List<HistoricalAvg>, private val gradeType: Int) : RecyclerView.Adapter<HistoricalAverageAdapter.AverageViewHolder>() {
internal class AverageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val grade: TextView = view.findViewById(R.id.grade)
val time: TextView = view.findViewById(R.id.time)
}
class AverageViewHolder(val binding: AverageCardBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AverageViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.average_card, parent, false)
return AverageViewHolder(v)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AverageViewHolder = AverageViewHolder(
AverageCardBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: AverageViewHolder, position: Int) {
val currentItem = averages!![position]
val currentItem = averages[position]
val leadingZero = if (currentItem.average.toDouble() < 10.0) "0%s" else "%s"
holder.grade.text = String.format(leadingZero, currentItem.average) // TODO this conflicts with Points (Precise)
holder.time.text = QwarkUtil.getSimpleDateTimeFormat().format(Date(currentItem.time))
}
override fun getItemCount(): Int = averages?.size ?: 0
fun setAverages(averages: List<HistoricalAvg>) {
this.averages = averages
notifyDataSetChanged()
with (holder.binding) {
grade.text = currentItem.average.getUserDefinedAverage(gradeType)
time.text = QwarkUtil.getSimpleDateTimeFormat().format(Date(currentItem.time))
}
}
override fun getItemCount(): Int = averages.size
// fun setAverages(averages: List<HistoricalAvg>) {
// this.averages = averages
// notifyDataSetChanged()
// }
}
@@ -1,26 +0,0 @@
package com.denizd.qwark.database
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.model.Course
import com.denizd.qwark.model.CourseExam
import com.denizd.qwark.model.HistoricalAvg
internal class CourseRepository(app: Application) {
private val dao: QwarkDao = QwarkDatabase.getInstance(app).dao()
// val allCourses: LiveData<List<Course>> = dao.allCourses
// val allHistoricalAverages: LiveData<List<HistoricalAvg>> = dao.allHistoricalAverages
fun insert(course: Course) { dao.insert(course) }
fun update(course: Course) { dao.update(course) }
fun delete(course: Course) { dao.delete(course) }
fun insert(avg: HistoricalAvg) { dao.insert(avg) }
fun getCoursesByYearId(yearId: Int): LiveData<List<CourseExam>> = dao.getCoursesByYearId(yearId)
fun getAveragesForCourses(courseId: Int): List<HistoricalAvg> = dao.getAveragesForCourses(courseId)
fun getCourse(courseId: Int): CourseExam = dao.getCourse(courseId)[0]
}
@@ -1,47 +0,0 @@
package com.denizd.qwark.database
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.util.QwarkPreferences
import com.denizd.qwark.model.FinalGrade
import java.math.BigDecimal
import java.math.RoundingMode
class FinalsRepository(app: Application) {
private val dao: QwarkDao = QwarkDatabase.getInstance(app).dao()
private val prefs: QwarkPreferences = QwarkPreferences.getPrefs(app)
fun getScoreProfileName(): String = prefs.getScoreProfileName()
fun getFinalGrades(finalScoreId: Int): LiveData<List<FinalGrade>> = dao.getFinalGrades(finalScoreId)
fun getFinalScoreId() = prefs.getScoreProfileId()
fun getCourseSortType() = prefs.getCourseSortType()
fun getGradeType() = prefs.getGradeType()
fun updateFinalGradeAverage(courseId: Int, finalGradeId: Int) {
val course = dao.getCourse(courseId)[0]
dao.updateFinalGradeAverage(
course.name,
BigDecimal(course.average).setScale(0, RoundingMode.HALF_UP).toInt(),
finalGradeId
)
}
fun updateLinkedGrades() {
val finalGrades = dao.getFinalGradesAsList(getFinalScoreId())
for (finalGrade in finalGrades) {
if (finalGrade.courseId != -1) {
updateFinalGradeAverage(finalGrade.courseId, finalGrade.finalGradeId)
}
}
}
fun getSchoolYearName(courseId: Int) = dao.getSchoolYearName(courseId)
fun getAllYears() = dao.getAllYears()
fun getAllCourses() = dao.getAllCourseExams()
fun getCourse(courseId: Int) = dao.getCourse(courseId)[0]
fun getFinalGrade(finalGradeId: Int) = dao.getFinalGrade(finalGradeId)[0]
fun update(finalGrade: FinalGrade) { dao.update(finalGrade) }
}
@@ -1,31 +0,0 @@
package com.denizd.qwark.database
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.model.Grade
import com.denizd.qwark.model.HistoricalAvg
import com.denizd.qwark.util.*
import com.denizd.qwark.util.QwarkPreferences
class GradeRepository(app: Application) {
private val dao: QwarkDao = QwarkDatabase.getInstance(app).dao()
private val prefs: QwarkPreferences = QwarkPreferences.getPrefs(app)
fun getGradeType(): Int = prefs.getInt(PreferenceKey.GRADE_TYPE)
// TODO this might crash
fun getCourse(courseId: Int) = dao.getCourse(courseId)[0]
fun insert(grade: Grade) { dao.insert(grade) }
fun update(grade: Grade) { dao.update(grade) }
fun delete(gradeId: Int) { dao.deleteGrade(gradeId) }
fun insert(avg: HistoricalAvg) { dao.insert(avg) }
fun updateAverage(average: String, gradeCount: Int, courseId: Int) {
dao.updateAverage(average, gradeCount, courseId)
}
fun getGradesByForeignKey(courseId: Int): LiveData<List<Grade>> = dao.getGradesByForeignKey(courseId)
fun getGrade(gradeId: Int) = dao.getGrade(gradeId)[0]
}
@@ -1,20 +0,0 @@
package com.denizd.qwark.database
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.model.Note
class NoteRepository(app: Application) {
private val dao: QwarkDao = QwarkDatabase.getInstance(app).dao()
val allNotes: LiveData<List<Note>> = dao.allNotes
fun getNotesForCategory(category: String): LiveData<List<Note>> = dao.notesForCategory(category)
fun getAllCategories(): List<String> = dao.getAllCategories()
fun insert(note: Note) { dao.insert(note) }
fun update(note: Note) { dao.update(note) }
fun updateDismissed(newDismissedStatus: Boolean, noteId: Int) { dao.updateDismissed(newDismissedStatus, noteId) }
fun delete(noteId: Int) { dao.deleteNote(noteId) }
fun getNote(noteId: Int) = dao.getNote(noteId)[0]
}
@@ -1,74 +0,0 @@
package com.denizd.qwark.database
import android.app.Application
import android.util.Log
import androidx.lifecycle.LiveData
import com.denizd.qwark.model.Course
import com.denizd.qwark.model.CourseExam
import com.denizd.qwark.model.Participation
import com.denizd.qwark.model.SchoolDay
import com.denizd.qwark.util.*
import com.denizd.qwark.util.QwarkPreferences
import java.util.*
class ParticipationRepository(app: Application) {
private val days: Array<String> = arrayOf("mon", "tue", "wed", "thu", "fri")
private val dao: QwarkDao = QwarkDatabase.getInstance(app).dao()
private val prefs: QwarkPreferences = QwarkPreferences.getPrefs(app.applicationContext)
// monday: 1, increment by 1 for each day
val dayId: Int = when (prefs.getParticipationDay()) {
0 -> if (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1 in 1..5)
Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1 else 1
else -> prefs.getParticipationDay()
}
val allCoursesForToday: LiveData<List<Course>> = dao.getCoursesByDayType(getDayType(), prefs.getSchoolYear())
fun initParticipationTables() {
for (day in days) {
dao.insert(SchoolDay(day, 0, prefs.getSchoolYear()))
}
}
fun getParticipationCount(participations: List<Participation>) = if (prefs.getParticipationDisplay() == 0) {
arrayOf(
(participations.map { it.timesHandRaised }.sum().toDouble() / participations.size.toDouble()).round(),
(participations.map { it.timesSpoken }.sum().toDouble() / participations.size.toDouble()).round()
)
} else {
arrayOf(
(participations.map { it.timesHandRaised }.sum()),
(participations.map { it.timesSpoken }.sum())
)
}
fun getDayType(): String = if (dayId in 1..5) days[dayId - 1] else days[1]
fun getDays(): List<SchoolDay> = dao.getDays(prefs.getSchoolYear())
fun getCourses(): List<CourseExam> = dao.getCoursesByYearIdAsList(prefs.getSchoolYear()).getSorted(
prefs.getCourseSortType()
)
fun link(courseId: Int) { dao.link(courseId, getDayType(), prefs.getSchoolYear()) }
fun removeLink(relationId: Int) { dao.removeLink(relationId) }
fun getAllParticipationsForCourse(courseId: Int): LiveData<List<Participation>> =
dao.getAllParticipationsForCourse(courseId)
fun insert(timesHandRaised: Int, timesSpoken: Int, time: Long, courseId: Int) {
dao.insert(
Participation(
timesHandRaised,
timesSpoken,
time,
0,
courseId,
dayId
)
)
}
fun delete(participation: Participation) { dao.delete(participation) }
fun updateParticipation(participation: String, courseId: Int) {
dao.updateParticipation(participation, courseId)
}
fun updateParticipation(timesHandRaised: Int, timesSpoken: Int, participationId: Int) {
dao.updateParticipation(timesHandRaised, timesSpoken, participationId)
}
fun getSchoolYearName() = prefs.getSchoolYearName()
}
@@ -30,7 +30,7 @@ interface QwarkDao {
fun getCoursesByYearIdAsList(yearId: Int): List<CourseExam>
@Query("SELECT *, -1 AS exam_time FROM course WHERE course_id = :courseId")
fun getCourse(courseId: Int): List<CourseExam>
fun getCourse(courseId: Int): CourseExam
@Insert
fun insert(course: Course)
@@ -68,7 +68,7 @@ interface QwarkDao {
fun deleteGrade(gradeId: Int)
@Query("SELECT * FROM grade WHERE grade_id = :gradeId")
fun getGrade(gradeId: Int): List<Grade>
fun getGrade(gradeId: Int): Grade
// notes
@@ -97,7 +97,7 @@ interface QwarkDao {
fun getAllCategories(): List<String>
@Query("SELECT * FROM note WHERE note_id = :noteId")
fun getNote(noteId: Int): List<Note>
fun getNote(noteId: Int): Note
// historical averages
@@ -165,7 +165,7 @@ interface QwarkDao {
fun insertAll(finalGrades: Array<FinalGrade>)
@Query("SELECT * FROM final_grade WHERE final_grade_id = :finalGradeId")
fun getFinalGrade(finalGradeId: Int): List<FinalGrade>
fun getFinalGrade(finalGradeId: Int): FinalGrade
// school days
@@ -14,7 +14,7 @@ import com.denizd.qwark.model.Note
import com.denizd.qwark.model.SchoolYear
@Database(entities = [Course::class, Grade::class, Note::class, HistoricalAvg::class, SchoolYear::class, FinalGrade::class, ScoreProfile::class, Participation::class, SchoolDay::class, CourseDayRelation::class], version = 9, exportSchema = false)
internal abstract class QwarkDatabase : RoomDatabase() {
abstract class QwarkDatabase : RoomDatabase() {
abstract fun dao(): QwarkDao
@@ -0,0 +1,204 @@
package com.denizd.qwark.database
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.model.*
import com.denizd.qwark.util.*
import java.util.*
class QwarkRepository(app: Application) {
private val dao: QwarkDao = QwarkDatabase.getInstance(app.applicationContext).dao()
val prefs: QwarkPreferences = QwarkPreferences(app.applicationContext)
// misc
private val days: Array<String> = arrayOf("mon", "tue", "wed", "thu", "fri")
// monday: 1, increment by 1 for each day
val dayId: Int = when (prefs.getParticipationDay()) {
0 -> with (Calendar.getInstance()) {
if (get(Calendar.DAY_OF_WEEK) - 1 in 1..5) get(Calendar.DAY_OF_WEEK) - 1 else 1
}
else -> prefs.getParticipationDay()
}
fun initParticipationTables() {
for (day in days) {
dao.insert(SchoolDay(day, 0, prefs.getSchoolYear()))
}
}
fun link(courseId: Int) { dao.link(courseId, getDayType(), prefs.getSchoolYear()) }
fun removeLink(relationId: Int) { dao.removeLink(relationId) }
fun copyCourses(yearId: Int) {
val currentSchoolYearId = prefs.getCurrentSchoolYearId()
val courses = dao.getCoursesByYearIdAsList(yearId)
for (course in courses) {
dao.insert(
Course(
name = course.name,
advanced = course.advanced,
icon = course.icon,
colour = course.colour,
average = if (prefs.getGradeType() == QwarkUtil.GRADE_PRECISE) "0.00" else "0",
oralWeighting = course.oralWeighting,
gradeCount = course.gradeCount,
time = System.currentTimeMillis(),
courseId = 0,
yearId = currentSchoolYearId
)
)
}
}
fun initNewFinalScore(name: String) {
val finalScoreId = getMaxFinalScoreId(true)
val finalGrade = FinalGrade("", "-1", "basic", "x 1", -1, 0, finalScoreId)
dao.insert(ScoreProfile(name, finalScoreId))
val values = ArrayList<FinalGrade>()
repeat(24) { values.add(finalGrade.copy(type = "basic", note = "x 1")) }
repeat(2) {
repeat(4) { values.add(finalGrade.copy(type = "adv", note = "x 2")) }
values.add(finalGrade.copy(note = "x 1"))
}
for (i in 1..5) {
values.add(finalGrade.copy(type = "exam", note = "P$i x ${if (i == 5) "2" else "5"}"))
}
dao.insertAll(values.toTypedArray())
}
// insert
fun insert(course: Course) { dao.insert(course) }
fun insert(grade: Grade) { dao.insert(grade) }
fun insert(note: Note) { dao.insert(note) }
fun insert(historicalAvg: HistoricalAvg) { dao.insert(historicalAvg) }
fun insert(schoolYear: SchoolYear) { dao.insert(schoolYear) }
fun insert(scoreProfile: ScoreProfile) { dao.insert(scoreProfile) }
fun insert(schoolDay: SchoolDay) { dao.insert(schoolDay) }
fun insert(participation: Participation) { dao.insert(participation) }
// insert multiple
fun insertAll(finalGrades: Array<FinalGrade>) { dao.insertAll(finalGrades) }
// set
fun setCurrentScoreProfile(scoreProfile: ScoreProfile) {
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)
}
// update
fun update(course: Course) { dao.update(course) }
fun update(finalGrade: FinalGrade) { dao.update(finalGrade) }
fun updateLinkedGrades() {
for (finalGrade in dao.getFinalGradesAsList(prefs.getFinalScoreId())) {
if (finalGrade.courseId != -1) {
updateFinalGradeAverage(finalGrade.courseId, finalGrade.finalGradeId)
}
}
}
fun updateFinalGradeAverage(courseId: Int, finalGradeId: Int) {
dao.getCourse(courseId).also { course ->
dao.updateFinalGradeAverage(
course.name,
course.average.roundToInt(),
finalGradeId
)
}
}
fun updateAverage(average: String, gradeCount: Int, courseId: Int) { dao.updateAverage(average, gradeCount, courseId) }
fun update(grade: Grade) { dao.update(grade) }
fun update(note: Note) { dao.update(note) }
fun updateDismissed(newDismissedStatus: Boolean, noteId: Int) { dao.updateDismissed(newDismissedStatus, noteId) }
fun updateParticipation(participation: String, courseId: Int) {
dao.updateParticipation(participation, courseId)
}
fun updateParticipation(timesHandRaised: Int, timesSpoken: Int, participationId: Int) {
dao.updateParticipation(timesHandRaised, timesSpoken, participationId)
}
fun updateSchoolYear(name: String) {
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()))
}
// delete
fun delete(course: Course) { dao.delete(course) }
fun deleteGrade(gradeId: Int) { dao.deleteGrade(gradeId) }
fun deleteNote(noteId: Int) { dao.deleteNote(noteId) }
fun delete(participation: Participation) { dao.delete(participation) }
fun deleteSchoolYear() {
dao.deleteSchoolYear(prefs.getCurrentSchoolYearId())
setCurrentSchoolYear(SchoolYear("", 0))
}
fun deleteScoreProfile() {
dao.deleteScoreProfile(prefs.getScoreProfileId())
setCurrentScoreProfile(ScoreProfile("", 0))
}
// live data
val allNotes: LiveData<List<Note>> = dao.allNotes
val allCoursesForToday: LiveData<List<Course>> = dao.getCoursesByDayType(getDayType(), prefs.getSchoolYear())
val allYears: LiveData<List<SchoolYear>> = dao.allYears
val allScoreProfiles: LiveData<List<ScoreProfile>> = dao.allScoreProfiles
// get
fun getCourse(courseId: Int): CourseExam = dao.getCourse(courseId)
fun getSchoolYearName(courseId: Int) = dao.getSchoolYearName(courseId)
fun getFinalGrade(finalGradeId: Int) = dao.getFinalGrade(finalGradeId)
fun getGrade(gradeId: Int) = dao.getGrade(gradeId)
fun getNote(noteId: Int) = dao.getNote(noteId)
fun getParticipationCount(participations: List<Participation>) = if (prefs.getParticipationDisplay() == 0) {
arrayOf(
(participations.map { it.timesHandRaised }.sum().toDouble() / participations.size.toDouble()).round(),
(participations.map { it.timesSpoken }.sum().toDouble() / participations.size.toDouble()).round()
)
} else {
arrayOf(
(participations.map { it.timesHandRaised }.sum()),
(participations.map { it.timesSpoken }.sum())
)
}
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)
.setInt(PreferenceKey.SCORE_PROFILE_ID, getMaxFinalScoreId(false) + 1)
}
return prefs.getInt(PreferenceKey.MAX_SCORE_PROFILE_ID)
}
// get multiple
fun getCoursesByYearId(yearId: Int): LiveData<List<CourseExam>> = dao.getCoursesByYearId(yearId)
fun getAllCourses() = dao.getAllCourseExams()
fun getAveragesForCourses(courseId: Int): List<HistoricalAvg> = dao.getAveragesForCourses(courseId)
fun getFinalGrades(finalScoreId: Int): LiveData<List<FinalGrade>> = dao.getFinalGrades(finalScoreId)
fun getAllYears(): List<SchoolYear> = dao.getAllYears()
fun getGradesByForeignKey(courseId: Int): LiveData<List<Grade>> = dao.getGradesByForeignKey(courseId)
fun getNotesForCategory(category: String): LiveData<List<Note>> = dao.notesForCategory(category)
fun getAllCategories(): List<String> = dao.getAllCategories()
fun getDays(): List<SchoolDay> = dao.getDays(prefs.getSchoolYear())
fun getCourses(): List<CourseExam> =
dao.getCoursesByYearIdAsList(prefs.getSchoolYear()).getSorted(prefs.getCourseSortType())
fun getAllParticipationsForCourse(courseId: Int): LiveData<List<Participation>> =
dao.getAllParticipationsForCourse(courseId)
fun insert(timesHandRaised: Int, timesSpoken: Int, time: Long, courseId: Int) {
dao.insert(
Participation(
timesHandRaised,
timesSpoken,
time,
0,
courseId,
dayId
)
)
}
}
@@ -1,125 +0,0 @@
package com.denizd.qwark.database
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.util.PreferenceKey
import com.denizd.qwark.util.QwarkPreferences
import com.denizd.qwark.util.QwarkUtil
import com.denizd.qwark.model.Course
import com.denizd.qwark.model.FinalGrade
import com.denizd.qwark.model.ScoreProfile
import com.denizd.qwark.model.SchoolYear
class SettingsRepository(app: Application) {
private val dao: QwarkDao = QwarkDatabase.getInstance(app).dao()
private val prefs: QwarkPreferences = QwarkPreferences.getPrefs(app.applicationContext)
val allYears: LiveData<List<SchoolYear>> = dao.allYears
val allScoreProfiles: LiveData<List<ScoreProfile>> = dao.allScoreProfiles
// Preference getters
fun getAppTheme(): Int = prefs.getInt(PreferenceKey.APP_THEME, 2)
fun getShowGradeAverage(): Boolean = prefs.getBool(PreferenceKey.SHOW_GRADE_AVERAGE)
fun getGradeType(): Int = prefs.getInt(PreferenceKey.GRADE_TYPE)
fun getCurrentSchoolYear(): String = prefs.getString(PreferenceKey.SCHOOL_YEAR_NAME)
fun getCurrentSchoolYearId(): Int = prefs.getInt(PreferenceKey.SCHOOL_YEAR_ID)
private fun getScoreProfileId(): Int = prefs.getInt(PreferenceKey.SCORE_PROFILE_ID, 0)
fun getScoreProfileName(): String = prefs.getString(PreferenceKey.SCORE_PROFILE_NAME)
fun getParticipationDisplay(): Int = prefs.getParticipationDisplay()
fun getParticipationDay(): Int = prefs.getParticipationDay()
private fun getMaxFinalScoreId(increment: Boolean): Int {
if (increment) {
prefs.putInt(PreferenceKey.MAX_SCORE_PROFILE_ID, getMaxFinalScoreId(false) + 1)
.putInt(PreferenceKey.SCORE_PROFILE_ID, getMaxFinalScoreId(false) + 1)
}
return prefs.getInt(PreferenceKey.MAX_SCORE_PROFILE_ID)
}
// Preference setters
fun setAppTheme(value: Int) { prefs.putInt(PreferenceKey.APP_THEME, value) }
fun setShowGradeAverage(value: Boolean) { prefs.putBool(PreferenceKey.SHOW_GRADE_AVERAGE, value) }
fun setGradeType(value: Int) { prefs.putInt(PreferenceKey.GRADE_TYPE, value) }
fun setParticipationDisplay(value: Int) { prefs.setParticipationDisplay(value) }
fun setParticipationDay(value: Int) { prefs.setParticipationDay(value) }
fun setCurrentScoreProfile(scoreProfile: ScoreProfile) {
prefs.putInt(PreferenceKey.SCORE_PROFILE_ID, scoreProfile.scoreProfileId)
.putString(PreferenceKey.SCORE_PROFILE_NAME, scoreProfile.name)
}
fun setCurrentSchoolYear(schoolYear: SchoolYear) {
prefs.putInt(PreferenceKey.SCHOOL_YEAR_ID, schoolYear.yearId)
.putString(PreferenceKey.SCHOOL_YEAR_NAME, schoolYear.year)
}
// Database functions
fun insert(schoolYear: SchoolYear) { dao.insert(schoolYear) }
fun insert(scoreProfile: ScoreProfile) { dao.insert(scoreProfile) }
fun initNewFinalScore(name: String) {
val finalScoreId = getMaxFinalScoreId(true)
dao.insert(ScoreProfile(name, finalScoreId))
val values = ArrayList<FinalGrade>()
for (i in 0 until 24) {
values.add(FinalGrade("", "-1", "basic", "x 1", -1, 0, finalScoreId))
}
for (i in 0 until 3) {
values.add(FinalGrade("", "-1", "adv", "x 2", -1, 0, finalScoreId))
}
values.add(FinalGrade("", "-1", "adv", "x 1", -1, 0, finalScoreId))
for (i in 0 until 3) {
values.add(FinalGrade("", "-1", "adv", "x 2", -1, 0, finalScoreId))
}
values.add(FinalGrade("", "-1", "adv", "x 1", -1, 0, finalScoreId))
for (i in 1..5) {
values.add(FinalGrade("", "-1", "exam", "P$i x ${if (i == 5) "2" else "5"}", -1, 0, finalScoreId))
}
dao.insertAll(values.toTypedArray())
}
fun updateSchoolYear(name: String) {
dao.update(SchoolYear(name, getCurrentSchoolYearId()))
setCurrentSchoolYear(SchoolYear(name, getCurrentSchoolYearId()))
}
fun updateScoreProfile(name: String) {
dao.update(ScoreProfile(name, getScoreProfileId()))
setCurrentScoreProfile(ScoreProfile(name, getScoreProfileId()))
}
fun deleteSchoolYear() {
dao.deleteSchoolYear(getCurrentSchoolYearId())
setCurrentSchoolYear(SchoolYear("", 0))
}
fun deleteScoreProfile() {
dao.deleteScoreProfile(getScoreProfileId())
setCurrentScoreProfile(ScoreProfile("", 0))
}
fun copyCourses(yearId: Int) {
val currentSchoolYearId = getCurrentSchoolYearId()
val courses = dao.getCoursesByYearIdAsList(yearId)
for (course in courses) {
dao.insert(
Course(
name = course.name,
advanced = course.advanced,
icon = course.icon,
colour = course.colour,
average = if (getGradeType() == QwarkUtil.GRADE_PRECISE) "0.00" else "0",
oralWeighting = course.oralWeighting,
gradeCount = course.gradeCount,
time = System.currentTimeMillis(),
courseId = 0,
yearId = currentSchoolYearId
)
)
}
}
}
@@ -11,6 +11,7 @@ import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.adapter.CourseAdapter
import com.denizd.qwark.sheet.ConfirmDeletionSheet
@@ -26,11 +27,9 @@ import com.denizd.qwark.viewmodel.CourseViewModel
import com.google.android.material.snackbar.Snackbar
import java.lang.NumberFormatException
class CourseFragment : QwarkFragment(), CourseAdapter.CourseClickListener {
private var _binding: PaddedRecyclerViewBinding? = null
private val binding: PaddedRecyclerViewBinding get() = _binding!!
class CourseFragment : QwarkFragment(R.layout.padded_recycler_view), CourseAdapter.CourseClickListener {
private val binding: PaddedRecyclerViewBinding by viewBinding(PaddedRecyclerViewBinding::bind)
private val viewModel: CourseViewModel by viewModels()
private lateinit var recyclerViewAdapter: CourseAdapter
@@ -42,10 +41,7 @@ class CourseFragment : QwarkFragment(), CourseAdapter.CourseClickListener {
viewModel.allCourses.observe(this, Observer { courses ->
recyclerViewAdapter.setCourses(courses.getSorted(viewModel.getCourseSortType()))
if (scrollPosition == null) {
binding.recyclerView.apply {
scrollToPosition(0)
scheduleLayoutAnimation()
}
binding.recyclerView.scheduleLayoutAnimation()
} else {
binding.recyclerView.layoutManager?.onRestoreInstanceState(scrollPosition)
}
@@ -70,11 +66,6 @@ class CourseFragment : QwarkFragment(), CourseAdapter.CourseClickListener {
)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = PaddedRecyclerViewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -102,18 +93,6 @@ class CourseFragment : QwarkFragment(), CourseAdapter.CourseClickListener {
}
}
override fun onResume() {
super.onResume()
binding.recyclerView.apply {
applyPadding(horizontalPadding = 4)
}
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
override fun onCourseClick(course: CourseExam) {
appBar.setExpanded(true)
val f = GradeFragment()
@@ -1,6 +1,5 @@
package com.denizd.qwark.fragment
import android.content.res.Configuration
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
@@ -11,22 +10,19 @@ import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.adapter.FinalGradeAdapter
import com.denizd.qwark.sheet.ConfirmDeletionSheet
import com.denizd.qwark.sheet.FinalsCreateSheet
import com.denizd.qwark.sheet.FinalsOptionsSheet
import com.denizd.qwark.databinding.FinalsFragmentBinding
import com.denizd.qwark.sheet.FinalsLinkSheet
import com.denizd.qwark.model.FinalGrade
import com.denizd.qwark.sheet.*
import com.denizd.qwark.viewmodel.FinalsViewModel
import com.google.android.material.snackbar.Snackbar
class FinalsFragment : QwarkFragment(), FinalGradeAdapter.FinalGradeClickListener {
class FinalsFragment : QwarkFragment(R.layout.finals_fragment), FinalGradeAdapter.FinalGradeClickListener {
private lateinit var viewModel: FinalsViewModel
private var _binding: FinalsFragmentBinding? = null
private val binding: FinalsFragmentBinding get() = _binding!!
private val binding: FinalsFragmentBinding by viewBinding(FinalsFragmentBinding::bind)
private var pointsText = ""
private var gradeText = ""
@@ -80,11 +76,6 @@ class FinalsFragment : QwarkFragment(), FinalGradeAdapter.FinalGradeClickListene
binding.gradeTextview.text = gradeText
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FinalsFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -94,7 +85,16 @@ class FinalsFragment : QwarkFragment(), FinalGradeAdapter.FinalGradeClickListene
} else {
getString(R.string.score_profile_template, viewModel.getScoreProfileName())
}
fab.hide()
fab.apply {
// temporary until the scroll situation can be figured out
// show()
hide()
// text = getString(R.string.conversion_table)
// setOnClickListener {
// openBottomSheet(FinalGradeTableSheet())
// }
}
// binding.scrollView.addFabScrollListener()
val layoutManagerBasic = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
val layoutManagerAdvanced = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
@@ -110,20 +110,9 @@ class FinalsFragment : QwarkFragment(), FinalGradeAdapter.FinalGradeClickListene
override fun onResume() {
super.onResume()
binding.paddingView.apply {
applyPadding()
}
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
binding.textLayout?.applyPadding()
}
setTextForGradeTextViews()
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
override fun onFinalGradeClick(finalGrade: FinalGrade) {
openBottomSheet(FinalsOptionsSheet().also { sheet ->
sheet.arguments = Bundle().apply { putInt("finalGradeId", finalGrade.finalGradeId) }
@@ -146,6 +135,7 @@ class FinalsFragment : QwarkFragment(), FinalGradeAdapter.FinalGradeClickListene
fun getAllCourses() = viewModel.getAllCourses()
fun viewLinkedCourse(courseId: Int) {
appBar.setExpanded(true)
val f = GradeFragment().also { fragment ->
fragment.arguments = Bundle().apply {
putInt("courseId", courseId)
@@ -4,12 +4,12 @@ import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.adapter.GradeAdapter
import com.denizd.qwark.sheet.ConfirmDeletionSheet
@@ -23,7 +23,7 @@ import com.denizd.qwark.util.getUserDefinedAverage
import com.denizd.qwark.viewmodel.GradeViewModel
import com.google.android.material.bottomnavigation.BottomNavigationView
class GradeFragment : QwarkFragment(), GradeAdapter.GradeClickListener {
class GradeFragment : QwarkFragment(R.layout.grade_fragment), GradeAdapter.GradeClickListener {
private lateinit var currentCourse: CourseExam
private var average = ""
@@ -35,8 +35,7 @@ class GradeFragment : QwarkFragment(), GradeAdapter.GradeClickListener {
private val viewModel: GradeViewModel by viewModels()
private lateinit var inflater: LayoutInflater
private var _binding: GradeFragmentBinding? = null
private val binding: GradeFragmentBinding get() = _binding!!
private val binding: GradeFragmentBinding by viewBinding(GradeFragmentBinding::bind)
private var scrollPosition: Parcelable? = null
@@ -75,11 +74,6 @@ class GradeFragment : QwarkFragment(), GradeAdapter.GradeClickListener {
adapter = GradeAdapter(ArrayList(), this, getGradeType())
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = GradeFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -109,16 +103,6 @@ class GradeFragment : QwarkFragment(), GradeAdapter.GradeClickListener {
}
}
override fun onResume() {
super.onResume()
binding.paddingView.applyPadding()
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
private fun insertNewHistoricalAverage() {
viewModel.insert(
HistoricalAvg(
@@ -145,7 +129,7 @@ class GradeFragment : QwarkFragment(), GradeAdapter.GradeClickListener {
override fun onGradeLongClick(gradeId: Int) {
val deletionSheet = ConfirmDeletionSheet(getString(R.string.confirm_grade_deletion)) {
viewModel.delete(gradeId)
viewModel.deleteGrade(gradeId)
}
openBottomSheet(deletionSheet)
}
@@ -9,6 +9,7 @@ import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.adapter.NoteAdapter
import com.denizd.qwark.sheet.ConfirmDeletionSheet
@@ -21,7 +22,7 @@ import com.denizd.qwark.model.Note
import com.denizd.qwark.viewmodel.NoteViewModel
import com.google.android.material.appbar.AppBarLayout
class NoteFragment : QwarkFragment(), NoteAdapter.OnNoteClickListener, OnBackPressed {
class NoteFragment : QwarkFragment(R.layout.padded_recycler_view), NoteAdapter.OnNoteClickListener, OnBackPressed {
private lateinit var viewModel: NoteViewModel
private val adapter = NoteAdapter(ArrayList(), this)
@@ -30,8 +31,7 @@ class NoteFragment : QwarkFragment(), NoteAdapter.OnNoteClickListener, OnBackPre
private lateinit var appBarLayout: AppBarLayout
private var _binding: PaddedRecyclerViewBinding? = null
private val binding: PaddedRecyclerViewBinding get() = _binding!!
private val binding: PaddedRecyclerViewBinding by viewBinding(PaddedRecyclerViewBinding::bind)
private var isInCategoryView = false
override fun onCreate(savedInstanceState: Bundle?) {
@@ -53,11 +53,6 @@ class NoteFragment : QwarkFragment(), NoteAdapter.OnNoteClickListener, OnBackPre
StaggeredGridLayoutManager(getGridColumnCount(newConfig), StaggeredGridLayoutManager.VERTICAL)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = PaddedRecyclerViewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -79,16 +74,6 @@ class NoteFragment : QwarkFragment(), NoteAdapter.OnNoteClickListener, OnBackPre
binding.recyclerView.addFabScrollListener()
}
override fun onResume() {
super.onResume()
binding.recyclerView.applyPadding(horizontalPadding = 4)
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
override fun onBackPressed(): Boolean {
return if (isInCategoryView) {
sortByCategory("")
@@ -9,6 +9,7 @@ import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.adapter.ParticipationAdapter
import com.denizd.qwark.databinding.GradeFragmentBinding
@@ -19,10 +20,9 @@ import com.denizd.qwark.viewmodel.ParticipationCourseViewModel
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.snackbar.Snackbar
class ParticipationCourseFragment : QwarkFragment(), ParticipationAdapter.ParticipationClickListener {
class ParticipationCourseFragment : QwarkFragment(R.layout.grade_fragment), ParticipationAdapter.ParticipationClickListener {
private var _binding: GradeFragmentBinding? = null
private val binding: GradeFragmentBinding get() = _binding!!
private val binding: GradeFragmentBinding by viewBinding(GradeFragmentBinding::bind)
private var course: String = ""
private var courseId: Int = 0
private var advanced: Boolean = false
@@ -55,11 +55,6 @@ class ParticipationCourseFragment : QwarkFragment(), ParticipationAdapter.Partic
})
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = GradeFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -99,16 +94,6 @@ class ParticipationCourseFragment : QwarkFragment(), ParticipationAdapter.Partic
binding.average.text = averageText
}
override fun onResume() {
super.onResume()
binding.paddingView.applyPadding()
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
override fun onParticipationClick(participation: Participation) {
if (participation.time > System.currentTimeMillis() - 1000 * 60 * 90) {
openBottomSheet(ClassSessionSheet().also { sheet ->
@@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentTransaction
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.adapter.CourseAdapter
import com.denizd.qwark.databinding.PaddedRecyclerViewBinding
@@ -19,10 +20,9 @@ import com.denizd.qwark.sheet.ConfirmDeletionSheet
import com.denizd.qwark.sheet.ParticipationLinkSheet
import com.denizd.qwark.viewmodel.ParticipationViewModel
internal class ParticipationFragment : QwarkFragment(), CourseAdapter.CourseClickListener {
internal class ParticipationFragment : QwarkFragment(R.layout.padded_recycler_view), CourseAdapter.CourseClickListener {
private var _binding: PaddedRecyclerViewBinding? = null
private val binding: PaddedRecyclerViewBinding get() = _binding!!
private val binding: PaddedRecyclerViewBinding by viewBinding(PaddedRecyclerViewBinding::bind)
private lateinit var viewModel: ParticipationViewModel
private val recyclerViewAdapter = CourseAdapter(ArrayList(), this, null, true)
@@ -59,11 +59,6 @@ internal class ParticipationFragment : QwarkFragment(), CourseAdapter.CourseClic
})
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = PaddedRecyclerViewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -85,16 +80,6 @@ internal class ParticipationFragment : QwarkFragment(), CourseAdapter.CourseClic
}
}
override fun onResume() {
super.onResume()
binding.recyclerView.applyPadding(horizontalPadding = 4)
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
override fun onCourseClick(course: CourseExam) {
appBar.setExpanded(true)
(context as FragmentActivity).supportFragmentManager.beginTransaction()
@@ -6,7 +6,9 @@ import android.os.Bundle
import android.util.TypedValue
import android.view.View
import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
@@ -15,7 +17,7 @@ import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
open class QwarkFragment : Fragment() {
open class QwarkFragment(@LayoutRes layoutId: Int) : Fragment(layoutId) {
private lateinit var _context: Context
@@ -32,7 +34,6 @@ open class QwarkFragment : Fragment() {
appBarTitleView.text = value
field = value
}
private lateinit var statusBarView: View
lateinit var appBar: AppBarLayout
lateinit var snackBarContainer: CoordinatorLayout
lateinit var fab: ExtendedFloatingActionButton
@@ -49,12 +50,17 @@ open class QwarkFragment : Fragment() {
/**
* Initialise view resources
*/
statusBarView = view.rootView.findViewById(R.id.status_bar_view)
appBarTitleView = view.rootView.findViewById(R.id.app_bar_title)
superTitleView = view.rootView.findViewById(R.id.super_title)
appBar = view.rootView.findViewById(R.id.app_bar_layout)
snackBarContainer = view.rootView.findViewById(R.id.root_view)
fab = view.rootView.findViewById(R.id.fab)
if (this is GradeFragment || this is ParticipationCourseFragment) {
snackBarContainer.resetBottomPadding()
} else {
snackBarContainer.applyBottomPadding()
}
}
/**
@@ -88,19 +94,21 @@ open class QwarkFragment : Fragment() {
})
}
/**
* This function must not be invoked in onViewCreated, as the view will not have been attached
* to its lifecycle owner and therefore cannot calculate the top padding properly. Invoke in
* onResume instead.
*/
protected fun <T : View> T.applyPadding(horizontalPadding: Int = 0) {
val horizontal = horizontalPadding.dpToPx()
setPadding(
horizontal,
(statusBarView.height / 1) + appBar.height,
horizontal,
0
)
protected fun NestedScrollView.addFabScrollListener() {
setOnScrollChangeListener { _, _, dy, _, doy ->
when {
dy > doy -> fab.hide()
dy < doy -> fab.show()
}
}
}
private fun <T : View> T.resetBottomPadding() {
setPadding(paddingLeft, paddingTop, paddingRight, 0)
}
private fun <T : View> T.applyBottomPadding() {
setPadding(paddingLeft, paddingTop, paddingRight, 56.dpToPx())
}
/**
@@ -1,12 +1,11 @@
package com.denizd.qwark.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.sheet.ConfirmDeletionSheet
import com.denizd.qwark.sheet.CopyCoursesSheet
@@ -17,17 +16,11 @@ import com.denizd.qwark.model.SchoolYear
import com.denizd.qwark.viewmodel.SettingsViewModel
import com.google.android.material.snackbar.Snackbar
class SettingsFragment : QwarkFragment() {
class SettingsFragment : QwarkFragment(R.layout.settings_fragment) {
private var _binding: SettingsFragmentBinding? = null
private val binding: SettingsFragmentBinding get() = _binding!!
private val binding: SettingsFragmentBinding by viewBinding(SettingsFragmentBinding::bind)
private val viewModel: SettingsViewModel by viewModels()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = SettingsFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -94,7 +87,7 @@ class SettingsFragment : QwarkFragment() {
)
)
try {
setText(viewModel.getCurrentSchoolYear(), false)
setText(viewModel.getSchoolYearName(), false)
} catch (e: IndexOutOfBoundsException) {
// do nothing if no school years exist or none has been selected
}
@@ -212,16 +205,6 @@ class SettingsFragment : QwarkFragment() {
}
}
override fun onResume() {
super.onResume()
binding.settingsScrollView.applyPadding()
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
fun copyCourses(yearId: Int) {
viewModel.copyCourses(yearId)
Snackbar
@@ -9,18 +9,16 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.Toast
import com.denizd.lawrence.util.viewBinding
import com.denizd.qwark.R
import com.denizd.qwark.databinding.ClassSessionSheetBinding
import com.denizd.qwark.fragment.ParticipationCourseFragment
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlin.random.Random
class ClassSessionSheet : BottomSheetDialogFragment() {
class ClassSessionSheet : QwarkSheet(R.layout.class_session_sheet) {
private var _binding: ClassSessionSheetBinding? = null
private val binding: ClassSessionSheetBinding get() = _binding!!
private lateinit var mContext: Context
private val binding: ClassSessionSheetBinding by viewBinding(ClassSessionSheetBinding::bind)
private lateinit var participationFragment: ParticipationCourseFragment
private var timesHandRaised: Int = 0
@@ -36,16 +34,6 @@ class ClassSessionSheet : BottomSheetDialogFragment() {
private var participationId = -1
private val time: Long = System.currentTimeMillis()
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = ClassSessionSheetBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -61,7 +49,7 @@ class ClassSessionSheet : BottomSheetDialogFragment() {
binding.handRaisedButton.apply {
setCompoundDrawables(context.getDrawable(R.drawable.hand)?.also { drawable ->
drawable.bounds = Rect(0, 0, 256, 256)
drawable.setTint(mContext.getColor(R.color.colorAccent))
drawable.setTint(context.getColor(R.color.colorAccent))
}, null, null, null)
text = "$timesHandRaised"
setOnClickListener {
@@ -78,7 +66,7 @@ class ClassSessionSheet : BottomSheetDialogFragment() {
binding.spokenButton.apply {
setCompoundDrawables(context.getDrawable(R.drawable.speech)?.also { drawable ->
drawable.bounds = Rect(0, 0, 256, 256)
drawable.setTint(mContext.getColor(R.color.colorAccent))
drawable.setTint(context.getColor(R.color.colorAccent))
}, null, null, null)
text = "$timesSpoken"
setOnClickListener {
@@ -102,7 +90,7 @@ class ClassSessionSheet : BottomSheetDialogFragment() {
}
}
binding.finishButton.apply {
binding.saveButton.apply {
setOnClickListener {
makeToast(R.string.long_press_to_finish)
}
@@ -124,14 +112,10 @@ class ClassSessionSheet : BottomSheetDialogFragment() {
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
private fun makeToast(stringResource: Int) {
Toast
.makeText(mContext, getString(stringResource), Toast.LENGTH_LONG)
.makeText(context, getString(stringResource), Toast.LENGTH_LONG)
.show()
}
@@ -0,0 +1,38 @@
package com.denizd.qwark.sheet
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.denizd.qwark.R
import com.denizd.qwark.databinding.TextSheetBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
class FinalGradeTableSheet : BottomSheetDialogFragment() {
private var _binding: TextSheetBinding? = null
private val binding: TextSheetBinding get() = _binding!!
private lateinit var mContext: Context
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = TextSheetBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.title.text = mContext.getString(R.string.points_to_grade_conversion_title)
binding.content.text = mContext.getString(R.string.points_to_grade_conversion)
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
@@ -119,7 +119,7 @@ class GradeCreateSheet : BottomSheetDialogFragment() {
note = binding.noteEditText.text.toString(),
time = if (::grade.isInitialized) grade.time else System.currentTimeMillis(),
gradeId = if (::grade.isInitialized) grade.gradeId else 0,
courseId = courseId,
courseId = if (::grade.isInitialized) grade.courseId else courseId,
examTime = if (binding.examSwitch.isChecked) examDate else -1L
)
if (::grade.isInitialized) {
@@ -37,7 +37,7 @@ class HistoricalAverageSheet : BottomSheetDialogFragment() {
binding.title.text = getString(R.string.averages_for_course, arguments?.getString("courseName"))
binding.recyclerView.apply {
layoutManager = GridLayoutManager(context, 1)
adapter = HistoricalAverageAdapter(data)
adapter = HistoricalAverageAdapter(data, targetFragment.getGradeType())
}
}
@@ -0,0 +1,24 @@
package com.denizd.qwark.sheet
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
open class QwarkSheet(@LayoutRes private val layoutId: Int) : BottomSheetDialogFragment() {
private lateinit var _context: Context
override fun getContext(): Context = _context
override fun onAttach(context: Context) {
super.onAttach(context)
_context = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? =
LayoutInflater.from(context).inflate(layoutId, container, false)
}
@@ -10,7 +10,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
open class TextInputSheet : BottomSheetDialogFragment() {
protected var _binding: TextInputSheetBinding? = null
private var _binding: TextInputSheetBinding? = null
protected val binding: TextInputSheetBinding get() = _binding!!
private lateinit var mContext: Context
@@ -0,0 +1,12 @@
package com.denizd.lawrence.util
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import androidx.viewbinding.ViewBinding
// written by Zhuinden (props to them!)
inline fun <T : ViewBinding> FragmentActivity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) =
lazy(LazyThreadSafetyMode.NONE) {
bindingInflater.invoke(layoutInflater)
}
@@ -0,0 +1,7 @@
package com.denizd.qwark.util
import com.denizd.qwark.database.QwarkRepository
object Dependencies {
lateinit var repo: QwarkRepository
}
@@ -0,0 +1,50 @@
package com.denizd.lawrence.util
import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.observe
import androidx.viewbinding.ViewBinding
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
// written by Zhuinden (props to them!)
class FragmentViewBindingDelegate<T : ViewBinding>(
val fragment: Fragment,
val viewBindingFactory: (View) -> T
) : ReadOnlyProperty<Fragment, T> {
private var _binding: T? = null
init {
fragment.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
fragment.viewLifecycleOwnerLiveData.observe(fragment) { viewLifecycleOwner ->
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
_binding = null
}
})
}
}
})
}
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
val binding = _binding
if (binding != null) {
return binding
}
val lifecycle = fragment.viewLifecycleOwner.lifecycle
if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.")
}
return viewBindingFactory(thisRef.requireView()).also { _binding = it }
}
}
fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) =
FragmentViewBindingDelegate(this, viewBindingFactory)
@@ -17,5 +17,6 @@ enum class PreferenceKey(val value: String) {
PARTICIPATION_DAY("participation_day"),
// Bools
SHOW_GRADE_AVERAGE("show_grade_average")
SHOW_GRADE_AVERAGE("show_grade_average"),
FIRST_LAUNCH("first_launch")
}
@@ -4,51 +4,48 @@ import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
class QwarkPreferences private constructor(context: Context) {
class QwarkPreferences(context: Context) {
private val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
private val edit: SharedPreferences.Editor = prefs.edit()
companion object {
private var qwarkPrefs: QwarkPreferences? = null
fun getPrefs(context: Context): QwarkPreferences {
if (qwarkPrefs == null) {
synchronized (QwarkPreferences::class) {
qwarkPrefs = QwarkPreferences(context)
}
}
return qwarkPrefs!!
}
}
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 putString(key: PreferenceKey, value: String): QwarkPreferences {
fun setString(key: PreferenceKey, value: String): QwarkPreferences {
edit.putString(key.value, value).apply()
return this
}
fun putInt(key: PreferenceKey, value: Int): QwarkPreferences {
fun setInt(key: PreferenceKey, value: Int): QwarkPreferences {
edit.putInt(key.value, value).apply()
return this
}
fun putBool(key: PreferenceKey, value: Boolean): QwarkPreferences {
fun setBool(key: PreferenceKey, value: Boolean): QwarkPreferences {
edit.putBoolean(key.value, value).apply()
return this
}
// TODO remove all of these
fun getShowGradeAverage(): Boolean = getBool(PreferenceKey.SHOW_GRADE_AVERAGE)
fun getGradeType(): Int = getInt(PreferenceKey.GRADE_TYPE)
fun getCourseSortType(): Int = getInt(PreferenceKey.COURSE_SORT_TYPE, 1)
fun setCourseSortType(value: Int) { putInt(PreferenceKey.COURSE_SORT_TYPE, value) }
fun getSchoolYear(): Int = getInt(PreferenceKey.SCHOOL_YEAR_ID)
fun getSchoolYearName(): String = getString(PreferenceKey.SCHOOL_YEAR_NAME)
fun getScoreProfileName(): String = getString(PreferenceKey.SCORE_PROFILE_NAME)
fun getScoreProfileId(): Int = getInt(PreferenceKey.SCORE_PROFILE_ID)
fun getParticipationDisplay(): Int = getInt(PreferenceKey.PARTICIPATION_DISPLAY)
fun getParticipationDay(): Int = getInt(PreferenceKey.PARTICIPATION_DAY)
fun getAppTheme(): Int = getInt(PreferenceKey.APP_THEME, 2)
fun getFinalScoreId(): Int = getInt(PreferenceKey.SCORE_PROFILE_ID)
fun getFirstLaunch(): Boolean = getBool(PreferenceKey.FIRST_LAUNCH)
fun getCurrentSchoolYearId(): Int = getInt(PreferenceKey.SCHOOL_YEAR_ID)
fun setParticipationDisplay(value: Int) { putInt(PreferenceKey.PARTICIPATION_DISPLAY, value) }
fun setParticipationDay(value: Int) { putInt(PreferenceKey.PARTICIPATION_DAY, value) }
fun setCourseSortType(value: Int) { setInt(PreferenceKey.COURSE_SORT_TYPE, value) }
fun setParticipationDisplay(value: Int) { setInt(PreferenceKey.PARTICIPATION_DISPLAY, value) }
fun setParticipationDay(value: Int) { setInt(PreferenceKey.PARTICIPATION_DAY, value) }
fun setAppTheme(value: Int) { setInt(PreferenceKey.APP_THEME, value) }
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) }
}
@@ -2,32 +2,29 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.database.CourseRepository
import com.denizd.qwark.model.Course
import com.denizd.qwark.model.CourseExam
import com.denizd.qwark.model.HistoricalAvg
import com.denizd.qwark.util.QwarkPreferences
class CourseViewModel(application: Application) : QwarkViewModel(application) {
private val repo = CourseRepository(application)
private val prefs: QwarkPreferences = QwarkPreferences.getPrefs(application)
val allCourses: LiveData<List<CourseExam>> = repo.getCoursesByYearId(getSchoolYear())
val allCourses: LiveData<List<CourseExam>> = repo.getCoursesByYearId(repo.prefs.getSchoolYear())
fun getShowGradeAverage(): Boolean = prefs.getShowGradeAverage()
fun getGradeType(): Int = prefs.getGradeType()
fun getCourseSortType(): Int = prefs.getCourseSortType()
fun getSchoolYear(): Int = prefs.getSchoolYear()
fun getSchoolYearName(): String = prefs.getSchoolYearName()
fun getShowGradeAverage(): Boolean = repo.prefs.getShowGradeAverage()
fun getGradeType(): Int = repo.prefs.getGradeType()
fun getCourseSortType(): Int = repo.prefs.getCourseSortType()
fun getSchoolYear(): Int = repo.prefs.getSchoolYear()
fun getSchoolYearName(): String = repo.prefs.getSchoolYearName()
fun insert(avg: HistoricalAvg) = doAsync { repo.insert(avg) }
fun getAveragesForCourses(courseId: Int): List<HistoricalAvg> = returnBlocking {
repo.getAveragesForCourses(courseId)
}
fun insert(course: Course) = doAsync { repo.insert(course) }
fun insert(historicalAvg: HistoricalAvg) = doAsync { repo.insert(historicalAvg) }
fun update(course: Course) = doAsync { repo.update(course) }
fun delete(course: Course) = doAsync { repo.delete(course) }
fun getCourse(courseId: Int): CourseExam = returnBlocking { repo.getCourse(courseId) }
}
@@ -3,7 +3,6 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import com.denizd.qwark.database.FinalsRepository
import com.denizd.qwark.model.CourseExam
import com.denizd.qwark.model.FinalGrade
import com.denizd.qwark.model.SchoolYear
@@ -13,8 +12,7 @@ import java.lang.NumberFormatException
class FinalsViewModel(app: Application) : QwarkViewModel(app) {
private val repo = FinalsRepository(app)
val allFinalGrades: LiveData<List<FinalGrade>> = repo.getFinalGrades(repo.getFinalScoreId())
val allFinalGrades: LiveData<List<FinalGrade>> = repo.getFinalGrades(repo.prefs.getFinalScoreId())
fun update(finalGrade: FinalGrade) = viewModelScope.launch {
withContext(Dispatchers.IO) {
@@ -24,8 +22,8 @@ class FinalsViewModel(app: Application) : QwarkViewModel(app) {
fun getSchoolYearName(courseId: Int) = returnBlocking { repo.getSchoolYearName(courseId) }
fun getScoreProfileName(): String = repo.getScoreProfileName()
fun getGradeType(): Int = repo.getGradeType()
fun getScoreProfileName(): String = repo.prefs.getScoreProfileName()
fun getGradeType(): Int = repo.prefs.getGradeType()
fun getFinalScore(basicGrades: List<FinalGrade>, advancedGrades: List<FinalGrade>, examGrades: List<FinalGrade>): Int = try {
var finalScore = 0
@@ -109,5 +107,5 @@ class FinalsViewModel(app: Application) : QwarkViewModel(app) {
fun getCourse(courseId: Int) = returnBlocking { repo.getCourse(courseId) }
fun getFinalGrade(finalGradeId: Int) = returnBlocking { repo.getFinalGrade(finalGradeId) }
fun getCourseSortType() = repo.getCourseSortType()
fun getCourseSortType() = repo.prefs.getCourseSortType()
}
@@ -2,14 +2,12 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.database.GradeRepository
import com.denizd.qwark.model.Grade
import com.denizd.qwark.model.HistoricalAvg
class GradeViewModel(application: Application) : QwarkViewModel(application) {
private val repo = GradeRepository(application)
fun getGradeType(): Int = repo.getGradeType()
fun getGradeType(): Int = repo.prefs.getGradeType()
fun getCourse(courseId: Int) = returnBlocking { repo.getCourse(courseId) }
@@ -22,7 +20,7 @@ class GradeViewModel(application: Application) : QwarkViewModel(application) {
fun updateAverage(average: String, gradeCount: Int, courseId: Int) = doAsync {
repo.updateAverage(average, gradeCount, courseId)
}
fun delete(gradeId: Int) = doAsync { repo.delete(gradeId) }
fun deleteGrade(gradeId: Int) = doAsync { repo.deleteGrade(gradeId) }
fun insert(avg: HistoricalAvg) = doAsync { repo.insert(avg) }
fun getGrade(gradeId: Int) = returnBlocking { repo.getGrade(gradeId) }
@@ -2,23 +2,24 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import android.content.Context
import android.util.Log
import android.view.Window
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.lifecycle.AndroidViewModel
import androidx.preference.PreferenceManager
import com.denizd.qwark.R
import com.denizd.qwark.database.QwarkRepository
import com.denizd.qwark.fragment.*
import com.denizd.qwark.fragment.CourseFragment
import com.denizd.qwark.fragment.FinalsFragment
import com.denizd.qwark.fragment.NoteFragment
import com.denizd.qwark.fragment.ParticipationFragment
import com.denizd.qwark.fragment.SettingsFragment
import com.denizd.qwark.util.Dependencies
import com.denizd.qwark.util.QwarkUtil
class MainViewModel(val app: Application) : AndroidViewModel(app) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(app.applicationContext)
class MainViewModel(val app: Application) : QwarkViewModel(app) {
fun getFragmentType(type: Int): String = when (type) { // TODO replace with Fragment#tag
R.id.courses -> "CourseFragment"
@@ -37,24 +38,25 @@ class MainViewModel(val app: Application) : AndroidViewModel(app) {
}
fun applyTheme(window: Window, context: Context) {
when (prefs.getInt("dark_mode", 2)) {
0 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
val barColour = ContextCompat.getColor(context, R.color.colorBackground)
AppCompatDelegate.setDefaultNightMode(when (repo.prefs.getAppTheme()) {
0 -> AppCompatDelegate.MODE_NIGHT_NO
1 -> AppCompatDelegate.MODE_NIGHT_YES
else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
})
ContextCompat.getColor(context, R.color.colorBackground).also { barColour ->
window.navigationBarColor = barColour
window.statusBarColor = barColour
}
}
fun checkForFirstTimeYearNotice(context: Context) {
if (prefs.getBoolean("first_launch", true)) {
if (repo.prefs.getFirstLaunch()) {
QwarkUtil.createInfoDialog(
context,
app.getString(R.string.alert_create_school_year_title),
app.getString(R.string.alert_create_school_year_desc)
)
prefs.edit().putBoolean("first_launch", false).apply()
repo.prefs.setFirstLaunch(false)
}
}
}
@@ -2,18 +2,12 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.*
import com.denizd.qwark.database.NoteRepository
import com.denizd.qwark.model.Note
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
class NoteViewModel(application: Application) : QwarkViewModel(application) {
private val repo = NoteRepository(application)
private val reloadTrigger = MutableLiveData<String>()
val allNotes: LiveData<List<Note>>? = Transformations.switchMap(reloadTrigger) { category ->
val allNotes: LiveData<List<Note>> = Transformations.switchMap(reloadTrigger) { category ->
if (category == "") {
repo.allNotes
} else {
@@ -21,60 +15,19 @@ class NoteViewModel(application: Application) : QwarkViewModel(application) {
}
}
init {
refresh("")
}
init { refresh("") }
fun refresh(category: String) {
reloadTrigger.value = category
}
fun refresh(category: String) { reloadTrigger.value = category }
fun insert(note: Note) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
repo.insert(note)
}
}
}
fun insert(note: Note) = doAsync { repo.insert(note) }
fun updateDismissedStatus(newDismissedStatus: Boolean, noteId: Int) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
repo.updateDismissed(newDismissedStatus, noteId)
}
}
}
fun updateDismissedStatus(newDismissedStatus: Boolean, noteId: Int) = doAsync { repo.updateDismissed(newDismissedStatus, noteId) }
fun delete(noteId: Int) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
repo.delete(noteId)
}
}
}
fun delete(noteId: Int) = doAsync { repo.deleteNote(noteId) }
// // TODO get this as LiveData variable to get changes
// fun getNotesForCategory(category: String): LiveData<List<Note>>? {
// return runBlocking {
// withContext(Dispatchers.IO) {
// repo.notesForCategory(category)
// }
// }
// }
fun update(note: Note) = doAsync { repo.update(note) }
fun update(note: Note) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
repo.update(note)
}
}
}
fun getAllCategories(): List<String> = runBlocking {
withContext(Dispatchers.IO) {
repo.getAllCategories()
}
}
fun getAllCategories(): List<String> = returnBlocking { repo.getAllCategories() }
fun getNote(noteId: Int) = returnBlocking { repo.getNote(noteId) }
}
@@ -2,13 +2,10 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.database.ParticipationRepository
import com.denizd.qwark.model.Participation
class ParticipationCourseViewModel(app: Application) : QwarkViewModel(app) {
private val repo = ParticipationRepository(app)
fun getAllParticipationsForCourse(courseId: Int): LiveData<List<Participation>> = returnBlocking {
repo.getAllParticipationsForCourse(courseId)
}
@@ -22,6 +19,6 @@ class ParticipationCourseViewModel(app: Application) : QwarkViewModel(app) {
fun createParticipation(timesHandRaised: Int, timesSpoken: Int, time: Long, courseId: Int) = doAsync {
repo.insert(timesHandRaised, timesSpoken, time, courseId)
}
fun getSchoolYearName() = repo.getSchoolYearName()
fun getSchoolYearName() = repo.prefs.getSchoolYearName()
fun delete(participation: Participation) = doAsync { repo.delete(participation) }
}
@@ -2,15 +2,12 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.database.ParticipationRepository
import com.denizd.qwark.model.Course
import com.denizd.qwark.model.CourseExam
import com.denizd.qwark.model.Participation
import com.denizd.qwark.model.SchoolDay
class ParticipationViewModel(app: Application) : QwarkViewModel(app) {
private val repo = ParticipationRepository(app)
val allCoursesForToday: LiveData<List<Course>> = repo.allCoursesForToday
val dayId: Int = repo.dayId
@@ -18,5 +15,5 @@ class ParticipationViewModel(app: Application) : QwarkViewModel(app) {
fun link(courseId: Int) = doAsync { repo.link(courseId) }
fun removeLink(relationId: Int) = doAsync { repo.removeLink(relationId) }
fun delete(participation: Participation) = doAsync { repo.delete(participation) }
fun getSchoolYearName() = repo.getSchoolYearName()
fun getSchoolYearName() = repo.prefs.getSchoolYearName()
}
@@ -3,24 +3,23 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.denizd.qwark.database.QwarkRepository
import com.denizd.qwark.util.Dependencies
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
open class QwarkViewModel(app: Application) : AndroidViewModel(app) {
protected val repo: QwarkRepository = Dependencies.repo
fun doAsync(function: () -> Unit) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
viewModelScope.launch(Dispatchers.IO) {
function()
}
}
}
fun <T> returnBlocking(function: () -> T): T = runBlocking {
withContext(Dispatchers.IO) {
fun <T> returnBlocking(function: () -> T): T = runBlocking(Dispatchers.IO) {
function()
}
}
}
@@ -3,38 +3,34 @@ package com.denizd.qwark.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizd.qwark.database.QwarkClient
import com.denizd.qwark.util.QwarkPreferences
import com.denizd.qwark.database.SettingsRepository
import com.denizd.qwark.model.ScoreProfile
import com.denizd.qwark.model.SchoolYear
class SettingsViewModel(private val app: Application) : QwarkViewModel(app) {
private val repo = SettingsRepository(app)
val allYears: LiveData<List<SchoolYear>> = repo.allYears
val allScoreProfiles: LiveData<List<ScoreProfile>> = repo.allScoreProfiles
private val prefs: QwarkPreferences = QwarkPreferences.getPrefs(app.applicationContext)
// Preference getters
fun getAppTheme() = repo.getAppTheme()
fun getShowGradeAverage() = repo.getShowGradeAverage()
fun getCourseSortType(): Int = prefs.getCourseSortType()
fun getGradeType() = repo.getGradeType()
fun getScoreProfileName() = repo.getScoreProfileName()
fun getCurrentSchoolYear(): String = repo.getCurrentSchoolYear()
fun getCurrentSchoolYearId(): Int = repo.getCurrentSchoolYearId()
fun getParticipationDisplay(): Int = repo.getParticipationDisplay()
fun getParticipationDay(): Int = repo.getParticipationDay()
fun getAppTheme() = repo.prefs.getAppTheme()
fun getShowGradeAverage() = repo.prefs.getShowGradeAverage()
fun getCourseSortType(): Int = repo.prefs.getCourseSortType()
fun getGradeType() = repo.prefs.getGradeType()
fun getScoreProfileName() = repo.prefs.getScoreProfileName()
fun getSchoolYearName(): String = repo.prefs.getSchoolYearName()
fun getCurrentSchoolYearId(): Int = repo.prefs.getCurrentSchoolYearId()
fun getParticipationDisplay(): Int = repo.prefs.getParticipationDisplay()
fun getParticipationDay(): Int = repo.prefs.getParticipationDay()
// Preference setters
fun setAppTheme(value: Int) { repo.setAppTheme(value) }
fun setShowGradeAverage(value: Boolean) { repo.setShowGradeAverage(value) }
fun setCourseSortType(value: Int) { prefs.setCourseSortType(value) }
fun setGradeType(value: Int) { repo.setGradeType(value) }
fun setAppTheme(value: Int) { repo.prefs.setAppTheme(value) }
fun setShowGradeAverage(value: Boolean) { repo.prefs.setShowGradeAverage(value) }
fun setCourseSortType(value: Int) { repo.prefs.setCourseSortType(value) }
fun setGradeType(value: Int) { repo.prefs.setGradeType(value) }
fun setCurrentScoreProfile(scoreProfile: ScoreProfile) { repo.setCurrentScoreProfile(scoreProfile) }
fun updateSchoolYear(schoolYear: SchoolYear) { repo.setCurrentSchoolYear(schoolYear) }
fun setParticipationDisplay(value: Int) { repo.setParticipationDisplay(value) }
fun setParticipationDay(value: Int) { repo.setParticipationDay(value) }
fun setParticipationDisplay(value: Int) { repo.prefs.setParticipationDisplay(value) }
fun setParticipationDay(value: Int) { repo.prefs.setParticipationDay(value) }
// Database functions
fun insert(schoolYear: SchoolYear) = doAsync { repo.insert(schoolYear) }
@@ -32,6 +32,7 @@
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:scrollbars="vertical"
@@ -16,7 +16,7 @@
android:id="@+id/average"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginTop="8dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="12dp"
android:textColor="@color/colorAccentedControl"
@@ -27,7 +27,7 @@
android:id="@+id/weighting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginTop="8dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="12dp"
android:textColor="@color/colorText"
@@ -59,6 +59,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="16dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
app:cornerRadius="12dp"
+46 -30
View File
@@ -7,46 +7,20 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:fitsSystemWindows="false"
android:background="@color/colorBackground"
tools:context=".activity.MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="56dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<View
android:id="@+id/status_bar_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/colorAppBarBackground"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/app_bar_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="84dp"
app:elevation="0dp"
android:background="@color/colorAppBarBackground"
android:background="@color/colorBackground"
android:layout_gravity="top"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -57,7 +31,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentInsetStart="0dp"
android:elevation="0dp">
android:elevation="0dp"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@@ -102,7 +77,11 @@
</com.google.android.material.appbar.AppBarLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab"
@@ -139,11 +118,48 @@
android:layout_height="1dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:background="@color/colorHintLight"
android:background="@color/strokeColor"
android:clickable="false"
android:focusable="false"
app:layout_anchor="@+id/bottom_nav"
android:layout_gravity="top"
android:fitsSystemWindows="false"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="false">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/splash_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBackground">
<ImageView
android:id="@+id/image_view"
android:layout_width="120dp"
android:layout_height="184dp"
android:scaleType="centerInside"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:src="@drawable/bolt"/>
<TextView
android:id="@+id/greeting_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:fontFamily="@font/manrope_semibold"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="@+id/image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
+2 -2
View File
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="3dp"
android:focusable="true"
android:clickable="true"
android:backgroundTint="@color/colorCardBackground">
android:clickable="true">
<LinearLayout
android:layout_width="match_parent"
@@ -55,14 +55,14 @@
<com.google.android.material.button.MaterialButton
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:id="@+id/finish_button"
android:id="@+id/save_button"
app:strokeWidth="2dp"
app:strokeColor="@color/colorAccent"
android:textColor="@color/colorAccent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="@string/finish"
android:text="@string/save"
app:rippleColor="@color/colorAccent"/>
</LinearLayout>
+3 -1
View File
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -7,6 +7,7 @@
android:clipToPadding="false">
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
+5 -3
View File
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -65,9 +67,9 @@
style="@android:style/Widget.ProgressBar.Horizontal"
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_height="3dp"
android:progressTint="@color/colorAccent"
android:progressBackgroundTint="@color/colorCardBackground"/>
android:progressBackgroundTint="@color/colorBackground"/>
</LinearLayout>
+3 -1
View File
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+3 -1
View File
@@ -2,6 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/colorBackground">
<androidx.recyclerview.widget.RecyclerView
@@ -9,6 +10,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/layout_animation_fall_down"
android:scrollbars="vertical"/>
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</LinearLayout>
+8 -16
View File
@@ -20,15 +20,13 @@
android:layoutAnimation="@anim/layout_animation_fall_down">
<com.google.android.material.card.MaterialCardView
style="@style/QwarkCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/cardCornerRadius"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/colorCardBackground">
android:layout_marginBottom="3dp">
<LinearLayout
android:layout_width="match_parent"
@@ -79,15 +77,13 @@
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
style="@style/QwarkCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/cardCornerRadius"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/colorCardBackground">
android:layout_marginBottom="3dp">
<LinearLayout
android:layout_width="match_parent"
@@ -290,15 +286,13 @@
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
style="@style/QwarkCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/cardCornerRadius"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/colorCardBackground">
android:layout_marginBottom="3dp">
<LinearLayout
android:layout_width="match_parent"
@@ -376,15 +370,13 @@
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
style="@style/QwarkCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/cardCornerRadius"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/colorCardBackground">
android:layout_marginBottom="3dp">
<LinearLayout
android:layout_width="match_parent"
+1 -5
View File
@@ -29,11 +29,7 @@
android:layout_marginEnd="24dp"
android:hint="@string/school_year_cap"
android:textColorHint="@color/colorHint"
android:importantForAutofill="no"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusBottomStart="12dp">
android:importantForAutofill="no">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_text"
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorBackground">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorText"
android:textSize="22sp"
android:fontFamily="@font/manrope_semibold"
android:layout_marginTop="16dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"/>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorText"
android:fontFeatureSettings="tnum"
android:layout_marginBottom="16dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"/>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
+4 -3
View File
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/QwarkCard"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="3dp"
android:backgroundTint="@color/colorCardBackground">
android:layout_marginVertical="3dp">
<LinearLayout
android:id="@+id/backgroundLayout"
+3
View File
@@ -11,6 +11,7 @@
<string name="edit">Bearbeiten</string>
<string name="finish">Beenden</string>
<string name="create">Erstellen</string>
<string name="save">Speichern</string>
<string name="general">Allgemein</string>
<string name="alert_create_school_year_title">Erstelle ein Schuljahr</string>
<string name="alert_create_school_year_desc">Bevor du Kurse und Abschlussnoten hinzufügst, gehe in die Einstellungen und erstelle ein Schuljahr und ein Abschlussprofil!</string>
@@ -138,6 +139,8 @@
<string name="clear_final_grade_error">Note kann nicht gelöscht werden; ist bereits leer</string>
<string name="pick_a_year">Wähle ein Schuljahr</string>
<string name="pick_a_course">Wähle einen Kurs</string>
<string name="conversion_table">Umrechnungstabelle</string>
<string name="points_to_grade_conversion_title">Punkte zu Note-Umrechnungstabelle</string>
<!-- SettingsFragment.kt -->
<string name="settings">Einstellungen</string>
+1 -1
View File
@@ -2,7 +2,6 @@
<resources>
<color name="colorAccent">#6abf69</color>
<color name="colorBackground">#121212</color>
<color name="colorAppBarBackground">#E6121212</color>
<color name="colorCardBackground">#222222</color>
<color name="colorTextHighlight">@color/colorAccent</color>
<color name="colorText">#e0e0e0</color>
@@ -14,4 +13,5 @@
<color name="colorTextWhite">#e0e0e0</color>
<color name="colorAccentedControl">@color/colorText</color>
<color name="colorSplashLogo">@color/colorText</color>
<color name="strokeColor">#424242</color>
</resources>
+3 -3
View File
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<color name="colorAccent">#388e3c</color>
<color name="colorBackground">#e0e0e0</color>
<color name="colorAppBarBackground">#E6e0e0e0</color>
<color name="colorCardBackground">#f5f5f5</color>
<color name="colorBackground">#ffffff</color>
<color name="colorCardBackground">#e0e0e0</color>
<color name="colorTextHighlight">@color/colorAccent</color>
<color name="colorText">#212121</color>
<color name="colorHint">#757575</color>
@@ -14,6 +13,7 @@
<color name="colorTextWhite">#e0e0e0</color>
<color name="colorAccentedControl">@color/colorAccent</color>
<color name="colorSplashLogo">@color/colorAccent</color>
<color name="strokeColor">#bdbdbd</color>
<color name="mtrl_textinput_default_box_stroke_color" tools:override="true">#757575</color>
</resources>
+10 -1
View File
@@ -11,6 +11,7 @@
<string name="edit">Edit</string>
<string name="finish">Finish</string>
<string name="create">Create</string>
<string name="save">Save</string>
<string name="general">General</string>
<string name="alert_create_school_year_title">Create a school year</string>
<string name="alert_create_school_year_desc">Before adding courses and final grades, please do make sure to go into the settings and create a school year and a score profile!</string>
@@ -18,6 +19,12 @@
<string name="powered_by_qwark" translatable="false">Powered by Qwark</string>
<string name="made_by_deniz" translatable="false">Made by Deniz</string>
<string-array name="greetings">
<item>Hello %s!</item>
<item>Hi %s!</item>
<item>Hope you\'re doing well, %s.</item>
</string-array>
<!-- CourseFragment.kt -->
<string name="course">Course</string>
<string name="courses">Courses</string>
@@ -196,7 +203,9 @@
<string name="clear_final_grade_error">Grade cannot be cleared; is already empty</string>
<string name="pick_a_year">Pick a school year</string>
<string name="pick_a_course">Pick a course</string>
<string name="points_to_grade_conversion" translatable="false">900 823 > 1.0\n822 805 > 1.1\n804 787 > 1.2\n786 769 > 1.3\n768 751 > 1.4\n750 733 > 1.5\n732 715 > 1.6\n714 697 > 1.7\n696 679 > 1.8\n678 661 > 1.9\n660 643 > 2.0\n\n642 625 > 2.1\n624 607 > 2.2\n606 589 > 2.3\n588 571 > 2.4\n570 553 > 2.5\n552 535 > 2.6\n534 517 > 2.7\n516 499 > 2.8\n498 481 > 2.9\n480 463 > 3.0\n\n462 445 > 3.1\n444 427 > 3.2\n426 409 > 3.3\n408 391 > 3.4\n390 373 > 3.5\n372 355 > 3.6\n354 337 > 3.7\n336 319 > 3.8\n318 301 > 3.9\n300 > 4.0</string>
<string name="conversion_table">Conversion table</string>
<string name="points_to_grade_conversion_title">Points to grade conversion table</string>
<string name="points_to_grade_conversion" translatable="false">900 823 → 1.0\n822 805 → 1.1\n804 787 → 1.2\n786 769 → 1.3\n768 751 → 1.4\n750 733 → 1.5\n732 715 → 1.6\n714 697 → 1.7\n696 679 → 1.8\n678 661 → 1.9\n660 643 → 2.0\n\n642 625 → 2.1\n624 607 → 2.2\n606 589 → 2.3\n588 571 → 2.4\n570 553 → 2.5\n552 535 → 2.6\n534 517 → 2.7\n516 499 → 2.8\n498 481 → 2.9\n480 463 → 3.0\n\n462 445 → 3.1\n444 427 → 3.2\n426 409 → 3.3\n408 391 → 3.4\n390 373 → 3.5\n372 355 → 3.6\n354 337 → 3.7\n336 319 → 3.8\n318 301 → 3.9\n300 → 4.0</string>
<string name="approximate_placeholder" translatable="false">≈ %s</string>
<!-- SettingsFragment.kt -->
+10 -3
View File
@@ -3,7 +3,7 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/colorAccent</item>
<item name="colorPrimaryDark">@android:color/transparent</item>
<item name="colorPrimaryDark">@color/colorBackground</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:fontFamily">@font/manrope_medium</item>
<item name="android:colorEdgeEffect">@color/colorAccent</item>
@@ -13,7 +13,6 @@
<item name="shapeAppearanceSmallComponent">@style/ShapeSmallComponent</item>
<item name="shapeAppearanceMediumComponent">@style/ShapeMediumComponent</item>
<item name="shapeAppearanceLargeComponent">@style/ShapeLargeComponent</item>
<item name="cardBackgroundColor">@color/colorCardBackground</item>
<item name="cornerRadius">@dimen/cardCornerRadius</item>
<item name="cardElevation">3dp</item>
<item name="android:textColor">@color/colorText</item>
@@ -23,11 +22,19 @@
<item name="boxCornerRadiusBottomEnd">@dimen/cardCornerRadius</item>
<item name="boxStrokeColor">@color/colorAccent</item>
<item name="boxStrokeWidth">1dp</item>
<!-- <item name="android:statusBarColor">@color/colorAppBarBackground</item>-->
<!-- <item name="android:statusBarColor">@color/colorBackground</item>-->
<!-- <item name="android:windowTranslucentStatus">true</item>-->
<!-- <item name="android:windowDrawsSystemBarBackgrounds">true</item>-->
</style>
<style name="QwarkCard" parent="Widget.MaterialComponents.CardView">
<item name="cardBackgroundColor">@color/colorBackground</item>
<item name="strokeColor">@color/strokeColor</item>
<item name="strokeWidth">1dp</item>
<item name="cardCornerRadius">12dp</item>
<item name="cardElevation">0dp</item>
</style>
<!-- Launch / splash screen -->
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/launch_screen</item>
+1 -1
View File
@@ -8,7 +8,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0-alpha09'
classpath 'com.android.tools.build:gradle:4.0.0-beta01'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+2 -2
View File
@@ -1,6 +1,6 @@
#Mon Feb 03 16:46:00 CET 2020
#Mon Mar 02 18:07:39 CET 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-rc-1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip