mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-20 21:24:44 +01:00
Refactor grade module (#156)
This commit is contained in:
parent
357b2350cb
commit
f2b7c0e781
@ -1,15 +1,15 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'// sync warning probably caused by bug https://issuetracker.google.com/issues/74537216, fix in AS 3.2
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'io.fabric'
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
apply from: 'jacoco.gradle'
|
||||
apply from: 'sonarqube.gradle'
|
||||
apply plugin: 'com.github.triplet.play'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.2'
|
||||
buildToolsVersion '28.0.3'
|
||||
|
||||
playAccountConfigs {
|
||||
defaultAccountConfig {
|
||||
@ -75,13 +75,15 @@ dependencies {
|
||||
implementation('com.github.wulkanowy:api:07201a4') {
|
||||
exclude module: "threetenbp"
|
||||
}
|
||||
|
||||
implementation "com.android.support:support-v4:$supportVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||
implementation "com.android.support:design:$supportVersion"
|
||||
implementation "com.android.support:cardview-v7:$supportVersion"
|
||||
implementation "com.android.support:preference-v14:$supportVersion"
|
||||
implementation 'com.android.support:multidex:1.0.3'
|
||||
|
||||
implementation "com.google.android.gms:play-services-oss-licenses:16.0.0"
|
||||
implementation "com.google.android.gms:play-services-oss-licenses:16.0.1"
|
||||
implementation "com.firebase:firebase-jobdispatcher:0.8.5"
|
||||
|
||||
implementation "com.google.dagger:dagger-android-support:2.17"
|
||||
@ -92,7 +94,7 @@ dependencies {
|
||||
implementation "android.arch.persistence.room:rxjava2:1.1.1"
|
||||
kapt "android.arch.persistence.room:compiler:1.1.1"
|
||||
|
||||
implementation "eu.davidea:flexible-adapter:5.0.5"
|
||||
implementation "eu.davidea:flexible-adapter:5.0.6"
|
||||
implementation "eu.davidea:flexible-adapter-ui:1.0.0-b5"
|
||||
implementation "com.aurelhubert:ahbottomnavigation:2.2.0"
|
||||
implementation 'com.ncapdevi:frag-nav:3.0.0-RC3'
|
||||
@ -101,8 +103,6 @@ dependencies {
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
|
||||
implementation "io.reactivex.rxjava2:rxjava:2.2.1"
|
||||
|
||||
implementation "org.apache.commons:commons-lang3:3.8"
|
||||
implementation "org.apache.commons:commons-collections4:4.2"
|
||||
implementation "com.jakewharton.threetenabp:threetenabp:1.1.0"
|
||||
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
|
@ -34,13 +34,13 @@ class AttendanceLocalTest {
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
attendanceLocal.saveAttendance(listOf(
|
||||
Attendance(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 10)),
|
||||
Attendance(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 14)),
|
||||
Attendance(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 17)) // in next week
|
||||
Attendance(0, "1", "2", LocalDate.of(2018, 9, 10), 0, "", ""),
|
||||
Attendance(0, "1", "2", LocalDate.of(2018, 9, 14), 0, "", ""),
|
||||
Attendance(0, "1", "2", LocalDate.of(2018, 9, 17), 0, "", "")
|
||||
))
|
||||
|
||||
val attendance = attendanceLocal
|
||||
.getAttendance(Semester(studentId = "1", diaryId = "2", semesterId = "3"),
|
||||
.getAttendance(Semester(1, "1", "2", "", "3", 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
)
|
||||
|
@ -34,13 +34,13 @@ class ExamLocalTest {
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
examLocal.saveExams(listOf(
|
||||
Exam(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 10)),
|
||||
Exam(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 14)),
|
||||
Exam(studentId = "1", diaryId = "2", date = LocalDate.of(2018, 9, 17)) // in next week
|
||||
Exam(0, "1", "2", LocalDate.of(2018, 9, 10), LocalDate.now(), "", "", "", "", "", ""),
|
||||
Exam(0, "1", "2", LocalDate.of(2018, 9, 14), LocalDate.now(), "", "", "", "", "", ""),
|
||||
Exam(0, "1", "2", LocalDate.of(2018, 9, 17), LocalDate.now(), "", "", "", "", "", "")
|
||||
))
|
||||
|
||||
val exams = examLocal
|
||||
.getExams(Semester(studentId = "1", diaryId = "2", semesterId = "3"),
|
||||
.getExams(Semester(1, "1", "2", "", "3", 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ import kotlin.test.assertEquals
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SessionLocalTest {
|
||||
|
||||
private lateinit var studentLocal: SessionLocal
|
||||
private lateinit var sessionLocal: SessionLocal
|
||||
|
||||
private lateinit var testDb: AppDatabase
|
||||
|
||||
@ -28,7 +28,7 @@ class SessionLocalTest {
|
||||
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
|
||||
.build()
|
||||
sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
|
||||
studentLocal = SessionLocal(testDb.studentDao(), testDb.semesterDao(), sharedHelper, context)
|
||||
sessionLocal = SessionLocal(testDb.studentDao(), testDb.semesterDao(), sharedHelper, context)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -38,12 +38,12 @@ class SessionLocalTest {
|
||||
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolId = "23")).blockingAwait()
|
||||
sessionLocal.saveStudent(Student(email = "test", password = "test123", schoolId = "23")).blockingAwait()
|
||||
assert(sharedHelper.getLong(SessionLocal.LAST_USER_KEY, 0) == 1L)
|
||||
|
||||
assert(studentLocal.isSessionSaved)
|
||||
assert(sessionLocal.isSessionSaved)
|
||||
|
||||
val student = studentLocal.getLastStudent().blockingGet()
|
||||
val student = sessionLocal.getLastStudent().blockingGet()
|
||||
assertEquals("23", student.schoolId)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.github.wulkanowy"
|
||||
android:installLocation="internalOnly">
|
||||
|
||||
@ -15,13 +14,11 @@
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/WulkanowyTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="m">
|
||||
android:usesCleartextTraffic="true">
|
||||
<activity
|
||||
android:name=".ui.splash.SplashActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/WulkanowyTheme.SplashTheme">
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/WulkanowyTheme.SplashScreen">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@ -32,39 +29,13 @@
|
||||
android:name=".ui.login.LoginActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/login_title"
|
||||
android:theme="@style/WulkanowyTheme.DarkActionBar"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name=".ui.main.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/main_title"
|
||||
android:launchMode="singleTop" />
|
||||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||
android:theme="@style/WulkanowyTheme.DarkActionBar" />
|
||||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
|
||||
android:theme="@style/WulkanowyTheme.DarkActionBar" />
|
||||
|
||||
<service
|
||||
android:name=".services.jobs.SyncJob"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".services.widgets.TimetableWidgetServices"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<receiver android:name=".ui.widgets.TimetableWidgetProvider">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/provider_widget_timetable" />
|
||||
</receiver>
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||
|
||||
<meta-data
|
||||
android:name="io.fabric.ApiKey"
|
||||
|
@ -9,9 +9,12 @@ import com.jakewharton.threetenabp.AndroidThreeTen
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.support.DaggerApplication
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.utils.Log
|
||||
import io.fabric.sdk.android.Fabric
|
||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||
import io.github.wulkanowy.di.DaggerAppComponent
|
||||
import io.github.wulkanowy.utils.LoggerUtils
|
||||
import io.github.wulkanowy.utils.CrashlyticsTree
|
||||
import io.github.wulkanowy.utils.DebugLogTree
|
||||
import timber.log.Timber
|
||||
|
||||
class WulkanowyApp : DaggerApplication() {
|
||||
@ -24,31 +27,27 @@ class WulkanowyApp : DaggerApplication() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
AndroidThreeTen.init(this)
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
enableDebugLog()
|
||||
}
|
||||
initializeFabric()
|
||||
if (DEBUG) enableDebugLog()
|
||||
}
|
||||
|
||||
private fun enableDebugLog() {
|
||||
FlexibleAdapter.enableLogs(eu.davidea.flexibleadapter.utils.Log.Level.DEBUG)
|
||||
Timber.plant(LoggerUtils.DebugLogTree())
|
||||
Timber.plant(DebugLogTree)
|
||||
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
|
||||
}
|
||||
|
||||
private fun initializeFabric() {
|
||||
Fabric.with(Fabric.Builder(this)
|
||||
.kits(
|
||||
Crashlytics.Builder()
|
||||
.core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
|
||||
.build(),
|
||||
Answers()
|
||||
)
|
||||
.kits(Crashlytics.Builder()
|
||||
.core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
|
||||
.build(),
|
||||
Answers())
|
||||
.debuggable(BuildConfig.DEBUG)
|
||||
.build())
|
||||
Timber.plant(LoggerUtils.CrashlyticsTree())
|
||||
Timber.plant(CrashlyticsTree)
|
||||
}
|
||||
|
||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
|
||||
DaggerAppComponent.builder().create(this)
|
||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
|
||||
return DaggerAppComponent.builder().create(this)
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
package io.github.wulkanowy.data
|
||||
|
||||
import android.arch.persistence.room.Room
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.support.v7.preference.PreferenceManager
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.SocketInternetObservingStrategy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import io.github.wulkanowy.utils.DATABASE_NAME
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@ -18,7 +17,10 @@ internal class RepositoryModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideInternetObservingSettings(): InternetObservingSettings {
|
||||
return InternetObservingSettings.create()
|
||||
return InternetObservingSettings
|
||||
.strategy(SocketInternetObservingStrategy())
|
||||
.host("www.google.com")
|
||||
.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@ -27,10 +29,7 @@ internal class RepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideDatabase(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
|
||||
.build()
|
||||
}
|
||||
fun provideDatabase(context: Context) = AppDatabase.newInstance(context)
|
||||
|
||||
@Provides
|
||||
fun provideErrorHandler(context: Context) = ErrorHandler(context.resources)
|
||||
@ -49,6 +48,14 @@ internal class RepositoryModule {
|
||||
@Provides
|
||||
fun provideSemesterDao(database: AppDatabase) = database.semesterDao()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGradeDao(database: AppDatabase) = database.gradeDao()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGradeSummaryDao(database: AppDatabase) = database.gradeSummaryDao()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideExamDao(database: AppDatabase) = database.examsDao()
|
||||
|
@ -1,16 +1,12 @@
|
||||
package io.github.wulkanowy.data.db
|
||||
|
||||
import android.arch.persistence.room.Database
|
||||
import android.arch.persistence.room.Room
|
||||
import android.arch.persistence.room.RoomDatabase
|
||||
import android.arch.persistence.room.TypeConverters
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import android.content.Context
|
||||
import io.github.wulkanowy.data.db.dao.*
|
||||
import io.github.wulkanowy.data.db.entities.*
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@ -19,7 +15,9 @@ import javax.inject.Singleton
|
||||
Student::class,
|
||||
Semester::class,
|
||||
Exam::class,
|
||||
Attendance::class
|
||||
Attendance::class,
|
||||
Grade::class,
|
||||
GradeSummary::class
|
||||
],
|
||||
version = 1,
|
||||
exportSchema = false
|
||||
@ -27,6 +25,13 @@ import javax.inject.Singleton
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun studentDao(): StudentDao
|
||||
|
||||
abstract fun semesterDao(): SemesterDao
|
||||
@ -34,4 +39,8 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun examsDao(): ExamDao
|
||||
|
||||
abstract fun attendanceDao(): AttendanceDao
|
||||
|
||||
abstract fun gradeDao(): GradeDao
|
||||
|
||||
abstract fun gradeSummaryDao(): GradeSummaryDao
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import android.arch.persistence.room.*
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.reactivex.Maybe
|
||||
|
||||
@Dao
|
||||
interface GradeDao {
|
||||
|
||||
@Insert
|
||||
fun insertAll(grades: List<Grade>)
|
||||
|
||||
@Update
|
||||
fun update(grade: Grade)
|
||||
|
||||
@Delete
|
||||
fun deleteAll(grades: List<Grade>)
|
||||
|
||||
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
|
||||
fun getGrades(semesterId: String, studentId: String): Maybe<List<Grade>>
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import android.arch.persistence.room.Dao
|
||||
import android.arch.persistence.room.Insert
|
||||
import android.arch.persistence.room.OnConflictStrategy.REPLACE
|
||||
import android.arch.persistence.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.reactivex.Maybe
|
||||
|
||||
@Dao
|
||||
interface GradeSummaryDao {
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
fun insertAll(gradesSummary: List<GradeSummary>)
|
||||
|
||||
@Query("SELECT * FROM grades_summary WHERE student_id = :studentId AND semester_id = :semesterId")
|
||||
fun getGradesSummary(semesterId: String, studentId: String): Maybe<List<GradeSummary>>
|
||||
}
|
@ -13,18 +13,18 @@ data class Attendance(
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String = "",
|
||||
var studentId: String,
|
||||
|
||||
@ColumnInfo(name = "diary_id")
|
||||
var diaryId: String = "",
|
||||
var diaryId: String,
|
||||
|
||||
var date: LocalDate,
|
||||
|
||||
var number: Int = 0,
|
||||
var number: Int,
|
||||
|
||||
var subject: String = "",
|
||||
var subject: String,
|
||||
|
||||
var name: String = "",
|
||||
var name: String,
|
||||
|
||||
var presence: Boolean = false,
|
||||
|
||||
|
@ -13,26 +13,26 @@ data class Exam(
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String = "",
|
||||
var studentId: String,
|
||||
|
||||
@ColumnInfo(name = "diary_id")
|
||||
var diaryId: String = "",
|
||||
var diaryId: String,
|
||||
|
||||
var date: LocalDate,
|
||||
|
||||
@ColumnInfo(name = "entry_date")
|
||||
var entryDate: LocalDate = LocalDate.now(),
|
||||
|
||||
var subject: String = "",
|
||||
var subject: String,
|
||||
|
||||
var group: String = "",
|
||||
var group: String,
|
||||
|
||||
var type: String = "",
|
||||
var type: String,
|
||||
|
||||
var description: String = "",
|
||||
var description: String,
|
||||
|
||||
var teacher: String = "",
|
||||
var teacher: String,
|
||||
|
||||
@ColumnInfo(name = "teacher_symbol")
|
||||
var teacherSymbol: String = ""
|
||||
var teacherSymbol: String
|
||||
) : Serializable
|
||||
|
@ -0,0 +1,49 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo
|
||||
import android.arch.persistence.room.Entity
|
||||
import android.arch.persistence.room.PrimaryKey
|
||||
import org.threeten.bp.LocalDate
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "Grades")
|
||||
data class Grade(
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
var semesterId: String,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String,
|
||||
|
||||
var subject: String,
|
||||
|
||||
var entry: String,
|
||||
|
||||
var value: Int,
|
||||
|
||||
var modifier: Double,
|
||||
|
||||
var comment: String,
|
||||
|
||||
var color: String,
|
||||
|
||||
@ColumnInfo(name = "grade_symbol")
|
||||
var gradeSymbol: String,
|
||||
|
||||
var description: String,
|
||||
|
||||
var weight: String,
|
||||
|
||||
var weightValue: Int,
|
||||
|
||||
var date: LocalDate,
|
||||
|
||||
var teacher: String
|
||||
) : Serializable {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
||||
@ColumnInfo(name = "is_new")
|
||||
var isNew: Boolean = false
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import android.arch.persistence.room.ColumnInfo
|
||||
import android.arch.persistence.room.Entity
|
||||
import android.arch.persistence.room.Index
|
||||
import android.arch.persistence.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "Grades_Summary",
|
||||
indices = [Index(value = ["semester_id", "student_id", "subject"], unique = true)])
|
||||
data class GradeSummary(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
var semesterId: String,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: String,
|
||||
|
||||
var subject: String,
|
||||
|
||||
var predictedGrade: String,
|
||||
|
||||
var finalGrade: String
|
||||
)
|
@ -19,13 +19,13 @@ data class Semester(
|
||||
var diaryId: String,
|
||||
|
||||
@ColumnInfo(name = "diary_name")
|
||||
var diaryName: String = "",
|
||||
var diaryName: String,
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
var semesterId: String,
|
||||
|
||||
@ColumnInfo(name = "semester_name")
|
||||
var semesterName: Int = 0,
|
||||
var semesterName: Int,
|
||||
|
||||
@ColumnInfo(name = "is_current")
|
||||
var current: Boolean = false
|
||||
|
@ -6,7 +6,7 @@ import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.AttendanceLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.AttendanceRemote
|
||||
import io.github.wulkanowy.utils.extension.getWeekFirstDayAlwaysCurrent
|
||||
import io.github.wulkanowy.utils.weekFirstDayAlwaysCurrent
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.DayOfWeek
|
||||
import org.threeten.bp.LocalDate
|
||||
@ -21,7 +21,7 @@ class AttendanceRepository @Inject constructor(
|
||||
) {
|
||||
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Attendance>> {
|
||||
val start = startDate.getWeekFirstDayAlwaysCurrent()
|
||||
val start = startDate.weekFirstDayAlwaysCurrent
|
||||
val end = endDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
|
||||
|
||||
return local.getAttendance(semester, start, end).filter { !forceRefresh }
|
||||
|
@ -6,8 +6,7 @@ import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.ExamLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.ExamRemote
|
||||
import io.github.wulkanowy.utils.extension.getWeekFirstDayAlwaysCurrent
|
||||
import io.github.wulkanowy.utils.extension.toDate
|
||||
import io.github.wulkanowy.utils.weekFirstDayAlwaysCurrent
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.DayOfWeek
|
||||
import org.threeten.bp.LocalDate
|
||||
@ -24,7 +23,7 @@ class ExamRepository @Inject constructor(
|
||||
) {
|
||||
|
||||
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
|
||||
val start = startDate.getWeekFirstDayAlwaysCurrent()
|
||||
val start = startDate.weekFirstDayAlwaysCurrent
|
||||
val end = endDate.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
|
||||
|
||||
return local.getExams(semester, start, end).filter { !forceRefresh }
|
||||
|
@ -0,0 +1,42 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
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.Grade
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.GradeLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.GradeRemote
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: GradeLocal,
|
||||
private val remote: GradeRemote
|
||||
) {
|
||||
|
||||
fun getGrades(semester: Semester, forceRefresh: Boolean = false): Single<List<Grade>> {
|
||||
return local.getGrades(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getGrades(semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { newGrades ->
|
||||
local.getGrades(semester).toSingle(emptyList())
|
||||
.doOnSuccess { oldGrades ->
|
||||
local.deleteGrades(oldGrades - newGrades)
|
||||
local.saveGrades((newGrades - oldGrades)
|
||||
.onEach { if (oldGrades.isNotEmpty()) it.isNew = true })
|
||||
}
|
||||
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
|
||||
|
||||
}
|
||||
|
||||
fun updateGrade(grade: Grade): Completable {
|
||||
return local.updateGrade(grade)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
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.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.local.GradeSummaryLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.GradeSummaryRemote
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeSummaryRepository @Inject constructor(
|
||||
private val settings: InternetObservingSettings,
|
||||
private val local: GradeSummaryLocal,
|
||||
private val remote: GradeSummaryRemote
|
||||
) {
|
||||
|
||||
fun getGradesSummary(semester: Semester, forceRefresh: Boolean = false): Single<List<GradeSummary>> {
|
||||
return local.getGradesSummary(semester).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getGradeSummary(semester)
|
||||
else Single.error(UnknownHostException())
|
||||
}
|
||||
).doOnSuccess { local.saveGradesSummary(it) }
|
||||
}
|
||||
}
|
@ -42,9 +42,8 @@ class SessionRepository @Inject constructor(
|
||||
}
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
return remote.getSemesters(student).flatMapCompletable {
|
||||
local.saveSemesters(it)
|
||||
}.concatWith(local.saveStudent(student))
|
||||
return remote.getSemesters(student).flatMapCompletable { local.saveSemesters(it) }
|
||||
.concatWith(local.saveStudent(student))
|
||||
}
|
||||
|
||||
fun clearCache() {
|
||||
|
@ -3,11 +3,8 @@ package io.github.wulkanowy.data.repositories.local
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.utils.extension.toDate
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.DayOfWeek
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import javax.inject.Inject
|
||||
|
||||
class ExamLocal @Inject constructor(private val examDb: ExamDao) {
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.GradeDao
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
|
||||
|
||||
fun getGrades(semester: Semester): Maybe<List<Grade>> {
|
||||
return gradeDb.getGrades(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveGrades(grades: List<Grade>) {
|
||||
gradeDb.insertAll(grades)
|
||||
}
|
||||
|
||||
fun updateGrade(grade: Grade): Completable {
|
||||
return Completable.fromCallable { gradeDb.update(grade) }
|
||||
}
|
||||
|
||||
fun deleteGrades(grades: List<Grade>) {
|
||||
gradeDb.deleteAll(grades)
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSummaryDao) {
|
||||
|
||||
fun getGradesSummary(semester: Semester): Maybe<List<GradeSummary>> {
|
||||
return gradeSummaryDb.getGradesSummary(semester.semesterId, semester.studentId)
|
||||
.filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
|
||||
gradeSummaryDb.insertAll(gradesSummary)
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package io.github.wulkanowy.data.repositories.remote
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.utils.extension.toLocalDate
|
||||
import io.github.wulkanowy.utils.toLocalDate
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
@ -3,7 +3,7 @@ package io.github.wulkanowy.data.repositories.remote
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.utils.extension.toLocalDate
|
||||
import io.github.wulkanowy.utils.toLocalDate
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
@ -0,0 +1,42 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.utils.toLocalDate
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getGrades(semester: Semester): Single<List<Grade>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getGrades(semester.semesterId.toInt()) }
|
||||
.map { grades ->
|
||||
grades.map {
|
||||
Grade(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.subject,
|
||||
entry = it.entry,
|
||||
value = it.value,
|
||||
modifier = it.modifier.toDouble(),
|
||||
comment = it.comment,
|
||||
color = it.color,
|
||||
gradeSymbol = it.symbol,
|
||||
description = it.description,
|
||||
weight = it.weight,
|
||||
weightValue = it.weightValue,
|
||||
date = it.date.toLocalDate(),
|
||||
teacher = it.teacher
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class GradeSummaryRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getGradeSummary(semester: Semester): Single<List<GradeSummary>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getGradesSummary(semester.semesterId.toInt()) }
|
||||
.map { gradesSummary ->
|
||||
gradesSummary.map {
|
||||
GradeSummary(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.name,
|
||||
predictedGrade = it.predicted,
|
||||
finalGrade = it.final
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,13 +8,16 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.WulkanowyApp
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersProvider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
internal class AppModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideContext(app: WulkanowyApp): Context = app
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSchedulers(): SchedulersManager = SchedulersProvider()
|
||||
|
||||
|
@ -6,11 +6,10 @@ import android.support.design.widget.Snackbar.LENGTH_LONG
|
||||
import android.support.v7.app.AppCompatDelegate
|
||||
import android.view.View
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
import io.github.wulkanowy.R
|
||||
|
||||
abstract class BaseActivity : DaggerAppCompatActivity(), BaseView {
|
||||
|
||||
protected lateinit var messageView: View
|
||||
protected lateinit var messageContainer: View
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -18,12 +17,7 @@ abstract class BaseActivity : DaggerAppCompatActivity(), BaseView {
|
||||
}
|
||||
|
||||
override fun showMessage(text: String) {
|
||||
Snackbar.make(messageView, text, LENGTH_LONG).show()
|
||||
|
||||
}
|
||||
|
||||
override fun showNoNetworkMessage() {
|
||||
showMessage(getString(R.string.all_no_internet))
|
||||
Snackbar.make(messageContainer, text, LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -1,24 +1,10 @@
|
||||
package io.github.wulkanowy.ui.base
|
||||
|
||||
import android.support.annotation.StringRes
|
||||
|
||||
import dagger.android.support.DaggerFragment
|
||||
|
||||
abstract class BaseFragment : DaggerFragment(), BaseView {
|
||||
|
||||
fun setTitle(title: String) {
|
||||
activity?.title = title
|
||||
}
|
||||
|
||||
override fun showMessage(text: String) {
|
||||
(activity as BaseActivity?)?.showMessage(text)
|
||||
}
|
||||
|
||||
fun showMessage(@StringRes stringId: Int) {
|
||||
showMessage(getString(stringId))
|
||||
}
|
||||
|
||||
override fun showNoNetworkMessage() {
|
||||
(activity as BaseActivity?)?.showNoNetworkMessage()
|
||||
}
|
||||
}
|
||||
|
@ -3,28 +3,30 @@ package io.github.wulkanowy.ui.base
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v4.app.FragmentStatePagerAdapter
|
||||
import android.view.ViewGroup
|
||||
|
||||
class BasePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
|
||||
|
||||
private val fragmentList = mutableListOf<Fragment>()
|
||||
val fragments = mutableMapOf<String?, Fragment>()
|
||||
|
||||
private val titleList = mutableListOf<String>()
|
||||
val registeredFragments = mutableMapOf<Int, Fragment>()
|
||||
|
||||
fun addFragment(fragment: Fragment, title: String) {
|
||||
fragmentList.add(fragment)
|
||||
titleList.add(title)
|
||||
}
|
||||
override fun getItem(position: Int) = fragments.values.elementAt(position)
|
||||
|
||||
fun addFragments(vararg fragments: Fragment) {
|
||||
fragmentList.addAll(fragments)
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): Fragment = fragmentList[position]
|
||||
|
||||
override fun getCount(): Int = fragmentList.size
|
||||
override fun getCount() = fragments.size
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
return if (!titleList.isEmpty() && titleList.size == fragmentList.size) titleList[position]
|
||||
else null
|
||||
return fragments.keys.elementAtOrNull(position)
|
||||
}
|
||||
|
||||
override fun instantiateItem(container: ViewGroup, position: Int): Any {
|
||||
return super.instantiateItem(container, position).also {
|
||||
registeredFragments[position] = it as Fragment
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, fragment: Any) {
|
||||
registeredFragments.remove(position)
|
||||
super.destroyItem(container, position, fragment)
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,4 @@ package io.github.wulkanowy.ui.base
|
||||
interface BaseView {
|
||||
|
||||
fun showMessage(text: String)
|
||||
|
||||
fun showNoNetworkMessage()
|
||||
}
|
||||
|
@ -8,10 +8,9 @@ import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.base.BasePagerAdapter
|
||||
import io.github.wulkanowy.ui.login.form.LoginFormFragment
|
||||
import io.github.wulkanowy.ui.login.options.LoginOptionsFragment
|
||||
import io.github.wulkanowy.utils.extension.setOnSelectPageListener
|
||||
import io.github.wulkanowy.utils.setOnSelectPageListener
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
|
||||
@ -19,7 +18,6 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
lateinit var presenter: LoginPresenter
|
||||
|
||||
@Inject
|
||||
@field:Named("Login")
|
||||
lateinit var loginAdapter: BasePagerAdapter
|
||||
|
||||
companion object {
|
||||
@ -30,7 +28,7 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_login)
|
||||
presenter.attachView(this)
|
||||
messageView = loginContainer
|
||||
messageContainer = loginContainer
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
@ -38,7 +36,10 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
}
|
||||
|
||||
override fun initAdapter() {
|
||||
loginAdapter.addFragments(LoginFormFragment(), LoginOptionsFragment())
|
||||
loginAdapter.fragments.putAll(mapOf(
|
||||
"1" to LoginFormFragment.newInstance(),
|
||||
"2" to LoginOptionsFragment.newInstance()
|
||||
))
|
||||
loginViewpager.run {
|
||||
adapter = loginAdapter
|
||||
setOnSelectPageListener { presenter.onPageSelected(it) }
|
||||
@ -61,7 +62,7 @@ class LoginActivity : BaseActivity(), LoginView, LoginSwitchListener {
|
||||
(loginAdapter.getItem(index) as LoginOptionsFragment).loadData()
|
||||
}
|
||||
|
||||
override fun currentViewPosition(): Int = loginViewpager.currentItem
|
||||
override fun currentViewPosition() = loginViewpager.currentItem
|
||||
|
||||
public override fun onDestroy() {
|
||||
presenter.detachView()
|
||||
|
@ -9,8 +9,6 @@ import io.github.wulkanowy.di.scopes.PerFragment
|
||||
import io.github.wulkanowy.ui.base.BasePagerAdapter
|
||||
import io.github.wulkanowy.ui.login.form.LoginFormFragment
|
||||
import io.github.wulkanowy.ui.login.options.LoginOptionsFragment
|
||||
import io.github.wulkanowy.ui.login.options.LoginOptionsModule
|
||||
import javax.inject.Named
|
||||
|
||||
@Module
|
||||
internal abstract class LoginModule {
|
||||
@ -19,8 +17,8 @@ internal abstract class LoginModule {
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
@PerActivity
|
||||
@Provides
|
||||
@Named("Login")
|
||||
fun provideLoginAdapter(activity: LoginActivity) = BasePagerAdapter(activity.supportFragmentManager)
|
||||
|
||||
@JvmStatic
|
||||
@ -34,6 +32,6 @@ internal abstract class LoginModule {
|
||||
abstract fun bindLoginFormFragment(): LoginFormFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector(modules = [LoginOptionsModule::class])
|
||||
@ContributesAndroidInjector()
|
||||
abstract fun bindLoginOptionsFragment(): LoginOptionsFragment
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import android.widget.ArrayAdapter
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.login.LoginSwitchListener
|
||||
import io.github.wulkanowy.utils.extension.hideSoftInput
|
||||
import io.github.wulkanowy.utils.extension.showSoftInput
|
||||
import io.github.wulkanowy.utils.hideSoftInput
|
||||
import io.github.wulkanowy.utils.showSoftInput
|
||||
import kotlinx.android.synthetic.main.fragment_login_form.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -21,6 +21,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
||||
@Inject
|
||||
lateinit var presenter: LoginFormPresenter
|
||||
|
||||
companion object {
|
||||
fun newInstance() = LoginFormFragment()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_login_form, container, false)
|
||||
}
|
||||
@ -132,8 +136,8 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
||||
loginFormProgressContainer.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.login.form
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.DEFAULT_SYMBOL
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -83,6 +82,6 @@ class LoginFormPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun normalizeSymbol(symbol: String): String {
|
||||
return if (symbol.isEmpty()) DEFAULT_SYMBOL else symbol
|
||||
return if (symbol.isEmpty()) "Default" else symbol
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.main.MainActivity
|
||||
import io.github.wulkanowy.utils.extension.setOnItemClickListener
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_login_options.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
package io.github.wulkanowy.ui.login.options
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import io.github.wulkanowy.di.scopes.PerFragment
|
||||
|
||||
@Module
|
||||
internal class LoginOptionsModule {
|
||||
|
||||
@Provides
|
||||
@PerFragment
|
||||
fun provideLoginOptionsAdapter() = FlexibleAdapter<LoginOptionsItem>(null)
|
||||
}
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.content.ContextCompat
|
||||
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation
|
||||
import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
|
||||
@ -16,10 +15,12 @@ import io.github.wulkanowy.ui.main.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.main.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.main.more.MoreFragment
|
||||
import io.github.wulkanowy.ui.main.timetable.TimetableFragment
|
||||
import io.github.wulkanowy.utils.setOnTabTransactionListener
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class MainActivity : BaseActivity(), MainView, FragNavController.TransactionListener {
|
||||
class MainActivity : BaseActivity(), MainView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: MainPresenter
|
||||
|
||||
@ -27,7 +28,7 @@ class MainActivity : BaseActivity(), MainView, FragNavController.TransactionList
|
||||
lateinit var navController: FragNavController
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_TAB = 0
|
||||
const val DEFAULT_TAB = 2
|
||||
|
||||
fun getStartIntent(context: Context) = Intent(context, MainActivity::class.java)
|
||||
}
|
||||
@ -35,27 +36,19 @@ class MainActivity : BaseActivity(), MainView, FragNavController.TransactionList
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
messageView = mainContainer
|
||||
setSupportActionBar(mainToolbar)
|
||||
messageContainer = mainFragmentContainer
|
||||
|
||||
presenter.attachView(this)
|
||||
navController.initialize(DEFAULT_TAB, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun initFragmentController() {
|
||||
navController.run {
|
||||
rootFragments = listOf(
|
||||
GradeFragment.newInstance(),
|
||||
AttendanceFragment.newInstance(),
|
||||
ExamFragment.newInstance(),
|
||||
TimetableFragment.newInstance(),
|
||||
MoreFragment.newInstance()
|
||||
)
|
||||
fragmentHideStrategy = DETACH_ON_NAVIGATE_HIDE_ON_SWITCH
|
||||
createEager = true
|
||||
transactionListener = this@MainActivity
|
||||
}
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
presenter.onStartView()
|
||||
}
|
||||
|
||||
override fun initBottomNav() {
|
||||
override fun initView() {
|
||||
mainBottomNav.run {
|
||||
addItems(mutableListOf(
|
||||
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_menu_main_grade_26dp, 0),
|
||||
@ -69,39 +62,63 @@ class MainActivity : BaseActivity(), MainView, FragNavController.TransactionList
|
||||
titleState = AHBottomNavigation.TitleState.ALWAYS_SHOW
|
||||
currentItem = DEFAULT_TAB
|
||||
isBehaviorTranslationEnabled = false
|
||||
setOnTabSelectedListener { position, _ ->
|
||||
presenter.onTabSelected(position)
|
||||
setTitleTextSizeInSp(10f, 10f)
|
||||
|
||||
setOnTabSelectedListener { position, wasSelected ->
|
||||
presenter.onTabSelected(position, wasSelected)
|
||||
}
|
||||
}
|
||||
|
||||
navController.run {
|
||||
setOnTabTransactionListener { presenter.onMenuViewChange(it) }
|
||||
fragmentHideStrategy = DETACH_ON_NAVIGATE_HIDE_ON_SWITCH
|
||||
rootFragments = listOf(
|
||||
GradeFragment.newInstance(),
|
||||
AttendanceFragment.newInstance(),
|
||||
ExamFragment.newInstance(),
|
||||
TimetableFragment.newInstance(),
|
||||
MoreFragment.newInstance()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentTransaction(fragment: Fragment?, transactionType: FragNavController.TransactionType) {}
|
||||
|
||||
override fun onTabTransaction(fragment: Fragment?, index: Int) {
|
||||
presenter.onMenuFragmentChange(index)
|
||||
}
|
||||
|
||||
override fun switchMenuFragment(position: Int) {
|
||||
override fun switchMenuView(position: Int) {
|
||||
navController.switchTab(position)
|
||||
}
|
||||
|
||||
override fun setViewTitle(title: String) {
|
||||
setTitle(title)
|
||||
supportActionBar?.title = title
|
||||
}
|
||||
|
||||
override fun defaultTitle(): String = getString(R.string.main_title)
|
||||
override fun expandActionBar(show: Boolean) {
|
||||
mainAppBarContainer.setExpanded(show, true)
|
||||
}
|
||||
|
||||
override fun mapOfTitles(): Map<Int, String> {
|
||||
return mapOf(0 to R.string.grade_title,
|
||||
1 to R.string.attendance_title,
|
||||
2 to R.string.exam_title,
|
||||
3 to R.string.timetable_title,
|
||||
4 to R.string.more_title
|
||||
).mapValues { getString(it.value) }
|
||||
override fun viewTitle(index: Int): String {
|
||||
return getString(listOf(R.string.grade_title,
|
||||
R.string.attendance_title,
|
||||
R.string.exam_title,
|
||||
R.string.timetable_title,
|
||||
R.string.more_title)[index])
|
||||
}
|
||||
|
||||
override fun currentMenuIndex() = navController.currentStackIndex
|
||||
|
||||
override fun notifyMenuViewReselected() {
|
||||
(navController.currentFrag as? MainView.MenuFragmentView)?.onFragmentReselected()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
navController.apply { if (isRootFragment) super.onBackPressed() else popFragment() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle?) {
|
||||
super.onSaveInstanceState(outState)
|
||||
navController.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import io.github.wulkanowy.di.scopes.PerFragment
|
||||
import io.github.wulkanowy.ui.main.attendance.AttendanceFragment
|
||||
import io.github.wulkanowy.ui.main.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.main.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.main.grade.GradeModule
|
||||
import io.github.wulkanowy.ui.main.more.MoreFragment
|
||||
import io.github.wulkanowy.ui.main.timetable.TimetableFragment
|
||||
|
||||
@ -36,7 +37,7 @@ abstract class MainModule {
|
||||
abstract fun bindExamFragment(): ExamFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
@ContributesAndroidInjector(modules = [GradeModule::class])
|
||||
abstract fun bindGradeFragment(): GradeFragment
|
||||
|
||||
@PerFragment
|
||||
@ -47,4 +48,3 @@ abstract class MainModule {
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindTimetableFragment(): TimetableFragment
|
||||
}
|
||||
|
||||
|
@ -9,21 +9,27 @@ class MainPresenter @Inject constructor(errorHandler: ErrorHandler)
|
||||
|
||||
override fun attachView(view: MainView) {
|
||||
super.attachView(view)
|
||||
view.run {
|
||||
initFragmentController()
|
||||
initBottomNav()
|
||||
}
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun onTabSelected(position: Int): Boolean {
|
||||
view?.switchMenuFragment(position)
|
||||
return true
|
||||
fun onStartView() {
|
||||
view?.run { setViewTitle(viewTitle(currentMenuIndex())) }
|
||||
}
|
||||
|
||||
fun onMenuFragmentChange(position: Int) {
|
||||
view?.run {
|
||||
setViewTitle(mapOfTitles()[position] ?: defaultTitle())
|
||||
}
|
||||
fun onMenuViewChange(index: Int) {
|
||||
view?.run { setViewTitle(viewTitle(index)) }
|
||||
}
|
||||
|
||||
fun onTabSelected(index: Int, wasSelected: Boolean): Boolean {
|
||||
return view?.run {
|
||||
expandActionBar(true)
|
||||
if (wasSelected) {
|
||||
notifyMenuViewReselected()
|
||||
false
|
||||
} else {
|
||||
switchMenuView(index)
|
||||
true
|
||||
}
|
||||
} == true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,15 +4,22 @@ import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface MainView : BaseView {
|
||||
|
||||
fun initFragmentController()
|
||||
fun initView()
|
||||
|
||||
fun initBottomNav()
|
||||
|
||||
fun switchMenuFragment(position: Int)
|
||||
fun switchMenuView(position: Int)
|
||||
|
||||
fun setViewTitle(title: String)
|
||||
|
||||
fun defaultTitle(): String
|
||||
fun expandActionBar(show: Boolean)
|
||||
|
||||
fun mapOfTitles(): Map<Int, String>
|
||||
}
|
||||
fun viewTitle(index: Int): String
|
||||
|
||||
fun currentMenuIndex(): Int
|
||||
|
||||
fun notifyMenuViewReselected()
|
||||
|
||||
interface MenuFragmentView {
|
||||
|
||||
fun onFragmentReselected()
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.utils.extension.toFormat
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.synthetic.main.dialog_attendance.*
|
||||
|
||||
class AttendanceDialog : DialogFragment() {
|
||||
@ -42,7 +42,7 @@ class AttendanceDialog : DialogFragment() {
|
||||
|
||||
attendanceDialogSubject.text = attendance.subject
|
||||
attendanceDialogDescription.text = attendance.name
|
||||
attendanceDialogDate.text = attendance.date.toFormat()
|
||||
attendanceDialogDate.text = attendance.date.toFormattedString()
|
||||
attendanceDialogNumber.text = attendance.number.toString()
|
||||
attendanceDialogClose.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.utils.extension.setOnItemClickListener
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_attendance.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.extension.*
|
||||
import io.github.wulkanowy.utils.*
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
@ -19,7 +19,7 @@ class AttendancePresenter @Inject constructor(
|
||||
private val sessionRepository: SessionRepository
|
||||
) : BasePresenter<AttendanceView>(errorHandler) {
|
||||
|
||||
var currentDate: LocalDate = LocalDate.now().getNearSchoolDayPrevOnWeekEnd()
|
||||
var currentDate: LocalDate = LocalDate.now().nearSchoolDayPrevOnWeekEnd
|
||||
private set
|
||||
|
||||
override fun attachView(view: AttendanceView) {
|
||||
@ -27,13 +27,14 @@ class AttendancePresenter @Inject constructor(
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun loadAttendanceForPreviousDay() = loadData(currentDate.getPreviousWorkDay().toEpochDay())
|
||||
fun loadAttendanceForPreviousDay() = loadData(currentDate.previousWorkDay.toEpochDay())
|
||||
|
||||
fun loadAttendanceForNextDay() = loadData(currentDate.getNextWorkDay().toEpochDay())
|
||||
fun loadAttendanceForNextDay() = loadData(currentDate.nextWorkDay.toEpochDay())
|
||||
|
||||
fun loadData(date: Long?, forceRefresh: Boolean = false) {
|
||||
this.currentDate = LocalDate.ofEpochDay(date ?: currentDate.getNearSchoolDayPrevOnWeekEnd().toEpochDay())
|
||||
if (currentDate.isHolidays()) return
|
||||
this.currentDate = LocalDate.ofEpochDay(date
|
||||
?: currentDate.nearSchoolDayPrevOnWeekEnd.toEpochDay())
|
||||
if (currentDate.isHolidays) return
|
||||
|
||||
disposable.clear()
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
@ -50,9 +51,9 @@ class AttendancePresenter @Inject constructor(
|
||||
showEmpty(false)
|
||||
clearData()
|
||||
}
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays())
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays())
|
||||
updateNavigationDay(currentDate.toFormat("EEEE \n dd.MM.YYYY").capitalize())
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
|
@ -7,7 +7,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.utils.extension.toFormat
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.synthetic.main.dialog_exam.*
|
||||
|
||||
class ExamDialog : DialogFragment() {
|
||||
@ -43,7 +43,7 @@ class ExamDialog : DialogFragment() {
|
||||
examDialogSubjectValue.text = exam.subject
|
||||
examDialogTypeValue.text = exam.type
|
||||
examDialogTeacherValue.text = exam.teacher
|
||||
examDialogDateValue.text = exam.entryDate.toFormat()
|
||||
examDialogDateValue.text = exam.entryDate.toFormattedString()
|
||||
examDialogDescriptionValue.text = exam.description
|
||||
|
||||
examDialogClose.setOnClickListener { dismiss() }
|
||||
|
@ -11,7 +11,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.utils.extension.setOnItemClickListener
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_exam.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -6,8 +6,8 @@ import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.ExpandableViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.utils.extension.getWeekDayName
|
||||
import io.github.wulkanowy.utils.extension.toFormat
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.weekDayName
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.header_exam.*
|
||||
import org.threeten.bp.LocalDate
|
||||
@ -40,8 +40,8 @@ class ExamHeader : AbstractHeaderItem<ExamHeader.ViewHolder>() {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
examHeaderDay.text = date.getWeekDayName().capitalize()
|
||||
examHeaderDate.text = date.toFormat()
|
||||
examHeaderDay.text = date.weekDayName.capitalize()
|
||||
examHeaderDate.text = date.toFormattedString()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,10 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.extension.getWeekFirstDayNextOnWeekEnd
|
||||
import io.github.wulkanowy.utils.extension.isHolidays
|
||||
import io.github.wulkanowy.utils.extension.toFormat
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.weekFirstDayNextOnWeekEnd
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -21,7 +21,7 @@ class ExamPresenter @Inject constructor(
|
||||
private val sessionRepository: SessionRepository
|
||||
) : BasePresenter<ExamView>(errorHandler) {
|
||||
|
||||
var currentDate: LocalDate = LocalDate.now().getWeekFirstDayNextOnWeekEnd()
|
||||
var currentDate: LocalDate = LocalDate.now().weekFirstDayNextOnWeekEnd
|
||||
private set
|
||||
|
||||
override fun attachView(view: ExamView) {
|
||||
@ -34,8 +34,9 @@ class ExamPresenter @Inject constructor(
|
||||
fun loadExamsForNextWeek() = loadData(currentDate.plusDays(7).toEpochDay())
|
||||
|
||||
fun loadData(date: Long?, forceRefresh: Boolean = false) {
|
||||
this.currentDate = LocalDate.ofEpochDay(date ?: currentDate.getWeekFirstDayNextOnWeekEnd().toEpochDay())
|
||||
if (currentDate.isHolidays()) return
|
||||
this.currentDate = LocalDate.ofEpochDay(date
|
||||
?: currentDate.weekFirstDayNextOnWeekEnd.toEpochDay())
|
||||
if (currentDate.isHolidays) return
|
||||
|
||||
disposable.clear()
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
@ -51,9 +52,10 @@ class ExamPresenter @Inject constructor(
|
||||
showProgress(!forceRefresh)
|
||||
if (!forceRefresh) showEmpty(false)
|
||||
showContent(null == date && forceRefresh)
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays())
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays())
|
||||
updateNavigationWeek("${currentDate.toFormat("dd.MM")}-${currentDate.plusDays(4).toFormat("dd.MM")}")
|
||||
showPreButton(!currentDate.minusDays(7).isHolidays)
|
||||
showNextButton(!currentDate.plusDays(7).isHolidays)
|
||||
updateNavigationWeek(currentDate.toFormattedString("dd.MM") +
|
||||
"-${currentDate.plusDays(4).toFormattedString("dd.MM")}")
|
||||
}
|
||||
}
|
||||
.doAfterSuccess {
|
||||
|
@ -1,19 +1,120 @@
|
||||
package io.github.wulkanowy.ui.main.grade
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.view.*
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.base.BasePagerAdapter
|
||||
import io.github.wulkanowy.ui.main.MainView
|
||||
import io.github.wulkanowy.ui.main.grade.details.GradeDetailsFragment
|
||||
import io.github.wulkanowy.ui.main.grade.summary.GradeSummaryFragment
|
||||
import io.github.wulkanowy.utils.setOnSelectPageListener
|
||||
import kotlinx.android.synthetic.main.fragment_grade.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeFragment : BaseFragment() {
|
||||
class GradeFragment : BaseFragment(), GradeView, MainView.MenuFragmentView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: GradePresenter
|
||||
|
||||
@Inject
|
||||
lateinit var pagerAdapter: BasePagerAdapter
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GradeFragment()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_grade, container, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
inflater?.inflate(R.menu.action_menu_grade, menu)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
pagerAdapter.fragments.putAll(mapOf(
|
||||
getString(R.string.all_details) to GradeDetailsFragment.newInstance(),
|
||||
getString(R.string.grade_menu_summary) to GradeSummaryFragment.newInstance()
|
||||
))
|
||||
gradeViewPager.run {
|
||||
adapter = pagerAdapter
|
||||
setOnSelectPageListener { presenter.onPageSelected(it) }
|
||||
}
|
||||
gradeTabLayout.setupWithViewPager(gradeViewPager)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return if (item?.itemId == R.id.gradeMenuSemester) presenter.onSemesterSwitch()
|
||||
else false
|
||||
}
|
||||
|
||||
override fun onFragmentReselected() {
|
||||
presenter.onViewReselected()
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
gradeViewPager.visibility = if (show) VISIBLE else INVISIBLE
|
||||
gradeTabLayout.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
gradeProgress.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showSemesterDialog(selectedIndex: Int) {
|
||||
arrayOf(getString(R.string.grade_semester, 1),
|
||||
getString(R.string.grade_semester, 2)).also { array ->
|
||||
context?.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setSingleChoiceItems(array, selectedIndex) { dialog, which ->
|
||||
presenter.onSemesterSelected(which)
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setTitle(R.string.grade_switch_semester)
|
||||
.setNegativeButton(R.string.all_cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun currentPageIndex() = gradeViewPager.currentItem
|
||||
|
||||
fun onChildRefresh() {
|
||||
presenter.onChildViewRefresh()
|
||||
}
|
||||
|
||||
fun onChildFragmentLoaded(semesterId: String) {
|
||||
presenter.onChildViewLoaded(semesterId)
|
||||
}
|
||||
|
||||
override fun notifyChildLoadData(index: Int, semesterId: String, forceRefresh: Boolean) {
|
||||
(childFragmentManager.fragments[index] as GradeView.GradeChildView).onParentLoadData(semesterId, forceRefresh)
|
||||
}
|
||||
|
||||
override fun notifyChildParentReselected(index: Int) {
|
||||
(pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentReselected()
|
||||
}
|
||||
|
||||
override fun notifyChildSemesterChange(index: Int) {
|
||||
(pagerAdapter.registeredFragments[index] as? GradeView.GradeChildView)?.onParentChangeSemester()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package io.github.wulkanowy.ui.main.grade
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import io.github.wulkanowy.di.scopes.PerChildFragment
|
||||
import io.github.wulkanowy.di.scopes.PerFragment
|
||||
import io.github.wulkanowy.ui.base.BasePagerAdapter
|
||||
import io.github.wulkanowy.ui.main.grade.details.GradeDetailsFragment
|
||||
import io.github.wulkanowy.ui.main.grade.summary.GradeSummaryFragment
|
||||
|
||||
@Module
|
||||
abstract class GradeModule {
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
@PerFragment
|
||||
@Provides
|
||||
fun provideGradePagerAdapter(fragment: GradeFragment) = BasePagerAdapter(fragment.childFragmentManager)
|
||||
}
|
||||
|
||||
@PerChildFragment
|
||||
@ContributesAndroidInjector()
|
||||
abstract fun bindGradeDetailsFragment(): GradeDetailsFragment
|
||||
|
||||
@PerChildFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun binGradeSummaryFragment(): GradeSummaryFragment
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
package io.github.wulkanowy.ui.main.grade
|
||||
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import io.reactivex.Completable
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradePresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersManager,
|
||||
private val sessionRepository: SessionRepository) : BasePresenter<GradeView>(errorHandler) {
|
||||
|
||||
private var semesters = emptyList<Semester>()
|
||||
|
||||
private var selectedIndex = 0
|
||||
|
||||
private val loadedSemesterId = mutableMapOf<Int, String>()
|
||||
|
||||
override fun attachView(view: GradeView) {
|
||||
super.attachView(view)
|
||||
disposable.add(Completable.timer(150, TimeUnit.MILLISECONDS, schedulers.mainThread())
|
||||
.subscribe {
|
||||
view.initView()
|
||||
loadData()
|
||||
})
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
view?.run { notifyChildParentReselected(currentPageIndex()) }
|
||||
}
|
||||
|
||||
fun onSemesterSwitch(): Boolean {
|
||||
if (semesters.isNotEmpty()) view?.showSemesterDialog(selectedIndex)
|
||||
return true
|
||||
}
|
||||
|
||||
fun onSemesterSelected(index: Int) {
|
||||
if (selectedIndex != index) {
|
||||
selectedIndex = index
|
||||
loadedSemesterId.clear()
|
||||
view?.let {
|
||||
notifyChildrenSemesterChange()
|
||||
loadChild(it.currentPageIndex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onChildViewRefresh() {
|
||||
view?.let { loadChild(it.currentPageIndex(), forceRefresh = true) }
|
||||
}
|
||||
|
||||
fun onChildViewLoaded(semesterId: String) {
|
||||
view?.apply {
|
||||
showContent(true)
|
||||
showProgress(false)
|
||||
loadedSemesterId[currentPageIndex()] = semesterId
|
||||
}
|
||||
}
|
||||
|
||||
fun onPageSelected(index: Int) {
|
||||
loadChild(index)
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map {
|
||||
it.first { item -> item.current }.also { current ->
|
||||
selectedIndex = current.semesterName - 1
|
||||
semesters = it.filter { semester -> semester.diaryId == current.diaryId }
|
||||
}
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.subscribe({ _ ->
|
||||
view?.let { loadChild(it.currentPageIndex()) }
|
||||
}) { errorHandler.proceed(it) })
|
||||
}
|
||||
|
||||
private fun loadChild(index: Int, forceRefresh: Boolean = false) {
|
||||
semesters.first { it.semesterName == selectedIndex + 1 }.semesterId.also {
|
||||
if (forceRefresh || loadedSemesterId[index] != it) {
|
||||
view?.notifyChildLoadData(index, it, forceRefresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyChildrenSemesterChange() {
|
||||
for (i in 0..1) view?.notifyChildSemesterChange(i)
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package io.github.wulkanowy.ui.main.grade
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface GradeView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun currentPageIndex(): Int
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showSemesterDialog(selectedIndex: Int)
|
||||
|
||||
fun notifyChildLoadData(index: Int, semesterId: String, forceRefresh: Boolean)
|
||||
|
||||
fun notifyChildParentReselected(index: Int)
|
||||
|
||||
fun notifyChildSemesterChange(index: Int)
|
||||
|
||||
interface GradeChildView {
|
||||
|
||||
fun onParentChangeSemester()
|
||||
|
||||
fun onParentLoadData(semesterId: String, forceRefresh: Boolean)
|
||||
|
||||
fun onParentReselected()
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package io.github.wulkanowy.ui.main.grade.details
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.ViewGroup
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.utils.colorStringId
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.github.wulkanowy.utils.valueColor
|
||||
import kotlinx.android.synthetic.main.dialog_grade.*
|
||||
|
||||
|
||||
class GradeDetailsDialog : DialogFragment() {
|
||||
|
||||
private lateinit var grade: Grade
|
||||
|
||||
companion object {
|
||||
private const val ARGUMENT_KEY = "Item"
|
||||
|
||||
fun newInstance(grade: Grade): GradeDetailsDialog {
|
||||
return GradeDetailsDialog().apply {
|
||||
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, grade) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.run {
|
||||
grade = getSerializable(ARGUMENT_KEY) as Grade
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_grade, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
gradeDialogSubject.text = grade.subject
|
||||
gradeDialogWeightValue.text = grade.weight
|
||||
gradeDialogDateValue.text = grade.date.toFormattedString()
|
||||
gradeDialogColorValue.text = getString(grade.colorStringId)
|
||||
|
||||
gradeDialogCommentValue.apply {
|
||||
if (grade.comment.isEmpty()) {
|
||||
visibility = GONE
|
||||
gradeDialogComment.visibility = GONE
|
||||
} else text = grade.comment
|
||||
}
|
||||
|
||||
gradeDialogValue.run {
|
||||
text = grade.entry
|
||||
setBackgroundResource(grade.valueColor)
|
||||
}
|
||||
|
||||
gradeDialogTeacherValue.text = if (grade.teacher.isEmpty()) {
|
||||
getString(R.string.all_no_data)
|
||||
} else grade.teacher
|
||||
|
||||
gradeDialogDescriptionValue.text = grade.run {
|
||||
when {
|
||||
description.isEmpty() && gradeSymbol.isNotEmpty() -> gradeSymbol
|
||||
description.isEmpty() && gradeSymbol.isEmpty() -> getString(R.string.all_no_description)
|
||||
gradeSymbol.isNotEmpty() && description.isNotEmpty() -> "$gradeSymbol - $description"
|
||||
else -> description
|
||||
}
|
||||
}
|
||||
|
||||
gradeDialogClose.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,134 @@
|
||||
package io.github.wulkanowy.ui.main.grade.details
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.*
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IExpandable
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.main.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.main.grade.GradeView
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.fragment_grade_details.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeChildView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: GradeDetailsPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var gradeDetailsAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GradeDetailsFragment()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_grade_details, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
gradeDetailsAdapter.run {
|
||||
isAutoCollapseOnExpand = true
|
||||
isAutoScrollOnExpand = true
|
||||
setOnItemClickListener { presenter.onGradeItemSelected(getItem(it)) }
|
||||
}
|
||||
|
||||
gradeDetailsRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = gradeDetailsAdapter
|
||||
}
|
||||
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
}
|
||||
|
||||
override fun updateData(data: List<GradeDetailsHeader>) {
|
||||
gradeDetailsAdapter.updateDataSet(data, true)
|
||||
}
|
||||
|
||||
override fun updateItem(item: AbstractFlexibleItem<*>) {
|
||||
gradeDetailsAdapter.updateItem(item)
|
||||
}
|
||||
|
||||
override fun clearView() {
|
||||
gradeDetailsAdapter.clear()
|
||||
}
|
||||
|
||||
override fun resetView() {
|
||||
gradeDetailsAdapter.apply {
|
||||
smoothScrollToPosition(0)
|
||||
collapseAll()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>? {
|
||||
return gradeDetailsAdapter.getExpandableOf(item)
|
||||
}
|
||||
|
||||
override fun isViewEmpty() = gradeDetailsAdapter.isEmpty
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
gradeDetailsProgress.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
gradeDetailsRecycler.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
gradeDetailsEmpty.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
gradeDetailsSwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun showGradeDialog(grade: Grade) {
|
||||
GradeDetailsDialog.newInstance(grade).show(fragmentManager, grade.toString())
|
||||
}
|
||||
|
||||
override fun onParentLoadData(semesterId: String, forceRefresh: Boolean) {
|
||||
presenter.loadData(semesterId, forceRefresh)
|
||||
}
|
||||
|
||||
override fun onParentReselected() {
|
||||
presenter.onParentViewReselected()
|
||||
}
|
||||
|
||||
override fun onParentChangeSemester() {
|
||||
presenter.onParentChangeSemester()
|
||||
}
|
||||
|
||||
override fun notifyParentDataLoaded(semesterId: String) {
|
||||
(parentFragment as? GradeFragment)?.onChildFragmentLoaded(semesterId)
|
||||
}
|
||||
|
||||
override fun notifyParentRefresh() {
|
||||
(parentFragment as? GradeFragment)?.onChildRefresh()
|
||||
}
|
||||
|
||||
override fun emptyAverageString(): String = getString(R.string.grade_no_average)
|
||||
|
||||
override fun averageString(): String = getString(R.string.grade_average)
|
||||
|
||||
override fun gradeNumberString(number: Int): String = resources.getQuantityString(R.plurals.grade_number_item, number, number)
|
||||
|
||||
override fun weightString(): String = getString(R.string.grade_weight)
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package io.github.wulkanowy.ui.main.grade.details
|
||||
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractExpandableItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.ExpandableViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.header_grade_details.*
|
||||
|
||||
class GradeDetailsHeader(
|
||||
private val subject: String,
|
||||
private val number: String,
|
||||
private val average: String,
|
||||
var newGrades: Int)
|
||||
: AbstractExpandableItem<GradeDetailsHeader.ViewHolder, GradeDetailsItem>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.header_grade_details
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
gradeHeaderSubject.text = subject
|
||||
gradeHeaderAverage.text = average
|
||||
gradeHeaderNumber.text = number
|
||||
gradeHeaderPredicted.visibility = GONE
|
||||
gradeHeaderFinal.visibility = GONE
|
||||
|
||||
gradeHeaderNote.visibility = if (newGrades > 0) VISIBLE else GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GradeDetailsHeader
|
||||
|
||||
if (subject != other.subject) return false
|
||||
if (number != other.number) return false
|
||||
if (average != other.average) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = subject.hashCode()
|
||||
result = 31 * result + number.hashCode()
|
||||
result = 31 * result + average.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : ExpandableViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
init {
|
||||
contentView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
override fun shouldNotifyParentOnClick() = true
|
||||
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package io.github.wulkanowy.ui.main.grade.details
|
||||
|
||||
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.Grade
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_grade_details.*
|
||||
|
||||
class GradeDetailsItem(val grade: Grade, private val weightString: String, private val valueColor: Int)
|
||||
: AbstractFlexibleItem<GradeDetailsItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_grade_details
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
gradeItemValue.run {
|
||||
text = grade.entry
|
||||
setBackgroundResource(valueColor)
|
||||
}
|
||||
gradeItemDescription.text = if (grade.description.isNotEmpty()) grade.description else grade.gradeSymbol
|
||||
gradeItemDate.text = grade.date.toFormattedString()
|
||||
gradeItemWeight.text = "$weightString: ${grade.weight}"
|
||||
gradeItemNote.visibility = if (grade.isNew) VISIBLE else GONE
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GradeDetailsItem
|
||||
|
||||
if (grade != other.grade) return false
|
||||
if (weightString != other.weightString) return false
|
||||
if (valueColor != other.valueColor) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = grade.hashCode()
|
||||
result = 31 * result + weightString.hashCode()
|
||||
result = 31 * result + valueColor
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package io.github.wulkanowy.ui.main.grade.details
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.calcAverage
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import io.github.wulkanowy.utils.valueColor
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeDetailsPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersManager,
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val sessionRepository: SessionRepository) : BasePresenter<GradeDetailsView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: GradeDetailsView) {
|
||||
super.attachView(view)
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun loadData(semesterId: String, forceRefresh: Boolean) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.flatMap { gradeRepository.getGrades(it.first { item -> item.semesterId == semesterId }, forceRefresh) }
|
||||
.map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) }
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}
|
||||
.subscribe({
|
||||
view?.run {
|
||||
showEmpty(it.isEmpty())
|
||||
showContent(it.isNotEmpty())
|
||||
updateData(it)
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
})
|
||||
}
|
||||
|
||||
fun onGradeItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||
if (item is GradeDetailsItem) {
|
||||
view?.apply {
|
||||
showGradeDialog(item.grade)
|
||||
if (item.grade.isNew) {
|
||||
item.grade.isNew = false
|
||||
updateItem(item)
|
||||
getHeaderOfItem(item)?.let { header ->
|
||||
if (header is GradeDetailsHeader) {
|
||||
header.newGrades--
|
||||
updateItem(header)
|
||||
}
|
||||
}
|
||||
updateGrade(item.grade)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
view?.notifyParentRefresh()
|
||||
}
|
||||
|
||||
fun onParentViewReselected() {
|
||||
view?.run {
|
||||
if (!isViewEmpty()) resetView()
|
||||
}
|
||||
}
|
||||
|
||||
fun onParentChangeSemester() {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showRefresh(false)
|
||||
showContent(false)
|
||||
showEmpty(false)
|
||||
clearView()
|
||||
}
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
private fun createGradeItems(items: Map<String, List<Grade>>): List<GradeDetailsHeader> {
|
||||
return items.map {
|
||||
it.value.calcAverage().let { average ->
|
||||
GradeDetailsHeader(
|
||||
subject = it.key,
|
||||
average = formatAverage(average),
|
||||
number = view?.gradeNumberString(it.value.size).orEmpty(),
|
||||
newGrades = it.value.filter { grade -> grade.isNew }.size
|
||||
).apply {
|
||||
subItems = it.value.map { item ->
|
||||
GradeDetailsItem(
|
||||
grade = item,
|
||||
weightString = view?.weightString().orEmpty(),
|
||||
valueColor = item.valueColor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatAverage(average: Double): String {
|
||||
return view?.run {
|
||||
if (average == 0.0) emptyAverageString()
|
||||
else averageString().format(average)
|
||||
}.orEmpty()
|
||||
}
|
||||
|
||||
private fun updateGrade(grade: Grade) {
|
||||
disposable.add(gradeRepository.updateGrade(grade)
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.subscribe({}) { error -> errorHandler.proceed(error) })
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package io.github.wulkanowy.ui.main.grade.details
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IExpandable
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface GradeDetailsView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<GradeDetailsHeader>)
|
||||
|
||||
fun updateItem(item: AbstractFlexibleItem<*>)
|
||||
|
||||
fun getHeaderOfItem(item: AbstractFlexibleItem<*>): IExpandable<*, out IFlexible<*>>?
|
||||
|
||||
fun resetView()
|
||||
|
||||
fun clearView()
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
|
||||
fun showGradeDialog(grade: Grade)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun emptyAverageString(): String
|
||||
|
||||
fun averageString(): String
|
||||
|
||||
fun gradeNumberString(number: Int): String
|
||||
|
||||
fun weightString(): String
|
||||
|
||||
fun notifyParentDataLoaded(semesterId: String)
|
||||
|
||||
fun notifyParentRefresh()
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package io.github.wulkanowy.ui.main.grade.summary
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.*
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
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.main.grade.GradeFragment
|
||||
import io.github.wulkanowy.ui.main.grade.GradeView
|
||||
import kotlinx.android.synthetic.main.fragment_grade_summary.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeChildView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: GradeSummaryPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var gradeSummaryAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||
|
||||
companion object {
|
||||
fun newInstance() = GradeSummaryFragment()
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_grade_summary, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.attachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
gradeSummaryAdapter.setDisplayHeadersAtStartUp(true)
|
||||
|
||||
gradeSummaryRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = gradeSummaryAdapter
|
||||
}
|
||||
gradeSummarySwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
}
|
||||
|
||||
override fun updateDataSet(data: List<GradeSummaryItem>, header: GradeSummaryScrollableHeader) {
|
||||
gradeSummaryAdapter.apply {
|
||||
updateDataSet(data, true)
|
||||
removeAllScrollableHeaders()
|
||||
addScrollableHeader(header)
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearView() {
|
||||
gradeSummaryAdapter.clear()
|
||||
}
|
||||
|
||||
override fun resetView() {
|
||||
gradeSummaryAdapter.smoothScrollToPosition(0)
|
||||
}
|
||||
|
||||
override fun isViewEmpty() = gradeSummaryAdapter.isEmpty
|
||||
|
||||
override fun showContent(show: Boolean) {
|
||||
gradeSummaryRecycler.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showEmpty(show: Boolean) {
|
||||
gradeSummaryEmpty.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showProgress(show: Boolean) {
|
||||
gradeSummaryProgress.visibility = if (show) VISIBLE else GONE
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
gradeSummarySwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun onParentLoadData(semesterId: String, forceRefresh: Boolean) {
|
||||
presenter.loadData(semesterId, forceRefresh)
|
||||
}
|
||||
|
||||
override fun onParentReselected() {
|
||||
presenter.onParentViewReselected()
|
||||
}
|
||||
|
||||
override fun onParentChangeSemester() {
|
||||
presenter.onParentChangeSemester()
|
||||
}
|
||||
|
||||
override fun notifyParentDataLoaded(semesterId: String) {
|
||||
(parentFragment as? GradeFragment)?.onChildFragmentLoaded(semesterId)
|
||||
}
|
||||
|
||||
override fun notifyParentRefresh() {
|
||||
(parentFragment as? GradeFragment)?.onChildRefresh()
|
||||
}
|
||||
|
||||
override fun predictedString() = getString(R.string.grade_summary_predicted_grade)
|
||||
|
||||
override fun finalString() = getString(R.string.grade_summary_final_grade)
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
presenter.detachView()
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package io.github.wulkanowy.ui.main.grade.summary
|
||||
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.header_grade_summary.*
|
||||
|
||||
class GradeSummaryHeader(private val name: String, private val average: String) : AbstractHeaderItem<GradeSummaryHeader.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.header_grade_summary
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.run {
|
||||
gradeSummaryHeaderName.text = name
|
||||
gradeSummaryHeaderAverage.text = average
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GradeSummaryHeader
|
||||
|
||||
if (name != other.name) return false
|
||||
if (average != other.average) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = name.hashCode()
|
||||
result = 31 * result + average.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) :
|
||||
FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
get() = contentView
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package io.github.wulkanowy.ui.main.grade.summary
|
||||
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_grade_summary.*
|
||||
|
||||
class GradeSummaryItem(header: GradeSummaryHeader, private val grade: String, private val title: String)
|
||||
: AbstractSectionableItem<GradeSummaryItem.ViewHolder, GradeSummaryHeader>(header) {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_grade_summary
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.run {
|
||||
gradeSummaryItemGrade.text = grade
|
||||
gradeSummaryItemTitle.text = title
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GradeSummaryItem
|
||||
|
||||
if (grade != other.grade) return false
|
||||
if (title != other.title) return false
|
||||
if (header != other.header) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = header.hashCode()
|
||||
result = 31 * result + grade.hashCode()
|
||||
result = 31 * result + title.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?)
|
||||
: FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
get() = contentView
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package io.github.wulkanowy.ui.main.grade.summary
|
||||
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.github.wulkanowy.data.repositories.GradeRepository
|
||||
import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.calcAverage
|
||||
import io.github.wulkanowy.utils.schedulers.SchedulersManager
|
||||
import java.lang.String.format
|
||||
import java.util.Locale.FRANCE
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradeSummaryPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val gradeSummaryRepository: GradeSummaryRepository,
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val schedulers: SchedulersManager)
|
||||
: BasePresenter<GradeSummaryView>(errorHandler) {
|
||||
|
||||
override fun attachView(view: GradeSummaryView) {
|
||||
super.attachView(view)
|
||||
view.initView()
|
||||
}
|
||||
|
||||
fun loadData(semesterId: String, forceRefresh: Boolean) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { semester -> semester.first { it.semesterId == semesterId } }
|
||||
.flatMap {
|
||||
gradeSummaryRepository.getGradesSummary(it, forceRefresh)
|
||||
.flatMap { gradesSummary ->
|
||||
gradeRepository.getGrades(it, forceRefresh)
|
||||
.map { grades ->
|
||||
grades.groupBy { grade -> grade.subject }
|
||||
.mapValues { entry -> entry.value.calcAverage() }
|
||||
.filterValues { value -> value != 0.0 }
|
||||
.let { averages ->
|
||||
createGradeSummaryItems(gradesSummary, averages) to
|
||||
GradeSummaryScrollableHeader(
|
||||
formatAverage(gradesSummary.calcAverage()),
|
||||
formatAverage(averages.values.average())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread())
|
||||
.observeOn(schedulers.mainThread())
|
||||
.doFinally {
|
||||
view?.run {
|
||||
showRefresh(false)
|
||||
showProgress(false)
|
||||
notifyParentDataLoaded(semesterId)
|
||||
}
|
||||
}.subscribe({
|
||||
view?.run {
|
||||
showEmpty(it.first.isEmpty())
|
||||
showContent(it.first.isNotEmpty())
|
||||
updateDataSet(it.first, it.second)
|
||||
}
|
||||
}) {
|
||||
view?.run { showEmpty(isViewEmpty()) }
|
||||
errorHandler.proceed(it)
|
||||
})
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
view?.notifyParentRefresh()
|
||||
}
|
||||
|
||||
fun onParentViewReselected() {
|
||||
view?.run {
|
||||
if (!isViewEmpty()) resetView()
|
||||
}
|
||||
}
|
||||
|
||||
fun onParentChangeSemester() {
|
||||
view?.run {
|
||||
showProgress(true)
|
||||
showRefresh(false)
|
||||
showContent(false)
|
||||
showEmpty(false)
|
||||
clearView()
|
||||
}
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
private fun createGradeSummaryItems(gradesSummary: List<GradeSummary>, averages: Map<String, Double>)
|
||||
: List<GradeSummaryItem> {
|
||||
return gradesSummary.filter { !checkEmpty(it, averages) }
|
||||
.flatMap { gradeSummary ->
|
||||
GradeSummaryHeader(
|
||||
name = gradeSummary.subject,
|
||||
average = formatAverage(averages.getOrElse(gradeSummary.subject) { 0.0 }, "")
|
||||
).let {
|
||||
listOf(GradeSummaryItem(
|
||||
header = it,
|
||||
title = view?.predictedString().orEmpty(),
|
||||
grade = gradeSummary.predictedGrade
|
||||
), GradeSummaryItem(
|
||||
header = it,
|
||||
title = view?.finalString().orEmpty(),
|
||||
grade = gradeSummary.finalGrade
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkEmpty(gradeSummary: GradeSummary, averages: Map<String, Double>): Boolean {
|
||||
return gradeSummary.run {
|
||||
finalGrade.isEmpty() && predictedGrade.isEmpty() && averages[subject] == null
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatAverage(average: Double, defaultValue: String = "-- --"): String {
|
||||
return if (average == 0.0 || average.isNaN()) defaultValue
|
||||
else format(FRANCE, "%.2f", average)
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package io.github.wulkanowy.ui.main.grade.summary
|
||||
|
||||
import android.view.View
|
||||
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 kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.scrollable_header_grade_summary.*
|
||||
|
||||
class GradeSummaryScrollableHeader(private val finalAverage: String, private val calculatedAverage: String)
|
||||
: AbstractFlexibleItem<GradeSummaryScrollableHeader.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.scrollable_header_grade_summary
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.apply {
|
||||
gradeSummaryScrollableHeaderFinal.text = finalAverage
|
||||
gradeSummaryScrollableHeaderCalculated.text = calculatedAverage
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GradeSummaryScrollableHeader
|
||||
|
||||
if (calculatedAverage != other.calculatedAverage) return false
|
||||
if (finalAverage != other.finalAverage) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = calculatedAverage.hashCode()
|
||||
result = 31 * result + finalAverage.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
get() = contentView
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package io.github.wulkanowy.ui.main.grade.summary
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface GradeSummaryView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateDataSet(data: List<GradeSummaryItem>, header: GradeSummaryScrollableHeader)
|
||||
|
||||
fun resetView()
|
||||
|
||||
fun clearView()
|
||||
|
||||
fun isViewEmpty(): Boolean
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun showContent(show: Boolean)
|
||||
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun predictedString(): String
|
||||
|
||||
fun finalString(): String
|
||||
|
||||
fun notifyParentDataLoaded(semesterId: String)
|
||||
|
||||
fun notifyParentRefresh()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.github.wulkanowy.utils.extension
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context.INPUT_METHOD_SERVICE
|
@ -1,40 +0,0 @@
|
||||
package io.github.wulkanowy.utils;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.view.View;
|
||||
|
||||
public final class AnimationUtils {
|
||||
|
||||
public static void slideDown(final View view) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setAlpha(0.f);
|
||||
|
||||
view.setTranslationY(-(view.getHeight() / 2));
|
||||
view.animate()
|
||||
.translationY(0)
|
||||
.alpha(1.f)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setAlpha(1.f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void slideUp(final View view) {
|
||||
view.animate()
|
||||
.translationY(-(view.getHeight() / 2))
|
||||
.alpha(0.f)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// superfluous restoration
|
||||
view.setVisibility(View.GONE);
|
||||
view.setAlpha(1.f);
|
||||
view.setTranslationY(0.f);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
const val APP_NAME = "Wulkanowy"
|
||||
|
||||
const val DATABASE_NAME = "wulkanowy_db"
|
||||
|
||||
const val DEFAULT_SYMBOL = "Default"
|
||||
|
||||
const val DATE_PATTERN = "yyyy-MM-dd"
|
||||
|
||||
const val REPO_URL = "https://github.com/wulkanowy/wulkanowy"
|
@ -1,44 +0,0 @@
|
||||
package io.github.wulkanowy.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.support.annotation.AttrRes;
|
||||
import android.support.annotation.ColorInt;
|
||||
|
||||
import io.github.wulkanowy.R;
|
||||
|
||||
public final class CommonUtils {
|
||||
|
||||
private CommonUtils() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static int colorHexToColorName(String hexColor) {
|
||||
switch (hexColor) {
|
||||
case "000000":
|
||||
return R.string.all_black;
|
||||
|
||||
case "F04C4C":
|
||||
return R.string.all_red;
|
||||
|
||||
case "20A4F7":
|
||||
return R.string.all_blue;
|
||||
|
||||
case "6ECD07":
|
||||
return R.string.all_green;
|
||||
|
||||
default:
|
||||
return R.string.all_empty_color;
|
||||
}
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
public static int getThemeAttrColor(Context context, @AttrRes int colorAttr) {
|
||||
final TypedArray array = context.obtainStyledAttributes(null, new int[]{colorAttr});
|
||||
try {
|
||||
return array.getColor(0, 0);
|
||||
} finally {
|
||||
array.recycle();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package io.github.wulkanowy.utils;
|
||||
|
||||
import com.crashlytics.android.answers.Answers;
|
||||
import com.crashlytics.android.answers.CustomEvent;
|
||||
import com.crashlytics.android.answers.LoginEvent;
|
||||
import com.crashlytics.android.answers.SignUpEvent;
|
||||
|
||||
public final class FabricUtils {
|
||||
|
||||
private FabricUtils() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static void logLogin(String method, boolean result) {
|
||||
Answers.getInstance().logLogin(new LoginEvent()
|
||||
.putMethod(method)
|
||||
.putSuccess(result)
|
||||
);
|
||||
}
|
||||
|
||||
public static void logRegister(boolean result, String symbol, String message) {
|
||||
Answers.getInstance().logSignUp(new SignUpEvent()
|
||||
.putMethod("Login activity")
|
||||
.putSuccess(result)
|
||||
.putCustomAttribute("symbol", symbol)
|
||||
.putCustomAttribute("message", message)
|
||||
);
|
||||
}
|
||||
|
||||
public static void logRefresh(String name, boolean result, String date) {
|
||||
Answers.getInstance().logCustom(
|
||||
new CustomEvent(name + " refresh")
|
||||
.putCustomAttribute("Success", result ? "true" : "false")
|
||||
.putCustomAttribute("Date", date)
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
|
||||
inline fun FlexibleAdapter<*>.setOnItemClickListener(crossinline listener: (position: Int) -> Unit) {
|
||||
addListener(FlexibleAdapter.OnItemClickListener { _, position ->
|
||||
listener(position)
|
||||
true
|
||||
})
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.support.v4.app.Fragment
|
||||
import com.ncapdevi.fragnav.FragNavController
|
||||
|
||||
inline fun FragNavController.setOnTabTransactionListener(crossinline listener: (index: Int) -> Unit) {
|
||||
transactionListener = object : FragNavController.TransactionListener {
|
||||
override fun onFragmentTransaction(fragment: Fragment?, transactionType: FragNavController.TransactionType) {}
|
||||
override fun onTabTransaction(fragment: Fragment?, index: Int) {
|
||||
listener(index)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
|
||||
fun List<Grade>.calcAverage(): Double {
|
||||
var counter = 0.0
|
||||
var denominator = 0.0
|
||||
|
||||
forEach {
|
||||
counter += (it.value + it.modifier) * it.weightValue
|
||||
denominator += it.weightValue
|
||||
}
|
||||
return if (denominator != 0.0) counter / denominator else 0.0
|
||||
}
|
||||
|
||||
@JvmName("calcSummaryAverage")
|
||||
fun List<GradeSummary>.calcAverage(): Double {
|
||||
return asSequence().mapNotNull {
|
||||
if (it.finalGrade.matches("[0-6]".toRegex())) it.finalGrade.toDouble() else null
|
||||
}.average()
|
||||
}
|
||||
|
||||
inline val Grade.valueColor: Int
|
||||
get() {
|
||||
return when (value) {
|
||||
6 -> R.color.grade_six
|
||||
5 -> R.color.grade_five
|
||||
4 -> R.color.grade_four
|
||||
3 -> R.color.grade_three
|
||||
2 -> R.color.grade_two
|
||||
1 -> R.color.grade_one
|
||||
else -> R.color.grade_default
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline val Grade.colorStringId: Int
|
||||
get() {
|
||||
return when (color) {
|
||||
"000000" -> R.string.all_black
|
||||
"F04C4C" -> R.string.all_red
|
||||
"20A4F7" -> R.string.all_blue
|
||||
"6ECD07" -> R.string.all_green
|
||||
else -> R.string.all_empty_color
|
||||
}
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
package io.github.wulkanowy.utils;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class GradeUtils {
|
||||
|
||||
private final static Pattern validGradePattern = Pattern.compile("^(\\++|-|--|=)?[0-6](\\++|-|--|=)?$");
|
||||
private final static Pattern simpleGradeValuePattern = Pattern.compile("([0-6])");
|
||||
|
||||
private GradeUtils() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
/*public static float calculateWeightedAverage(List<Grade> gradeList) {
|
||||
|
||||
float counter = 0f;
|
||||
float denominator = 0f;
|
||||
|
||||
for (Grade grade : gradeList) {
|
||||
int weight = getWeightValue(grade.getWeight());
|
||||
float value = getWeightedGradeValue(grade.getValue());
|
||||
|
||||
if (value != -1.0f) {
|
||||
counter += value * weight;
|
||||
denominator += weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == 0f) {
|
||||
return -1.0f;
|
||||
}
|
||||
return counter / denominator;
|
||||
}
|
||||
|
||||
public static float calculateSubjectsAverage(List<Subject> subjectList, boolean usePredicted) {
|
||||
return calculateSubjectsAverage(subjectList, usePredicted, false);
|
||||
}
|
||||
|
||||
public static float calculateDetailedSubjectsAverage(List<Subject> subjectList) {
|
||||
return calculateSubjectsAverage(subjectList, false, true);
|
||||
}
|
||||
|
||||
public static int getValueColor(String value) {
|
||||
Matcher m1 = validGradePattern.matcher(value);
|
||||
if (!m1.find()) {
|
||||
return R.color.grade_default;
|
||||
}
|
||||
|
||||
Matcher m2 = simpleGradeValuePattern.matcher(m1.group());
|
||||
if (!m2.find()) {
|
||||
return R.color.grade_default;
|
||||
}
|
||||
|
||||
switch (Integer.parseInt(m2.group())) {
|
||||
case 6:
|
||||
return R.color.grade_six;
|
||||
case 5:
|
||||
return R.color.grade_five;
|
||||
case 4:
|
||||
return R.color.grade_four;
|
||||
case 3:
|
||||
return R.color.grade_three;
|
||||
case 2:
|
||||
return R.color.grade_two;
|
||||
case 1:
|
||||
return R.color.grade_one;
|
||||
default:
|
||||
return R.color.grade_default;
|
||||
}
|
||||
}
|
||||
|
||||
private static float calculateSubjectsAverage(List<Subject> subjectList, boolean usePredicted, boolean useSubjectsAverages) {
|
||||
float counter = 0f;
|
||||
float denominator = 0f;
|
||||
|
||||
for (Subject subject : subjectList) {
|
||||
float value;
|
||||
|
||||
if (useSubjectsAverages) {
|
||||
value = calculateWeightedAverage(subject.getGradeList());
|
||||
} else {
|
||||
value = getGradeValue(usePredicted ? subject.getPredictedRating() : subject.getFinalRating());
|
||||
}
|
||||
|
||||
if (value != -1.0f) {
|
||||
counter += Math.round(value);
|
||||
denominator++;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == 0) {
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
return counter / denominator;
|
||||
}
|
||||
|
||||
public static float getGradeValue(String grade) {
|
||||
if (validGradePattern.matcher(grade).matches()) {
|
||||
return getWeightedGradeValue(grade);
|
||||
}
|
||||
|
||||
return getVerbalGradeValue(grade);
|
||||
}
|
||||
|
||||
private static float getVerbalGradeValue(String grade) {
|
||||
switch (grade) {
|
||||
case "celujący":
|
||||
return 6f;
|
||||
case "bardzo dobry":
|
||||
return 5f;
|
||||
case "dobry":
|
||||
return 4f;
|
||||
case "dostateczny":
|
||||
return 3f;
|
||||
case "dopuszczający":
|
||||
return 2f;
|
||||
case "niedostateczny":
|
||||
return 1f;
|
||||
default:
|
||||
return -1f;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getShortGradeValue(String grade) {
|
||||
switch (grade) {
|
||||
case "celujący":
|
||||
return "6";
|
||||
case "bardzo dobry":
|
||||
return "5";
|
||||
case "dobry":
|
||||
return "4";
|
||||
case "dostateczny":
|
||||
return "3";
|
||||
case "dopuszczający":
|
||||
return "2";
|
||||
case "niedostateczny":
|
||||
return "1";
|
||||
default:
|
||||
return grade;
|
||||
}
|
||||
}
|
||||
|
||||
private static float getWeightedGradeValue(String value) {
|
||||
if (validGradePattern.matcher(value).matches()) {
|
||||
if (value.matches("[-][0-6]") || value.matches("[0-6][-]")) {
|
||||
String replacedValue = value.replaceAll("[-]", "");
|
||||
return Float.valueOf(replacedValue) - 0.33f;
|
||||
} else if (value.matches("[+][0-6]") || value.matches("[0-6][+]")) {
|
||||
String replacedValue = value.replaceAll("[+]", "");
|
||||
return Float.valueOf((replacedValue)) + 0.33f;
|
||||
} else if (value.matches("[-|=]{1,2}[0-6]") || value.matches("[0-6][-|=]{1,2}")) {
|
||||
String replacedValue = value.replaceAll("[-|=]{1,2}", "");
|
||||
return Float.valueOf((replacedValue)) - 0.5f;
|
||||
} else {
|
||||
return Float.valueOf(value);
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getWeightValue(String weightOfGrade) {
|
||||
return Integer.valueOf(weightOfGrade.substring(0, weightOfGrade.length() - 3));
|
||||
}*/
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package io.github.wulkanowy.utils;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public final class LoggerUtils {
|
||||
|
||||
public static class CrashlyticsTree extends Timber.Tree {
|
||||
|
||||
@Override
|
||||
protected void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable t) {
|
||||
Crashlytics.setInt("priority", priority);
|
||||
Crashlytics.setString("tag", tag);
|
||||
|
||||
if (t == null) {
|
||||
Crashlytics.log(message);
|
||||
} else {
|
||||
Crashlytics.setString("message", message);
|
||||
Crashlytics.logException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DebugLogTree extends Timber.DebugTree {
|
||||
|
||||
@Override
|
||||
protected void log(int priority, String tag, @NonNull String message, Throwable t) {
|
||||
if ("HUAWEI".equals(Build.MANUFACTURER) || "samsung".equals(Build.MANUFACTURER)) {
|
||||
if (priority == Log.VERBOSE || priority == Log.DEBUG || priority == Log.INFO) {
|
||||
priority = Log.ERROR;
|
||||
}
|
||||
}
|
||||
super.log(priority, AppConstantKt.APP_NAME, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createStackElementTag(@NonNull StackTraceElement element) {
|
||||
return super.createStackElementTag(element) + " - " + element.getLineNumber();
|
||||
}
|
||||
}
|
||||
}
|
27
app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt
Normal file
27
app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import timber.log.Timber
|
||||
|
||||
object CrashlyticsTree : Timber.Tree() {
|
||||
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
Crashlytics.setInt("priority", priority)
|
||||
Crashlytics.setString("tag", tag)
|
||||
|
||||
if (t == null) {
|
||||
Crashlytics.log(message)
|
||||
} else {
|
||||
Crashlytics.setString("message", message)
|
||||
Crashlytics.logException(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DebugLogTree : Timber.DebugTree() {
|
||||
|
||||
override fun createStackElementTag(element: StackTraceElement): String? {
|
||||
return super.createStackElementTag(element) + " - ${element.lineNumber}"
|
||||
}
|
||||
}
|
||||
|
87
app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt
Normal file
87
app/src/main/java/io/github/wulkanowy/utils/TimeExtension.kt
Normal file
@ -0,0 +1,87 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import org.threeten.bp.DayOfWeek.*
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.format.DateTimeFormatter
|
||||
import org.threeten.bp.format.DateTimeFormatter.ofPattern
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import org.threeten.bp.temporal.TemporalAdjusters.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
private const val DATE_PATTERN = "yyyy-MM-dd"
|
||||
|
||||
fun Date.toLocalDate(): LocalDate {
|
||||
return LocalDate.parse(SimpleDateFormat(DATE_PATTERN, Locale.getDefault()).format(this))
|
||||
}
|
||||
|
||||
fun String.toLocalDate(format: String = DATE_PATTERN): LocalDate {
|
||||
return LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
|
||||
}
|
||||
|
||||
fun LocalDate.toFormattedString(format: String): String = this.format(ofPattern(format))
|
||||
|
||||
fun LocalDate.toFormattedString(): String = this.toFormattedString(DATE_PATTERN)
|
||||
|
||||
inline val LocalDate.nextWorkDay: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
FRIDAY, SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
else -> this.plusDays(1)
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.previousWorkDay: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY, MONDAY -> this.with(previous(FRIDAY))
|
||||
else -> this.minusDays(1)
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.nearSchoolDayPrevOnWeekEnd: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(previous(FRIDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.nearSchoolDayNextOnWeekEnd: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
inline val LocalDate.weekDayName: String
|
||||
get() = this.format(ofPattern("EEEE", Locale.getDefault()))
|
||||
|
||||
inline val LocalDate.weekFirstDayAlwaysCurrent: LocalDate
|
||||
get() = this.with(TemporalAdjusters.previousOrSame(MONDAY))
|
||||
|
||||
inline val LocalDate.weekFirstDayNextOnWeekEnd: LocalDate
|
||||
get() {
|
||||
return when (this.dayOfWeek) {
|
||||
SATURDAY, SUNDAY -> this.with(next(MONDAY))
|
||||
else -> this.with(previousOrSame(MONDAY))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Dz.U. 2016 poz. 1335](http://prawo.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20160001335)
|
||||
*/
|
||||
inline val LocalDate.isHolidays: Boolean
|
||||
get() {
|
||||
return LocalDate.of(this.year, 9, 1).run {
|
||||
when (dayOfWeek) {
|
||||
FRIDAY, SATURDAY, SUNDAY -> with(firstInMonth(MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}.let { firstSchoolDay ->
|
||||
LocalDate.of(this.year, 6, 20)
|
||||
.with(next(FRIDAY))
|
||||
.let { lastSchoolDay -> this.isBefore(firstSchoolDay) && this.isAfter(lastSchoolDay) }
|
||||
}
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
package io.github.wulkanowy.utils.extension
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.support.v4.view.ViewPager
|
||||
|
||||
fun ViewPager.setOnSelectPageListener(selectListener: (position: Int) -> Unit) {
|
||||
inline fun ViewPager.setOnSelectPageListener(crossinline selectListener: (position: Int) -> Unit) {
|
||||
addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageSelected(position: Int) {
|
||||
selectListener(position)
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
})
|
@ -1,15 +0,0 @@
|
||||
package io.github.wulkanowy.utils.extension
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
|
||||
fun FlexibleAdapter<*>.setOnItemClickListener(listener: (position: Int) -> Unit) {
|
||||
addListener(FlexibleAdapter.OnItemClickListener { _, position ->
|
||||
listener(position)
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
fun FlexibleAdapter<*>.setOnUpdateListener(listener: (size: Int) -> Unit) {
|
||||
addListener(FlexibleAdapter.OnUpdateListener { listener(it) })
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
package io.github.wulkanowy.utils.extension
|
||||
|
||||
import io.github.wulkanowy.utils.DATE_PATTERN
|
||||
import org.threeten.bp.*
|
||||
import org.threeten.bp.format.DateTimeFormatter
|
||||
import org.threeten.bp.temporal.TemporalAdjusters
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
fun Date.toLocalDate(): LocalDate = LocalDate.parse(SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(this))
|
||||
|
||||
fun String.toDate(format: String = "yyyy-MM-dd"): LocalDate = LocalDate.parse(this, DateTimeFormatter.ofPattern(format))
|
||||
|
||||
fun LocalDate.toFormat(format: String): String = this.format(DateTimeFormatter.ofPattern(format))
|
||||
|
||||
fun LocalDate.toFormat(): String = this.toFormat(DATE_PATTERN)
|
||||
|
||||
fun LocalDate.getNextWorkDay(): LocalDate {
|
||||
return when(this.dayOfWeek) {
|
||||
DayOfWeek.FRIDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY -> this.with(TemporalAdjusters.next(DayOfWeek.MONDAY))
|
||||
else -> this.plusDays(1)
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDate.getPreviousWorkDay(): LocalDate {
|
||||
return when(this.dayOfWeek) {
|
||||
DayOfWeek.SATURDAY, DayOfWeek.SUNDAY, DayOfWeek.MONDAY -> this.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY))
|
||||
else -> this.minusDays(1)
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDate.getNearSchoolDayPrevOnWeekEnd(): LocalDate {
|
||||
return when(this.dayOfWeek) {
|
||||
DayOfWeek.SATURDAY, DayOfWeek.SUNDAY -> this.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDate.getNearSchoolDayNextOnWeekEnd(): LocalDate {
|
||||
return when(this.dayOfWeek) {
|
||||
DayOfWeek.SATURDAY, DayOfWeek.SUNDAY -> this.with(TemporalAdjusters.next(DayOfWeek.MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDate.getWeekDayName(): String = this.format(DateTimeFormatter.ofPattern("EEEE", Locale.getDefault()))
|
||||
|
||||
fun LocalDate.getWeekFirstDayAlwaysCurrent(): LocalDate {
|
||||
return this.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||
}
|
||||
|
||||
fun LocalDate.getWeekFirstDayNextOnWeekEnd(): LocalDate {
|
||||
return when(this.dayOfWeek) {
|
||||
DayOfWeek.SATURDAY, DayOfWeek.SUNDAY -> this.with(TemporalAdjusters.next(DayOfWeek.MONDAY))
|
||||
else -> this.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Dz.U. 2016 poz. 1335](http://prawo.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20160001335)
|
||||
*/
|
||||
fun LocalDate.isHolidays(): Boolean = this.isAfter(this.getLastSchoolDay()) && this.isBefore(this.getFirstSchoolDay())
|
||||
|
||||
fun LocalDate.getSchoolYear(): Int = if (this.monthValue <= 8) this.year - 1 else this.year
|
||||
|
||||
fun LocalDate.getFirstSchoolDay(): LocalDate {
|
||||
return LocalDate.of(this.year, 9, 1).run {
|
||||
when (dayOfWeek) {
|
||||
DayOfWeek.FRIDAY, DayOfWeek.SATURDAY, DayOfWeek.SUNDAY -> with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY))
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun LocalDate.getLastSchoolDay(): LocalDate {
|
||||
return LocalDate
|
||||
.of(this.year, 6, 20)
|
||||
.with(TemporalAdjusters.next(DayOfWeek.FRIDAY))
|
||||
}
|
@ -12,7 +12,6 @@ import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties.*
|
||||
import android.util.Base64
|
||||
import android.util.Base64.DEFAULT
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import timber.log.Timber
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
@ -76,7 +75,7 @@ object Scrambler {
|
||||
|
||||
@JvmStatic
|
||||
fun decrypt(cipherText: String): String {
|
||||
if (StringUtils.isEmpty(cipherText)) throw ScramblerException("Text to be encrypted is empty")
|
||||
if (cipherText.isEmpty()) throw ScramblerException("Text to be encrypted is empty")
|
||||
|
||||
if (SDK_INT < JELLY_BEAN_MR2 || cipherText.length < 250) {
|
||||
return String(Base64.decode(cipherText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
||||
|
BIN
app/src/main/res/drawable-v15/img_splash_logo.png
Normal file
BIN
app/src/main/res/drawable-v15/img_splash_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
@ -1,5 +1,9 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="#FFF" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="left|right|top|bottom"
|
BIN
app/src/main/res/drawable-v23/img_splash_logo.png
Normal file
BIN
app/src/main/res/drawable-v23/img_splash_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
12
app/src/main/res/drawable-v23/layer_splash_background.xml
Normal file
12
app/src/main/res/drawable-v23/layer_splash_background.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="#FFF" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:width="200dp"
|
||||
android:height="200dp"
|
||||
android:gravity="center"
|
||||
android:drawable="@drawable/img_splash_logo" />
|
||||
</layer-list>
|
Binary file not shown.
Before Width: | Height: | Size: 28 KiB |
Binary file not shown.
Before Width: | Height: | Size: 49 KiB |
BIN
app/src/main/res/drawable/img_timetable_widget_preview.webp
Normal file
BIN
app/src/main/res/drawable/img_timetable_widget_preview.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@ -1,19 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/mainContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/mainAppBarContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:elevation="0dp">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/mainToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/mainFragmentContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/bottom_navigation_height"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
|
||||
android:id="@+id/mainBottomNav"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" />
|
||||
</LinearLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
@ -5,45 +5,42 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="300dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
android:minWidth="300dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:padding="20dp"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_value"
|
||||
android:id="@+id/gradeDialogValue"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_gravity="end"
|
||||
android:background="@color/grade_default"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/grade_text"
|
||||
android:background="@color/grade_default"
|
||||
android:textSize="30sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_subject"
|
||||
android:id="@+id/gradeDialogSubject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginEnd="90dp"
|
||||
android:layout_marginRight="90dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="5"
|
||||
android:minHeight="80dp"
|
||||
@ -53,134 +50,157 @@
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_description"
|
||||
android:id="@+id/gradeDialogDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogSubject"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_subject"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:text="@string/all_description"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_description_value"
|
||||
android:id="@+id/gradeDialogDescriptionValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogDescription"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_description"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_no_description"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_weight"
|
||||
android:id="@+id/gradeDialogWeight"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogDescriptionValue"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_description_value"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/grade_weight"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_weight_value"
|
||||
android:id="@+id/gradeDialogWeightValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogWeight"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_weight"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/grade_weight"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_teacher"
|
||||
android:id="@+id/gradeDialogComment"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogWeightValue"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_weight_value"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/grade_comment"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeDialogCommentValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/gradeDialogComment"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/grade_comment"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeDialogTeacher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/gradeDialogCommentValue"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/all_teacher"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_teacher_value"
|
||||
android:id="@+id/gradeDialogTeacherValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogTeacher"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_teacher"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_teacher"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_color"
|
||||
android:id="@+id/gradeDialogColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogTeacherValue"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_teacher_value"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/all_color"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_color_value"
|
||||
android:id="@+id/gradeDialogColorValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogColor"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_color"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_color"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_date"
|
||||
android:id="@+id/gradeDialogDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogColorValue"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_color_value"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/all_date"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_dialog_date_value"
|
||||
android:id="@+id/gradeDialogDateValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/gradeDialogDate"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/grade_dialog_date"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginTop="3dp"
|
||||
android:text="@string/all_date"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/grade_dialog_close_button"
|
||||
android:id="@+id/gradeDialogClose"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignTop="@+id/gradeDialogDateValue"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignTop="@+id/grade_dialog_date_value"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginTop="25dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:focusable="true"
|
||||
android:text="@string/all_close"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="15sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -1,174 +1,33 @@
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/grade_fragment_container"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/gradeTabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/colorPrimary"
|
||||
android:elevation="5dp"
|
||||
android:visibility="invisible"
|
||||
app:tabGravity="fill"
|
||||
app:tabIndicatorColor="@android:color/white"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="fixed"
|
||||
app:tabTextColor="@android:color/white" />
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/gradeViewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="Grade" />
|
||||
android:layout_below="@id/gradeTabLayout"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<!--<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/grade_fragment_swipe_refresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/grade_fragment_details_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/grade_fragment_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</FrameLayout>
|
||||
|
||||
<android.support.v4.widget.NestedScrollView
|
||||
android:id="@+id/grade_fragment_summary_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="blocksDescendants">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/grade_fragment_summary_calculated_container"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_toLeftOf="@id/grade_fragment_summary_final_container"
|
||||
android:layout_toStartOf="@id/grade_fragment_summary_final_container">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_summary_calculated_average_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center"
|
||||
android:text="@string/grades_summary_calculated_average"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_summary_calculated_average"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grade_fragment_summary_calculated_average_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:text="6,00"
|
||||
android:textSize="21sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/grade_fragment_summary_final_container"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_summary_final_average_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center"
|
||||
android:minLines="2"
|
||||
android:text="@string/grades_summary_final_average"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_summary_final_average"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grade_fragment_summary_final_average_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:text="6,00"
|
||||
android:textSize="21sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/grade_fragment_summary_predicted_container"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_toEndOf="@id/grade_fragment_summary_final_container"
|
||||
android:layout_toRightOf="@id/grade_fragment_summary_final_container">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_summary_predicted_average_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:text="@string/grades_summary_predicted_average"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_summary_predicted_average"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grade_fragment_summary_predicted_average_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:text="6,00"
|
||||
android:textSize="21sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/grade_fragment_summary_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/grade_fragment_summary_calculated_container"
|
||||
android:layout_marginTop="20dp" />
|
||||
</RelativeLayout>
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/grade_fragment_no_item_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center">
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:id="@+id/grade_fragment_no_item_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/grade_fragment_no_item_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="40dp"
|
||||
android:minHeight="100dp"
|
||||
android:minWidth="100dp"
|
||||
app:srcCompat="@drawable/ic_menu_main_grade_26dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_fragment_no_item_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="46dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/fragment_no_grades"
|
||||
android:textSize="20sp" />
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
</android.support.v4.widget.SwipeRefreshLayout>-->
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
<ProgressBar
|
||||
android:id="@+id/gradeProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
50
app/src/main/res/layout/fragment_grade_details.xml
Normal file
50
app/src/main/res/layout/fragment_grade_details.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<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">
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/gradeDetailsSwipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/gradeDetailsRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/gradeDetailsProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gradeDetailsEmpty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="invisible">
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
app:srcCompat="@drawable/ic_menu_main_grade_26dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/grade_no_items"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
50
app/src/main/res/layout/fragment_grade_summary.xml
Normal file
50
app/src/main/res/layout/fragment_grade_summary.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<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">
|
||||
|
||||
<android.support.v4.widget.SwipeRefreshLayout
|
||||
android:id="@+id/gradeSummarySwipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/gradeSummaryRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/gradeSummaryProgress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gradeSummaryEmpty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="invisible">
|
||||
|
||||
<android.support.v7.widget.AppCompatImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="100dp"
|
||||
android:minHeight="100dp"
|
||||
app:srcCompat="@drawable/ic_menu_main_grade_26dp"
|
||||
app:tint="?android:attr/textColorPrimary"
|
||||
tools:ignore="contentDescription" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/grade_no_items"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
@ -68,7 +68,7 @@
|
||||
android:layout_marginBottom="15dp"
|
||||
android:hint="@string/login_email_hint">
|
||||
|
||||
<EditText
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/loginEmailEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -82,7 +82,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/login_password_hint">
|
||||
|
||||
<EditText
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/loginPassEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -1,4 +1,4 @@
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/timetable_fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -9,22 +9,4 @@
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="Timetable" />
|
||||
|
||||
<!--<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/timetable_fragment_tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabMinWidth="125dp"
|
||||
app:tabMode="scrollable"/>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/timetable_fragment_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/timetable_fragment_tab_layout" />
|
||||
</RelativeLayout>-->
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
@ -9,10 +9,10 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_header_day"
|
||||
|
@ -1,56 +1,57 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tool="http://schemas.android.com/tools"
|
||||
android:id="@+id/grade_header_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ic_all_divider"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_header_subject_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/gradeHeaderSubject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="35dp"
|
||||
android:layout_marginRight="35dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_toLeftOf="@id/gradeHeaderNote"
|
||||
android:layout_toStartOf="@id/gradeHeaderNote"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp" />
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_header_average_text"
|
||||
android:id="@+id/gradeHeaderAverage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/grade_header_subject_text"
|
||||
android:layout_below="@+id/gradeHeaderSubject"
|
||||
android:layout_marginTop="5dp"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_header_number_of_grade_text"
|
||||
android:id="@+id/gradeHeaderNumber"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grade_header_subject_text"
|
||||
android:layout_below="@id/gradeHeaderSubject"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_toEndOf="@+id/grade_header_average_text"
|
||||
android:layout_toRightOf="@+id/grade_header_average_text"
|
||||
android:layout_toEndOf="@+id/gradeHeaderAverage"
|
||||
android:layout_toRightOf="@+id/gradeHeaderAverage"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_header_predicted_rating_text"
|
||||
android:id="@+id/gradeHeaderPredicted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grade_header_average_text"
|
||||
android:layout_below="@id/gradeHeaderAverage"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
@ -59,19 +60,19 @@
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_header_final_rating_text"
|
||||
android:id="@+id/gradeHeaderFinal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/grade_header_average_text"
|
||||
android:layout_below="@id/gradeHeaderAverage"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_toEndOf="@+id/grade_header_predicted_rating_text"
|
||||
android:layout_toRightOf="@+id/grade_header_predicted_rating_text"
|
||||
android:layout_toEndOf="@+id/gradeHeaderPredicted"
|
||||
android:layout_toRightOf="@+id/gradeHeaderPredicted"
|
||||
android:text="@string/grade_final"
|
||||
android:textColor="?android:attr/android:textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/grade_header_alert_image"
|
||||
android:id="@+id/gradeHeaderNote"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
@ -9,19 +9,19 @@
|
||||
android:paddingTop="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grades_summary_header_name"
|
||||
android:id="@+id/gradeSummaryHeaderName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_toLeftOf="@id/grades_summary_header_average"
|
||||
android:layout_toStartOf="@id/grades_summary_header_average"
|
||||
android:layout_toLeftOf="@id/gradeSummaryHeaderAverage"
|
||||
android:layout_toStartOf="@id/gradeSummaryHeaderAverage"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grades_summary_header_average"
|
||||
android:id="@+id/gradeSummaryHeaderAverage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
|
@ -9,10 +9,10 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timetable_header_day"
|
||||
|
@ -1,88 +0,0 @@
|
||||
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tool="http://schemas.android.com/tools"
|
||||
android:id="@+id/grade_subitem_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
card_view:cardElevation="0dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="7dp"
|
||||
android:layout_marginEnd="7dp"
|
||||
android:layout_marginLeft="7dp"
|
||||
android:layout_marginRight="7dp"
|
||||
android:layout_marginStart="7dp"
|
||||
android:layout_marginTop="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_subitem_value"
|
||||
android:layout_width="45dp"
|
||||
android:layout_height="45dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:maxLength="5"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/grade_text"
|
||||
android:background="@color/grade_default"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_subitem_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="40dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_toEndOf="@+id/grade_subitem_value"
|
||||
android:layout_toRightOf="@+id/grade_subitem_value"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/all_description"
|
||||
android:textSize="15sp"
|
||||
tool:ignore="all" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_subitem_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/grade_subitem_value"
|
||||
android:layout_alignLeft="@+id/grade_subitem_description"
|
||||
android:layout_alignStart="@+id/grade_subitem_description"
|
||||
android:text="@string/all_date"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/grade_subitem_weight"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/grade_subitem_date"
|
||||
android:layout_toRightOf="@+id/grade_subitem_date"
|
||||
android:layout_alignBottom="@+id/grade_subitem_value"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:text="@string/grade_weight"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/grade_subitem_alert_image"
|
||||
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_all_round_note_24dp"
|
||||
tool:ignore="contentDescription" />
|
||||
|
||||
</RelativeLayout>
|
||||
</android.support.v7.widget.CardView>
|
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