[UI] Upgrade to Material 3 design, refactor some core elements (#201)

* Material 3 theme and color support, filled cards

* Change drawer header, dark bottombar color

* Replace MaterialComponents with Material3

* wielki powrót pr m3 do szkolnego (nie czytajcie tego kodu)

* fix M3 UI code & upgrade kotlin

* update dependencies

* fix missing Intent receiver flags for Tiramisu+

* fix kapt errors related to SelectiveDAO + migrate BuildConfig

* adapt code to updated dependencies + align lessons (based by szkolny-eu/szkolny-android#196)

* fix: no query filtering

* fix: duplicated items in about card

* fix: "Back button opens drawer" (redundant super call)

* fix: too small heading in agenda dialog

* adapt notes fragment to MD3

* add lock layout function (szkolny-eu/szkolny-android#199)

* hide classroom heading when no classroom is specified

* add support for grade column codes

* grades: join code and category together

* add cosmetic ui changes + fix build issues

* fix proguard rules (attempt 1)

* add new Retrofit2 rules

* add new ProGuard rules + fix QR scanning

* fix agenda view crash when building release variant

* improve LessonDetailsDialog

* remove duplicated string extension

* set separate app ID & icon for debug version

* remove unneeded import statement

* fix collapsing toolbar title when doing back gesture

* remove useless dependencies

* fix UI issues on old Android versions

* fix missing color resources + cleanup dependencies

* fix release building issue

* fix release building issue & remove ripple from NavView

* move version badge to the top bar

* Revert changes introduced by rebase

* Update NavLib from sadorowo/NavLib

* Revert "add lock layout function (szkolny-eu/szkolny-android#199)"

This reverts commit 2fd7038d0c.

* Revert "add support for grade column codes"

* Revert unnecessary code changes, part 1

* Lower minSdk to 19

* Revert unnecessary code changes, part 2

* Add new application logo

* Restore bottom bar support in NavLib, revert unnecessary changes

* Use new IconicsMaterialButton in MessageFragment

* Migrate NavView to view binding

* Support IconButton in IconicsMaterialButton

* Cleanup NavLib w600dp styles

* Remove NavLib text styles

* Refactor all application themes, update styles in layouts

* Move enums and config entry to .data, fix app crashing

* Rename non-theme styles to AppStyle

* Restructure app config classes, move config to .data

* Add Theme enum and UiManager, support basic theme changing

* Actually support basic theme changing

* Serialize enum as string, fix config migration, bring back DebugDb

* Fix changing themes, apply night mode in App

* Fix resolving ColorStateList attributes, add LabPlaygroundFragment

* add Iconics methods into ProGuard rules

* Replace home card icon buttons, remove unused icons

* Update gradle properties

* Update build.gradle

* Remove unnecessary dependencies

* Remove playstore icon

* Apply fixes after review

---------

Co-authored-by: Adam Kasprzycki <66315787+santoni0@users.noreply.github.com>
Co-authored-by: Kuba Szczodrzyński <kuba@szczodrzynski.pl>
This commit is contained in:
Franek 2024-06-30 16:12:07 +02:00 committed by GitHub
parent fadf1d7754
commit 0823e72328
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
595 changed files with 5725 additions and 3910 deletions

View File

@ -1,7 +1,23 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<AndroidXmlCodeStyleSettings>
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
<option name="MANIFEST_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
<option name="OTHER_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="ALLOW_TRAILING_COMMA" value="true" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
@ -127,6 +143,8 @@
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="PARAMETER_ANNOTATION_WRAP" value="2" />
<option name="ENUM_CONSTANTS_WRAP" value="2" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -4,6 +4,7 @@
<w>autoryzacji</w>
<w>ciasteczko</w>
<w>csrf</w>
<w>daynight</w>
<w>edziennik</w>
<w>eggfall</w>
<w>elearning</w>

View File

@ -10,8 +10,10 @@ apply from: 'git-info.gradle'
android {
compileSdkVersion setup.compileSdk
namespace "pl.szczodrzynski.edziennik"
defaultConfig {
applicationId 'pl.szczodrzynski.edziennik'
applicationId "pl.szczodrzynski.edziennik"
minSdkVersion setup.minSdk
targetSdkVersion setup.targetSdk
@ -20,8 +22,9 @@ android {
buildConfigField "java.util.Map<String, String>", "GIT_INFO", gitInfoMap
buildConfigField "String", "VERSION_BASE", "\"${release.versionName}\""
manifestPlaceholders = [
buildTimestamp: String.valueOf(System.currentTimeMillis())
buildTimestamp: String.valueOf(System.currentTimeMillis())
]
multiDexEnabled = true
@ -36,6 +39,8 @@ android {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
correctErrorTypes = true
}
}
@ -43,10 +48,12 @@ android {
debug {
getIsDefault().set(true)
minifyEnabled = false
applicationIdSuffix = ".debug"
manifestPlaceholders = [
buildTimestamp: 0
buildTimestamp: 0
]
}
release {
minifyEnabled = true
shrinkResources = true
@ -54,28 +61,35 @@ android {
proguardFiles fileTree('proguard').asList().toArray()
}
}
flavorDimensions "platform"
flavorDimensions += "platform"
productFlavors {
unofficial {
getIsDefault().set(true)
versionName "${release.versionName}-${gitInfo.versionSuffix}"
}
official {}
play {}
}
variantFilter { variant ->
def flavors = variant.flavors*.name
setIgnore(variant.buildType.name == "debug" && !flavors.contains("unofficial") || flavors.contains("main"))
}
sourceSets {
unofficial {
java.srcDirs = ["src/main/java", "src/play-not/java"]
manifest.srcFile("src/play-not/AndroidManifest.xml")
}
official {
java.srcDirs = ["src/main/java", "src/play-not/java"]
manifest.srcFile("src/play-not/AndroidManifest.xml")
}
play {
java.srcDirs = ["src/main/java", "src/play/java"]
}
@ -84,29 +98,36 @@ android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
buildFeatures {
dataBinding = true
viewBinding = true
buildConfig = true
}
compileOptions {
coreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
packagingOptions {
resources {
excludes += ['META-INF/library-core_release.kotlin_module']
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
lint {
checkReleaseBuilds false
}
@ -115,6 +136,7 @@ android {
tasks.whenTaskAdded { task ->
if (!task.name.endsWith("Release") && !task.name.endsWith("ReleaseWithR8"))
return
def renameTaskName = "rename${task.name.capitalize()}"
def flavor = ""
@ -125,16 +147,20 @@ tasks.whenTaskAdded { task ->
if (task.name.startsWith("minify"))
flavor = task.name.substring("minify".length(), task.name.indexOf("Release")).uncapitalize()
def taskName = "package${flavor.capitalize()}Release"
if (flavor != "") {
tasks.create(renameTaskName, Copy) {
tasks.register(renameTaskName, Copy) {
dependsOn(taskName)
from file("${projectDir}/${flavor}/release/"),
file("${buildDir}/outputs/mapping/${flavor}Release/"),
file("${buildDir}/outputs/apk/${flavor}/release/"),
file("${buildDir}/outputs/bundle/${flavor}Release/")
file("${layout.buildDirectory}/outputs/mapping/${flavor}Release/"),
file("${layout.buildDirectory}/outputs/apk/${flavor}/release/"),
file("${layout.buildDirectory}/outputs/bundle/${flavor}Release/")
include "*.aab", "*.apk", "mapping.txt", "output-metadata.json"
destinationDir file("${projectDir}/release/")
rename ".+?\\.(.+)", "Edziennik_${android.defaultConfig.versionName}_${flavor}." + '$1'
}
task.finalizedBy(renameTaskName)
}
}
@ -145,29 +171,29 @@ dependencies {
// Language cores
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.multidex:multidex:2.0.1"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
// Android Jetpack
implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.appcompat:appcompat:1.7.0"
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.core:core-ktx:1.9.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.room:room-runtime:2.4.3"
implementation "androidx.room:room-ktx:2.4.3"
implementation "androidx.work:work-runtime-ktx:2.7.1"
kapt "androidx.room:room-compiler:2.4.3"
implementation "androidx.core:core-ktx:1.13.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.2"
implementation "androidx.navigation:navigation-fragment-ktx:2.7.7"
implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.room:room-runtime:2.6.1"
implementation "androidx.room:room-ktx:2.6.1"
implementation "androidx.work:work-runtime-ktx:2.9.0"
kapt "androidx.room:room-compiler:2.6.1"
// Google design libs
implementation "com.google.android.material:material:1.6.1"
implementation "com.google.android.material:material:1.12.0"
implementation "com.google.android.flexbox:flexbox:3.0.0"
// Play Services/Firebase
implementation "com.google.android.gms:play-services-wearable:17.1.0"
implementation "com.google.android.gms:play-services-wearable:18.2.0"
implementation("com.google.firebase:firebase-core") { version { strictly "19.0.2" } }
implementation "com.google.firebase:firebase-crashlytics:18.2.13"
implementation "com.google.firebase:firebase-crashlytics:19.0.1"
implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
// OkHttp, Retrofit, Gson, Jsoup
@ -175,7 +201,7 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "com.squareup.retrofit2:converter-scalars:2.9.0"
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'org.jsoup:jsoup:1.14.3'
implementation "pl.droidsonroids:jspoon:1.3.2"
implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
@ -189,19 +215,22 @@ dependencies {
implementation "eu.szkolny:material-about-library:1d5ebaf47c"
implementation "eu.szkolny:mhttp:af4b62e6e9"
implementation "eu.szkolny:nachos:0e5dfcaceb"
implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
implementation "eu.szkolny.selective-dao:annotation:6a337f9"
officialImplementation "eu.szkolny:ssl-provider:1.0.0"
unofficialImplementation "eu.szkolny:ssl-provider:1.0.0"
implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
implementation "pl.szczodrzynski:recyclertablayout:700f980584"
implementation "pl.szczodrzynski:tachyon:551943a6b5"
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
kapt "eu.szkolny.selective-dao:codegen:6a337f9"
// Iconics & related
implementation "com.mikepenz:iconics-core:5.3.2"
implementation "com.mikepenz:iconics-views:5.3.2"
implementation "com.mikepenz:materialdrawer:9.0.1"
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
implementation "eu.szkolny:szkolny-font:77e33acc2a"
implementation 'com.mikepenz:google-material-typeface:4.0.0.2-kotlin@aar'
implementation "eu.szkolny:szkolny-font:95eabe7"
// Other dependencies
implementation "cat.ereza:customactivityoncrash:2.3.0"

View File

@ -5,7 +5,7 @@
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath "org.eclipse.jgit:org.eclipse.jgit:5.5.+"

View File

@ -36,6 +36,37 @@
"status": 2
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:640759989760:android:4aa71407b25cdc8d",
"android_client_info": {
"package_name": "pl.szczodrzynski.edziennik.debug"
}
},
"oauth_client": [
{
"client_id": "640759989760-6f8q00u864lnuh3gh36e8g4cer9lv8pv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAvq9HMPxulz9ntdAHZ0eZuPf2YQs4nDSU"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"

View File

@ -19,7 +19,10 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keepattributes Signature
-keep class android.support.v7.widget.** { *; }
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
-keep class pl.szczodrzynski.edziennik.data.db.enums.* { *; }
@ -32,8 +35,8 @@
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
-keep class pl.szczodrzynski.edziennik.config.AppData { *; }
-keep class pl.szczodrzynski.edziennik.config.AppData$** { *; }
-keep class pl.szczodrzynski.edziennik.data.config.AppData { *; }
-keep class pl.szczodrzynski.edziennik.data.config.AppData$** { *; }
-keep class pl.szczodrzynski.edziennik.utils.managers.TextStylingManager$HtmlMode { *; }
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
@ -42,6 +45,15 @@
-keepclassmembernames class androidx.appcompat.view.menu.MenuItemImpl { private *; }
-keepclassmembernames class com.mikepenz.materialdrawer.widget.MiniDrawerSliderView { private *; }
-keepclassmembernames class com.mikepenz.iconics.internal.IconicsViewsAttrsApplier {
<fields>;
readIconicsTextView(android.content.Context, android.util.AttributeSet, com.mikepenz.iconics.internal.CompoundIconsBundle);
getIconicsImageViewDrawable(android.content.Context, android.util.AttributeSet);
}
-keepclassmembernames class com.mikepenz.iconics.internal.CompoundIconsBundle {
setIcons(android.widget.TextView);
}
-keep class .R
-keep class **.R$* {
@ -55,8 +67,19 @@
-keep class com.google.android.material.tabs.** {*;}
# Exclude AgendaCalendarView
# Preserve generic type information for EventRenderer and its subclasses
-keepclassmembers class * extends com.github.tibolte.agendacalendarview.render.EventRenderer {
<fields>;
<methods>;
}
# Keep the EventRenderer class itself and all its subclasses
-keep class com.github.tibolte.agendacalendarview.render.EventRenderer
-keep class * extends com.github.tibolte.agendacalendarview.render.EventRenderer
# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
# Most of volatile fields are updated with AFU and should not be mangled
@ -70,9 +93,36 @@
-keep class pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing { public final byte[] pleaseStopRightNow(java.lang.String, long); }
-keepclassmembers class pl.szczodrzynski.edziennik.ui.login.qr.* { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.login.LoginInfo$Platform { *; }
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData { *; }
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData$Type { *; }
# Exclude Retrofit2
-keepattributes Signature, InnerClasses, EnclosingMethod
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
-keepattributes AnnotationDefault
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn javax.annotation.**
-dontwarn kotlin.Unit
-dontwarn retrofit2.KotlinExtensions
-dontwarn retrofit2.KotlinExtensions$*
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface * extends <1>
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
-if interface * { @retrofit2.http.* public *** *(...); }
-keep,allowoptimization,allowshrinking,allowobfuscation class <3>
-keep,allowobfuscation,allowshrinking class retrofit2.Response

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="pl.szczodrzynski.edziennik">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
@ -12,19 +11,21 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
<uses-sdk
tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core, com.mikepenz:materialdrawer, com.mikepenz.iconics.typeface.library.navlibfont, androidx.appcompat.resources, androidx.appcompat, com.google.android.gms.wearable, com.google.android.gms.base, com.google.firebase.crashlytics, com.google.firebase.sessions, com.google.firebase.ktx, com.google.firebase, com.google.android.gms.tasks, com.google.android.gms.common, com.google.firebase.components" />
<application
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_descriptor"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/ic_launcher_v5"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:theme="@style/AppTheme.Dark"
android:theme="@style/AppTheme.M3.Blue"
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute">
@ -40,7 +41,6 @@
|___/ -->
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:exported="true"
android:theme="@style/SplashTheme">
@ -67,7 +67,7 @@
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true"
android:theme="@style/AppTheme.Dark.NoDisplay">
android:theme="@style/AppTheme.M3.NoDisplay">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
@ -84,14 +84,14 @@
android:resource="@xml/widget_timetable_info" />
</receiver>
<service android:name=".ui.widgets.timetable.WidgetTimetableService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
android:permission="android.permission.BIND_REMOTEVIEWS" android:foregroundServiceType="dataSync"/>
<activity android:name=".ui.widgets.LessonDialogActivity"
android:label=""
android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true"
android:theme="@style/AppTheme.Dark.NoDisplay" />
android:theme="@style/AppTheme.M3.NoDisplay" />
<!-- NOTIFICATIONS -->
<receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
android:label="@string/widget_notifications_title"
@ -105,7 +105,7 @@
android:resource="@xml/widget_notifications_info" />
</receiver>
<service android:name=".ui.widgets.notifications.WidgetNotificationsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
android:permission="android.permission.BIND_REMOTEVIEWS" android:foregroundServiceType="dataSync"/>
<!-- LUCKY NUMBER -->
<receiver android:name=".ui.widgets.luckynumber.WidgetLuckyNumberProvider"
android:label="@string/widget_lucky_number_title"
@ -133,26 +133,24 @@
android:theme="@style/DeadTheme" />
<activity android:name=".ui.intro.ChangelogIntroActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:exported="false"
android:theme="@style/Theme.Intro" />
<activity android:name=".ui.login.LoginActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"
android:exported="false"
android:theme="@style/AppTheme.Light" />
android:theme="@style/AppTheme.M3" />
<activity android:name=".ui.home.CounterActivity"
android:exported="false"
android:theme="@style/AppTheme.Black" />
android:theme="@style/AppTheme.M3" />
<activity android:name=".ui.feedback.FeedbackActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name"
android:exported="false"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme.M3" />
<activity android:name=".ui.settings.SettingsLicenseActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme.M3" />
<activity android:name="com.canhub.cropper.CropImageActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
@ -202,15 +200,15 @@
____) | __/ | \ V /| | (_| __/\__ \
|_____/ \___|_| \_/ |_|\___\___||___/
-->
<service android:name=".data.api.ApiService" />
<service android:name=".data.api.ApiService" android:foregroundServiceType="dataSync"/>
<service android:name=".data.firebase.MyFirebaseService"
android:exported="false">
android:exported="false" android:foregroundServiceType="dataSync">
<intent-filter android:priority="10000000">
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name=".sync.UpdateDownloaderService" />
<service android:name=".sync.UpdateDownloaderService" android:foregroundServiceType="dataSync"/>
<!--
_____ _ _

View File

@ -36,27 +36,25 @@ import kotlinx.coroutines.withContext
import me.leolin.shortcutbadger.ShortcutBadger
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.config.Config
import pl.szczodrzynski.edziennik.data.config.AppData
import pl.szczodrzynski.edziennik.data.config.Config
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.data.enums.LoginType
import pl.szczodrzynski.edziennik.ext.DAY
import pl.szczodrzynski.edziennik.ext.MS
import pl.szczodrzynski.edziennik.ext.putExtras
import pl.szczodrzynski.edziennik.ext.setLanguage
import pl.szczodrzynski.edziennik.network.SSLProviderInstaller
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.sync.UpdateWorker
import pl.szczodrzynski.edziennik.ui.base.CrashActivity
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.utils.DebugLogFormat
import pl.szczodrzynski.edziennik.utils.PermissionChecker
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.managers.AttendanceManager
@ -69,6 +67,7 @@ import pl.szczodrzynski.edziennik.utils.managers.NoteManager
import pl.szczodrzynski.edziennik.utils.managers.NotificationChannelsManager
import pl.szczodrzynski.edziennik.utils.managers.PermissionManager
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager
import pl.szczodrzynski.edziennik.utils.managers.UiManager
import pl.szczodrzynski.edziennik.utils.managers.TimetableManager
import pl.szczodrzynski.edziennik.utils.managers.UpdateManager
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
@ -107,6 +106,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
val permissionManager by lazy { PermissionManager(this) }
val textStylingManager by lazy { TextStylingManager(this) }
val timetableManager by lazy { TimetableManager(this) }
val uiManager by lazy { UiManager(this) }
val updateManager by lazy { UpdateManager(this) }
val userActionManager by lazy { UserActionManager(this) }
@ -124,7 +124,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun getWorkManagerConfiguration() = Configuration.Builder()
override val workManagerConfiguration: Configuration = Configuration.Builder()
.setMinimumLoggingLevel(Log.VERBOSE)
.build()
@ -210,10 +211,13 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
// initialize companion object values
AppData.read(this)
App.db = AppDb(this)
App.config = Config(App.db)
App.config = Config(this)
App.config.migrate()
debugMode = BuildConfig.DEBUG
devMode = config.devMode ?: debugMode
enableChucker = config.enableChucker ?: devMode
uiManager.applyNightMode()
uiManager.applyLanguage(this)
if (devMode) {
HyperLog.initialize(this)
@ -229,18 +233,11 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
buildHttp()
Themes.themeInt = config.ui.theme
config.ui.language?.let {
setLanguage(it)
}
Signing.getCert(this)
Utils.initializeStorageDir(this)
launch {
withContext(Dispatchers.Default) {
config.migrate(this@App)
SSLProviderInstaller.install(applicationContext, this@App::buildHttp)
if (config.devModePassword != null)
@ -426,8 +423,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
// apply newly-added config overrides, if not changed by the user yet
for ((key, value) in App.data.configOverrides) {
val config = App.profile.config
if (!config.has(key))
config.set(key, value)
if (key !in config)
config[key] = value
}
} catch (e: Exception) {
Log.e("App", "Cannot load AppData", e)

View File

@ -15,10 +15,12 @@ import android.view.Gravity
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
import androidx.navigation.NavOptions
import com.danimahardhika.cafebar.CafeBar
import com.danimahardhika.cafebar.CafeBarTheme
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jetradarmobile.snowfall.SnowfallView
import com.mikepenz.iconics.IconicsDrawable
@ -39,9 +41,8 @@ import pl.szczodrzynski.edziennik.data.api.events.*
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
@ -49,8 +50,8 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.sync.UpdateStateEvent
import pl.szczodrzynski.edziennik.sync.UpdateWorker
import pl.szczodrzynski.edziennik.ui.base.MainSnackbar
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
import pl.szczodrzynski.edziennik.ui.base.enums.NavTargetLocation
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.data.enums.NavTargetLocation
import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
@ -66,19 +67,16 @@ import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
import pl.szczodrzynski.edziennik.utils.*
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.*
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import pl.szczodrzynski.navlib.drawer.NavDrawer
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
import java.io.IOException
import java.util.*
import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
@ -127,12 +125,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
d(TAG, "Activity created")
setTheme(Themes.appTheme)
app.config.ui.language?.let {
setLanguage(it)
}
app.uiManager.applyTheme(this)
app.uiManager.applyLanguage(this)
app.buildManager.validateBuild(this)
if (App.profileId == 0) {
@ -148,10 +142,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
val versionBadge = app.buildManager.versionBadge
b.nightlyText.isVisible = versionBadge != null
b.nightlyText.text = versionBadge
navView.nightlyText.isVisible = versionBadge != null
navView.nightlyText.text = versionBadge
if (versionBadge != null) {
b.nightlyText.background.setTintColor(0xa0ff0000.toInt())
navView.nightlyText.background.setTintColor(0xa0ff0000.toInt())
}
navLoading = true
@ -159,51 +153,31 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
b.navView.apply {
drawer.init(this@MainActivity)
SystemBarsUtil(this@MainActivity).run {
//paddingByKeyboard = b.navView
appFullscreen = false
statusBarColor = getColorFromAttr(context, android.R.attr.colorBackground)
statusBarDarker = false
statusBarFallbackLight = COLOR_HALF_TRANSPARENT
statusBarFallbackGradient = COLOR_HALF_TRANSPARENT
navigationBarTransparent = false
b.navView.configSystemBarsUtil(this)
// fix for setting status bar color to window color, outside of navlib
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = statusBarColor
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ColorUtils.calculateLuminance(statusBarColor) > 0.6
) {
@Suppress("deprecation")
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
// TODO fix navlib navbar detection, orientation change issues, status bar color setting if not fullscreen
commit()
val statusBarColor = getColorFromAttr(context, android.R.attr.colorBackground)
// fix for setting status bar color to window color, outside of navlib
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = statusBarColor
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ColorUtils.calculateLuminance(statusBarColor) > 0.6
) {
@Suppress("deprecation")
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
enable = true
enableMenuControls = true
}
bottomBar.apply {
enable = false
enableMenuControls = false
fabEnable = false
fabExtendable = true
fabExtended = false
fabGravity = Gravity.CENTER
if (Themes.isDark) {
setBackgroundColor(blendColors(
getColorFromAttr(context, R.attr.colorSurface),
getColorFromRes(R.color.colorSurface_4dp)
))
elevation = dpToPx(4).toFloat()
}
fabGravity = Gravity.END
}
bottomSheet.apply {
@ -226,7 +200,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (item is ExpandableDrawerItem)
false
else
navigate(navTarget = id.asNavTargetOrNull())
navigate(navTarget = NavTarget.getById(id))
}
drawerProfileSelectedListener = { id, _, _, _ ->
// why is this negated -_-
@ -358,6 +332,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (app.config.appRateSnackbarTime != 0L && app.config.appRateSnackbarTime <= System.currentTimeMillis()) {
navView.coordinator.postDelayed({
CafeBar.builder(this)
.theme(CafeBarTheme.Custom(getColorFromAttr(this, R.attr.colorSurfaceInverse)))
.content(R.string.rate_snackbar_text)
.icon(IconicsDrawable(this).apply {
icon = CommunityMaterial.Icon3.cmd_star_outline
@ -417,7 +392,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
private var profileSettingClickListener = { itemId: Int, _: View? ->
when (val item = itemId.asNavTarget()) {
when (val item = NavTarget.getById(itemId)) {
NavTarget.PROFILE_ADD -> {
requestHandler.requestLogin()
}
@ -560,8 +535,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
swipeRefreshLayout.isRefreshing = true
if (event.profileId == App.profileId) {
navView.toolbar.apply {
subtitleFormat = null
subtitleFormatWithUnread = null
subtitle = getString(R.string.toolbar_subtitle_syncing)
}
}
@ -579,8 +552,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
if (event.profileId == App.profileId) {
navView.toolbar.apply {
subtitleFormat = null
subtitleFormatWithUnread = null
subtitle = if (event.progress < 0f)
event.progressText ?: ""
else
@ -599,8 +570,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
EventBus.getDefault().removeStickyEvent(event)
if (event.profileId == App.profileId) {
navView.toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
subtitle = "Gotowe"
}
}
@ -621,8 +590,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
ErrorDetailsDialog(this, listOf(event.error)).show()
}
navView.toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
subtitle = "Gotowe"
}
mainSnackbar.dismiss()
@ -705,7 +672,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
d(TAG, "}")
val intentProfileId = extras.getIntOrNull("profileId").takePositive()
var intentNavTarget = extras.getIntOrNull("fragmentId").asNavTargetOrNull()
var intentNavTarget = extras.getEnum<NavTarget>("fragmentId")
if (extras?.containsKey("action") == true) {
val handled = when (extras.getString("action")) {
@ -808,7 +775,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (arguments != null)
intent.putExtras(arguments)
if (navTarget != null) {
intent.putExtra("fragmentId", navTarget.id)
intent.putExtras("fragmentId" to navTarget)
}
finish()
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
@ -829,7 +796,12 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
d(TAG, "Activity resumed")
val filter = IntentFilter()
filter.addAction(Intent.ACTION_MAIN)
registerReceiver(intentReceiver, filter)
ContextCompat.registerReceiver(
this,
intentReceiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
EventBus.getDefault().register(this)
super.onResume()
}
@ -984,7 +956,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
d("NavDebug", "Navigating from ${this.navTarget.name} to ${navTarget.name}")
val fragment = navTarget.fragmentClass?.newInstance() ?: return
val fragment = navTarget.fragmentClass?.getDeclaredConstructor()?.newInstance() ?: return
fragment.arguments = arguments
val transaction = fragmentManager.beginTransaction()
@ -1052,7 +1024,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// TASK DESCRIPTION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val bm = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
val bm = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_v5)
@Suppress("deprecation")
val taskDesc = ActivityManager.TaskDescription(
@ -1061,7 +1033,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
else
getString(R.string.app_task_format, getString(navTarget.nameRes)),
bm,
getColorFromAttr(this, R.attr.colorSurface)
getColorFromAttr(this, R.attr.colorPrimary)
)
setTaskDescription(taskDesc)
}
@ -1105,9 +1077,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fun gainAttention() {
if (app.config.ui.bottomSheetOpened)
return
b.navView.postDelayed({
navView.gainAttentionOnBottomBar()
}, 2000)
}
fun gainAttentionFAB() {

View File

@ -1,48 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.ext.takePositive
import kotlin.coroutines.CoroutineContext
abstract class BaseConfig(
@Transient
val db: AppDb,
val profileId: Int? = null,
protected var entries: List<ConfigEntry>? = null,
) : CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Default
val values = hashMapOf<String, String?>()
init {
if (entries == null)
entries = db.configDao().getAllNow()
values.clear()
for ((profileId, key, value) in entries!!) {
if (profileId.takePositive() != this.profileId)
continue
values[key] = value
}
}
fun set(key: String, value: String?) {
values[key] = value
launch(Dispatchers.IO) {
db.configDao().add(ConfigEntry(profileId ?: -1, key, value))
}
}
fun has(key: String) = values.containsKey(key)
}

View File

@ -1,63 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.config.utils.*
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
import pl.szczodrzynski.edziennik.data.db.AppDb
@Suppress("RemoveExplicitTypeArguments")
class Config(db: AppDb) : BaseConfig(db) {
companion object {
const val DATA_VERSION = 12
}
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
val ui by lazy { ConfigUI(this) }
val sync by lazy { ConfigSync(this) }
val timetable by lazy { ConfigTimetable(this) }
val grades by lazy { ConfigGrades(this) }
var dataVersion by config<Int>(DATA_VERSION)
var hash by config<String>("")
var lastProfileId by config<Int>(0)
var loginFinished by config<Boolean>(false)
var privacyPolicyAccepted by config<Boolean>(false)
var update by config<Update?>(null)
var updatesChannel by config<String>("release")
var devMode by config<Boolean?>("debugMode", null)
var devModePassword by config<String?>(null)
var enableChucker by config<Boolean?>(null)
var apiAvailabilityCheck by config<Boolean>(true)
var apiInvalidCert by config<String?>(null)
var apiKeyCustom by config<String?>(null)
var appInstalledTime by config<Long>(0L)
var appRateSnackbarTime by config<Long>(0L)
var appVersion by config<Int>(BuildConfig.VERSION_CODE)
var validation by config<String?>(null, "buildValidation")
var archiverEnabled by config<Boolean>(true)
var runSync by config<Boolean>(false)
var widgetConfigs by config<JsonObject> { JsonObject() }
fun migrate(app: App) {
if (dataVersion < DATA_VERSION || hash == "")
// migrate old data version OR freshly installed app (or updated from 3.x)
ConfigMigration(app, this)
}
operator fun get(profileId: Int): ProfileConfig {
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also {
profileConfigs[profileId] = it
}
}
}

View File

@ -1,13 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
@Suppress("RemoveExplicitTypeArguments")
class ConfigGrades(base: Config) {
var orderBy by base.config<Int>("gradesOrderBy", ORDER_BY_DATE_DESC)
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
import pl.szczodrzynski.edziennik.ext.HOUR
import pl.szczodrzynski.edziennik.utils.models.Time
@Suppress("RemoveExplicitTypeArguments")
class ConfigSync(base: Config) {
var enabled by base.config<Boolean>("syncEnabled", true)
var interval by base.config<Int>("syncInterval", 1 * HOUR.toInt())
var onlyWifi by base.config<Boolean>("syncOnlyWifi", false)
var dontShowAppManagerDialog by base.config<Boolean>(false)
var lastAppSync by base.config<Long>(0L)
var notifyAboutUpdates by base.config<Boolean>(true)
var webPushEnabled by base.config<Boolean>(true)
// Quiet Hours
var quietHoursEnabled by base.config<Boolean>(false)
var quietHoursStart by base.config<Time?>(null)
var quietHoursEnd by base.config<Time?>(null)
var quietDuringLessons by base.config<Boolean>(false)
// FCM Tokens
var tokenApp by base.config<String?>(null)
var tokenMobidziennik by base.config<String?>(null)
var tokenLibrus by base.config<String?>(null)
var tokenVulcan by base.config<String?>(null)
var tokenVulcanHebe by base.config<String?>(null)
var tokenMobidziennikList by base.config<List<Int>> { listOf() }
var tokenLibrusList by base.config<List<Int>> { listOf() }
var tokenVulcanList by base.config<List<Int>> { listOf() }
var tokenVulcanHebeList by base.config<List<Int>> { listOf() }
// Register Availability
private var registerAvailabilityMap by base.config<Map<String, RegisterAvailabilityStatus>>("registerAvailability") { mapOf() }
private var registerAvailabilityFlavor by base.config<String?>(null)
var registerAvailability: Map<String, RegisterAvailabilityStatus>
get() {
if (BuildConfig.FLAVOR != registerAvailabilityFlavor)
return mapOf()
return registerAvailabilityMap
}
set(value) {
registerAvailabilityMap = value
registerAvailabilityFlavor = BuildConfig.FLAVOR
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.utils.models.Time
@Suppress("RemoveExplicitTypeArguments")
class ConfigTimetable(base: Config) {
var bellSyncMultiplier by base.config<Int>(0)
var bellSyncDiff by base.config<Time?>(null)
var countInSeconds by base.config<Boolean>(false)
}

View File

@ -1,35 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
@Suppress("RemoveExplicitTypeArguments")
class ConfigUI(base: Config) {
var theme by base.config<Int>(1)
var language by base.config<String?>(null)
var appBackground by base.config<String?>("appBg", null)
var headerBackground by base.config<String?>("headerBg", null)
var miniMenuVisible by base.config<Boolean>(false)
var miniMenuButtons by base.config<Set<NavTarget>> {
setOf(
NavTarget.HOME,
NavTarget.TIMETABLE,
NavTarget.AGENDA,
NavTarget.GRADES,
NavTarget.MESSAGES,
NavTarget.HOMEWORK,
NavTarget.SETTINGS
)
}
var openDrawerOnBackPressed by base.config<Boolean>(false)
var bottomSheetOpened by base.config<Boolean>(false)
var snowfall by base.config<Boolean>(false)
var eggfall by base.config<Boolean>(false)
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
import pl.szczodrzynski.edziennik.config.utils.ProfileConfigMigration
import pl.szczodrzynski.edziennik.data.db.AppDb
@Suppress("RemoveExplicitTypeArguments")
class ProfileConfig(
db: AppDb,
profileId: Int,
entries: List<ConfigEntry>?,
) : BaseConfig(db, profileId, entries) {
companion object {
const val DATA_VERSION = 5
}
val grades by lazy { ProfileConfigGrades(this) }
val ui by lazy { ProfileConfigUI(this) }
val sync by lazy { ProfileConfigSync(this) }
val attendance by lazy { ProfileConfigAttendance(this) }
/*
val timetable by lazy { ConfigTimetable(this) }
val grades by lazy { ConfigGrades(this) }*/
var dataVersion by config<Int>(DATA_VERSION)
var hash by config<String>("")
var shareByDefault by config<Boolean>(false)
init {
if (dataVersion < DATA_VERSION)
ProfileConfigMigration(this)
}
}

View File

@ -1,14 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-29.
*/
package pl.szczodrzynski.edziennik.config
@Suppress("RemoveExplicitTypeArguments")
class ProfileConfigAttendance(base: ProfileConfig) {
var attendancePageSelection by base.config<Int>(1)
var groupConsecutiveDays by base.config<Boolean>(true)
var showPresenceInMonth by base.config<Boolean>(false)
var useSymbols by base.config<Boolean>(false)
}

View File

@ -1,22 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
@Suppress("RemoveExplicitTypeArguments")
class ProfileConfigGrades(base: ProfileConfig) {
var averageWithoutWeight by base.config<Boolean>(true)
var colorMode by base.config<Int>(COLOR_MODE_WEIGHTED)
var dontCountEnabled by base.config<Boolean>(false)
var dontCountGrades by base.config<List<String>> { listOf() }
var hideImproved by base.config<Boolean>(false)
var hideSticksFromOld by base.config<Boolean>(false)
var minusValue by base.config<Float?>(null)
var plusValue by base.config<Float?>(null)
var yearAverageMode by base.config<Int>(YEAR_ALL_GRADES)
}

View File

@ -1,17 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-2-21.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
@Suppress("RemoveExplicitTypeArguments")
class ProfileConfigSync(base: ProfileConfig) {
var notificationFilter by base.config<Set<NotificationType>> {
NotificationType.values()
.filter { it.enabledByDefault == false }
.toSet()
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
@Suppress("RemoveExplicitTypeArguments")
class ProfileConfigUI(base: ProfileConfig) {
var agendaViewType by base.config<Int>(AGENDA_DEFAULT)
var agendaCompactMode by base.config<Boolean>(false)
var agendaGroupByType by base.config<Boolean>(false)
var agendaLessonChanges by base.config<Boolean>(true)
var agendaTeacherAbsence by base.config<Boolean>(true)
var agendaSubjectImportant by base.config<Boolean>(false)
var agendaElearningMark by base.config<Boolean>(false)
var agendaElearningGroup by base.config<Boolean>(true)
var homeCards by base.config<List<HomeCardModel>> { listOf() }
var messagesGreetingOnCompose by base.config<Boolean>(true)
var messagesGreetingOnReply by base.config<Boolean>(true)
var messagesGreetingOnForward by base.config<Boolean>(false)
var messagesGreetingText by base.config<String?>(null)
var timetableShowAttendance by base.config<Boolean>(true)
var timetableShowEvents by base.config<Boolean>(true)
var timetableTrimHourRange by base.config<Boolean>(false)
var timetableColorSubjectName by base.config<Boolean>(false)
}

View File

@ -1,92 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-19.
*/
package pl.szczodrzynski.edziennik.config.utils
import android.content.SharedPreferences
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.config.Config
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.asNavTargetOrNull
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
import pl.szczodrzynski.edziennik.utils.models.Time
import kotlin.math.abs
class AppConfigMigrationV3(p: SharedPreferences, config: Config) {
init {
val s = "app.appConfig"
config.apply {
ui.theme = p.getString("$s.appTheme", null)?.toIntOrNull() ?: 1
sync.enabled = p.getString("$s.registerSyncEnabled", null)?.toBoolean() ?: true
sync.interval = p.getString("$s.registerSyncInterval", null)?.toIntOrNull() ?: 3600
val oldButtons = p.getString("$s.miniDrawerButtonIds", null)?.let { str ->
str.replace("[\\[\\]]*".toRegex(), "")
.split(",\\s?".toRegex())
.mapNotNull { it.toIntOrNull().asNavTargetOrNull() }
.toSet()
}
ui.miniMenuButtons = oldButtons ?: setOf(
NavTarget.HOME,
NavTarget.TIMETABLE,
NavTarget.AGENDA,
NavTarget.GRADES,
NavTarget.MESSAGES,
NavTarget.HOMEWORK,
NavTarget.SETTINGS
)
devModePassword = p.getString("$s.devModePassword", null).fix()
sync.tokenApp = p.getString("$s.fcmToken", null).fix()
timetable.bellSyncMultiplier = p.getString("$s.bellSyncMultiplier", null)?.toIntOrNull() ?: 0
appRateSnackbarTime = p.getString("$s.appRateSnackbarTime", null)?.toLongOrNull() ?: 0
timetable.countInSeconds = p.getString("$s.countInSeconds", null)?.toBoolean() ?: false
ui.headerBackground = p.getString("$s.headerBackground", null).fix()
ui.appBackground = p.getString("$s.appBackground", null).fix()
ui.language = p.getString("$s.language", null).fix()
appVersion = p.getString("$s.lastAppVersion", null)?.toIntOrNull() ?: BuildConfig.VERSION_CODE
appInstalledTime = p.getString("$s.appInstalledTime", null)?.toLongOrNull() ?: 0
grades.orderBy = p.getString("$s.gradesOrderBy", null)?.toIntOrNull() ?: 0
sync.quietDuringLessons = p.getString("$s.quietDuringLessons", null)?.toBoolean() ?: false
ui.miniMenuVisible = p.getString("$s.miniDrawerVisible", null)?.toBoolean() ?: false
loginFinished = p.getString("$s.loginFinished", null)?.toBoolean() ?: false
sync.onlyWifi = p.getString("$s.registerSyncOnlyWifi", null)?.toBoolean() ?: false
sync.notifyAboutUpdates = p.getString("$s.notifyAboutUpdates", null)?.toBoolean() ?: true
timetable.bellSyncDiff = p.getString("$s.bellSyncDiff", null)?.let { Gson().fromJson(it, Time::class.java) }
val startMillis = p.getString("$s.quietHoursStart", null)?.toLongOrNull() ?: 0
val endMillis = p.getString("$s.quietHoursEnd", null)?.toLongOrNull() ?: 0
if (startMillis > 0) {
try {
sync.quietHoursStart = Time.fromMillis(abs(startMillis))
sync.quietHoursEnd = Time.fromMillis(abs(endMillis))
sync.quietHoursEnabled = true
}
catch (_: Exception) {}
}
else {
sync.quietHoursEnabled = false
sync.quietHoursStart = null
sync.quietHoursEnd = null
}
sync.tokenMobidziennikList = listOf()
sync.tokenVulcanList = listOf()
sync.tokenLibrusList = listOf()
val tokens = p.getString("$s.fcmTokens", null)?.let { Gson().fromJson<Map<Int, Pair<String, List<Int>>>>(it, object: TypeToken<Map<Int, Pair<String, List<Int>>>>(){}.type) }
tokens?.forEach {
val token = it.value.first
when (it.key) {
LoginType.MOBIDZIENNIK.id -> sync.tokenMobidziennik = token
LoginType.VULCAN.id -> sync.tokenVulcan = token
LoginType.LIBRUS.id -> sync.tokenLibrus = token
}
}
}
}
private fun String?.fix(): String? {
return this?.replace("\"", "")?.let { if (it == "null") null else it }
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config.utils
import android.content.Context
import androidx.core.content.edit
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.config.Config
import pl.szczodrzynski.edziennik.utils.models.Time
import kotlin.math.abs
class ConfigMigration(app: App, config: Config) {
init { config.apply {
val p = app.getSharedPreferences("pl.szczodrzynski.edziennik_profiles", Context.MODE_PRIVATE)
if (p.contains("app.appConfig.appTheme")) {
// migrate appConfig from app version 3.x and lower.
// Updates dataVersion to level 2.
AppConfigMigrationV3(p, config)
p.edit {
remove("app.appConfig.appTheme")
}
}
if (dataVersion < 11) {
val startMillis = config.values["quietHoursStart"]?.toLongOrNull() ?: 0L
val endMillis = config.values["quietHoursEnd"]?.toLongOrNull() ?: 0L
if (startMillis > 0) {
try {
sync.quietHoursStart = Time.fromMillis(abs(startMillis))
sync.quietHoursEnd = Time.fromMillis(abs(endMillis))
sync.quietHoursEnabled = true
}
catch (_: Exception) {}
}
else {
sync.quietHoursEnabled = false
sync.quietHoursStart = null
sync.quietHoursEnd = null
}
dataVersion = 11
}
hash = "invalid"
}}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-1.
*/
package pl.szczodrzynski.edziennik.config.utils
import pl.szczodrzynski.edziennik.config.ProfileConfig
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
import pl.szczodrzynski.edziennik.data.db.enums.SchoolType
import pl.szczodrzynski.edziennik.ui.home.HomeCard
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
class ProfileConfigMigration(config: ProfileConfig) {
init { config.apply {
val profile = db.profileDao().getByIdNow(profileId ?: -1)
if (dataVersion < 2) {
sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE
dataVersion = 2
}
if (dataVersion < 3) {
if (ui.homeCards.isNotEmpty()) {
ui.homeCards = ui.homeCards + HomeCardModel(
profileId = config.profileId ?: -1,
cardId = HomeCard.CARD_NOTES,
)
}
dataVersion = 3
}
if (dataVersion < 4) {
// switch to new event types (USOS)
dataVersion = 4
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
db.eventTypeDao().clear(profileId ?: -1)
db.eventTypeDao().addDefaultTypes(profile)
}
}
if (dataVersion < 5) {
// update USOS event types and the appropriate events (2022-12-25)
dataVersion = 5
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
db.eventTypeDao().getAllWithDefaults(profile)
// wejściówka (4) -> kartkówka (3)
db.eventDao().getRawNow("UPDATE events SET eventType = 3 WHERE profileId = $profileId AND eventType = 4;")
// zadanie (6) -> zadanie domowe (-1)
db.eventDao().getRawNow("UPDATE events SET eventType = -1 WHERE profileId = $profileId AND eventType = 6;")
}
}
}}
}

View File

@ -5,10 +5,8 @@ import pl.szczodrzynski.edziennik.data.api.models.Feature
import pl.szczodrzynski.edziennik.data.db.entity.EndpointTimer
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_NEVER
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.getFeatureTypesNecessary
import pl.szczodrzynski.edziennik.ext.getFeatureTypesUnnecessary
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
fun Data.prepare(
@ -28,8 +26,8 @@ fun Data.prepare(
val syncFeatureTypes = when {
featureTypes.isNotNullNorEmpty() -> featureTypes!!
else -> getFeatureTypesUnnecessary()
} + getFeatureTypesNecessary()
else -> FeatureType.getUnnecessary()
} + FeatureType.getNecessary()
val forceFeatureType = featureTypes?.singleOrNull()
this.targetEndpoints.clear()

View File

@ -23,8 +23,8 @@ import pl.szczodrzynski.edziennik.data.api.task.IApiTask
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.LoginType
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull

View File

@ -7,7 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik
import android.content.Intent
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.data.enums.LoginType
import pl.szczodrzynski.edziennik.ext.Intent
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.models.Date

View File

@ -8,7 +8,7 @@ import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.models.Data
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.data.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty

View File

@ -24,8 +24,8 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.LoginMethod
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull

View File

@ -5,9 +5,9 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
import pl.szczodrzynski.edziennik.data.api.models.Feature
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.LoginMethod
import pl.szczodrzynski.edziennik.data.enums.LoginType
const val ENDPOINT_LIBRUS_API_ME = 1001
const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002

View File

@ -12,7 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus,

View File

@ -11,7 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.utils.models.Date

View File

@ -12,7 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.utils.models.Date

View File

@ -14,7 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.utils.models.Date
import java.text.DecimalFormat

View File

@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_TEXT
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.utils.models.Date

View File

@ -13,7 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time

Some files were not shown because too many files have changed in this diff Show More