forked from github/wulkanowy-mirror
Merge branch 'release/0.11.0'
This commit is contained in:
commit
8f617f4ca1
@ -98,7 +98,7 @@ jobs:
|
||||
command: yes | sdkmanager --licenses && yes | sdkmanager --update
|
||||
- run:
|
||||
name: Setup emulator
|
||||
command: sdkmanager "system-images;android-19;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-19;default;armeabi-v7a"
|
||||
command: sdkmanager "system-images;android-22;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-22;default;armeabi-v7a"
|
||||
- run:
|
||||
name: Launch emulator
|
||||
command: export LD_LIBRARY_PATH=${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib && emulator64-arm -avd test -noaudio -no-boot-anim -no-window -accel on
|
||||
@ -116,7 +116,7 @@ jobs:
|
||||
adb shell input keyevent 82
|
||||
- run:
|
||||
name: Run instrumented tests
|
||||
command: ./gradlew clean createPlayDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||
command: ./gradlew clean createFdroidDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex
|
||||
- run:
|
||||
name: Collect logs from emulator
|
||||
command: adb logcat -d > ./app/build/reports/logcat_emulator.txt
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -110,4 +110,5 @@ Thumbs.db
|
||||
|
||||
### AndroidStudio Patch ###
|
||||
|
||||
!/gradle/wrapper/gradle-wrapper.jar
|
||||
!/gradle/wrapper/gradle-wrapper.jar
|
||||
.idea/jarRepositories.xml
|
||||
|
3
.idea/codeStyles/Project.xml
generated
3
.idea/codeStyles/Project.xml
generated
@ -1,6 +1,9 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="LINE_SEPARATOR" value=" " />
|
||||
<AndroidXmlCodeStyleSettings>
|
||||
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
|
||||
</AndroidXmlCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
|
14
.travis.yml
14
.travis.yml
@ -3,8 +3,8 @@ jdk: oraclejdk8
|
||||
|
||||
env:
|
||||
global:
|
||||
- ANDROID_API_LEVEL=28
|
||||
- ANDROID_BUILD_TOOLS_VERSION=28.0.3
|
||||
- ANDROID_API_LEVEL=29
|
||||
- ANDROID_BUILD_TOOLS_VERSION=29.0.2
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@ -14,7 +14,7 @@ cache:
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- 0.10.2
|
||||
- 0.11.0
|
||||
|
||||
android:
|
||||
licenses:
|
||||
@ -34,12 +34,12 @@ android:
|
||||
- extra-android-m2repository
|
||||
- addon-google_apis-google-$ANDROID_API_LEVEL
|
||||
# Android emulator
|
||||
- android-19
|
||||
- sys-img-armeabi-v7a-android-19
|
||||
- android-22
|
||||
- sys-img-armeabi-v7a-android-22
|
||||
|
||||
before_script:
|
||||
# Launch emulator before the execution
|
||||
- echo no | android create avd --force -n test -t android-19 --abi armeabi-v7a
|
||||
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
|
||||
- emulator -avd test -no-audio -no-window &
|
||||
- android-wait-for-emulator
|
||||
- adb shell input keyevent 82 &
|
||||
@ -50,7 +50,7 @@ script:
|
||||
- fossa --no-ansi || true
|
||||
#- ./gradlew lintPlayRelease -x fabricGenerateResourcesPlayRelease --stacktrace --daemon
|
||||
- ./gradlew testPlayDebugUnitTest -x fabricGenerateResourcesPlay --stacktrace --daemon
|
||||
- ./gradlew createPlayDebugCoverageReport --stacktrace --daemon
|
||||
- ./gradlew createFdroidDebugCoverageReport --stacktrace --daemon
|
||||
- ./gradlew jacocoTestReport --stacktrace --daemon
|
||||
- if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else
|
||||
git fetch --unshallow;
|
||||
|
@ -4,8 +4,8 @@
|
||||
[](https://travis-ci.com/wulkanowy/wulkanowy)
|
||||
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||
[](https://discord.gg/vccAQBr)
|
||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||
|
||||
Unofficial android VULCAN UONET+ register client for student and parent
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
[](https://travis-ci.com/wulkanowy/wulkanowy)
|
||||
[](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||
[](https://discord.gg/vccAQBr)
|
||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||
[](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||
[](https://github.com/wulkanowy/wulkanowy/releases)
|
||||
|
||||
Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
||||
|
||||
|
@ -9,16 +9,16 @@ apply from: 'sonarqube.gradle'
|
||||
apply from: 'hooks.gradle'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.2'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "io.github.wulkanowy"
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionCode 45
|
||||
versionName "0.10.2"
|
||||
targetSdkVersion 29
|
||||
versionCode 46
|
||||
versionName "0.11.0"
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@ -28,8 +28,10 @@ android {
|
||||
]
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = ["room.schemaLocation": "$projectDir/schemas".toString(),
|
||||
"room.incremental" : "true"]
|
||||
arguments = [
|
||||
"room.schemaLocation": "$projectDir/schemas".toString(),
|
||||
"room.incremental" : "true"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,7 +63,6 @@ android {
|
||||
versionNameSuffix "-dev"
|
||||
testCoverageEnabled = true
|
||||
ext.enableCrashlytics = project.hasProperty("enableCrashlytics")
|
||||
multiDexKeepProguard file('proguard-multidex-rules.pro')
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +115,6 @@ ext {
|
||||
dagger = "2.24"
|
||||
chucker = "2.0.4"
|
||||
mockk = "1.9.2"
|
||||
mockito_core = "3.0.7"
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@ -123,7 +123,7 @@ configurations.all {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:api:0.10.2"
|
||||
implementation "io.github.wulkanowy:api:0.11.0"
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "androidx.core:core-ktx:1.1.0"
|
||||
@ -167,13 +167,13 @@ dependencies {
|
||||
|
||||
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6"
|
||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||
implementation "io.reactivex.rxjava2:rxjava:2.2.12"
|
||||
implementation "io.reactivex.rxjava2:rxjava:2.2.13"
|
||||
|
||||
implementation "com.google.code.gson:gson:2.8.5"
|
||||
implementation "com.google.code.gson:gson:2.8.6"
|
||||
implementation "com.jakewharton.threetenabp:threetenabp:1.2.1"
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:3.12.4"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:3.12.6"
|
||||
implementation "com.mikepenz:aboutlibraries:7.0.3"
|
||||
|
||||
playImplementation "com.google.firebase:firebase-core:17.2.0"
|
||||
@ -187,10 +187,7 @@ dependencies {
|
||||
testImplementation "junit:junit:4.12"
|
||||
testImplementation "io.mockk:mockk:$mockk"
|
||||
testImplementation "org.threeten:threetenbp:1.4.0"
|
||||
testImplementation "org.mockito:mockito-core:$mockito_core"
|
||||
testImplementation("org.mockito:mockito-inline:3.0.7") {
|
||||
exclude group: "org.mockito", module: "mockito-core"
|
||||
}
|
||||
testImplementation "org.mockito:mockito-inline:3.1.0"
|
||||
|
||||
androidTestImplementation "androidx.test:core:1.2.0"
|
||||
androidTestImplementation "androidx.test:runner:1.2.0"
|
||||
@ -198,10 +195,7 @@ dependencies {
|
||||
androidTestImplementation "io.mockk:mockk-android:$mockk"
|
||||
androidTestImplementation "androidx.room:room-testing:$room"
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
androidTestImplementation "org.mockito:mockito-core:$mockito_core"
|
||||
androidTestImplementation("org.mockito:mockito-android:3.0.7") {
|
||||
exclude group: 'org.mockito', module: 'mockito-core'
|
||||
}
|
||||
androidTestImplementation "org.mockito:mockito-android:3.1.0"
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
@ -1,3 +0,0 @@
|
||||
-keep class android.support.test.internal** { *; }
|
||||
-keep class org.junit.** { *; }
|
||||
-keep public class io.github.wulkanowy** { *; }
|
1480
app/schemas/io.github.wulkanowy.data.db.AppDatabase/16.json
Normal file
1480
app/schemas/io.github.wulkanowy.data.db.AppDatabase/16.json
Normal file
File diff suppressed because it is too large
Load Diff
1530
app/schemas/io.github.wulkanowy.data.db.AppDatabase/17.json
Normal file
1530
app/schemas/io.github.wulkanowy.data.db.AppDatabase/17.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,12 +22,7 @@ abstract class AbstractMigrationTest {
|
||||
fun getMigratedRoomDatabase(): AppDatabase {
|
||||
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
|
||||
AppDatabase::class.java, dbName)
|
||||
.addMigrations(
|
||||
Migration12(),
|
||||
Migration13(),
|
||||
Migration14(),
|
||||
Migration15()
|
||||
)
|
||||
.addMigrations(*AppDatabase.getMigrations())
|
||||
.build()
|
||||
// close the database and release any stream resources when the test finishes
|
||||
helper.closeWhenFinished(database)
|
||||
|
@ -3,10 +3,14 @@ package io.github.wulkanowy.data.db.migrations
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.github.wulkanowy.data.db.Converters
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import org.threeten.bp.LocalDate.of
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class Migration13Test : AbstractMigrationTest() {
|
||||
@ -97,11 +101,9 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
|
||||
val db = helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
|
||||
val semesters1 = db.semesterDao.loadAll(1, 5).blockingGet()
|
||||
val semesters1 = getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 1 AND class_id = 5")
|
||||
assertTrue { semesters1.single { it.isCurrent }.isCurrent }
|
||||
semesters1[0].run {
|
||||
assertFalse(isCurrent)
|
||||
@ -119,7 +121,7 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
assertEquals(2, diaryId)
|
||||
}
|
||||
|
||||
db.semesterDao.loadAll(2, 5).blockingGet().let {
|
||||
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let {
|
||||
assertTrue { it.single { it.isCurrent }.isCurrent }
|
||||
assertEquals(1970, it[0].schoolYear)
|
||||
assertEquals(of(1970, 1, 1), it[0].end)
|
||||
@ -130,7 +132,7 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
assertTrue(it[3].isCurrent)
|
||||
}
|
||||
|
||||
db.semesterDao.loadAll(2, 5).blockingGet().let {
|
||||
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let {
|
||||
assertTrue { it.single { it.isCurrent }.isCurrent }
|
||||
assertFalse(it[0].isCurrent)
|
||||
assertFalse(it[1].isCurrent)
|
||||
@ -139,6 +141,30 @@ class Migration13Test : AbstractMigrationTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSemesters(db: SupportSQLiteDatabase, query: String): List<Semester> {
|
||||
val semesters = mutableListOf<Semester>()
|
||||
|
||||
val cursor = db.query(query)
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
semesters.add(Semester(
|
||||
studentId = cursor.getInt(1),
|
||||
diaryId = cursor.getInt(2),
|
||||
diaryName = cursor.getString(3),
|
||||
semesterId = cursor.getInt(4),
|
||||
semesterName = cursor.getInt(5),
|
||||
isCurrent = cursor.getInt(6) == 1,
|
||||
classId = cursor.getInt(7),
|
||||
unitId = cursor.getInt(8),
|
||||
schoolYear = cursor.getInt(9),
|
||||
start = Converters().timestampToDate(cursor.getLong(10))!!,
|
||||
end = Converters().timestampToDate(cursor.getLong(11))!!
|
||||
))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
return semesters.toList()
|
||||
}
|
||||
|
||||
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, schoolName: String = "", classId: Int = -1, schoolId: Int = 123) {
|
||||
db.insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
|
||||
put("endpoint", "https://fakelog.cf")
|
||||
|
@ -4,6 +4,7 @@ import androidx.room.Room
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import org.junit.After
|
||||
@ -24,7 +25,7 @@ class GradeStatisticsLocalTest {
|
||||
fun createDb() {
|
||||
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
|
||||
.build()
|
||||
gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradeStatistics)
|
||||
gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradeStatistics, testDb.gradePointsStatistics)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -63,7 +64,52 @@ class GradeStatisticsLocalTest {
|
||||
assertEquals(stats[0].subject, "Wszystkie")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveAndRead_points() {
|
||||
gradeStatisticsLocal.saveGradesPointsStatistics(listOf(
|
||||
getGradePointsStatistics("Matematyka", 2, 1),
|
||||
getGradePointsStatistics("Chemia", 2, 1),
|
||||
getGradePointsStatistics("Fizyka", 1, 2)
|
||||
))
|
||||
|
||||
val stats = gradeStatisticsLocal.getGradesPointsStatistics(
|
||||
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
"Matematyka"
|
||||
).blockingGet()
|
||||
with(stats) {
|
||||
assertEquals(subject, "Matematyka")
|
||||
assertEquals(others, 5.0)
|
||||
assertEquals(student, 5.0)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveAndRead_subjectEmpty() {
|
||||
gradeStatisticsLocal.saveGradesPointsStatistics(listOf())
|
||||
|
||||
val stats = gradeStatisticsLocal.getGradesPointsStatistics(
|
||||
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
"Matematyka"
|
||||
).blockingGet()
|
||||
assertEquals(null, stats)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveAndRead_allEmpty() {
|
||||
gradeStatisticsLocal.saveGradesPointsStatistics(listOf())
|
||||
|
||||
val stats = gradeStatisticsLocal.getGradesPointsStatistics(
|
||||
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
"Wszystkie"
|
||||
).blockingGet()
|
||||
assertEquals(null, stats)
|
||||
}
|
||||
|
||||
private fun getGradeStatistics(subject: String, studentId: Int, semesterId: Int): GradeStatistics {
|
||||
return GradeStatistics(studentId, semesterId, subject, 5, 5, false)
|
||||
}
|
||||
|
||||
private fun getGradePointsStatistics(subject: String, studentId: Int, semesterId: Int): GradePointsStatistics {
|
||||
return GradePointsStatistics(studentId, semesterId, subject, 5.0, 5.0)
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,10 @@ internal class RepositoryModule {
|
||||
@Provides
|
||||
fun provideGradeStatisticsDao(database: AppDatabase) = database.gradeStatistics
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGradePointsStatisticsDao(database: AppDatabase) = database.gradePointsStatistics
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideMessagesDao(database: AppDatabase) = database.messagesDao
|
||||
@ -136,4 +140,8 @@ internal class RepositoryModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideMobileDevicesDao(database: AppDatabase) = database.mobileDeviceDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTeacherDao(database: AppDatabase) = database.teacherDao
|
||||
}
|
||||
|
@ -6,11 +6,13 @@ import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeDao
|
||||
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||
import io.github.wulkanowy.data.db.dao.HomeworkDao
|
||||
@ -23,12 +25,14 @@ import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||
import io.github.wulkanowy.data.db.dao.TimetableDao
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
@ -41,6 +45,7 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.migrations.Migration10
|
||||
import io.github.wulkanowy.data.db.migrations.Migration11
|
||||
@ -48,6 +53,8 @@ import io.github.wulkanowy.data.db.migrations.Migration12
|
||||
import io.github.wulkanowy.data.db.migrations.Migration13
|
||||
import io.github.wulkanowy.data.db.migrations.Migration14
|
||||
import io.github.wulkanowy.data.db.migrations.Migration15
|
||||
import io.github.wulkanowy.data.db.migrations.Migration16
|
||||
import io.github.wulkanowy.data.db.migrations.Migration17
|
||||
import io.github.wulkanowy.data.db.migrations.Migration2
|
||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||
@ -70,6 +77,7 @@ import javax.inject.Singleton
|
||||
Grade::class,
|
||||
GradeSummary::class,
|
||||
GradeStatistics::class,
|
||||
GradePointsStatistics::class,
|
||||
Message::class,
|
||||
Note::class,
|
||||
Homework::class,
|
||||
@ -78,7 +86,8 @@ import javax.inject.Singleton
|
||||
CompletedLesson::class,
|
||||
ReportingUnit::class,
|
||||
Recipient::class,
|
||||
MobileDevice::class
|
||||
MobileDevice::class,
|
||||
Teacher::class
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
@ -87,29 +96,35 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 15
|
||||
const val VERSION_SCHEMA = 17
|
||||
|
||||
fun getMigrations(): Array<Migration> {
|
||||
return arrayOf(
|
||||
Migration2(),
|
||||
Migration3(),
|
||||
Migration4(),
|
||||
Migration5(),
|
||||
Migration6(),
|
||||
Migration7(),
|
||||
Migration8(),
|
||||
Migration9(),
|
||||
Migration10(),
|
||||
Migration11(),
|
||||
Migration12(),
|
||||
Migration13(),
|
||||
Migration14(),
|
||||
Migration15(),
|
||||
Migration16(),
|
||||
Migration17()
|
||||
)
|
||||
}
|
||||
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||
.setJournalMode(TRUNCATE)
|
||||
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
|
||||
.fallbackToDestructiveMigrationOnDowngrade()
|
||||
.addMigrations(
|
||||
Migration2(),
|
||||
Migration3(),
|
||||
Migration4(),
|
||||
Migration5(),
|
||||
Migration6(),
|
||||
Migration7(),
|
||||
Migration8(),
|
||||
Migration9(),
|
||||
Migration10(),
|
||||
Migration11(),
|
||||
Migration12(),
|
||||
Migration13(),
|
||||
Migration14(),
|
||||
Migration15()
|
||||
)
|
||||
.addMigrations(*getMigrations())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@ -132,6 +147,8 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
abstract val gradeStatistics: GradeStatisticsDao
|
||||
|
||||
abstract val gradePointsStatistics: GradePointsStatisticsDao
|
||||
|
||||
abstract val messagesDao: MessagesDao
|
||||
|
||||
abstract val noteDao: NoteDao
|
||||
@ -149,4 +166,6 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract val recipientDao: RecipientDao
|
||||
|
||||
abstract val mobileDeviceDao: MobileDeviceDao
|
||||
|
||||
abstract val teacherDao: TeacherDao
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface GradePointsStatisticsDao {
|
||||
|
||||
@Insert
|
||||
fun insertAll(gradesStatistics: List<GradePointsStatistics>)
|
||||
|
||||
@Delete
|
||||
fun deleteAll(gradesStatistics: List<GradePointsStatistics>)
|
||||
|
||||
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName")
|
||||
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Maybe<GradePointsStatistics>
|
||||
|
||||
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
|
||||
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradePointsStatistics>>
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface TeacherDao {
|
||||
|
||||
@Insert
|
||||
fun insertAll(devices: List<Teacher>)
|
||||
|
||||
@Delete
|
||||
fun deleteAll(devices: List<Teacher>)
|
||||
|
||||
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
|
||||
fun loadAll(studentId: Int, classId: Int): Maybe<List<Teacher>>
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "GradesPointsStatistics")
|
||||
data class GradePointsStatistics(
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
val studentId: Int,
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
val semesterId: Int,
|
||||
|
||||
val subject: String,
|
||||
|
||||
val others: Double,
|
||||
|
||||
val student: Double
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "Teachers")
|
||||
data class Teacher(
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
val studentId: Int,
|
||||
|
||||
@ColumnInfo(name = "class_id")
|
||||
val classId: Int,
|
||||
|
||||
val subject: String,
|
||||
|
||||
val name: String,
|
||||
|
||||
@ColumnInfo(name = "short_name")
|
||||
val shortName: String
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration16 : Migration(15, 16) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("""
|
||||
CREATE TABLE IF NOT EXISTS Teachers (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
student_id INTEGER NOT NULL,
|
||||
class_id INTEGER NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
short_name TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration17 : Migration(16, 17) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
createGradesPointsStatisticsTable(database)
|
||||
truncateSemestersTable(database)
|
||||
}
|
||||
|
||||
private fun createGradesPointsStatisticsTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("""
|
||||
CREATE TABLE IF NOT EXISTS GradesPointsStatistics(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
student_id INTEGER NOT NULL,
|
||||
semester_id INTEGER NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
others REAL NOT NULL,
|
||||
student REAL NOT NULL
|
||||
)
|
||||
""")
|
||||
}
|
||||
|
||||
private fun truncateSemestersTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DELETE FROM Semesters")
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package io.github.wulkanowy.data.repositories.gradestatistics
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
|
||||
import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Maybe
|
||||
@ -8,27 +10,57 @@ import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeStatisticsLocal @Inject constructor(private val gradeStatisticsDb: GradeStatisticsDao) {
|
||||
class GradeStatisticsLocal @Inject constructor(
|
||||
private val gradeStatisticsDb: GradeStatisticsDao,
|
||||
private val gradePointsStatisticsDb: GradePointsStatisticsDao
|
||||
) {
|
||||
|
||||
fun getGradesStatistics(semester: Semester, isSemester: Boolean): Maybe<List<GradeStatistics>> {
|
||||
return gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester)
|
||||
.filter { !it.isEmpty() }
|
||||
return gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester).filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun getGradesPointsStatistics(semester: Semester): Maybe<List<GradePointsStatistics>> {
|
||||
return gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun getGradesStatistics(semester: Semester, isSemester: Boolean, subjectName: String): Maybe<List<GradeStatistics>> {
|
||||
return (if ("Wszystkie" == subjectName) gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester).map { list ->
|
||||
list.groupBy { it.grade }.map {
|
||||
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key, it.value.fold(0) { acc, e -> acc + e.amount }, false)
|
||||
return when (subjectName) {
|
||||
"Wszystkie" -> gradeStatisticsDb.loadAll(semester.semesterId, semester.studentId, isSemester).map { list ->
|
||||
list.groupBy { it.grade }.map {
|
||||
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key,
|
||||
it.value.fold(0) { acc, e -> acc + e.amount }, false)
|
||||
}
|
||||
}
|
||||
else -> gradeStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName, isSemester)
|
||||
}.filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fun getGradesPointsStatistics(semester: Semester, subjectName: String): Maybe<GradePointsStatistics> {
|
||||
return when (subjectName) {
|
||||
"Wszystkie" -> gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId).flatMap { list ->
|
||||
if (list.isEmpty()) return@flatMap Maybe.empty<GradePointsStatistics>()
|
||||
Maybe.just(GradePointsStatistics(semester.studentId, semester.semesterId, subjectName,
|
||||
list.fold(.0) { acc, e -> acc + e.others },
|
||||
list.fold(.0) { acc, e -> acc + e.student })
|
||||
)
|
||||
}
|
||||
else -> gradePointsStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName)
|
||||
}
|
||||
else gradeStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName, isSemester)).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveGradesStatistics(gradesStatistics: List<GradeStatistics>) {
|
||||
gradeStatisticsDb.insertAll(gradesStatistics)
|
||||
}
|
||||
|
||||
fun saveGradesPointsStatistics(gradePointsStatistics: List<GradePointsStatistics>) {
|
||||
gradePointsStatisticsDb.insertAll(gradePointsStatistics)
|
||||
}
|
||||
|
||||
fun deleteGradesStatistics(gradesStatistics: List<GradeStatistics>) {
|
||||
gradeStatisticsDb.deleteAll(gradesStatistics)
|
||||
}
|
||||
|
||||
fun deleteGradesPointsStatistics(gradesPointsStatistics: List<GradePointsStatistics>) {
|
||||
gradePointsStatisticsDb.deleteAll(gradesPointsStatistics)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.github.wulkanowy.data.repositories.gradestatistics
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Single
|
||||
@ -12,7 +13,10 @@ class GradeStatisticsRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getGradeStatistics(semester: Semester, isSemester: Boolean): Single<List<GradeStatistics>> {
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getGradesStatistics(semester.semesterId, isSemester) }
|
||||
.flatMap {
|
||||
if (isSemester) it.getGradesAnnualStatistics(semester.semesterId)
|
||||
else it.getGradesPartialStatistics(semester.semesterId)
|
||||
}
|
||||
.map { gradeStatistics ->
|
||||
gradeStatistics.map {
|
||||
GradeStatistics(
|
||||
@ -26,4 +30,20 @@ class GradeStatisticsRemote @Inject constructor(private val api: Api) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getGradePointsStatistics(semester: Semester): Single<List<GradePointsStatistics>> {
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getGradesPointsStatistics(semester.semesterId) }
|
||||
.map { gradePointsStatistics ->
|
||||
gradePointsStatistics.map {
|
||||
GradePointsStatistics(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.subject,
|
||||
others = it.others,
|
||||
student = it.student
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package io.github.wulkanowy.data.repositories.gradestatistics
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
@ -31,4 +33,19 @@ class GradeStatisticsRepository @Inject constructor(
|
||||
}
|
||||
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
|
||||
}
|
||||
|
||||
fun getGradesPointsStatistics(semester: Semester, subjectName: String, forceRefresh: Boolean): Maybe<GradePointsStatistics> {
|
||||
return local.getGradesPointsStatistics(semester, subjectName).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMapMaybe {
|
||||
if (it) remote.getGradePointsStatistics(semester).toMaybe()
|
||||
else Maybe.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getGradesPointsStatistics(semester).defaultIfEmpty(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteGradesPointsStatistics(old.uniqueSubtract(new))
|
||||
local.saveGradesPointsStatistics(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getGradesPointsStatistics(semester, subjectName) })
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package io.github.wulkanowy.data.repositories.teacher
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
|
||||
class TeacherLocal @Inject constructor(private val teacherDb: TeacherDao) {
|
||||
fun saveTeachers(teachers: List<Teacher>) {
|
||||
teacherDb.insertAll(teachers)
|
||||
}
|
||||
|
||||
fun deleteTeachers(teachers: List<Teacher>) {
|
||||
teacherDb.deleteAll(teachers)
|
||||
}
|
||||
|
||||
fun getTeachers(semester: Semester): Maybe<List<Teacher>> {
|
||||
return teacherDb.loadAll(semester.studentId, semester.classId).filter { it.isNotEmpty() }
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.github.wulkanowy.data.repositories.teacher
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class TeacherRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getTeachers(semester: Semester): Single<List<Teacher>> {
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getTeachers() }
|
||||
.map { teachers ->
|
||||
teachers.map {
|
||||
Teacher(
|
||||
studentId = semester.studentId,
|
||||
name = it.name,
|
||||
subject = it.subject,
|
||||
shortName = it.short,
|
||||
classId = semester.classId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package io.github.wulkanowy.data.repositories.teacher
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import io.github.wulkanowy.utils.uniqueSubtract
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class TeacherRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: TeacherLocal,
|
||||
private val remote: TeacherRemote
|
||||
) {
|
||||
fun getTeachers(semester: Semester, forceRefresh: Boolean = false): Single<List<Teacher>> {
|
||||
return local.getTeachers(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getTeachers(semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getTeachers(semester).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteTeachers(old.uniqueSubtract(new))
|
||||
local.saveTeachers(new.uniqueSubtract(old))
|
||||
}
|
||||
}.flatMap { local.getTeachers(semester).toSingle(emptyList()) })
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import io.github.wulkanowy.services.sync.works.LuckyNumberWork
|
||||
import io.github.wulkanowy.services.sync.works.MessageWork
|
||||
import io.github.wulkanowy.services.sync.works.NoteWork
|
||||
import io.github.wulkanowy.services.sync.works.RecipientWork
|
||||
import io.github.wulkanowy.services.sync.works.TeacherWork
|
||||
import io.github.wulkanowy.services.sync.works.TimetableWork
|
||||
import io.github.wulkanowy.services.sync.works.Work
|
||||
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
||||
@ -75,6 +76,10 @@ abstract class ServicesModule {
|
||||
@IntoSet
|
||||
abstract fun provideTimetableWork(work: TimetableWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideTeacherWork(work: TeacherWork): Work
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideLuckyNumberWork(work: LuckyNumberWork): Work
|
||||
|
@ -0,0 +1,14 @@
|
||||
package io.github.wulkanowy.services.sync.works
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.teacher.TeacherRepository
|
||||
import io.reactivex.Completable
|
||||
import javax.inject.Inject
|
||||
|
||||
class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return teacherRepository.getTeachers(semester, true).ignoreElement()
|
||||
}
|
||||
}
|
@ -43,16 +43,17 @@ class ErrorDialog : DialogFragment() {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
StringWriter().let { writer ->
|
||||
error.printStackTrace(PrintWriter(writer))
|
||||
|
||||
errorDialogContent.text = writer.toString()
|
||||
errorDialogCopy.setOnClickListener {
|
||||
ClipData.newPlainText("wulkanowyError", writer.toString()).let { clip ->
|
||||
activity?.getSystemService<ClipboardManager>()?.primaryClip = clip
|
||||
}
|
||||
Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show()
|
||||
}
|
||||
val stringWriter = StringWriter().apply {
|
||||
error.printStackTrace(PrintWriter(this))
|
||||
}
|
||||
|
||||
errorDialogContent.text = stringWriter.toString()
|
||||
errorDialogCopy.setOnClickListener {
|
||||
val clip = ClipData.newPlainText("wulkanowy", stringWriter.toString())
|
||||
activity?.getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
|
||||
|
||||
Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show()
|
||||
}
|
||||
errorDialogCancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ class AttendancePresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class AttendanceSummaryFragment : BaseFragment(), AttendanceSummaryView, MainVie
|
||||
override fun updateDataSet(data: List<AttendanceSummaryItem>, header: AttendanceSummaryScrollableHeader) {
|
||||
with(attendanceSummaryAdapter) {
|
||||
updateDataSet(data, true)
|
||||
removeAllScrollableFooters()
|
||||
removeAllScrollableHeaders()
|
||||
addScrollableHeader(header)
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
@Inject
|
||||
lateinit var gradeDetailsAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||
|
||||
private var gradeDetailsMenu: Menu? = null
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GradeDetailsFragment()
|
||||
}
|
||||
@ -69,6 +71,8 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.action_menu_grade_details, menu)
|
||||
gradeDetailsMenu = menu
|
||||
presenter.updateMarkAsDoneButton()
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
@ -165,6 +169,10 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
(parentFragment as? GradeFragment)?.onChildRefresh()
|
||||
}
|
||||
|
||||
override fun enableMarkAsDoneButton(enable: Boolean) {
|
||||
gradeDetailsMenu?.findItem(R.id.gradeDetailsMenuRead)?.isEnabled = enable
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.onDetachView()
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.details
|
||||
|
||||
import android.widget.Toast
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
||||
@ -26,6 +27,8 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
) : BasePresenter<GradeDetailsView>(errorHandler, studentRepository, schedulers) {
|
||||
|
||||
private var newGradesAmount: Int = 0
|
||||
|
||||
private var currentSemesterId = 0
|
||||
|
||||
override fun onAttachView(view: GradeDetailsView) {
|
||||
@ -52,6 +55,8 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
updateItem(header)
|
||||
}
|
||||
}
|
||||
newGradesAmount--
|
||||
updateMarkAsDoneButton()
|
||||
updateGrade(item.grade)
|
||||
}
|
||||
}
|
||||
@ -106,6 +111,10 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
fun updateMarkAsDoneButton() {
|
||||
view?.enableMarkAsDoneButton(newGradesAmount > 0)
|
||||
}
|
||||
|
||||
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
||||
Timber.i("Loading grade details data started")
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
@ -131,6 +140,8 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
.subscribe({
|
||||
Timber.i("Loading grade details result: Success")
|
||||
newGradesAmount = it.sumBy { gradeDetailsHeader -> gradeDetailsHeader.newGrades }
|
||||
updateMarkAsDoneButton()
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
|
@ -46,6 +46,8 @@ interface GradeDetailsView : BaseView {
|
||||
|
||||
fun notifyParentRefresh()
|
||||
|
||||
fun enableMarkAsDoneButton(enable: Boolean)
|
||||
|
||||
fun getGradeNumberString(number: Int): String
|
||||
|
||||
fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>?
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.Color.WHITE
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@ -10,11 +11,15 @@ import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.github.mikephil.charting.components.Legend
|
||||
import com.github.mikephil.charting.components.LegendEntry
|
||||
import com.github.mikephil.charting.data.BarData
|
||||
import com.github.mikephil.charting.data.BarDataSet
|
||||
import com.github.mikephil.charting.data.BarEntry
|
||||
import com.github.mikephil.charting.data.PieData
|
||||
import com.github.mikephil.charting.data.PieDataSet
|
||||
import com.github.mikephil.charting.data.PieEntry
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||
@ -38,7 +43,9 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
fun newInstance() = GradeStatisticsFragment()
|
||||
}
|
||||
|
||||
override val isViewEmpty get() = gradeStatisticsChart.isEmpty
|
||||
override val isPieViewEmpty get() = gradeStatisticsChart.isEmpty
|
||||
|
||||
override val isBarViewEmpty get() = gradeStatisticsChartPoints.isEmpty
|
||||
|
||||
private lateinit var gradeColors: List<Pair<Int, Int>>
|
||||
|
||||
@ -60,6 +67,11 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
1 to R.color.grade_material_one
|
||||
)
|
||||
|
||||
private val gradePointsColors = listOf(
|
||||
Color.parseColor("#37c69c"),
|
||||
Color.parseColor("#d8b12a")
|
||||
)
|
||||
|
||||
private val gradeLabels = listOf(
|
||||
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
||||
)
|
||||
@ -70,8 +82,8 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
messageContainer = gradeStatisticsChart
|
||||
presenter.onAttachView(this, savedInstanceState?.getBoolean(SAVED_CHART_TYPE))
|
||||
messageContainer = gradeStatisticsSwipe
|
||||
presenter.onAttachView(this, savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? ViewType)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
@ -84,6 +96,13 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
legend.textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||
}
|
||||
|
||||
with(gradeStatisticsChartPoints) {
|
||||
description.isEnabled = false
|
||||
|
||||
animateXY(1000, 1000)
|
||||
legend.textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||
}
|
||||
|
||||
subjectsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
||||
subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
|
||||
|
||||
@ -105,23 +124,25 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateData(items: List<GradeStatistics>, theme: String) {
|
||||
override fun updatePieData(items: List<GradeStatistics>, theme: String) {
|
||||
gradeColors = when (theme) {
|
||||
"vulcan" -> vulcanGradeColors
|
||||
else -> materialGradeColors
|
||||
}
|
||||
|
||||
gradeStatisticsChart.run {
|
||||
data = PieData(PieDataSet(items.map {
|
||||
PieEntry(it.amount.toFloat(), it.grade.toString())
|
||||
}, "Legenda").apply {
|
||||
valueTextSize = 12f
|
||||
sliceSpace = 1f
|
||||
valueTextColor = WHITE
|
||||
setColors(items.map {
|
||||
gradeColors.single { color -> color.first == it.grade }.second
|
||||
}.toIntArray(), context)
|
||||
}).apply {
|
||||
val dataset = PieDataSet(items.map {
|
||||
PieEntry(it.amount.toFloat(), it.grade.toString())
|
||||
}, "Legenda").apply {
|
||||
valueTextSize = 12f
|
||||
sliceSpace = 1f
|
||||
valueTextColor = WHITE
|
||||
setColors(items.map {
|
||||
gradeColors.single { color -> color.first == it.grade }.second
|
||||
}.toIntArray(), context)
|
||||
}
|
||||
|
||||
with(gradeStatisticsChart) {
|
||||
data = PieData(dataset).apply {
|
||||
setTouchEnabled(false)
|
||||
setValueFormatter(object : ValueFormatter() {
|
||||
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
||||
@ -144,6 +165,47 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateBarData(item: GradePointsStatistics) {
|
||||
val dataset = BarDataSet(listOf(
|
||||
BarEntry(1f, item.others.toFloat()),
|
||||
BarEntry(2f, item.student.toFloat())
|
||||
), "Legenda").apply {
|
||||
valueTextSize = 12f
|
||||
valueTextColor = requireContext().getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||
valueFormatter = object : ValueFormatter() {
|
||||
override fun getBarLabel(barEntry: BarEntry) = "${barEntry.y}%"
|
||||
}
|
||||
colors = gradePointsColors
|
||||
}
|
||||
|
||||
with(gradeStatisticsChartPoints) {
|
||||
data = BarData(dataset).apply {
|
||||
barWidth = 0.5f
|
||||
setFitBars(true)
|
||||
}
|
||||
setTouchEnabled(false)
|
||||
xAxis.setDrawLabels(false)
|
||||
xAxis.setDrawGridLines(false)
|
||||
requireContext().getThemeAttrColor(android.R.attr.textColorPrimary).let {
|
||||
axisLeft.textColor = it
|
||||
axisRight.textColor = it
|
||||
}
|
||||
legend.setCustom(listOf(
|
||||
LegendEntry().apply {
|
||||
label = "Średnia klasy"
|
||||
formColor = gradePointsColors[0]
|
||||
form = Legend.LegendForm.SQUARE
|
||||
},
|
||||
LegendEntry().apply {
|
||||
label = "Uczeń"
|
||||
formColor = gradePointsColors[1]
|
||||
form = Legend.LegendForm.SQUARE
|
||||
}
|
||||
))
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun showSubjects(show: Boolean) {
|
||||
gradeStatisticsSubjectsContainer.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||
gradeStatisticsTypeSwitch.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||
@ -151,12 +213,17 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
|
||||
override fun clearView() {
|
||||
gradeStatisticsChart.clear()
|
||||
gradeStatisticsChartPoints.clear()
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
override fun showPieContent(show: Boolean) {
|
||||
gradeStatisticsChart.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showBarContent(show: Boolean) {
|
||||
gradeStatisticsChartPoints.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
gradeStatisticsEmpty.visibility = if (show) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
@ -196,13 +263,17 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
|
||||
presenter.onTypeChange(checkedId == R.id.gradeStatisticsTypeSemester)
|
||||
presenter.onTypeChange(when (checkedId) {
|
||||
R.id.gradeStatisticsTypeSemester -> ViewType.SEMESTER
|
||||
R.id.gradeStatisticsTypePartial -> ViewType.PARTIAL
|
||||
else -> ViewType.POINTS
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBoolean(SAVED_CHART_TYPE, presenter.currentIsSemester)
|
||||
outState.putSerializable(SAVED_CHART_TYPE, presenter.currentType)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
@ -30,19 +30,19 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
|
||||
private var currentSubjectName: String = "Wszystkie"
|
||||
|
||||
var currentIsSemester = false
|
||||
var currentType: ViewType = ViewType.PARTIAL
|
||||
private set
|
||||
|
||||
fun onAttachView(view: GradeStatisticsView, isSemester: Boolean?) {
|
||||
fun onAttachView(view: GradeStatisticsView, type: ViewType?) {
|
||||
super.onAttachView(view)
|
||||
currentIsSemester = isSemester ?: false
|
||||
currentType = type ?: ViewType.PARTIAL
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
||||
currentSemesterId = semesterId
|
||||
loadSubjects()
|
||||
loadData(semesterId, currentSubjectName, currentIsSemester, forceRefresh)
|
||||
loadDataByType(semesterId, currentSubjectName, currentType, forceRefresh)
|
||||
}
|
||||
|
||||
fun onParentViewChangeSemester() {
|
||||
@ -50,7 +50,7 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
showProgress(true)
|
||||
enableSwipe(false)
|
||||
showRefresh(false)
|
||||
showContent(false)
|
||||
showBarContent(false)
|
||||
showEmpty(false)
|
||||
clearView()
|
||||
}
|
||||
@ -65,28 +65,30 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
fun onSubjectSelected(name: String?) {
|
||||
Timber.i("Select grade stats subject $name")
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showBarContent(false)
|
||||
showPieContent(false)
|
||||
showProgress(true)
|
||||
enableSwipe(false)
|
||||
showEmpty(false)
|
||||
clearView()
|
||||
}
|
||||
(subjects.singleOrNull { it.name == name }?.name)?.let {
|
||||
if (it != currentSubjectName) loadData(currentSemesterId, it, currentIsSemester)
|
||||
if (it != currentSubjectName) loadDataByType(currentSemesterId, it, currentType)
|
||||
}
|
||||
}
|
||||
|
||||
fun onTypeChange(isSemester: Boolean) {
|
||||
Timber.i("Select grade stats semester: $isSemester")
|
||||
fun onTypeChange(type: ViewType) {
|
||||
Timber.i("Select grade stats semester: $type")
|
||||
disposable.clear()
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showBarContent(false)
|
||||
showPieContent(false)
|
||||
showProgress(true)
|
||||
enableSwipe(false)
|
||||
showEmpty(false)
|
||||
clearView()
|
||||
}
|
||||
loadData(currentSemesterId, currentSubjectName, isSemester)
|
||||
loadDataByType(currentSemesterId, currentSubjectName, type)
|
||||
}
|
||||
|
||||
private fun loadSubjects() {
|
||||
@ -111,10 +113,18 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) {
|
||||
currentSubjectName = subjectName
|
||||
currentType = type
|
||||
when (type) {
|
||||
ViewType.SEMESTER -> loadData(semesterId, subjectName, true, forceRefresh)
|
||||
ViewType.PARTIAL -> loadData(semesterId, subjectName, false, forceRefresh)
|
||||
ViewType.POINTS -> loadPointsData(semesterId, subjectName, forceRefresh)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData(semesterId: Int, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading grade stats data started")
|
||||
currentSubjectName = subjectName
|
||||
currentIsSemester = isSemester
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getSemesters(it) }
|
||||
.flatMap { gradeStatisticsRepository.getGradesStatistics(it.first { item -> item.semesterId == semesterId }, subjectName, isSemester, forceRefresh) }
|
||||
@ -134,14 +144,53 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
Timber.i("Loading grade stats result: Success")
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
updateData(it, preferencesRepository.gradeColorTheme)
|
||||
showBarContent(false)
|
||||
showPieContent(it.isNotEmpty())
|
||||
updatePieData(it, preferencesRepository.gradeColorTheme)
|
||||
}
|
||||
analytics.logEvent("load_grade_statistics", "items" to it.size, "force_refresh" to forceRefresh)
|
||||
}) {
|
||||
Timber.e("Loading grade stats result: An exception occurred")
|
||||
view?.run { showEmpty(isViewEmpty) }
|
||||
view?.run { showEmpty(isPieViewEmpty) }
|
||||
errorHandler.dispatch(it)
|
||||
})
|
||||
}
|
||||
|
||||
private fun loadPointsData(semesterId: Int, subjectName: String, forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading grade points stats data started")
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getSemesters(it) }
|
||||
.flatMapMaybe { gradeStatisticsRepository.getGradesPointsStatistics(it.first { item -> item.semesterId == semesterId }, subjectName, forceRefresh) }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
Timber.i("Loading grade points stats result: Success")
|
||||
view?.run {
|
||||
showEmpty(false)
|
||||
showPieContent(false)
|
||||
showBarContent(true)
|
||||
updateBarData(it)
|
||||
}
|
||||
analytics.logEvent("load_grade_points_statistics", "force_refresh" to forceRefresh)
|
||||
}, {
|
||||
Timber.e("Loading grade points stats result: An exception occurred")
|
||||
view?.run { showEmpty(isBarViewEmpty) }
|
||||
errorHandler.dispatch(it)
|
||||
}, {
|
||||
Timber.d("Loading grade points stats result: No point stats found")
|
||||
view?.run {
|
||||
showBarContent(false)
|
||||
showEmpty(true)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface GradeStatisticsView : BaseView {
|
||||
|
||||
val isViewEmpty: Boolean
|
||||
val isPieViewEmpty: Boolean
|
||||
|
||||
val isBarViewEmpty: Boolean
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateSubjects(data: ArrayList<String>)
|
||||
|
||||
fun updateData(items: List<GradeStatistics>, theme: String)
|
||||
fun updatePieData(items: List<GradeStatistics>, theme: String)
|
||||
|
||||
fun updateBarData(item: GradePointsStatistics)
|
||||
|
||||
fun showSubjects(show: Boolean)
|
||||
|
||||
@ -21,7 +26,9 @@ interface GradeStatisticsView : BaseView {
|
||||
|
||||
fun clearView()
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
fun showPieContent(show: Boolean)
|
||||
|
||||
fun showBarContent(show: Boolean)
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||
|
||||
enum class ViewType {
|
||||
SEMESTER,
|
||||
PARTIAL,
|
||||
POINTS
|
||||
}
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.login
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
@ -23,22 +24,28 @@ class LoginActivity : BaseActivity<LoginPresenter>(), LoginView {
|
||||
lateinit var loginAdapter: BaseFragmentPagerAdapter
|
||||
|
||||
companion object {
|
||||
|
||||
fun getStartIntent(context: Context) = Intent(context, LoginActivity::class.java)
|
||||
}
|
||||
|
||||
override val currentViewIndex: Int
|
||||
get() = loginViewpager.currentItem
|
||||
override val currentViewIndex get() = loginViewpager.currentItem
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_login)
|
||||
setSupportActionBar(loginToolbar)
|
||||
messageContainer = loginContainer
|
||||
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initAdapter() {
|
||||
loginAdapter.apply {
|
||||
override fun initView() {
|
||||
with(requireNotNull(supportActionBar)) {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowTitleEnabled(false)
|
||||
}
|
||||
|
||||
with(loginAdapter) {
|
||||
containerId = loginViewpager.id
|
||||
addFragments(listOf(
|
||||
LoginFormFragment.newInstance(),
|
||||
@ -47,19 +54,24 @@ class LoginActivity : BaseActivity<LoginPresenter>(), LoginView {
|
||||
))
|
||||
}
|
||||
|
||||
loginViewpager.run {
|
||||
with(loginViewpager) {
|
||||
offscreenPageLimit = 2
|
||||
adapter = loginAdapter
|
||||
setOnSelectPageListener { presenter.onViewSelected(it) }
|
||||
setOnSelectPageListener(presenter::onViewSelected)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) onBackPressed()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun switchView(index: Int) {
|
||||
loginViewpager.setCurrentItem(index, false)
|
||||
}
|
||||
|
||||
override fun showActionBar(show: Boolean) {
|
||||
supportActionBar?.apply { if (show) show() else hide() }
|
||||
supportActionBar?.run { if (show) show() else hide() }
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
@ -16,8 +16,8 @@ class LoginPresenter @Inject constructor(
|
||||
|
||||
override fun onAttachView(view: LoginView) {
|
||||
super.onAttachView(view)
|
||||
view.run {
|
||||
initAdapter()
|
||||
with(view) {
|
||||
initView()
|
||||
showActionBar(false)
|
||||
}
|
||||
Timber.i("Login view was initialized")
|
||||
@ -48,8 +48,8 @@ class LoginPresenter @Inject constructor(
|
||||
fun onViewSelected(index: Int) {
|
||||
view?.apply {
|
||||
when (index) {
|
||||
0, 1 -> showActionBar(false)
|
||||
2 -> showActionBar(true)
|
||||
0 -> showActionBar(false)
|
||||
1, 2 -> showActionBar(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ interface LoginView : BaseView {
|
||||
|
||||
val currentViewIndex: Int
|
||||
|
||||
fun initAdapter()
|
||||
fun initView()
|
||||
|
||||
fun switchView(index: Int)
|
||||
|
||||
|
@ -38,7 +38,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
||||
|
||||
override val formPassValue get() = loginFormPass.text.toString()
|
||||
|
||||
override val formHostValue get() = hostValues[(hostKeys.indexOf(loginFormHost.text.toString()))]
|
||||
override val formHostValue get() = hostValues.getOrNull(hostKeys.indexOf(loginFormHost.text.toString()))
|
||||
|
||||
private lateinit var hostKeys: Array<String>
|
||||
|
||||
@ -146,13 +146,8 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
||||
loginFormPrivacyLink.visibility = VISIBLE
|
||||
}
|
||||
|
||||
override fun notifyParentAccountLogged(students: List<Student>) {
|
||||
(activity as? LoginActivity)?.onFormFragmentAccountLogged(students,
|
||||
Triple(
|
||||
loginFormName.text.toString(),
|
||||
loginFormPass.text.toString(),
|
||||
formHostValue
|
||||
))
|
||||
override fun notifyParentAccountLogged(students: List<Student>, loginData: Triple<String, String, String>) {
|
||||
(activity as? LoginActivity)?.onFormFragmentAccountLogged(students, loginData)
|
||||
}
|
||||
|
||||
override fun openPrivacyPolicyPage() {
|
||||
|
@ -40,7 +40,9 @@ class LoginFormPresenter @Inject constructor(
|
||||
view?.apply {
|
||||
clearPassError()
|
||||
clearNameError()
|
||||
if (formHostValue.contains("fakelog")) setCredentials("jan@fakelog.cf", "jan123")
|
||||
if (formHostValue?.contains("fakelog") == true) {
|
||||
setCredentials("jan@fakelog.cf", "jan123")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +81,7 @@ class LoginFormPresenter @Inject constructor(
|
||||
.subscribe({
|
||||
Timber.i("Login result: Success")
|
||||
analytics.logEvent("registration_form", "success" to true, "students" to it.size, "endpoint" to endpoint, "error" to "No error")
|
||||
view?.notifyParentAccountLogged(it)
|
||||
view?.notifyParentAccountLogged(it, Triple(email, password, endpoint))
|
||||
}, {
|
||||
Timber.i("Login result: An exception occurred")
|
||||
analytics.logEvent("registration_form", "success" to false, "students" to -1, "endpoint" to endpoint, "error" to it.message.ifNullOrBlank { "No message" })
|
||||
|
@ -11,7 +11,7 @@ interface LoginFormView : BaseView {
|
||||
|
||||
val formPassValue: String
|
||||
|
||||
val formHostValue: String
|
||||
val formHostValue: String?
|
||||
|
||||
fun setCredentials(name: String, pass: String)
|
||||
|
||||
@ -39,7 +39,7 @@ interface LoginFormView : BaseView {
|
||||
|
||||
fun showPrivacyPolicy()
|
||||
|
||||
fun notifyParentAccountLogged(students: List<Student>)
|
||||
fun notifyParentAccountLogged(students: List<Student>, loginData: Triple<String, String, String>)
|
||||
|
||||
fun openPrivacyPolicyPage()
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
@ -25,6 +26,8 @@ class LuckyNumberWidgetConfigureActivity : BaseActivity<LuckyNumberWidgetConfigu
|
||||
@Inject
|
||||
override lateinit var presenter: LuckyNumberWidgetConfigurePresenter
|
||||
|
||||
private var dialog: AlertDialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setResult(RESULT_CANCELED)
|
||||
@ -36,11 +39,27 @@ class LuckyNumberWidgetConfigureActivity : BaseActivity<LuckyNumberWidgetConfigu
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
widgetConfigureRecycler.apply {
|
||||
with(widgetConfigureRecycler) {
|
||||
adapter = configureAdapter
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
}
|
||||
configureAdapter.setOnItemClickListener { presenter.onItemSelect(it) }
|
||||
|
||||
configureAdapter.setOnItemClickListener(presenter::onItemSelect)
|
||||
}
|
||||
|
||||
override fun showThemeDialog() {
|
||||
val items = arrayOf(
|
||||
getString(R.string.widget_timetable_theme_light),
|
||||
getString(R.string.widget_timetable_theme_dark)
|
||||
)
|
||||
|
||||
dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher)
|
||||
.setTitle(R.string.widget_timetable_theme_title)
|
||||
.setOnDismissListener { presenter.onDismissThemeView() }
|
||||
.setSingleChoiceItems(items, -1) { _, which ->
|
||||
presenter.onThemeSelect(which)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun updateData(data: List<LuckyNumberWidgetConfigureItem>) {
|
||||
@ -70,4 +89,9 @@ class LuckyNumberWidgetConfigureActivity : BaseActivity<LuckyNumberWidgetConfigu
|
||||
override fun openLoginView() {
|
||||
startActivity(LoginActivity.getStartIntent(this))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getStudentWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider.Companion.getThemeWidgetKey
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -19,6 +20,8 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||
|
||||
private var appWidgetId: Int? = null
|
||||
|
||||
private var selectedStudent: Student? = null
|
||||
|
||||
fun onAttachView(view: LuckyNumberWidgetConfigureView, appWidgetId: Int?) {
|
||||
super.onAttachView(view)
|
||||
this.appWidgetId = appWidgetId
|
||||
@ -28,10 +31,22 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||
|
||||
fun onItemSelect(item: AbstractFlexibleItem<*>) {
|
||||
if (item is LuckyNumberWidgetConfigureItem) {
|
||||
registerStudent(item.student)
|
||||
selectedStudent = item.student
|
||||
view?.showThemeDialog()
|
||||
}
|
||||
}
|
||||
|
||||
fun onThemeSelect(index: Int) {
|
||||
appWidgetId?.let {
|
||||
sharedPref.putLong(getThemeWidgetKey(it), index.toLong())
|
||||
}
|
||||
registerStudent(selectedStudent)
|
||||
}
|
||||
|
||||
fun onDismissThemeView(){
|
||||
view?.finishView()
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
disposable.add(studentRepository.getSavedStudents(false)
|
||||
.map { it to appWidgetId?.let { id -> sharedPref.getLong(getStudentWidgetKey(id), 0) } }
|
||||
@ -49,12 +64,14 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
||||
}, { errorHandler.dispatch(it) }))
|
||||
}
|
||||
|
||||
private fun registerStudent(student: Student) {
|
||||
appWidgetId?.also {
|
||||
sharedPref.putLong(getStudentWidgetKey(it), student.id)
|
||||
view?.apply {
|
||||
updateLuckyNumberWidget(it)
|
||||
setSuccessResult(it)
|
||||
private fun registerStudent(student: Student?) {
|
||||
requireNotNull(student)
|
||||
|
||||
appWidgetId?.let { id ->
|
||||
sharedPref.putLong(getStudentWidgetKey(id), student.id)
|
||||
view?.run {
|
||||
updateLuckyNumberWidget(id)
|
||||
setSuccessResult(id)
|
||||
}
|
||||
}
|
||||
view?.finishView()
|
||||
|
@ -1,12 +1,13 @@
|
||||
package io.github.wulkanowy.ui.modules.luckynumberwidget
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureItem
|
||||
|
||||
interface LuckyNumberWidgetConfigureView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun showThemeDialog()
|
||||
|
||||
fun updateData(data: List<LuckyNumberWidgetConfigureItem>)
|
||||
|
||||
fun updateLuckyNumberWidget(widgetId: Int)
|
||||
|
@ -55,7 +55,10 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
lateinit var sharedPref: SharedPrefProvider
|
||||
|
||||
companion object {
|
||||
|
||||
fun getStudentWidgetKey(appWidgetId: Int) = "lucky_number_widget_student_$appWidgetId"
|
||||
|
||||
fun getThemeWidgetKey(appWidgetId: Int) = "lucky_number_widget_theme_$appWidgetId"
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
@ -70,24 +73,26 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
|
||||
private fun onUpdate(context: Context, intent: Intent) {
|
||||
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
|
||||
RemoteViews(context.packageName, R.layout.widget_luckynumber).apply {
|
||||
setTextViewText(R.id.luckyNumberWidgetNumber,
|
||||
getLuckyNumber(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)?.luckyNumber?.toString() ?: "#"
|
||||
)
|
||||
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer,
|
||||
PendingIntent.getActivity(context, MainView.Section.LUCKY_NUMBER.id,
|
||||
MainActivity.getStartIntent(context, MainView.Section.LUCKY_NUMBER, true), FLAG_UPDATE_CURRENT))
|
||||
}.also {
|
||||
setStyles(it, intent)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, it)
|
||||
val savedTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0)
|
||||
val layoutId = if (savedTheme == 0L) R.layout.widget_luckynumber else R.layout.widget_luckynumber_dark
|
||||
|
||||
val luckyNumber = getLuckyNumber(sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0), appWidgetId)
|
||||
val appIntent = PendingIntent.getActivity(context, MainView.Section.LUCKY_NUMBER.id,
|
||||
MainActivity.getStartIntent(context, MainView.Section.LUCKY_NUMBER, true), FLAG_UPDATE_CURRENT)
|
||||
|
||||
val remoteView = RemoteViews(context.packageName, layoutId).apply {
|
||||
setTextViewText(R.id.luckyNumberWidgetNumber, luckyNumber?.luckyNumber?.toString() ?: "#")
|
||||
setOnClickPendingIntent(R.id.luckyNumberWidgetContainer, appIntent)
|
||||
}
|
||||
|
||||
setStyles(remoteView, intent)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, remoteView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDelete(intent: Intent) {
|
||||
intent.getIntExtra(EXTRA_APPWIDGET_ID, 0).let {
|
||||
if (it != 0) sharedPref.delete(getStudentWidgetKey(it))
|
||||
}
|
||||
val appWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID, 0)
|
||||
if (appWidgetId != 0) sharedPref.delete(getStudentWidgetKey(appWidgetId))
|
||||
}
|
||||
|
||||
private fun getLuckyNumber(studentId: Long, appWidgetId: Int): LuckyNumber? {
|
||||
@ -96,19 +101,17 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getSavedStudents().toMaybe() }
|
||||
.flatMap { students ->
|
||||
students.singleOrNull { student -> student.id == studentId }
|
||||
.let { student ->
|
||||
when {
|
||||
student != null -> Maybe.just(student)
|
||||
studentId != 0L -> {
|
||||
studentRepository.isCurrentStudentSet()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getCurrentStudent(false).toMaybe() }
|
||||
.doOnSuccess { sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id) }
|
||||
}
|
||||
else -> Maybe.empty()
|
||||
}
|
||||
val student = students.singleOrNull { student -> student.id == studentId }
|
||||
when {
|
||||
student != null -> Maybe.just(student)
|
||||
studentId != 0L -> {
|
||||
studentRepository.isCurrentStudentSet()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getCurrentStudent(false).toMaybe() }
|
||||
.doOnSuccess { sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id) }
|
||||
}
|
||||
else -> Maybe.empty()
|
||||
}
|
||||
}
|
||||
.flatMap { semesterRepository.getCurrentSemester(it).toMaybe() }
|
||||
.flatMap { luckyNumberRepository.getLuckyNumber(it) }
|
||||
@ -123,11 +126,14 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
}
|
||||
|
||||
private fun onOptionsChange(context: Context, intent: Intent) {
|
||||
intent.extras?.let { extras ->
|
||||
RemoteViews(context.packageName, R.layout.widget_luckynumber).apply {
|
||||
setStyles(this, intent)
|
||||
appWidgetManager.updateAppWidget(extras.getInt(EXTRA_APPWIDGET_ID), this)
|
||||
}
|
||||
intent.extras?.getInt(EXTRA_APPWIDGET_ID)?.let { appWidgetId ->
|
||||
val savedTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0)
|
||||
val layoutId = if (savedTheme == 0L) R.layout.widget_luckynumber else R.layout.widget_luckynumber_dark
|
||||
|
||||
val remoteView = RemoteViews(context.packageName, layoutId)
|
||||
|
||||
setStyles(remoteView, intent)
|
||||
appWidgetManager.updateAppWidget(appWidgetId, remoteView)
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +150,7 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
// 1x1
|
||||
maxWidth < 150 && maxHeight < 110 -> {
|
||||
Timber.d("Lucky number widget size: 1x1")
|
||||
views.run {
|
||||
with(views) {
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageTop, GONE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageLeft, GONE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetTitle, GONE)
|
||||
@ -154,7 +160,7 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
// 1x2
|
||||
maxWidth < 150 && maxHeight > 110 -> {
|
||||
Timber.d("Lucky number widget size: 1x2")
|
||||
views.run {
|
||||
with(views) {
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageTop, VISIBLE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageLeft, GONE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetTitle, GONE)
|
||||
@ -164,7 +170,7 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
// 2x1
|
||||
maxWidth >= 150 && maxHeight <= 110 -> {
|
||||
Timber.d("Lucky number widget size: 2x1")
|
||||
views.run {
|
||||
with(views) {
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageTop, GONE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageLeft, VISIBLE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetTitle, GONE)
|
||||
@ -174,7 +180,7 @@ class LuckyNumberWidgetProvider : BroadcastReceiver() {
|
||||
// 2x2 and bigger
|
||||
else -> {
|
||||
Timber.d("Lucky number widget size: 2x2 and bigger")
|
||||
views.run {
|
||||
with(views) {
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageTop, GONE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetImageLeft, GONE)
|
||||
setViewVisibility(R.id.luckyNumberWidgetTitle, VISIBLE)
|
||||
|
@ -27,6 +27,7 @@ import io.github.wulkanowy.ui.modules.mobiledevice.token.MobileDeviceTokenDialog
|
||||
import io.github.wulkanowy.ui.modules.more.MoreFragment
|
||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||
import io.github.wulkanowy.ui.modules.teacher.TeacherFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
|
||||
|
||||
@ -120,4 +121,8 @@ abstract class MainModule {
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector(modules = [LicenseModule::class])
|
||||
abstract fun bindLicenseFragment(): LicenseFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindTeacherFragment(): TeacherFragment
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.mobiledevice.token
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Bundle
|
||||
import android.util.Base64
|
||||
@ -9,6 +11,7 @@ import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.getSystemService
|
||||
import dagger.android.support.DaggerDialogFragment
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.pojos.MobileDeviceToken
|
||||
@ -45,9 +48,18 @@ class MobileDeviceTokenDialog : DaggerDialogFragment(), MobileDeviceTokenVIew {
|
||||
}
|
||||
|
||||
override fun updateData(token: MobileDeviceToken) {
|
||||
mobileDeviceDialogToken.text = token.token
|
||||
mobileDeviceDialogSymbol.text = token.symbol
|
||||
mobileDeviceDialogPin.text = token.pin
|
||||
with(mobileDeviceDialogToken) {
|
||||
text = token.token
|
||||
setOnClickListener { clickCopy(token.token) }
|
||||
}
|
||||
with(mobileDeviceDialogSymbol) {
|
||||
text = token.symbol
|
||||
setOnClickListener { clickCopy(token.symbol) }
|
||||
}
|
||||
with(mobileDeviceDialogPin) {
|
||||
text = token.pin
|
||||
setOnClickListener { clickCopy(token.pin) }
|
||||
}
|
||||
|
||||
mobileDeviceQr.setImageBitmap(Base64.decode(token.qr, Base64.DEFAULT).let {
|
||||
BitmapFactory.decodeByteArray(it, 0, it.size)
|
||||
@ -86,4 +98,10 @@ class MobileDeviceTokenDialog : DaggerDialogFragment(), MobileDeviceTokenVIew {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
fun clickCopy(text: String) {
|
||||
val clip = ClipData.newPlainText("wulkanowy", text)
|
||||
activity?.getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
|
||||
Toast.makeText(context, R.string.all_copied, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
|
||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||
import io.github.wulkanowy.ui.modules.teacher.TeacherFragment
|
||||
import io.github.wulkanowy.utils.getCompatDrawable
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_more.*
|
||||
@ -54,6 +55,9 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
||||
override val mobileDevicesRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.mobile_devices_title) to getCompatDrawable(R.drawable.ic_more_mobile_devices) }
|
||||
|
||||
override val teachersRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.teachers_title) to getCompatDrawable((R.drawable.ic_more_teacher)) }
|
||||
|
||||
override val settingsRes: Pair<String, Drawable?>?
|
||||
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
|
||||
|
||||
@ -106,6 +110,10 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
||||
(activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openTeachersView() {
|
||||
(activity as? MainActivity)?.pushView(TeacherFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun openSettingsView() {
|
||||
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ class MorePresenter @Inject constructor(
|
||||
noteRes?.first -> openNoteView()
|
||||
luckyNumberRes?.first -> openLuckyNumberView()
|
||||
mobileDevicesRes?.first -> openMobileDevicesView()
|
||||
teachersRes?.first -> openTeachersView()
|
||||
settingsRes?.first -> openSettingsView()
|
||||
aboutRes?.first -> openAboutView()
|
||||
}
|
||||
@ -51,6 +52,7 @@ class MorePresenter @Inject constructor(
|
||||
noteRes?.let { MoreItem(it.first, it.second) },
|
||||
luckyNumberRes?.let { MoreItem(it.first, it.second) },
|
||||
mobileDevicesRes?.let { MoreItem(it.first, it.second) },
|
||||
teachersRes?.let { MoreItem(it.first, it.second) },
|
||||
settingsRes?.let { MoreItem(it.first, it.second) },
|
||||
aboutRes?.let { MoreItem(it.first, it.second) })
|
||||
)
|
||||
|
@ -15,6 +15,8 @@ interface MoreView : BaseView {
|
||||
|
||||
val mobileDevicesRes: Pair<String, Drawable?>?
|
||||
|
||||
val teachersRes: Pair<String, Drawable?>?
|
||||
|
||||
val settingsRes: Pair<String, Drawable?>?
|
||||
|
||||
val aboutRes: Pair<String, Drawable?>?
|
||||
@ -38,4 +40,6 @@ interface MoreView : BaseView {
|
||||
fun openLuckyNumberView()
|
||||
|
||||
fun openMobileDevicesView()
|
||||
|
||||
fun openTeachersView()
|
||||
}
|
||||
|
@ -0,0 +1,93 @@
|
||||
package io.github.wulkanowy.ui.modules.teacher
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import kotlinx.android.synthetic.main.fragment_teacher.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView {
|
||||
@Inject
|
||||
lateinit var presenter: TeacherPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var teacherAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||
|
||||
companion object {
|
||||
fun newInstance() = TeacherFragment()
|
||||
}
|
||||
|
||||
override val titleStringId: Int
|
||||
get() = R.string.teachers_title
|
||||
|
||||
override val noSubjectString get() = getString(R.string.teacher_no_subject)
|
||||
|
||||
override val isViewEmpty: Boolean
|
||||
get() = teacherAdapter.isEmpty
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_teacher, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
teacherRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = teacherAdapter
|
||||
addItemDecoration(FlexibleItemDecoration(context)
|
||||
.withDefaultDivider()
|
||||
.withDrawDividerOnLastItem(false)
|
||||
)
|
||||
}
|
||||
teacherSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
}
|
||||
|
||||
override fun updateData(data: List<TeacherItem>) {
|
||||
teacherAdapter.updateDataSet(data, true)
|
||||
}
|
||||
|
||||
override fun updateItem(item: AbstractFlexibleItem<*>) {
|
||||
teacherAdapter.updateItem(item)
|
||||
}
|
||||
|
||||
override fun clearData() {
|
||||
teacherAdapter.clear()
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
teacherEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
teacherProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun enableSwipe(enable: Boolean) {
|
||||
teacherSwipe.isEnabled = enable
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
teacherRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun hideRefresh() {
|
||||
teacherSwipe.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package io.github.wulkanowy.ui.modules.teacher
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Teacher
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_teacher.*
|
||||
|
||||
class TeacherItem(val teacher: Teacher, private val noSubjectText: String) : AbstractFlexibleItem<TeacherItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_teacher
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): TeacherItem.ViewHolder {
|
||||
return TeacherItem.ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: TeacherItem.ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
teacherItemName.text = teacher.name
|
||||
teacherItemSubject.text = if (teacher.subject.isNotBlank()) teacher.subject else noSubjectText
|
||||
if (teacher.shortName.isNotBlank()) {
|
||||
teacherItemShortName.visibility = VISIBLE
|
||||
teacherItemShortName.text = "[${teacher.shortName}]"
|
||||
} else {
|
||||
teacherItemShortName.visibility = GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as TeacherItem
|
||||
|
||||
if (teacher != other.teacher) return false
|
||||
if (teacher.id != other.teacher.id) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = teacher.hashCode()
|
||||
result = 31 * result + teacher.id.toInt()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package io.github.wulkanowy.ui.modules.teacher
|
||||
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.teacher.TeacherRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class TeacherPresenter @Inject constructor(
|
||||
schedulers: SchedulersProvider,
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val teacherRepository: TeacherRepository,
|
||||
private val analytics: FirebaseAnalyticsHelper
|
||||
) : BasePresenter<TeacherView>(errorHandler, studentRepository, schedulers) {
|
||||
|
||||
override fun onAttachView(view: TeacherView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
Timber.i("Teacher view was initialized")
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
loadData(true)
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
Timber.i("Loading teachers data started")
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { teacherRepository.getTeachers(it, forceRefresh) }
|
||||
.map { it.filter { teacher -> teacher.name.isNotBlank() } }
|
||||
.map { items -> items.map { TeacherItem(it, view?.noSubjectString.orEmpty()) } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doFinally {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
showProgress(false)
|
||||
enableSwipe(true)
|
||||
}
|
||||
}.subscribe({
|
||||
Timber.i("Loading teachers result: Success")
|
||||
view?.run {
|
||||
updateData(it)
|
||||
showContent(it.isNotEmpty())
|
||||
showEmpty(it.isEmpty())
|
||||
}
|
||||
analytics.logEvent("load_teachers", "items" to it.size, "force_refresh" to forceRefresh)
|
||||
}) {
|
||||
Timber.i("Loading teachers result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.github.wulkanowy.ui.modules.teacher
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface TeacherView : BaseView {
|
||||
|
||||
val isViewEmpty: Boolean
|
||||
|
||||
val noSubjectString: String
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<TeacherItem>)
|
||||
|
||||
fun updateItem(item: AbstractFlexibleItem<*>)
|
||||
|
||||
fun hideRefresh()
|
||||
|
||||
fun clearData()
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun enableSwipe(enable: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
}
|
@ -11,6 +11,7 @@ import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.synthetic.main.dialog_timetable.*
|
||||
import org.threeten.bp.LocalDateTime
|
||||
@ -72,13 +73,22 @@ class TimetableDialog : DialogFragment() {
|
||||
|
||||
private fun setInfo(info: String, teacher: String, canceled: Boolean, changes: Boolean) {
|
||||
when {
|
||||
info.isNotBlank() -> timetableDialogChanges.text = when {
|
||||
canceled && !changes -> "Lekcja odwołana: $info"
|
||||
changes && teacher.isNotBlank() -> "Zastępstwo: $teacher"
|
||||
changes && teacher.isBlank() -> "Zastępstwo, ${info.decapitalize()}"
|
||||
else -> info.capitalize()
|
||||
}
|
||||
else -> {
|
||||
info.isNotBlank() -> {
|
||||
if (canceled) {
|
||||
timetableDialogChangesTitle.setTextColor(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
timetableDialogChanges.setTextColor(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||
} else {
|
||||
timetableDialogChangesTitle.setTextColor(requireContext().getThemeAttrColor(R.attr.colorTimetableChange))
|
||||
timetableDialogChanges.setTextColor(requireContext().getThemeAttrColor(R.attr.colorTimetableChange))
|
||||
}
|
||||
|
||||
timetableDialogChanges.text = when {
|
||||
canceled && !changes -> "Lekcja odwołana: $info"
|
||||
changes && teacher.isNotBlank() -> "Zastępstwo: $teacher"
|
||||
changes && teacher.isBlank() -> "Zastępstwo, ${info.decapitalize()}"
|
||||
else -> info.capitalize()
|
||||
}
|
||||
} else -> {
|
||||
timetableDialogChangesTitle.visibility = GONE
|
||||
timetableDialogChanges.visibility = GONE
|
||||
}
|
||||
|
@ -39,8 +39,6 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView,
|
||||
|
||||
override val titleStringId get() = R.string.timetable_title
|
||||
|
||||
override val roomString get() = getString(R.string.timetable_room)
|
||||
|
||||
override val isViewEmpty get() = timetableAdapter.isEmpty
|
||||
|
||||
override val currentStackSize get() = (activity as? MainActivity)?.currentStackSize
|
||||
|
@ -11,11 +11,12 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_timetable.*
|
||||
|
||||
class TimetableItem(val lesson: Timetable, private val roomText: String) :
|
||||
class TimetableItem(val lesson: Timetable) :
|
||||
AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_timetable
|
||||
@ -26,16 +27,97 @@ class TimetableItem(val lesson: Timetable, private val roomText: String) :
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
timetableItemRoom.text = if (lesson.room.isNotBlank()) "$roomText ${lesson.room}" else ""
|
||||
timetableItemTime.text = "${lesson.start.toFormattedString("HH:mm")} - ${lesson.end.toFormattedString("HH:mm")}"
|
||||
timetableItemAlert.visibility = if (lesson.changes || lesson.canceled) VISIBLE else GONE
|
||||
updateFields(holder)
|
||||
|
||||
with(holder) {
|
||||
timetableItemSubject.paintFlags =
|
||||
if (lesson.canceled) timetableItemSubject.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else timetableItemSubject.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
}
|
||||
|
||||
updateDescription(holder)
|
||||
updateColors(holder)
|
||||
}
|
||||
|
||||
private fun updateFields(holder: ViewHolder) {
|
||||
with(holder) {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
timetableItemRoom.text = lesson.room
|
||||
timetableItemTeacher.text = lesson.teacher
|
||||
timetableItemTimeStart.text = lesson.start.toFormattedString("HH:mm")
|
||||
timetableItemTimeFinish.text = lesson.end.toFormattedString("HH:mm")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDescription(holder: ViewHolder) {
|
||||
with(holder) {
|
||||
if (lesson.info.isNotBlank() && !lesson.changes) {
|
||||
updateDescriptionNoChanges(this)
|
||||
} else {
|
||||
timetableItemDescription.visibility = GONE
|
||||
|
||||
timetableItemRoom.visibility = VISIBLE
|
||||
timetableItemTeacher.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDescriptionNoChanges(holder: ViewHolder) {
|
||||
with(holder) {
|
||||
timetableItemDescription.visibility = VISIBLE
|
||||
timetableItemDescription.text = lesson.info
|
||||
|
||||
timetableItemRoom.visibility = GONE
|
||||
timetableItemTeacher.visibility = GONE
|
||||
|
||||
timetableItemDescription.setTextColor(holder.view.context.getThemeAttrColor(
|
||||
if (lesson.canceled) R.attr.colorPrimary
|
||||
else R.attr.colorTimetableChange
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateColors(holder: ViewHolder) {
|
||||
with(holder) {
|
||||
if (lesson.canceled) {
|
||||
timetableItemNumber.setTextColor(holder.view.context.getThemeAttrColor(R.attr.colorPrimary))
|
||||
timetableItemSubject.setTextColor(holder.view.context.getThemeAttrColor(R.attr.colorPrimary))
|
||||
} else {
|
||||
updateNumberColor(this)
|
||||
updateSubjectColor(this)
|
||||
updateRoomColor(this)
|
||||
updateTeacherColor(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNumberColor(holder: ViewHolder) {
|
||||
holder.timetableItemNumber.setTextColor(holder.view.context.getThemeAttrColor(
|
||||
if (lesson.changes || lesson.info.isNotBlank()) R.attr.colorTimetableChange
|
||||
else android.R.attr.textColorPrimary
|
||||
))
|
||||
}
|
||||
|
||||
private fun updateSubjectColor(holder: ViewHolder) {
|
||||
holder.timetableItemSubject.setTextColor(holder.view.context.getThemeAttrColor(
|
||||
if (lesson.subjectOld.isNotBlank() && lesson.subjectOld != lesson.subject) R.attr.colorTimetableChange
|
||||
else android.R.attr.textColorPrimary
|
||||
))
|
||||
}
|
||||
|
||||
private fun updateRoomColor(holder: ViewHolder) {
|
||||
holder.timetableItemRoom.setTextColor(holder.view.context.getThemeAttrColor(
|
||||
if (lesson.roomOld.isNotBlank() && lesson.roomOld != lesson.room) R.attr.colorTimetableChange
|
||||
else android.R.attr.textColorSecondary
|
||||
))
|
||||
}
|
||||
|
||||
private fun updateTeacherColor(holder: ViewHolder) {
|
||||
holder.timetableItemTeacher.setTextColor(holder.view.context.getThemeAttrColor(
|
||||
if (lesson.teacherOld.isNotBlank() && lesson.teacherOld != lesson.teacher) R.attr.colorTimetableChange
|
||||
else android.R.attr.textColorSecondary
|
||||
))
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
@ -108,7 +109,7 @@ class TimetablePresenter @Inject constructor(
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.delay(200, MILLISECONDS)
|
||||
.flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) }
|
||||
.map { items -> items.map { TimetableItem(it, view?.roomString.orEmpty()) } }
|
||||
.map { items -> items.map { TimetableItem(it) } }
|
||||
.map { items -> items.sortedBy { it.lesson.number } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
@ -147,11 +148,12 @@ class TimetablePresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun reloadNavigation() {
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface TimetableView : BaseView {
|
||||
|
||||
val roomString: String
|
||||
|
||||
val isViewEmpty: Boolean
|
||||
|
||||
val currentStackSize: Int?
|
||||
|
@ -9,6 +9,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.CompletedLesson
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_completed_lesson.*
|
||||
|
||||
@ -23,6 +24,10 @@ class CompletedLessonItem(val completedLesson: CompletedLesson) : AbstractFlexib
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: CompletedLessonItem.ViewHolder?, position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.apply {
|
||||
completedLessonItemNumber.text = completedLesson.number.toString()
|
||||
completedLessonItemNumber.setTextColor(holder.contentView.context.getThemeAttrColor(
|
||||
if (completedLesson.substitution.isNotEmpty()) R.attr.colorTimetableChange
|
||||
else android.R.attr.textColorPrimary
|
||||
))
|
||||
completedLessonItemSubject.text = completedLesson.subject
|
||||
completedLessonItemTopic.text = completedLesson.topic
|
||||
completedLessonItemAlert.visibility = if (completedLesson.substitution.isNotEmpty()) VISIBLE else GONE
|
||||
|
@ -135,7 +135,7 @@ class CompletedLessonsPresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE, dd.MM").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import android.widget.Toast.LENGTH_LONG
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
@ -27,6 +28,8 @@ class TimetableWidgetConfigureActivity : BaseActivity<TimetableWidgetConfigurePr
|
||||
@Inject
|
||||
override lateinit var presenter: TimetableWidgetConfigurePresenter
|
||||
|
||||
private var dialog: AlertDialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setResult(RESULT_CANCELED)
|
||||
@ -38,11 +41,27 @@ class TimetableWidgetConfigureActivity : BaseActivity<TimetableWidgetConfigurePr
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
widgetConfigureRecycler.apply {
|
||||
with(widgetConfigureRecycler) {
|
||||
adapter = configureAdapter
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
}
|
||||
configureAdapter.setOnItemClickListener { presenter.onItemSelect(it) }
|
||||
|
||||
configureAdapter.setOnItemClickListener(presenter::onItemSelect)
|
||||
}
|
||||
|
||||
override fun showThemeDialog() {
|
||||
val items = arrayOf(
|
||||
getString(R.string.widget_timetable_theme_light),
|
||||
getString(R.string.widget_timetable_theme_dark)
|
||||
)
|
||||
|
||||
dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher)
|
||||
.setTitle(R.string.widget_timetable_theme_title)
|
||||
.setOnDismissListener { presenter.onDismissThemeView() }
|
||||
.setSingleChoiceItems(items, -1) { _, which ->
|
||||
presenter.onThemeSelect(which)
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun updateData(data: List<TimetableWidgetConfigureItem>) {
|
||||
@ -72,4 +91,9 @@ class TimetableWidgetConfigureActivity : BaseActivity<TimetableWidgetConfigurePr
|
||||
override fun openLoginView() {
|
||||
startActivity(LoginActivity.getStartIntent(this))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getThemeWidgetKey
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -21,6 +22,8 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
|
||||
|
||||
private var isFromProvider = false
|
||||
|
||||
private var selectedStudent: Student? = null
|
||||
|
||||
fun onAttachView(view: TimetableWidgetConfigureView, appWidgetId: Int?, isFromProvider: Boolean?) {
|
||||
super.onAttachView(view)
|
||||
this.appWidgetId = appWidgetId
|
||||
@ -31,10 +34,24 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
|
||||
|
||||
fun onItemSelect(item: AbstractFlexibleItem<*>) {
|
||||
if (item is TimetableWidgetConfigureItem) {
|
||||
registerStudent(item.student)
|
||||
selectedStudent = item.student
|
||||
|
||||
if (isFromProvider) registerStudent(selectedStudent)
|
||||
else view?.showThemeDialog()
|
||||
}
|
||||
}
|
||||
|
||||
fun onThemeSelect(index: Int) {
|
||||
appWidgetId?.let {
|
||||
sharedPref.putLong(getThemeWidgetKey(it), index.toLong())
|
||||
}
|
||||
registerStudent(selectedStudent)
|
||||
}
|
||||
|
||||
fun onDismissThemeView(){
|
||||
view?.finishView()
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
disposable.add(studentRepository.getSavedStudents(false)
|
||||
.map { it to appWidgetId?.let { id -> sharedPref.getLong(getStudentWidgetKey(id), 0) } }
|
||||
@ -46,18 +63,23 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
|
||||
.subscribe({
|
||||
when {
|
||||
it.isEmpty() -> view?.openLoginView()
|
||||
it.size == 1 && !isFromProvider -> registerStudent(it.single().student)
|
||||
it.size == 1 && !isFromProvider -> {
|
||||
selectedStudent = it.single().student
|
||||
view?.showThemeDialog()
|
||||
}
|
||||
else -> view?.updateData(it)
|
||||
}
|
||||
}, { errorHandler.dispatch(it) }))
|
||||
}
|
||||
|
||||
private fun registerStudent(student: Student) {
|
||||
appWidgetId?.also {
|
||||
sharedPref.putLong(getStudentWidgetKey(it), student.id)
|
||||
view?.apply {
|
||||
updateTimetableWidget(it)
|
||||
setSuccessResult(it)
|
||||
private fun registerStudent(student: Student?) {
|
||||
requireNotNull(student)
|
||||
|
||||
appWidgetId?.let { id ->
|
||||
sharedPref.putLong(getStudentWidgetKey(id), student.id)
|
||||
view?.run {
|
||||
updateTimetableWidget(id)
|
||||
setSuccessResult(id)
|
||||
}
|
||||
}
|
||||
view?.finishView()
|
||||
|
@ -10,6 +10,8 @@ interface TimetableWidgetConfigureView : BaseView {
|
||||
|
||||
fun updateTimetableWidget(widgetId: Int)
|
||||
|
||||
fun showThemeDialog()
|
||||
|
||||
fun setSuccessResult(widgetId: Int)
|
||||
|
||||
fun finishView()
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.timetablewidget
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -18,7 +19,9 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getDateWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getStudentWidgetKey
|
||||
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.getThemeWidgetKey
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.getCompatColor
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
@ -36,6 +39,14 @@ class TimetableWidgetFactory(
|
||||
|
||||
private var lessons = emptyList<Timetable>()
|
||||
|
||||
private var layoutId: Int? = null
|
||||
|
||||
private var primaryColor: Int? = null
|
||||
|
||||
private var textColor: Int? = null
|
||||
|
||||
private var timetableChangeColor: Int? = null
|
||||
|
||||
override fun getLoadingView() = null
|
||||
|
||||
override fun hasStableIds() = true
|
||||
@ -55,63 +66,141 @@ class TimetableWidgetFactory(
|
||||
val date = LocalDate.ofEpochDay(sharedPref.getLong(getDateWidgetKey(appWidgetId), 0))
|
||||
val studentId = sharedPref.getLong(getStudentWidgetKey(appWidgetId), 0)
|
||||
|
||||
lessons = try {
|
||||
studentRepository.isStudentSaved()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getSavedStudents().toMaybe() }
|
||||
.flatMap {
|
||||
it.singleOrNull { student -> student.id == studentId }
|
||||
.let { student ->
|
||||
if (student != null) Maybe.just(student)
|
||||
else Maybe.empty()
|
||||
}
|
||||
}
|
||||
.flatMap { semesterRepository.getCurrentSemester(it).toMaybe() }
|
||||
.flatMap { timetableRepository.getTimetable(it, date, date).toMaybe() }
|
||||
.map { item -> item.sortedBy { it.number } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.blockingGet(emptyList())
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "An error has occurred in timetable widget factory")
|
||||
emptyList()
|
||||
}
|
||||
updateTheme(appWidgetId)
|
||||
|
||||
updateLessons(date, studentId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTheme(appWidgetId: Int) {
|
||||
val savedTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0)
|
||||
layoutId = if (savedTheme == 0L) R.layout.item_widget_timetable else R.layout.item_widget_timetable_dark
|
||||
|
||||
primaryColor = if (savedTheme == 0L) R.color.colorPrimary else R.color.colorPrimaryLight
|
||||
textColor = if (savedTheme == 0L) android.R.color.black else android.R.color.white
|
||||
timetableChangeColor = if (savedTheme == 0L) R.color.timetable_change_dark else R.color.timetable_change_light
|
||||
}
|
||||
|
||||
private fun updateLessons(date: LocalDate, studentId: Long) {
|
||||
lessons = try {
|
||||
studentRepository.isStudentSaved()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getSavedStudents().toMaybe() }
|
||||
.flatMap {
|
||||
val student = it.singleOrNull { student -> student.id == studentId }
|
||||
|
||||
if (student != null) Maybe.just(student)
|
||||
else Maybe.empty()
|
||||
}
|
||||
.flatMap { semesterRepository.getCurrentSemester(it).toMaybe() }
|
||||
.flatMap { timetableRepository.getTimetable(it, date, date).toMaybe() }
|
||||
.map { item -> item.sortedBy { it.number } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.blockingGet(emptyList())
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "An error has occurred in timetable widget factory")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
override fun getViewAt(position: Int): RemoteViews? {
|
||||
if (position == INVALID_POSITION || lessons.getOrNull(position) == null) return null
|
||||
|
||||
return RemoteViews(context.packageName, R.layout.item_widget_timetable).apply {
|
||||
lessons[position].let {
|
||||
setTextViewText(R.id.timetableWidgetItemSubject, it.subject)
|
||||
setTextViewText(R.id.timetableWidgetItemNumber, it.number.toString())
|
||||
setTextViewText(R.id.timetableWidgetItemTime, it.start.toFormattedString("HH:mm") +
|
||||
" - ${it.end.toFormattedString("HH:mm")}")
|
||||
return RemoteViews(context.packageName, layoutId!!).apply {
|
||||
val lesson = lessons[position]
|
||||
|
||||
if (it.room.isNotBlank()) {
|
||||
setTextViewText(R.id.timetableWidgetItemRoom, "${context.getString(R.string.timetable_room)} ${it.room}")
|
||||
} else setTextViewText(R.id.timetableWidgetItemRoom, "")
|
||||
setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject)
|
||||
setTextViewText(R.id.timetableWidgetItemNumber, lesson.number.toString())
|
||||
setTextViewText(R.id.timetableWidgetItemTimeStart, lesson.start.toFormattedString("HH:mm"))
|
||||
setTextViewText(R.id.timetableWidgetItemTimeFinish, lesson.end.toFormattedString("HH:mm"))
|
||||
|
||||
if (it.info.isNotBlank()) {
|
||||
setViewVisibility(R.id.timetableWidgetItemDescription, VISIBLE)
|
||||
setTextViewText(R.id.timetableWidgetItemDescription, it.run {
|
||||
when (true) {
|
||||
canceled && !changes -> "Lekcja odwołana: $info"
|
||||
changes && teacher.isNotBlank() -> "Zastępstwo: $teacher"
|
||||
changes && teacher.isBlank() -> "Zastępstwo, ${info.decapitalize()}"
|
||||
else -> it.info.capitalize()
|
||||
}
|
||||
})
|
||||
} else setViewVisibility(R.id.timetableWidgetItemDescription, GONE)
|
||||
updateDescription(this, lesson)
|
||||
|
||||
if (it.canceled) {
|
||||
setInt(R.id.timetableWidgetItemSubject, "setPaintFlags",
|
||||
STRIKE_THRU_TEXT_FLAG or ANTI_ALIAS_FLAG)
|
||||
} else {
|
||||
setInt(R.id.timetableWidgetItemSubject, "setPaintFlags", ANTI_ALIAS_FLAG)
|
||||
}
|
||||
if (lesson.canceled) {
|
||||
updateStylesCanceled(this)
|
||||
} else {
|
||||
updateStylesNotCanceled(this, lesson)
|
||||
}
|
||||
|
||||
setOnClickFillInIntent(R.id.timetableWidgetItemContainer, Intent())
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDescription(remoteViews: RemoteViews, lesson: Timetable) {
|
||||
with(remoteViews) {
|
||||
if (lesson.info.isNotBlank() && !lesson.changes) {
|
||||
setTextViewText(R.id.timetableWidgetItemDescription, lesson.info)
|
||||
setViewVisibility(R.id.timetableWidgetItemDescription, VISIBLE)
|
||||
setViewVisibility(R.id.timetableWidgetItemRoom, GONE)
|
||||
setViewVisibility(R.id.timetableWidgetItemTeacher, GONE)
|
||||
} else {
|
||||
setViewVisibility(R.id.timetableWidgetItemDescription, GONE)
|
||||
setViewVisibility(R.id.timetableWidgetItemRoom, VISIBLE)
|
||||
setViewVisibility(R.id.timetableWidgetItemTeacher, VISIBLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateStylesCanceled(remoteViews: RemoteViews) {
|
||||
with(remoteViews) {
|
||||
setInt(R.id.timetableWidgetItemSubject, "setPaintFlags",
|
||||
STRIKE_THRU_TEXT_FLAG or ANTI_ALIAS_FLAG)
|
||||
setTextColor(R.id.timetableWidgetItemNumber, context.getCompatColor(primaryColor!!))
|
||||
setTextColor(R.id.timetableWidgetItemSubject, context.getCompatColor(primaryColor!!))
|
||||
setTextColor(R.id.timetableWidgetItemDescription, context.getCompatColor(primaryColor!!))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateStylesNotCanceled(remoteViews: RemoteViews, lesson: Timetable) {
|
||||
with(remoteViews) {
|
||||
setInt(R.id.timetableWidgetItemSubject, "setPaintFlags", ANTI_ALIAS_FLAG)
|
||||
setTextColor(R.id.timetableWidgetItemSubject, context.getCompatColor(textColor!!))
|
||||
setTextColor(R.id.timetableWidgetItemDescription, context.getCompatColor(timetableChangeColor!!))
|
||||
|
||||
updateNotCanceledLessonNumberColor(this, lesson)
|
||||
updateNotCanceledSubjectColor(this, lesson)
|
||||
|
||||
val teacherChange = lesson.teacherOld.isNotBlank() && lesson.teacher != lesson.teacherOld
|
||||
updateNotCanceledRoom(this, lesson, teacherChange)
|
||||
updateNotCanceledTeacher(this, lesson, teacherChange)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotCanceledLessonNumberColor(remoteViews: RemoteViews, lesson: Timetable) {
|
||||
remoteViews.setTextColor(R.id.timetableWidgetItemNumber, context.getCompatColor(
|
||||
if (lesson.changes || (lesson.info.isNotBlank() && !lesson.canceled)) timetableChangeColor!!
|
||||
else textColor!!
|
||||
))
|
||||
}
|
||||
|
||||
private fun updateNotCanceledSubjectColor(remoteViews: RemoteViews, lesson: Timetable) {
|
||||
remoteViews.setTextColor(R.id.timetableWidgetItemSubject, context.getCompatColor(
|
||||
if (lesson.subjectOld.isNotBlank() && lesson.subject != lesson.subjectOld) timetableChangeColor!!
|
||||
else textColor!!
|
||||
))
|
||||
}
|
||||
|
||||
private fun updateNotCanceledRoom(remoteViews: RemoteViews, lesson: Timetable, teacherChange: Boolean) {
|
||||
with(remoteViews) {
|
||||
if (lesson.room.isNotBlank()) {
|
||||
setTextViewText(R.id.timetableWidgetItemRoom,
|
||||
if (teacherChange) lesson.room
|
||||
else "${context.getString(R.string.timetable_room)} ${lesson.room}"
|
||||
)
|
||||
|
||||
setTextColor(R.id.timetableWidgetItemRoom, context.getCompatColor(
|
||||
if (lesson.roomOld.isNotBlank() && lesson.room != lesson.roomOld) timetableChangeColor!!
|
||||
else textColor!!
|
||||
))
|
||||
} else setTextViewText(R.id.timetableWidgetItemRoom, "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNotCanceledTeacher(remoteViews: RemoteViews, lesson: Timetable, teacherChange: Boolean) {
|
||||
remoteViews.setTextViewText(R.id.timetableWidgetItemTeacher,
|
||||
if (teacherChange) lesson.teacher
|
||||
else ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -54,21 +54,24 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
lateinit var analytics: FirebaseAnalyticsHelper
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_TOGGLED_WIDGET_ID = "extraToggledWidget"
|
||||
|
||||
private const val EXTRA_BUTTON_TYPE = "extraButtonType"
|
||||
|
||||
private const val BUTTON_NEXT = "buttonNext"
|
||||
|
||||
private const val BUTTON_PREV = "buttonPrev"
|
||||
|
||||
private const val BUTTON_RESET = "buttonReset"
|
||||
|
||||
const val EXTRA_FROM_PROVIDER = "extraFromProvider"
|
||||
|
||||
const val EXTRA_TOGGLED_WIDGET_ID = "extraToggledWidget"
|
||||
|
||||
const val EXTRA_BUTTON_TYPE = "extraButtonType"
|
||||
|
||||
const val BUTTON_NEXT = "buttonNext"
|
||||
|
||||
const val BUTTON_PREV = "buttonPrev"
|
||||
|
||||
const val BUTTON_RESET = "buttonReset"
|
||||
|
||||
fun getDateWidgetKey(appWidgetId: Int) = "timetable_widget_date_$appWidgetId"
|
||||
|
||||
fun getStudentWidgetKey(appWidgetId: Int) = "timetable_widget_student_$appWidgetId"
|
||||
|
||||
fun getThemeWidgetKey(appWidgetId: Int) = "timetable_widget_theme_$appWidgetId"
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
@ -102,45 +105,56 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
}
|
||||
|
||||
private fun onDelete(intent: Intent) {
|
||||
intent.getIntExtra(EXTRA_APPWIDGET_ID, 0).let {
|
||||
if (it != 0) {
|
||||
sharedPref.apply {
|
||||
delete(getStudentWidgetKey(it))
|
||||
delete(getDateWidgetKey(it))
|
||||
}
|
||||
val appWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID, 0)
|
||||
|
||||
if (appWidgetId != 0) {
|
||||
with(sharedPref) {
|
||||
delete(getStudentWidgetKey(appWidgetId))
|
||||
delete(getDateWidgetKey(appWidgetId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private fun updateWidget(context: Context, appWidgetId: Int, date: LocalDate, student: Student?) {
|
||||
RemoteViews(context.packageName, R.layout.widget_timetable).apply {
|
||||
val savedTheme = sharedPref.getLong(getThemeWidgetKey(appWidgetId), 0)
|
||||
val layoutId = if (savedTheme == 0L) R.layout.widget_timetable else R.layout.widget_timetable_dark
|
||||
|
||||
val nextNavIntent = createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT)
|
||||
val prevNavIntent = createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV)
|
||||
val resetNavIntent = createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET)
|
||||
val adapterIntent = Intent(context, TimetableWidgetService::class.java)
|
||||
.apply {
|
||||
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
//make Intent unique
|
||||
action = appWidgetId.toString()
|
||||
}
|
||||
val accountIntent = PendingIntent.getActivity(context, -Int.MAX_VALUE + appWidgetId,
|
||||
Intent(context, TimetableWidgetConfigureActivity::class.java).apply {
|
||||
addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
|
||||
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
putExtra(EXTRA_FROM_PROVIDER, true)
|
||||
}, FLAG_UPDATE_CURRENT)
|
||||
val appIntent = PendingIntent.getActivity(context, MainView.Section.TIMETABLE.id,
|
||||
MainActivity.getStartIntent(context, MainView.Section.TIMETABLE, true), FLAG_UPDATE_CURRENT)
|
||||
|
||||
val remoteView = RemoteViews(context.packageName, layoutId).apply {
|
||||
setEmptyView(R.id.timetableWidgetList, R.id.timetableWidgetEmpty)
|
||||
setTextViewText(R.id.timetableWidgetDate, "${date.shortcutWeekDayName.capitalize()} ${date.toFormattedString()}")
|
||||
setTextViewText(R.id.timetableWidgetDate, date.toFormattedString("EEEE, dd.MM").capitalize())
|
||||
setTextViewText(R.id.timetableWidgetName, student?.studentName ?: context.getString(R.string.all_no_data))
|
||||
setRemoteAdapter(R.id.timetableWidgetList, Intent(context, TimetableWidgetService::class.java)
|
||||
.apply { putExtra(EXTRA_APPWIDGET_ID, appWidgetId) })
|
||||
setOnClickPendingIntent(R.id.timetableWidgetNext, createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT))
|
||||
setOnClickPendingIntent(R.id.timetableWidgetPrev, createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV))
|
||||
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET).let {
|
||||
setOnClickPendingIntent(R.id.timetableWidgetDate, it)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetName, it)
|
||||
}
|
||||
setOnClickPendingIntent(R.id.timetableWidgetAccount, PendingIntent.getActivity(context, -Int.MAX_VALUE + appWidgetId,
|
||||
Intent(context, TimetableWidgetConfigureActivity::class.java).apply {
|
||||
addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
|
||||
putExtra(EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
putExtra(EXTRA_FROM_PROVIDER, true)
|
||||
}, FLAG_UPDATE_CURRENT))
|
||||
setPendingIntentTemplate(R.id.timetableWidgetList,
|
||||
PendingIntent.getActivity(context, MainView.Section.TIMETABLE.id,
|
||||
MainActivity.getStartIntent(context, MainView.Section.TIMETABLE, true), FLAG_UPDATE_CURRENT))
|
||||
}.also {
|
||||
sharedPref.putLong(getDateWidgetKey(appWidgetId), date.toEpochDay(), true)
|
||||
appWidgetManager.apply {
|
||||
notifyAppWidgetViewDataChanged(appWidgetId, R.id.timetableWidgetList)
|
||||
updateAppWidget(appWidgetId, it)
|
||||
}
|
||||
setRemoteAdapter(R.id.timetableWidgetList, adapterIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetNext, nextNavIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetPrev, prevNavIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetDate, resetNavIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetName, resetNavIntent)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetAccount, accountIntent)
|
||||
setPendingIntentTemplate(R.id.timetableWidgetList, appIntent)
|
||||
}
|
||||
|
||||
sharedPref.putLong(getDateWidgetKey(appWidgetId), date.toEpochDay(), true)
|
||||
with(appWidgetManager) {
|
||||
notifyAppWidgetViewDataChanged(appWidgetId, R.id.timetableWidgetList)
|
||||
updateAppWidget(appWidgetId, remoteView)
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,19 +173,17 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getSavedStudents(false).toMaybe() }
|
||||
.flatMap { students ->
|
||||
students.singleOrNull { student -> student.id == studentId }
|
||||
.let { student ->
|
||||
when {
|
||||
student != null -> Maybe.just(student)
|
||||
studentId != 0L -> {
|
||||
studentRepository.isCurrentStudentSet()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getCurrentStudent(false).toMaybe() }
|
||||
.doOnSuccess { sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id) }
|
||||
}
|
||||
else -> Maybe.empty()
|
||||
}
|
||||
val student = students.singleOrNull { student -> student.id == studentId }
|
||||
when {
|
||||
student != null -> Maybe.just(student)
|
||||
studentId != 0L -> {
|
||||
studentRepository.isCurrentStudentSet()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getCurrentStudent(false).toMaybe() }
|
||||
.doOnSuccess { sharedPref.putLong(getStudentWidgetKey(appWidgetId), it.id) }
|
||||
}
|
||||
else -> Maybe.empty()
|
||||
}
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.blockingGet()
|
||||
|
@ -1,7 +1,10 @@
|
||||
Wersja 0.10
|
||||
Wersja 0.11.0
|
||||
|
||||
- odświeżyliśmy wygląd aplikacji
|
||||
- poprawiliśmy wyświetlanie nauczycieli w planie lekcji
|
||||
- naprawiliśmy szczęsliwy numerek
|
||||
- ciemny motyw dla widżetów
|
||||
- lista nauczycieli
|
||||
- statystyka ocen punktowych ucznia na tle klasy i lepsze wyświetlanie punktów na liście ocen
|
||||
- ładniejsza nawigacja między datami w planie lekcji i nie tylko
|
||||
- naprawiony szczęśliwy numerek
|
||||
- naprawione logowanie do dziennika Resman
|
||||
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#FFF" />
|
||||
<solid android:color="@android:color/white" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/colorWidgetBackground" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
5
app/src/main/res/drawable/ic_chevron_left.xml
Normal file
5
app/src/main/res/drawable/ic_chevron_left.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_chevron_right.xml
Normal file
5
app/src/main/res/drawable/ic_chevron_right.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_more_teacher.xml
Normal file
7
app/src/main/res/drawable/ic_more_teacher.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path android:fillColor="#fff" android:pathData="M16.36 12.76C18.31 13.42 20 14.5 20 16V21H4V16C4 14.5 5.69 13.42 7.65 12.76L8.27 14L8.5 14.5C7 14.96 5.9 15.62 5.9 16V19.1H10.12L11 14.03L10.06 12.15C10.68 12.08 11.33 12.03 12 12.03C12.67 12.03 13.32 12.08 13.94 12.15L13 14.03L13.88 19.1H18.1V16C18.1 15.62 17 14.96 15.5 14.5L15.73 14L16.36 12.76M12 5C10.9 5 10 5.9 10 7C10 8.1 10.9 9 12 9C13.1 9 14 8.1 14 7C14 5.9 13.1 5 12 5M12 11C9.79 11 8 9.21 8 7C8 4.79 9.79 3 12 3C14.21 3 16 4.79 16 7C16 9.21 14.21 11 12 11Z" />
|
||||
</vector>
|
@ -1,10 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/loginContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/loginToolbar"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.aurelhubert.ahbottomnavigation.AHBottomNavigationViewPager
|
||||
android:id="@+id/loginViewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
@ -80,7 +80,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/timetable_changes"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
@ -89,7 +89,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_no_data"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="300dp"
|
||||
@ -22,7 +23,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/timetable_changes"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
@ -31,7 +32,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_no_data"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
@ -57,10 +58,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_no_data"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableDialogTeacherTitle"
|
||||
@ -85,10 +87,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_no_data"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableDialogGroupTitle"
|
||||
@ -130,10 +133,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_no_data"
|
||||
android:textColor="?colorPrimary"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -58,40 +58,49 @@
|
||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||
android:id="@+id/attendanceNavContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/attendancePreviousButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:insetLeft="8dp"
|
||||
android:text="@string/all_prev"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitStart"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_left"
|
||||
android:contentDescription="@string/all_prev"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendanceNavDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name" />
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/attendanceNextButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="4dp"
|
||||
android:gravity="end|center_vertical"
|
||||
android:insetRight="8dp"
|
||||
android:text="@string/all_next"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_right"
|
||||
android:contentDescription="@string/all_next" />
|
||||
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -58,39 +58,49 @@
|
||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||
android:id="@+id/examNavContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/examPreviousButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:insetLeft="8dp"
|
||||
android:text="@string/all_prev"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitStart"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_left"
|
||||
android:contentDescription="@string/all_prev"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/examNavDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name" />
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/examNextButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:insetLeft="8dp"
|
||||
android:text="@string/all_next"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_right"
|
||||
android:contentDescription="@string/all_next" />
|
||||
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -72,6 +72,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="annual"
|
||||
android:text="@string/grade_statistics_semester" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/gradeStatisticsTypePoints"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tag="points"
|
||||
android:text="@string/grade_statistics_points" />
|
||||
</RadioGroup>
|
||||
|
||||
<FrameLayout
|
||||
@ -88,6 +95,16 @@
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/gradeStatisticsChartPoints"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="10dp"
|
||||
android:background="?android:windowBackground"
|
||||
android:minHeight="400dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||
android:id="@+id/gradeStatisticsProgress"
|
||||
style="@style/Widget.MaterialProgressBar.ProgressBar"
|
||||
|
@ -58,39 +58,49 @@
|
||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||
android:id="@+id/homeworkNavContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/homeworkPreviousButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:insetLeft="8dp"
|
||||
android:text="@string/all_prev"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitStart"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_left"
|
||||
android:contentDescription="@string/all_prev"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/homeworkNavDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name" />
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/homeworkNextButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:insetRight="8dp"
|
||||
android:text="@string/all_next"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_right"
|
||||
android:contentDescription="@string/all_next" />
|
||||
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -136,45 +136,41 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginRight="24dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:text="@string/login_sign_in"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/loginFormHostLayout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginFormVersion"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginRight="24dp"
|
||||
android:maxLines="2"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/loginFormSignIn"
|
||||
app:layout_constraintEnd_toStartOf="@+id/loginFormSignIn"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/loginFormHostLayout"
|
||||
app:layout_constraintTop_toTopOf="@+id/loginFormSignIn"
|
||||
tools:text="Version 1.0.0" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/loginFormPrivacyLink"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginRight="24dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:text="@string/login_privacy_policy"
|
||||
android:visibility="invisible"
|
||||
app:fontFamily="sans-serif-medium"
|
||||
app:layout_constraintBottom_toBottomOf="@id/loginFormSignIn"
|
||||
app:layout_constraintEnd_toStartOf="@+id/loginFormSignIn"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="@id/loginFormHostLayout"
|
||||
app:layout_constraintTop_toTopOf="@+id/loginFormSignIn"
|
||||
tools:visibility="visible" />
|
||||
|
@ -25,7 +25,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginRight="32dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
|
51
app/src/main/res/layout/fragment_teacher.xml
Normal file
51
app/src/main/res/layout/fragment_teacher.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||
android:id="@+id/teacherProgress"
|
||||
style="@style/Widget.MaterialProgressBar.ProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true" />
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/teacherSwipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/teacherRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/teacherEmpty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp"
|
||||
android:visibility="gone"
|
||||
tools:ignore="UseCompoundDrawables">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
app:srcCompat="@drawable/ic_more_teacher"
|
||||
app:tint="?colorOnBackground"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/teacher_no_items"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
@ -58,39 +58,48 @@
|
||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||
android:id="@+id/timetableNavContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/timetablePreviousButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:insetLeft="8dp"
|
||||
android:text="@string/all_prev"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitStart"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_left"
|
||||
android:contentDescription="@string/all_prev"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableNavDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name" />
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/timetableNextButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:insetRight="8dp"
|
||||
android:text="@string/all_next"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_right"
|
||||
android:contentDescription="@string/all_next" />
|
||||
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -62,39 +62,49 @@
|
||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||
android:id="@+id/completedLessonsNavContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/completedLessonsPreviousButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:insetLeft="8dp"
|
||||
android:text="@string/all_prev"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitStart"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_left"
|
||||
android:contentDescription="@string/all_prev"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/completedLessonsNavDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name" />
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
<ImageButton
|
||||
android:id="@+id/completedLessonsNextButton"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end|center_vertical"
|
||||
android:insetRight="8dp"
|
||||
android:text="@string/all_next"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:scaleType="fitEnd"
|
||||
android:tint="?colorPrimary"
|
||||
app:srcCompat="@drawable/ic_chevron_right"
|
||||
android:contentDescription="@string/all_next" />
|
||||
</io.github.wulkanowy.ui.widgets.MaterialLinearLayout>
|
||||
</FrameLayout>
|
||||
|
@ -5,12 +5,12 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingBottom="6dp"
|
||||
tools:context=".ui.modules.timetable.completed.CompletedLessonItem"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
@ -31,8 +31,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toStartOf="@id/completedLessonItemAlert"
|
||||
@ -67,8 +67,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:tint="?colorPrimary"
|
||||
android:layout_centerVertical="true"
|
||||
android:tint="?colorTimetableChange"
|
||||
app:srcCompat="@drawable/ic_timetable_swap"
|
||||
tools:ignore="contentDescription" />
|
||||
</RelativeLayout>
|
||||
|
54
app/src/main/res/layout/item_teacher.xml
Normal file
54
app/src/main/res/layout/item_teacher.xml
Normal file
@ -0,0 +1,54 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="7dp"
|
||||
tools:context=".ui.modules.teacher.TeacherItem">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/teacherItemName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="17sp"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/teacherItemShortName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toEndOf="@+id/teacherItemName"
|
||||
android:layout_toRightOf="@+id/teacherItemName"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="17sp"
|
||||
tools:text="[LI]" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/teacherItemSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/teacherItemName"
|
||||
android:layout_alignStart="@id/teacherItemName"
|
||||
android:layout_alignLeft="@id/teacherItemName"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
tools:text="11:11-12:00" />
|
||||
|
||||
</RelativeLayout>
|
@ -1,26 +1,25 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingBottom="6dp"
|
||||
tools:context=".ui.modules.timetable.TimetableItem">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableItemNumber"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLength="2"
|
||||
android:textSize="32sp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
tools:text="5" />
|
||||
|
||||
<TextView
|
||||
@ -32,24 +31,41 @@
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toEndOf="@+id/timetableItemNumber"
|
||||
android:layout_toRightOf="@+id/timetableItemNumber"
|
||||
android:layout_toEndOf="@+id/timetableItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableItemTimeStart"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="17sp"
|
||||
android:textSize="15sp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableItemTime"
|
||||
android:id="@+id/timetableItemTimeStart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignStart="@id/timetableItemSubject"
|
||||
android:layout_alignLeft="@id/timetableItemSubject"
|
||||
android:layout_toEndOf="@id/timetableItemNumber"
|
||||
android:layout_toRightOf="@id/timetableItemNumber"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_alignTop="@id/timetableItemNumber"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="13sp"
|
||||
tools:text="11:11" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableItemTimeFinish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/timetableItemNumber"
|
||||
android:layout_toRightOf="@id/timetableItemNumber"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
tools:text="11:11-12:00" />
|
||||
android:textSize="13sp"
|
||||
tools:text="12:00" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableItemRoom"
|
||||
@ -58,25 +74,47 @@
|
||||
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toStartOf="@id/timetableItemAlert"
|
||||
android:layout_toLeftOf="@id/timetableItemAlert"
|
||||
android:layout_toEndOf="@+id/timetableItemTime"
|
||||
android:layout_toRightOf="@+id/timetableItemTime"
|
||||
android:layout_toEndOf="@+id/timetableItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableItemTimeStart"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
tools:text="Room 22" />
|
||||
android:textSize="13sp"
|
||||
tools:text="22"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/timetableItemAlert"
|
||||
<TextView
|
||||
android:id="@+id/timetableItemTeacher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="10dp"
|
||||
app:srcCompat="@drawable/ic_timetable_swap"
|
||||
app:tint="?colorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
android:layout_alignBottom="@+id/timetableItemNumber"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_toEndOf="@id/timetableItemRoom"
|
||||
android:layout_toRightOf="@id/timetableItemRoom"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="13sp"
|
||||
tools:text="Agata Kowalska - Błaszczyk"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableItemDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/timetableItemTimeFinish"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_toEndOf="@+id/timetableItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableItemTimeStart"
|
||||
android:textColor="?colorTimetableChange"
|
||||
android:textSize="13sp"
|
||||
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -1,85 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/timetableWidgetItemContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:minHeight="45dp"
|
||||
android:orientation="horizontal"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetFactory">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemNumber"
|
||||
android:layout_width="45dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="25sp"
|
||||
tools:text="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTime"
|
||||
android:layout_width="wrap_content"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemNumber"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textSize="13sp"
|
||||
tools:text="08:00 - 08:45" />
|
||||
android:background="@android:color/white"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingRight="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginRight="25dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemTime"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemTime"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textSize="13sp"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemNumber"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLength="2"
|
||||
android:textSize="28sp"
|
||||
android:textColor="@android:color/black"
|
||||
tools:text="5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/timetableWidgetItemSubject"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginRight="25dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemTime"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemTime"
|
||||
android:textColor="@color/colorPrimaryDark"
|
||||
android:textSize="12sp"
|
||||
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu" />
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toEndOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@android:color/black"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemRoom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/timetableWidgetItemTime"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemNumber"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
android:textSize="12sp"
|
||||
tools:text="Sala 25" />
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_alignTop="@id/timetableWidgetItemNumber"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="13sp"
|
||||
tools:text="11:11" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTimeFinish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemNumber"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="13sp"
|
||||
tools:text="12:00" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemRoom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_toEndOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/black"
|
||||
android:textSize="13sp"
|
||||
tools:text="22"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTeacher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemRoom"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemRoom"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/timetable_change_dark"
|
||||
android:textSize="13sp"
|
||||
android:visibility="gone"
|
||||
tools:text="Agata Kowalska - Błaszczyk"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/timetableWidgetItemTimeFinish"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_toEndOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:textColor="@color/timetable_change_dark"
|
||||
android:textSize="13sp"
|
||||
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
||||
tools:visibility="gone"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/colorDivider" />
|
||||
</LinearLayout>
|
||||
|
134
app/src/main/res/layout/item_widget_timetable_dark.xml
Normal file
134
app/src/main/res/layout/item_widget_timetable_dark.xml
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/timetableWidgetItemContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="45dp"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetFactory">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/colorWidgetBackground"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingRight="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemNumber"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLength="2"
|
||||
android:textSize="28sp"
|
||||
android:textColor="@android:color/white"
|
||||
tools:text="5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toEndOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="15sp"
|
||||
android:textColor="@android:color/white"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_alignTop="@id/timetableWidgetItemNumber"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="13sp"
|
||||
tools:text="11:11" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTimeFinish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemNumber"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemNumber"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="13sp"
|
||||
tools:text="12:00" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemRoom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_toEndOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="13sp"
|
||||
tools:text="22"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemTeacher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/timetableWidgetItemNumber"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_toEndOf="@id/timetableWidgetItemRoom"
|
||||
android:layout_toRightOf="@id/timetableWidgetItemRoom"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/timetable_change_light"
|
||||
android:textSize="13sp"
|
||||
android:visibility="gone"
|
||||
tools:text="Agata Kowalska - Błaszczyk"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetItemDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/timetableWidgetItemTimeFinish"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_toEndOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:layout_toRightOf="@+id/timetableWidgetItemTimeStart"
|
||||
android:textColor="@color/timetable_change_light"
|
||||
android:textSize="13sp"
|
||||
tools:text="Lekcja odwołana: uczniowie zwolnieni do domu"
|
||||
tools:visibility="gone"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/colorDividerInverse" />
|
||||
</LinearLayout>
|
@ -4,7 +4,7 @@
|
||||
android:id="@+id/luckyNumberWidgetContainer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/backgorund_luckynumber_widget"
|
||||
android:background="@drawable/background_luckynumber_widget"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
tools:context=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider">
|
||||
|
65
app/src/main/res/layout/widget_luckynumber_dark.xml
Normal file
65
app/src/main/res/layout/widget_luckynumber_dark.xml
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/luckyNumberWidgetContainer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/background_luckynumber_widget_dark"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
tools:context=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/luckyNumberWidgetImageTop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/luckyNumberWidgetNumber"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:contentDescription="@string/lucky_number_title"
|
||||
android:gravity="center"
|
||||
android:src="@drawable/ic_widget_clover"
|
||||
android:tint="@android:color/white"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/luckyNumberWidgetTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:gravity="center"
|
||||
android:labelFor="@id/luckyNumberWidgetImageTop"
|
||||
android:text="@string/lucky_number_title"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="22sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/luckyNumberWidgetImageLeft"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/luckyNumberWidgetNumber"
|
||||
android:contentDescription="@string/lucky_number_title"
|
||||
android:src="@drawable/ic_widget_clover"
|
||||
android:tint="@android:color/white"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/luckyNumberWidgetNumber"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/luckyNumberWidgetTitle"
|
||||
android:layout_toEndOf="@id/luckyNumberWidgetImageLeft"
|
||||
android:layout_toRightOf="@id/luckyNumberWidgetImageLeft"
|
||||
android:gravity="center"
|
||||
android:text="#"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="34sp"
|
||||
tools:ignore="HardcodedText"
|
||||
tools:text="13" />
|
||||
</RelativeLayout>
|
99
app/src/main/res/layout/widget_timetable_dark.xml
Normal file
99
app/src/main/res/layout/widget_timetable_dark.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorWidgetBackground"
|
||||
tools:context=".ui.modules.timetablewidget.TimetableWidgetProvider">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:background="@color/colorWidgetTopBar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@id/timetableWidgetAccount"
|
||||
android:layout_toLeftOf="@id/timetableWidgetAccount"
|
||||
android:layout_toEndOf="@id/timetableWidgetNext"
|
||||
android:layout_toRightOf="@id/timetableWidgetNext"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="15sp"
|
||||
tools:text="Pon. 30.03.2019" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="13sp"
|
||||
tools:text="Jan Kowalski" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/timetableWidgetAccount"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:contentDescription="@string/account_title"
|
||||
android:src="@drawable/ic_widget_account" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/timetableWidgetPrev"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:backgroundTint="@color/colorWidgetNavButton"
|
||||
android:contentDescription="@string/all_prev"
|
||||
android:src="@drawable/ic_widget_chevron"
|
||||
tools:targetApi="lollipop" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/timetableWidgetNext"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/timetableWidgetPrev"
|
||||
android:layout_toRightOf="@id/timetableWidgetPrev"
|
||||
android:backgroundTint="@color/colorWidgetNavButton"
|
||||
android:contentDescription="@string/all_next"
|
||||
android:rotation="180"
|
||||
android:src="@drawable/ic_widget_chevron"
|
||||
tools:targetApi="lollipop" />
|
||||
</RelativeLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/timetableWidgetList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="56dp"
|
||||
tools:listitem="@layout/item_widget_timetable_dark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetableWidgetEmpty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/widget_timetable_no_items"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
tools:visibility="invisible" />
|
||||
</FrameLayout>
|
@ -3,6 +3,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/gradeDetailsMenuRead"
|
||||
android:enabled="false"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/grade_menu_read"
|
||||
app:iconTint="@color/mtrl_on_surface_emphasis_medium"
|
||||
|
@ -3,6 +3,7 @@
|
||||
<style name="WulkanowyTheme" parent="@style/Theme.MaterialComponents">
|
||||
<item name="colorPrimary">@color/colorPrimaryLight</item>
|
||||
<item name="colorSecondary">@color/colorPrimaryLight</item>
|
||||
<item name="colorTimetableChange">@color/timetable_change_light</item>
|
||||
<item name="colorError">@color/colorErrorLight</item>
|
||||
<item name="colorDivider">@color/colorDividerInverse</item>
|
||||
<item name="android:windowBackground">?colorSurface</item>
|
||||
|
@ -66,8 +66,9 @@
|
||||
<string name="grade_menu_summary">Podsumowanie</string>
|
||||
<string name="grade_menu_statistics">Klasa</string>
|
||||
<string name="grade_menu_read">Oznacz jako przeczytane</string>
|
||||
<string name="grade_statistics_partial">Oceny cząstkowe</string>
|
||||
<string name="grade_statistics_semester">Oceny semestralne</string>
|
||||
<string name="grade_statistics_partial">Cząstkowe</string>
|
||||
<string name="grade_statistics_semester">Semestralne</string>
|
||||
<string name="grade_statistics_points">Punkty</string>
|
||||
<plurals name="grade_number_item">
|
||||
<item quantity="one">%d ocena</item>
|
||||
<item quantity="few">%d oceny</item>
|
||||
@ -111,7 +112,7 @@
|
||||
<string name="attendance_absence_excused">Nieobecność usprawiedliwiona</string>
|
||||
<string name="attendance_absence_unexcused">Nieobecność nieusprawiedliwiona</string>
|
||||
<string name="attendance_exemption">Zwolniony</string>
|
||||
<string name="attendance_excused_lateness">Spóźnienie usprawiedliowione</string>
|
||||
<string name="attendance_excused_lateness">Spóźnienie usprawiedliwione</string>
|
||||
<string name="attendance_unexcused_lateness">Spóźnienie nieusprawiedliwione</string>
|
||||
<string name="attendance_present">Obecny</string>
|
||||
<string name="attendance_number">Numer lekcji</string>
|
||||
@ -216,6 +217,12 @@
|
||||
<string name="mobile_device_pin">PIN</string>
|
||||
|
||||
|
||||
<!--Teacher-->
|
||||
<string name="teachers_title">Nauczyciele</string>
|
||||
<string name="teacher_no_items">Brak informacji o nauczycielach</string>
|
||||
<string name="teacher_no_subject">Brak przedmiotu</string>
|
||||
|
||||
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Dodaj konto</string>
|
||||
<string name="account_logout">Wyloguj</string>
|
||||
@ -260,6 +267,9 @@
|
||||
|
||||
<!--Timetable Widget-->
|
||||
<string name="widget_timetable_no_items">Brak lekcji</string>
|
||||
<string name="widget_timetable_theme_title">Wybierz motyw</string>
|
||||
<string name="widget_timetable_theme_light">Jasny</string>
|
||||
<string name="widget_timetable_theme_dark">Ciemny</string>
|
||||
|
||||
|
||||
<!--Preferences-->
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<attr name="colorDivider" format="color" />
|
||||
<attr name="colorTimetableChange" format="color" />
|
||||
</resources>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user