mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-20 21:24:44 +01:00
Add account manager (#183)
This commit is contained in:
parent
1f30deb36e
commit
7a3c0de7ad
@ -52,7 +52,7 @@ script:
|
||||
- ./gradlew createDebugCoverageReport --stacktrace -PdisableCrashlytics --daemon
|
||||
- ./gradlew jacocoTestReport --stacktrace --daemon
|
||||
- if [ "$TRAVIS_PULL_REQUEST" != "false" ] || [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=$TRAVIS_BRANCH -PdisableCrashlytics --stacktrace --daemon;
|
||||
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} -PdisableCrashlytics --stacktrace --daemon;
|
||||
fi
|
||||
- |
|
||||
if [ $TRAVIS_TAG ]; then
|
||||
|
@ -31,7 +31,7 @@ android {
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
playAccountConfig = playAccountConfigs.defaultAccountConfig
|
||||
manifestPlaceholders = [ fabricApiKey: fabricApiKey ]
|
||||
manifestPlaceholders = [fabricApiKey: fabricApiKey]
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@ -74,16 +74,18 @@ play {
|
||||
uploadImages = true
|
||||
}
|
||||
|
||||
ext.androidx_version = "1.0.0"
|
||||
configurations.all {
|
||||
resolutionStrategy.force "com.squareup.okhttp3:okhttp-urlconnection:3.11.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation('com.github.wulkanowy:api:a80b8e5') { exclude module: "threetenbp" }
|
||||
implementation('com.github.wulkanowy:api:0ac961607b') { exclude module: "threetenbp" }
|
||||
|
||||
implementation "androidx.legacy:legacy-support-v4:$androidx_version"
|
||||
implementation "androidx.appcompat:appcompat:$androidx_version"
|
||||
implementation "androidx.cardview:cardview:$androidx_version"
|
||||
implementation "com.google.android.material:material:$androidx_version"
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
implementation "com.google.android.material:material:1.0.0"
|
||||
implementation 'androidx.multidex:multidex:2.0.0'
|
||||
|
||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||
@ -113,7 +115,6 @@ dependencies {
|
||||
|
||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||
implementation 'com.akaita.java:rxjava2-debug:1.3.0'
|
||||
implementation("com.crashlytics.sdk.android:crashlytics:2.9.5@aar") {
|
||||
transitive = true
|
||||
}
|
||||
@ -132,6 +133,5 @@ dependencies {
|
||||
androidTestImplementation 'androidx.test:runner:1.1.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.0.0'
|
||||
androidTestImplementation "org.mockito:mockito-android:2.23.0"
|
||||
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class AttendanceLocalTest {
|
||||
@Before
|
||||
fun createDb() {
|
||||
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
|
||||
attendanceLocal = AttendanceLocal(testDb.attendanceDao())
|
||||
attendanceLocal = AttendanceLocal(testDb.attendanceDao)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -23,7 +23,7 @@ class ExamLocalTest {
|
||||
@Before
|
||||
fun createDb() {
|
||||
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
|
||||
examLocal = ExamLocal(testDb.examsDao())
|
||||
examLocal = ExamLocal(testDb.examsDao)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -14,9 +14,9 @@ import org.junit.runner.RunWith
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SessionLocalTest {
|
||||
class StudentLocalTest {
|
||||
|
||||
private lateinit var sessionLocal: SessionLocal
|
||||
private lateinit var studentLocal: StudentLocal
|
||||
|
||||
private lateinit var testDb: AppDatabase
|
||||
|
||||
@ -26,9 +26,9 @@ class SessionLocalTest {
|
||||
fun createDb() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
|
||||
.build()
|
||||
.build()
|
||||
sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
|
||||
sessionLocal = SessionLocal(testDb.studentDao(), testDb.semesterDao(), sharedHelper, context)
|
||||
studentLocal = StudentLocal(testDb.studentDao, sharedHelper, context)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -38,12 +38,11 @@ class SessionLocalTest {
|
||||
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
sessionLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO")).blockingAwait()
|
||||
assert(sharedHelper.getLong(SessionLocal.LAST_USER_KEY, 0) == 1L)
|
||||
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true))
|
||||
.blockingAwait()
|
||||
assert(studentLocal.isStudentSaved)
|
||||
|
||||
assert(sessionLocal.isSessionSaved)
|
||||
|
||||
val student = sessionLocal.getLastStudent().blockingGet()
|
||||
val student = studentLocal.getCurrentStudent().blockingGet()
|
||||
assertEquals("23", student.schoolSymbol)
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ class TimetableLocalTest {
|
||||
@Before
|
||||
fun createDb() {
|
||||
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build()
|
||||
timetableDb = TimetableLocal(testDb.timetableDao())
|
||||
timetableDb = TimetableLocal(testDb.timetableDao)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -38,7 +38,6 @@
|
||||
android:name=".ui.modules.main.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/main_title"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||
|
||||
<service
|
||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.multidex.MultiDex
|
||||
import com.akaita.java.rxjava2debug.RxJava2Debug
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import com.crashlytics.android.answers.Answers
|
||||
import com.crashlytics.android.core.CrashlyticsCore
|
||||
@ -36,7 +35,6 @@ class WulkanowyApp : DaggerApplication() {
|
||||
AndroidThreeTen.init(this)
|
||||
initializeFabric()
|
||||
if (DEBUG) enableDebugLog()
|
||||
RxJava2Debug.enableRxJava2AssemblyTracking(arrayOf(BuildConfig.APPLICATION_ID))
|
||||
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
|
||||
}
|
||||
|
||||
|
27
app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
Normal file
27
app/src/main/java/io/github/wulkanowy/data/ApiHelper.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package io.github.wulkanowy.data
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
|
||||
class ApiHelper @Inject constructor(private val api: Api) {
|
||||
|
||||
fun initApi(student: Student) {
|
||||
api.apply {
|
||||
email = student.email
|
||||
password = student.password
|
||||
symbol = student.symbol
|
||||
schoolSymbol = student.schoolSymbol
|
||||
studentId = student.studentId
|
||||
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
|
||||
ssl = student.endpoint.startsWith("https")
|
||||
loginType = Api.LoginType.valueOf(student.loginType)
|
||||
}
|
||||
}
|
||||
|
||||
fun initApi(email: String, password: String, symbol: String, endpoint: String) {
|
||||
initApi(Student(email = email, password = password, symbol = symbol, endpoint = endpoint, loginType = "AUTO"))
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package io.github.wulkanowy.data
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.akaita.java.rxjava2debug.RxJava2Debug
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.api.login.NotLoggedInException
|
||||
import timber.log.Timber
|
||||
@ -10,12 +9,12 @@ import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
|
||||
open class ErrorHandler @Inject constructor(private val resources: Resources) {
|
||||
open class ErrorHandler @Inject constructor(protected val resources: Resources) {
|
||||
|
||||
var showErrorMessage: (String) -> Unit = {}
|
||||
|
||||
open fun proceed(error: Throwable) {
|
||||
Timber.e(RxJava2Debug.getEnhancedStackTrace(error), "An exception occurred while the Wulkanowy was running")
|
||||
Timber.e(error, "An exception occurred while the Wulkanowy was running")
|
||||
|
||||
showErrorMessage((when (error) {
|
||||
is UnknownHostException -> resources.getString(R.string.all_no_internet)
|
||||
|
@ -9,6 +9,10 @@ import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC
|
||||
import okhttp3.logging.HttpLoggingInterceptor.Level.NONE
|
||||
import timber.log.Timber
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@ -18,14 +22,19 @@ internal class RepositoryModule {
|
||||
@Provides
|
||||
fun provideInternetObservingSettings(): InternetObservingSettings {
|
||||
return InternetObservingSettings.builder()
|
||||
.strategy(SocketInternetObservingStrategy())
|
||||
.host("www.google.com")
|
||||
.build()
|
||||
.strategy(SocketInternetObservingStrategy())
|
||||
.host("www.google.com")
|
||||
.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideApi() = Api()
|
||||
fun provideApi(): Api {
|
||||
return Api().apply {
|
||||
logLevel = NONE
|
||||
setInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { Timber.d(it) }).setLevel(BASIC))
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@ -36,43 +45,41 @@ internal class RepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSharedPref(context: Context): SharedPreferences {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||
}
|
||||
fun provideSharedPref(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideStudentDao(database: AppDatabase) = database.studentDao()
|
||||
fun provideStudentDao(database: AppDatabase) = database.studentDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSemesterDao(database: AppDatabase) = database.semesterDao()
|
||||
fun provideSemesterDao(database: AppDatabase) = database.semesterDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGradeDao(database: AppDatabase) = database.gradeDao()
|
||||
fun provideGradeDao(database: AppDatabase) = database.gradeDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGradeSummaryDao(database: AppDatabase) = database.gradeSummaryDao()
|
||||
fun provideGradeSummaryDao(database: AppDatabase) = database.gradeSummaryDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideExamDao(database: AppDatabase) = database.examsDao()
|
||||
fun provideExamDao(database: AppDatabase) = database.examsDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideAttendanceDao(database: AppDatabase) = database.attendanceDao()
|
||||
fun provideAttendanceDao(database: AppDatabase) = database.attendanceDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideTimetableDao(database: AppDatabase) = database.timetableDao()
|
||||
fun provideTimetableDao(database: AppDatabase) = database.timetableDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideNoteDao(database: AppDatabase) = database.noteDao()
|
||||
fun provideNoteDao(database: AppDatabase) = database.noteDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideHomeworkDao(database: AppDatabase) = database.homeworkDao()
|
||||
fun provideHomeworkDao(database: AppDatabase) = database.homeworkDao
|
||||
}
|
||||
|
@ -51,21 +51,21 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun studentDao(): StudentDao
|
||||
abstract val studentDao: StudentDao
|
||||
|
||||
abstract fun semesterDao(): SemesterDao
|
||||
abstract val semesterDao: SemesterDao
|
||||
|
||||
abstract fun examsDao(): ExamDao
|
||||
abstract val examsDao: ExamDao
|
||||
|
||||
abstract fun timetableDao(): TimetableDao
|
||||
abstract val timetableDao: TimetableDao
|
||||
|
||||
abstract fun attendanceDao(): AttendanceDao
|
||||
abstract val attendanceDao: AttendanceDao
|
||||
|
||||
abstract fun gradeDao(): GradeDao
|
||||
abstract val gradeDao: GradeDao
|
||||
|
||||
abstract fun gradeSummaryDao(): GradeSummaryDao
|
||||
abstract val gradeSummaryDao: GradeSummaryDao
|
||||
|
||||
abstract fun noteDao(): NoteDao
|
||||
abstract val noteDao: NoteDao
|
||||
|
||||
abstract fun homeworkDao(): HomeworkDao
|
||||
abstract val homeworkDao: HomeworkDao
|
||||
}
|
||||
|
@ -19,6 +19,14 @@ class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPrefere
|
||||
return sharedPref.getLong(key, defaultValue)
|
||||
}
|
||||
|
||||
fun putBoolean(key: String, value: Boolean) {
|
||||
sharedPref.edit().putBoolean(key, value).apply()
|
||||
}
|
||||
|
||||
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
|
||||
return sharedPref.getBoolean(key, defaultValue)
|
||||
}
|
||||
|
||||
fun delete(key: String) {
|
||||
sharedPref.edit().remove(key).apply()
|
||||
}
|
||||
|
@ -18,5 +18,5 @@ interface AttendanceDao {
|
||||
fun deleteAll(exams: List<Attendance>)
|
||||
|
||||
@Query("SELECT * FROM Attendance WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||
fun getExams(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Attendance>>
|
||||
fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Attendance>>
|
||||
}
|
||||
|
@ -18,5 +18,5 @@ interface ExamDao {
|
||||
fun deleteAll(exams: List<Exam>)
|
||||
|
||||
@Query("SELECT * FROM Exams WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||
fun getExams(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Exam>>
|
||||
fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Exam>>
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.*
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.reactivex.Maybe
|
||||
|
||||
@ -20,8 +24,8 @@ interface GradeDao {
|
||||
fun deleteAll(grades: List<Grade>)
|
||||
|
||||
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
|
||||
fun getGrades(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
||||
fun load(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
||||
|
||||
@Query("SELECT * FROM Grades WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
|
||||
fun getNewGrades(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
||||
fun loadNew(semesterId: Int, studentId: Int): Maybe<List<Grade>>
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.dao
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.REPLACE
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.reactivex.Maybe
|
||||
@ -18,5 +17,5 @@ interface GradeSummaryDao {
|
||||
fun deleteAll(gradesSummary: List<GradeSummary>)
|
||||
|
||||
@Query("SELECT * FROM grades_summary WHERE student_id = :studentId AND semester_id = :semesterId")
|
||||
fun getGradesSummary(semesterId: Int, studentId: Int): Maybe<List<GradeSummary>>
|
||||
fun load(semesterId: Int, studentId: Int): Maybe<List<GradeSummary>>
|
||||
}
|
||||
|
@ -18,5 +18,5 @@ interface HomeworkDao {
|
||||
fun deleteAll(homework: List<Homework>)
|
||||
|
||||
@Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date = :date")
|
||||
fun getHomework(semesterId: Int, studentId: Int, date: LocalDate): Maybe<List<Homework>>
|
||||
fun load(semesterId: Int, studentId: Int, date: LocalDate): Maybe<List<Homework>>
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ interface NoteDao {
|
||||
fun deleteAll(notes: List<Note>)
|
||||
|
||||
@Query("SELECT * FROM Notes WHERE semester_id = :semesterId AND student_id = :studentId")
|
||||
fun getNotes(semesterId: Int, studentId: Int): Maybe<List<Note>>
|
||||
fun load(semesterId: Int, studentId: Int): Maybe<List<Note>>
|
||||
|
||||
@Query("SELECT * FROM Notes WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
|
||||
fun getNewNotes(semesterId: Int, studentId: Int): Maybe<List<Note>>
|
||||
fun loadNew(semesterId: Int, studentId: Int): Maybe<List<Note>>
|
||||
}
|
||||
|
@ -2,22 +2,23 @@ package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.IGNORE
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.Maybe
|
||||
|
||||
@Dao
|
||||
interface SemesterDao {
|
||||
|
||||
@Insert
|
||||
@Insert(onConflict = IGNORE)
|
||||
fun insertAll(semester: List<Semester>)
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId AND diary_id = :diaryId")
|
||||
fun update(semesterId: Int, diaryId: Int)
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||
fun getSemester(studentId: Int): Single<List<Semester>>
|
||||
fun load(studentId: Int): Maybe<List<Semester>>
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 0")
|
||||
fun resetCurrentSemester()
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId")
|
||||
fun setCurrentSemester(semesterId: Int)
|
||||
@Query("UPDATE Semesters SET is_current = 0 WHERE student_id = :studentId")
|
||||
fun resetCurrent(studentId: Int)
|
||||
}
|
||||
|
@ -1,17 +1,32 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.FAIL
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
|
||||
@Dao
|
||||
interface StudentDao {
|
||||
|
||||
@Insert
|
||||
fun insert(student: Student): Long
|
||||
@Insert(onConflict = FAIL)
|
||||
fun insert(student: Student)
|
||||
|
||||
@Query("SELECT * FROM Students WHERE id = :id")
|
||||
fun load(id: Long): Maybe<Student>
|
||||
@Update
|
||||
fun update(student: Student)
|
||||
|
||||
@Delete
|
||||
fun delete(student: Student)
|
||||
|
||||
@Query("SELECT * FROM Students WHERE is_current = 1")
|
||||
fun loadCurrent(): Maybe<Student>
|
||||
|
||||
@Query("SELECT * FROM Students")
|
||||
fun loadAll(): Maybe<List<Student>>
|
||||
|
||||
@Query("UPDATE Students SET is_current = 0")
|
||||
fun resetCurrent()
|
||||
}
|
||||
|
@ -18,5 +18,5 @@ interface TimetableDao {
|
||||
fun deleteAll(exams: List<Timetable>)
|
||||
|
||||
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
|
||||
fun getTimetable(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Timetable>>
|
||||
fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Timetable>>
|
||||
}
|
||||
|
@ -2,29 +2,30 @@ package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "Semesters")
|
||||
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
|
||||
data class Semester(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: Int,
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: Int,
|
||||
|
||||
@ColumnInfo(name = "diary_id")
|
||||
var diaryId: Int,
|
||||
@ColumnInfo(name = "diary_id")
|
||||
var diaryId: Int,
|
||||
|
||||
@ColumnInfo(name = "diary_name")
|
||||
var diaryName: String,
|
||||
@ColumnInfo(name = "diary_name")
|
||||
var diaryName: String,
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
var semesterId: Int,
|
||||
@ColumnInfo(name = "semester_id")
|
||||
var semesterId: Int,
|
||||
|
||||
@ColumnInfo(name = "semester_name")
|
||||
var semesterName: Int,
|
||||
@ColumnInfo(name = "semester_name")
|
||||
var semesterName: Int,
|
||||
|
||||
@ColumnInfo(name = "is_current")
|
||||
var current: Boolean = false
|
||||
@ColumnInfo(name = "is_current")
|
||||
var isCurrent: Boolean = false
|
||||
)
|
||||
|
@ -2,33 +2,37 @@ package io.github.wulkanowy.data.db.entities
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "Students")
|
||||
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id"], unique = true)])
|
||||
data class Student(
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0,
|
||||
|
||||
var endpoint: String,
|
||||
var endpoint: String,
|
||||
|
||||
var loginType: String,
|
||||
var loginType: String,
|
||||
|
||||
var email: String,
|
||||
var email: String,
|
||||
|
||||
var password: String,
|
||||
var password: String,
|
||||
|
||||
var symbol: String = "",
|
||||
var symbol: String = "",
|
||||
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: Int = 0,
|
||||
@ColumnInfo(name = "student_id")
|
||||
var studentId: Int = 0,
|
||||
|
||||
@ColumnInfo(name = "student_name")
|
||||
var studentName: String = "",
|
||||
@ColumnInfo(name = "student_name")
|
||||
var studentName: String = "",
|
||||
|
||||
@ColumnInfo(name = "school_id")
|
||||
var schoolSymbol: String = "",
|
||||
@ColumnInfo(name = "school_id")
|
||||
var schoolSymbol: String = "",
|
||||
|
||||
@ColumnInfo(name = "school_name")
|
||||
var schoolName: String = ""
|
||||
@ColumnInfo(name = "school_name")
|
||||
var schoolName: String = "",
|
||||
|
||||
@ColumnInfo(name = "is_current")
|
||||
var isCurrent: Boolean = false
|
||||
)
|
||||
|
@ -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.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.local.SemesterLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.SemesterRemote
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SemesterRepository @Inject constructor(
|
||||
private val remote: SemesterRemote,
|
||||
private val local: SemesterLocal,
|
||||
private val settings: InternetObservingSettings,
|
||||
private val apiHelper: ApiHelper
|
||||
) {
|
||||
|
||||
fun getSemesters(student: Student, forceRefresh: Boolean = false): Single<List<Semester>> {
|
||||
return Maybe.just(apiHelper.initApi(student))
|
||||
.flatMap { local.getSemesters(student).filter { !forceRefresh } }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getSemesters(student) else Single.error(UnknownHostException())
|
||||
}.map { newSemesters ->
|
||||
local.apply {
|
||||
saveSemesters(newSemesters)
|
||||
setCurrentSemester(newSemesters.single { it.isCurrent })
|
||||
}
|
||||
}.flatMap { local.getSemesters(student).toSingle(emptyList()) })
|
||||
}
|
||||
|
||||
fun getCurrentSemester(student: Student, forceRefresh: Boolean = false): Single<Semester> {
|
||||
return getSemesters(student, forceRefresh).map { item -> item.single { it.isCurrent } }
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
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.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.local.SessionLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.SessionRemote
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SessionRepository @Inject constructor(
|
||||
private val local: SessionLocal,
|
||||
private val remote: SessionRemote,
|
||||
private val settings: InternetObservingSettings
|
||||
) {
|
||||
|
||||
val isSessionSaved
|
||||
get() = local.isSessionSaved
|
||||
|
||||
lateinit var cachedStudents: Single<List<Student>>
|
||||
private set
|
||||
|
||||
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
||||
cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap { isConnected ->
|
||||
if (isConnected) remote.getConnectedStudents(email, password, symbol, endpoint)
|
||||
else Single.error<List<Student>>(UnknownHostException("No internet connection"))
|
||||
}.doOnSuccess { cachedStudents = Single.just(it) }
|
||||
return cachedStudents
|
||||
}
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
return remote.getSemesters(student)
|
||||
.flatMapCompletable { local.saveSemesters(it) }
|
||||
.concatWith(local.saveStudent(student))
|
||||
}
|
||||
|
||||
fun getSemesters(forceRefresh: Boolean = false): Single<List<Semester>> {
|
||||
return local.getLastStudent()
|
||||
.flatMapSingle { student ->
|
||||
remote.initApi(student)
|
||||
local.getSemesters(student).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||
if (it) remote.getCurrentSemester(student)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { current ->
|
||||
local.getSemesters(student).doOnSuccess { semesters ->
|
||||
if (semesters.single { it.current }.semesterId != current.semesterId) {
|
||||
local.saveSemesters(listOf(current)).andThen {
|
||||
local.setCurrentSemester(current.semesterId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.flatMap {
|
||||
local.getSemesters(student)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
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.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.local.StudentLocal
|
||||
import io.github.wulkanowy.data.repositories.remote.StudentRemote
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class StudentRepository @Inject constructor(
|
||||
private val local: StudentLocal,
|
||||
private val remote: StudentRemote,
|
||||
private val settings: InternetObservingSettings,
|
||||
private val apiHelper: ApiHelper
|
||||
) {
|
||||
|
||||
val isStudentSaved
|
||||
get() = local.isStudentSaved
|
||||
|
||||
lateinit var cachedStudents: Single<List<Student>>
|
||||
private set
|
||||
|
||||
fun getStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
||||
cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
apiHelper.initApi(email, password, symbol, endpoint)
|
||||
if (it) remote.getStudents(email, password, endpoint)
|
||||
else Single.error(UnknownHostException("No internet connection"))
|
||||
}.doOnSuccess { cachedStudents = Single.just(it) }
|
||||
return cachedStudents
|
||||
}
|
||||
|
||||
fun getSavedStudents(): Single<List<Student>> {
|
||||
return local.getStudents().toSingle(emptyList())
|
||||
}
|
||||
|
||||
fun getCurrentStudent(): Single<Student> {
|
||||
return local.getCurrentStudent().toSingle()
|
||||
}
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
return local.saveStudent(student)
|
||||
}
|
||||
|
||||
fun switchStudent(student: Student): Completable {
|
||||
return local.setCurrentStudent(student)
|
||||
}
|
||||
|
||||
fun logoutCurrentStudent(): Completable {
|
||||
return local.logoutCurrentStudent()
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import javax.inject.Inject
|
||||
class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) {
|
||||
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Attendance>> {
|
||||
return attendanceDb.getExams(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
return attendanceDb.load(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
.filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import javax.inject.Inject
|
||||
class ExamLocal @Inject constructor(private val examDb: ExamDao) {
|
||||
|
||||
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Exam>> {
|
||||
return examDb.getExams(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
return examDb.load(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
.filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,11 @@ import javax.inject.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() }
|
||||
return gradeDb.load(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun getNewGrades(semester: Semester): Maybe<List<Grade>> {
|
||||
return gradeDb.getNewGrades(semester.semesterId, semester.studentId)
|
||||
return gradeDb.loadNew(semester.semesterId, semester.studentId)
|
||||
}
|
||||
|
||||
fun saveGrades(grades: List<Grade>) {
|
||||
|
@ -11,7 +11,7 @@ import javax.inject.Singleton
|
||||
class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSummaryDao) {
|
||||
|
||||
fun getGradesSummary(semester: Semester): Maybe<List<GradeSummary>> {
|
||||
return gradeSummaryDb.getGradesSummary(semester.semesterId, semester.studentId)
|
||||
return gradeSummaryDb.load(semester.semesterId, semester.studentId)
|
||||
.filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import javax.inject.Singleton
|
||||
class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
|
||||
|
||||
fun getHomework(semester: Semester, date: LocalDate): Maybe<List<Homework>> {
|
||||
return homeworkDb.getHomework(semester.semesterId, semester.studentId, date).filter { !it.isEmpty() }
|
||||
return homeworkDb.load(semester.semesterId, semester.studentId, date).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveHomework(homework: List<Homework>) {
|
||||
|
@ -12,11 +12,11 @@ import javax.inject.Singleton
|
||||
class NoteLocal @Inject constructor(private val noteDb: NoteDao) {
|
||||
|
||||
fun getNotes(semester: Semester): Maybe<List<Note>> {
|
||||
return noteDb.getNotes(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
||||
return noteDb.load(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun getNewNotes(semester: Semester): Maybe<List<Note>> {
|
||||
return noteDb.getNewNotes(semester.semesterId, semester.studentId)
|
||||
return noteDb.loadNew(semester.semesterId, semester.studentId)
|
||||
}
|
||||
|
||||
fun saveNotes(notes: List<Note>) {
|
||||
|
@ -0,0 +1,27 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SemesterLocal @Inject constructor(private val semesterDb: SemesterDao) {
|
||||
|
||||
fun saveSemesters(semesters: List<Semester>) {
|
||||
return semesterDb.insertAll(semesters)
|
||||
}
|
||||
|
||||
fun getSemesters(student: Student): Maybe<List<Semester>> {
|
||||
return semesterDb.load(student.studentId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun setCurrentSemester(semester: Semester) {
|
||||
semesterDb.run {
|
||||
resetCurrent(semester.studentId)
|
||||
update(semester.semesterId, semester.diaryId)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import android.content.Context
|
||||
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.utils.security.decrypt
|
||||
import io.github.wulkanowy.utils.security.encrypt
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SessionLocal @Inject constructor(
|
||||
private val studentDb: StudentDao,
|
||||
private val semesterDb: SemesterDao,
|
||||
private val sharedPref: SharedPrefHelper,
|
||||
private val context: Context) {
|
||||
|
||||
companion object {
|
||||
const val LAST_USER_KEY: String = "last_user_id"
|
||||
}
|
||||
|
||||
val isSessionSaved
|
||||
get() = sharedPref.getLong(LAST_USER_KEY, defaultValue = 0L) != 0L
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) }
|
||||
.map { sharedPref.putLong(LAST_USER_KEY, it) }
|
||||
.ignoreElement()
|
||||
}
|
||||
|
||||
fun getLastStudent(): Maybe<Student> {
|
||||
return studentDb.load(sharedPref.getLong(LAST_USER_KEY, defaultValue = 0))
|
||||
.map { it.apply { password = decrypt(password) } }
|
||||
}
|
||||
|
||||
fun saveSemesters(semesters: List<Semester>): Completable {
|
||||
return Single.fromCallable { semesterDb.insertAll(semesters) }.ignoreElement()
|
||||
}
|
||||
|
||||
fun getSemesters(student: Student): Single<List<Semester>> {
|
||||
return semesterDb.getSemester(student.studentId)
|
||||
}
|
||||
|
||||
fun setCurrentSemester(semesterId: Int): Completable {
|
||||
return Single.fromCallable { semesterDb.resetCurrentSemester() }.ignoreElement().andThen {
|
||||
semesterDb.setCurrentSemester(semesterId)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package io.github.wulkanowy.data.repositories.local
|
||||
|
||||
import android.content.Context
|
||||
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.utils.security.decrypt
|
||||
import io.github.wulkanowy.utils.security.encrypt
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class StudentLocal @Inject constructor(
|
||||
private val studentDb: StudentDao,
|
||||
private val sharedPref: SharedPrefHelper,
|
||||
private val context: Context
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val STUDENT_SAVED_KEY: String = "is_student_saved"
|
||||
}
|
||||
|
||||
val isStudentSaved
|
||||
get() = sharedPref.getBoolean(STUDENT_SAVED_KEY, false)
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
return Completable.fromCallable {
|
||||
studentDb.run {
|
||||
resetCurrent()
|
||||
studentDb.insert(student.copy(password = encrypt(student.password, context)))
|
||||
}
|
||||
}.doOnComplete { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
|
||||
}
|
||||
|
||||
fun getCurrentStudent(): Maybe<Student> {
|
||||
return studentDb.loadCurrent().map { it.apply { password = decrypt(password) } }
|
||||
}
|
||||
|
||||
fun getStudents(): Maybe<List<Student>> {
|
||||
return studentDb.loadAll()
|
||||
}
|
||||
|
||||
fun setCurrentStudent(student: Student): Completable {
|
||||
return Completable.fromCallable {
|
||||
studentDb.run {
|
||||
resetCurrent()
|
||||
update(student.apply { isCurrent = true })
|
||||
}
|
||||
}.doOnComplete { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
|
||||
}
|
||||
|
||||
fun logoutCurrentStudent(): Completable {
|
||||
return studentDb.loadCurrent().doOnSuccess {
|
||||
studentDb.delete(it)
|
||||
sharedPref.putBoolean(STUDENT_SAVED_KEY, false)
|
||||
}.ignoreElement()
|
||||
}
|
||||
}
|
@ -10,8 +10,8 @@ import javax.inject.Inject
|
||||
class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao) {
|
||||
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Timetable>> {
|
||||
return timetableDb.getTimetable(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
.filter { !it.isEmpty() }
|
||||
return timetableDb.load(semester.diaryId, semester.studentId, startDate, endDate)
|
||||
.filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun saveTimetable(timetables: List<Timetable>) {
|
||||
|
@ -11,14 +11,10 @@ import javax.inject.Inject
|
||||
class AttendanceRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getAttendance(startDate, endDate) }.map { attendance ->
|
||||
attendance.map {
|
||||
Attendance(
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getAttendance(startDate, endDate) }.map { attendance ->
|
||||
attendance.map {
|
||||
Attendance(
|
||||
studentId = semester.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
date = it.date.toLocalDate(),
|
||||
@ -31,8 +27,8 @@ class AttendanceRemote @Inject constructor(private val api: Api) {
|
||||
lateness = it.lateness,
|
||||
excused = it.excused,
|
||||
deleted = it.deleted
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,10 @@ import javax.inject.Inject
|
||||
class ExamRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getExams(startDate, endDate) }.map { exams ->
|
||||
exams.map {
|
||||
Exam(
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getExams(startDate, endDate) }.map { exams ->
|
||||
exams.map {
|
||||
Exam(
|
||||
studentId = semester.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
date = it.date.toLocalDate(),
|
||||
@ -29,8 +25,8 @@ class ExamRemote @Inject constructor(private val api: Api) {
|
||||
description = it.description,
|
||||
teacher = it.teacher,
|
||||
teacherSymbol = it.teacherSymbol
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,31 +12,27 @@ import javax.inject.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) }
|
||||
.map { grades ->
|
||||
grades.map {
|
||||
Grade(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.subject,
|
||||
entry = it.entry,
|
||||
value = it.value,
|
||||
modifier = it.modifier,
|
||||
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
|
||||
)
|
||||
}
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getGrades(semester.semesterId) }
|
||||
.map { grades ->
|
||||
grades.map {
|
||||
Grade(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.subject,
|
||||
entry = it.entry,
|
||||
value = it.value,
|
||||
modifier = it.modifier,
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,22 +11,18 @@ import javax.inject.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) }
|
||||
.map { gradesSummary ->
|
||||
gradesSummary.map {
|
||||
GradeSummary(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.name,
|
||||
predictedGrade = it.predicted,
|
||||
finalGrade = it.final
|
||||
)
|
||||
}
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getGradesSummary(semester.semesterId) }
|
||||
.map { gradesSummary ->
|
||||
gradesSummary.map {
|
||||
GradeSummary(
|
||||
semesterId = semester.semesterId,
|
||||
studentId = semester.studentId,
|
||||
subject = it.name,
|
||||
predictedGrade = it.predicted,
|
||||
finalGrade = it.final
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,8 @@ import javax.inject.Singleton
|
||||
class HomeworkRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getHomework(semester: Semester, date: LocalDate): Single<List<Homework>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getHomework(date, date) }
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getHomework(date, date) }
|
||||
.map { homework ->
|
||||
homework.map {
|
||||
Homework(
|
||||
|
@ -12,12 +12,8 @@ import javax.inject.Singleton
|
||||
class NoteRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getNotes(semester: Semester): Single<List<Note>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getNotes() }
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getNotes() }
|
||||
.map { notes ->
|
||||
notes.map {
|
||||
Note(
|
||||
|
@ -0,0 +1,30 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SemesterRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getSemesters(student: Student): Single<List<Semester>> {
|
||||
return api.getSemesters().map { semesters ->
|
||||
semesters.map { semester ->
|
||||
Semester(
|
||||
studentId = student.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
diaryName = semester.diaryName,
|
||||
semesterId = semester.semesterId,
|
||||
semesterName = semester.semesterNumber,
|
||||
isCurrent = semester.current
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,96 +0,0 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Single
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class SessionRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
|
||||
return Single.just(
|
||||
initApi(
|
||||
Student(
|
||||
email = email,
|
||||
password = password,
|
||||
symbol = symbol,
|
||||
endpoint = endpoint,
|
||||
loginType = "AUTO"
|
||||
), true
|
||||
)
|
||||
).flatMap {
|
||||
api.getPupils().map { students ->
|
||||
students.map { pupil ->
|
||||
Student(
|
||||
email = email,
|
||||
password = password,
|
||||
symbol = pupil.symbol,
|
||||
studentId = pupil.studentId,
|
||||
studentName = pupil.studentName,
|
||||
schoolSymbol = pupil.schoolSymbol,
|
||||
schoolName = pupil.schoolName,
|
||||
endpoint = endpoint,
|
||||
loginType = pupil.loginType.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSemesters(student: Student): Single<List<Semester>> {
|
||||
return Single.just(initApi(student)).flatMap {
|
||||
api.getSemesters().map { semesters ->
|
||||
semesters.map { semester ->
|
||||
Semester(
|
||||
studentId = student.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
diaryName = semester.diaryName,
|
||||
semesterId = semester.semesterId,
|
||||
semesterName = semester.semesterNumber,
|
||||
current = semester.current
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentSemester(student: Student): Single<Semester> {
|
||||
return api.getCurrentSemester().map {
|
||||
Semester(
|
||||
studentId = student.studentId,
|
||||
diaryId = it.diaryId,
|
||||
diaryName = it.diaryName,
|
||||
semesterId = it.semesterId,
|
||||
semesterName = it.semesterNumber,
|
||||
current = it.current
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun initApi(student: Student, reInitialize: Boolean = false) {
|
||||
if (if (reInitialize) true else 0 == api.studentId) {
|
||||
api.run {
|
||||
logLevel = HttpLoggingInterceptor.Level.NONE
|
||||
email = student.email
|
||||
password = student.password
|
||||
symbol = student.symbol
|
||||
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
|
||||
ssl = student.endpoint.startsWith("https")
|
||||
schoolSymbol = student.schoolSymbol
|
||||
studentId = student.studentId
|
||||
loginType = Api.LoginType.valueOf(student.loginType)
|
||||
notifyDataChanged()
|
||||
setInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
|
||||
Timber.d(it)
|
||||
}).setLevel(HttpLoggingInterceptor.Level.BASIC))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class StudentRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getStudents(email: String, password: String, endpoint: String): Single<List<Student>> {
|
||||
return api.getPupils().map { students ->
|
||||
students.map { pupil ->
|
||||
Student(
|
||||
email = email,
|
||||
password = password,
|
||||
symbol = pupil.symbol,
|
||||
studentId = pupil.studentId,
|
||||
studentName = pupil.studentName,
|
||||
schoolSymbol = pupil.schoolSymbol,
|
||||
schoolName = pupil.schoolName,
|
||||
endpoint = endpoint,
|
||||
loginType = pupil.loginType.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,14 +12,11 @@ import javax.inject.Inject
|
||||
class TimetableRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
|
||||
return Single.just(api.run {
|
||||
if (diaryId != semester.diaryId) {
|
||||
diaryId = semester.diaryId
|
||||
notifyDataChanged()
|
||||
}
|
||||
}).flatMap { api.getTimetable(startDate, endDate) }.map { lessons ->
|
||||
lessons.map {
|
||||
Timetable(
|
||||
return Single.just(api.apply { diaryId = semester.diaryId })
|
||||
.flatMap { it.getTimetable(startDate, endDate) }
|
||||
.map { lessons ->
|
||||
lessons.map {
|
||||
Timetable(
|
||||
studentId = semester.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
number = it.number,
|
||||
@ -33,8 +30,8 @@ class TimetableRemote @Inject constructor(private val api: Api) {
|
||||
info = it.info,
|
||||
changes = it.changes,
|
||||
canceled = it.canceled
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ import io.github.wulkanowy.data.repositories.GradeSummaryRepository
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.services.notification.GradeNotification
|
||||
import io.github.wulkanowy.services.notification.NoteNotification
|
||||
@ -26,7 +27,10 @@ import javax.inject.Inject
|
||||
class SyncWorker : SimpleJobService() {
|
||||
|
||||
@Inject
|
||||
lateinit var session: SessionRepository
|
||||
lateinit var student: StudentRepository
|
||||
|
||||
@Inject
|
||||
lateinit var semester: SemesterRepository
|
||||
|
||||
@Inject
|
||||
lateinit var gradesDetails: GradeRepository
|
||||
@ -73,8 +77,8 @@ class SyncWorker : SimpleJobService() {
|
||||
|
||||
var error: Throwable? = null
|
||||
|
||||
disposable.add(session.getSemesters(true)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
disposable.add(student.getCurrentStudent()
|
||||
.flatMap { semester.getCurrentSemester(it, true) }
|
||||
.flatMapPublisher {
|
||||
Single.merge(
|
||||
listOf(
|
||||
@ -107,8 +111,8 @@ class SyncWorker : SimpleJobService() {
|
||||
}
|
||||
|
||||
private fun sendGradeNotifications() {
|
||||
disposable.add(session.getSemesters()
|
||||
.map { it.single { semester -> semester.current } }
|
||||
disposable.add(student.getCurrentStudent()
|
||||
.flatMap { semester.getCurrentSemester(it, true) }
|
||||
.flatMap { gradesDetails.getNewGrades(it) }
|
||||
.map { it.filter { grade -> !grade.isNotified } }
|
||||
.subscribe({
|
||||
@ -121,8 +125,8 @@ class SyncWorker : SimpleJobService() {
|
||||
}
|
||||
|
||||
private fun sendNoteNotification() {
|
||||
disposable.add(session.getSemesters()
|
||||
.map { it.single { semester -> semester.current } }
|
||||
disposable.add(student.getCurrentStudent()
|
||||
.flatMap { semester.getCurrentSemester(it, true) }
|
||||
.flatMap { note.getNewNotes(it) }
|
||||
.map { it.filter { note -> !note.isNotified } }
|
||||
.subscribe({
|
||||
|
@ -4,7 +4,8 @@ import android.content.Intent
|
||||
import android.widget.RemoteViewsService
|
||||
import dagger.android.AndroidInjection
|
||||
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetFactory
|
||||
import javax.inject.Inject
|
||||
@ -12,16 +13,19 @@ import javax.inject.Inject
|
||||
class TimetableWidgetService : RemoteViewsService() {
|
||||
|
||||
@Inject
|
||||
lateinit var timetableRepository: TimetableRepository
|
||||
lateinit var timetableRepo: TimetableRepository
|
||||
|
||||
@Inject
|
||||
lateinit var sessionRepository: SessionRepository
|
||||
lateinit var studentRepo: StudentRepository
|
||||
|
||||
@Inject
|
||||
lateinit var semesterRepo: SemesterRepository
|
||||
|
||||
@Inject
|
||||
lateinit var sharedPref: SharedPrefHelper
|
||||
|
||||
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
|
||||
AndroidInjection.inject(this)
|
||||
return TimetableWidgetFactory(timetableRepository, sessionRepository, sharedPref, applicationContext, intent)
|
||||
return TimetableWidgetFactory(timetableRepo, studentRepo, semesterRepo, sharedPref, applicationContext, intent)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,99 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import android.widget.Toast.LENGTH_LONG
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import dagger.android.support.DaggerAppCompatDialogFragment
|
||||
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.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||
import kotlinx.android.synthetic.main.dialog_account.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
|
||||
|
||||
@Inject
|
||||
lateinit var presenter: AccountPresenter
|
||||
|
||||
@Inject
|
||||
lateinit var accountAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
|
||||
|
||||
companion object {
|
||||
fun newInstance() = AccountDialog()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setStyle(STYLE_NO_TITLE, 0)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.dialog_account, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
presenter.onAttachView(this)
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
accountAdapter.setOnItemClickListener { presenter.onItemSelected(it) }
|
||||
|
||||
accountDialogAdd.setOnClickListener { presenter.onAddSelected() }
|
||||
accountDialogRemove.setOnClickListener { presenter.onRemoveSelected() }
|
||||
accountDialogRecycler.apply {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
adapter = accountAdapter
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateData(data: List<AccountItem>) {
|
||||
accountAdapter.updateDataSet(data)
|
||||
}
|
||||
|
||||
override fun showMessage(text: String) {
|
||||
Toast.makeText(context, text, LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun dismissView() {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
override fun openLoginView() {
|
||||
activity?.also {
|
||||
startActivity(LoginActivity.getStartIntent(it))
|
||||
}
|
||||
}
|
||||
|
||||
override fun showConfirmDialog() {
|
||||
context?.let {
|
||||
AlertDialog.Builder(it)
|
||||
.setTitle(R.string.account_logout_student)
|
||||
.setMessage(R.string.account_confirm)
|
||||
.setPositiveButton(R.string.account_logout) { _, _ -> presenter.onLogoutConfirm() }
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun recreateView() {
|
||||
activity?.also {
|
||||
startActivity(MainActivity.getStartIntent(it))
|
||||
it.finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
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 io.github.wulkanowy.data.db.entities.Student
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_account.*
|
||||
|
||||
class AccountItem(val student: Student) : AbstractFlexibleItem<AccountItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_account
|
||||
|
||||
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 {
|
||||
accountItemName.text = student.studentName
|
||||
accountItemSchool.text = student.schoolName
|
||||
accountItemImage.setBackgroundResource(if (student.isCurrent) R.drawable.ic_account_circular_border else 0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as AccountItem
|
||||
|
||||
if (student != other.student) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return student.hashCode()
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
get() = contentView
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
|
||||
class AccountPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val schedulers: SchedulersProvider
|
||||
) : BasePresenter<AccountView>(errorHandler) {
|
||||
|
||||
override fun onAttachView(view: AccountView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onAddSelected() {
|
||||
view?.openLoginView()
|
||||
}
|
||||
|
||||
fun onRemoveSelected() {
|
||||
view?.showConfirmDialog()
|
||||
}
|
||||
|
||||
fun onLogoutConfirm() {
|
||||
disposable.add(studentRepository.logoutCurrentStudent()
|
||||
.andThen(studentRepository.getSavedStudents())
|
||||
.flatMap {
|
||||
if (it.isNotEmpty()) studentRepository.switchStudent(it[0]).toSingle { it }
|
||||
else Single.just(it)
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doFinally { view?.dismissView() }
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
if (it.isEmpty()) openLoginView()
|
||||
else recreateView()
|
||||
}
|
||||
}, { errorHandler.proceed(it) }))
|
||||
}
|
||||
|
||||
fun onItemSelected(item: AbstractFlexibleItem<*>) {
|
||||
if (item is AccountItem) {
|
||||
if (item.student.isCurrent) {
|
||||
view?.dismissView()
|
||||
} else {
|
||||
disposable.add(studentRepository.switchStudent(item.student)
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.subscribe({ view?.recreateView() }, { errorHandler.proceed(it) }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
disposable.add(studentRepository.getSavedStudents()
|
||||
.map { it.map { item -> AccountItem(item) } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.subscribe({ view?.updateData(it) }, { errorHandler.proceed(it) }))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface AccountView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<AccountItem>)
|
||||
|
||||
fun dismissView()
|
||||
|
||||
fun showConfirmDialog()
|
||||
|
||||
fun openLoginView()
|
||||
|
||||
fun recreateView()
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class AttendanceFragment : BaseFragment(), AttendanceView, MainView.MainChildVie
|
||||
|
||||
override fun initView() {
|
||||
attendanceAdapter.apply {
|
||||
setOnItemClickListener { presenter.onAttendanceItemSelected(getItem(it)) }
|
||||
setOnItemClickListener { presenter.onAttendanceItemSelected(it) }
|
||||
}
|
||||
|
||||
attendanceRecycler.run {
|
||||
|
@ -4,7 +4,8 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.repositories.AttendanceRepository
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
@ -23,7 +24,8 @@ class AttendancePresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val attendanceRepository: AttendanceRepository,
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val prefRepository: PreferencesRepository
|
||||
) : BasePresenter<AttendanceView>(errorHandler) {
|
||||
|
||||
@ -66,9 +68,9 @@ class AttendancePresenter @Inject constructor(
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
add(studentRepository.getCurrentStudent()
|
||||
.delay(200, MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { attendanceRepository.getAttendance(it, date, date, forceRefresh) }
|
||||
.map { list ->
|
||||
if (prefRepository.isShowPresent) list
|
||||
|
@ -3,7 +3,9 @@ package io.github.wulkanowy.ui.modules.exam
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.*
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
@ -48,7 +50,7 @@ class ExamFragment : BaseFragment(), ExamView, MainView.MainChildView, MainView.
|
||||
|
||||
override fun initView() {
|
||||
examAdapter.run {
|
||||
setOnItemClickListener { presenter.onExamItemSelected(getItem(it)) }
|
||||
setOnItemClickListener { presenter.onExamItemSelected(it) }
|
||||
}
|
||||
examRecycler.run {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
|
@ -4,7 +4,8 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.friday
|
||||
@ -23,7 +24,8 @@ class ExamPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val examRepository: ExamRepository,
|
||||
private val sessionRepository: SessionRepository
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<ExamView>(errorHandler) {
|
||||
|
||||
lateinit var currentDate: LocalDate
|
||||
@ -65,9 +67,9 @@ class ExamPresenter @Inject constructor(
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
add(studentRepository.getCurrentStudent()
|
||||
.delay(200, MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap {
|
||||
examRepository.getExams(it, currentDate.monday, currentDate.friday, forceRefresh)
|
||||
}.map { it.groupBy { exam -> exam.date }.toSortedMap() }
|
||||
|
@ -1,9 +1,14 @@
|
||||
package io.github.wulkanowy.ui.modules.grade
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
@ -55,8 +60,8 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MainChildView, MainVie
|
||||
|
||||
override fun initView() {
|
||||
pagerAdapter.fragments.putAll(mapOf(
|
||||
getString(R.string.all_details) to GradeDetailsFragment.newInstance(),
|
||||
getString(R.string.grade_menu_summary) to GradeSummaryFragment.newInstance()
|
||||
getString(R.string.all_details) to GradeDetailsFragment.newInstance(),
|
||||
getString(R.string.grade_menu_summary) to GradeSummaryFragment.newInstance()
|
||||
))
|
||||
gradeViewPager.run {
|
||||
adapter = pagerAdapter
|
||||
@ -85,16 +90,16 @@ class GradeFragment : BaseFragment(), GradeView, MainView.MainChildView, MainVie
|
||||
|
||||
override fun showSemesterDialog(selectedIndex: Int) {
|
||||
arrayOf(getString(R.string.grade_semester, 1),
|
||||
getString(R.string.grade_semester, 2)).also { array ->
|
||||
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()
|
||||
.setSingleChoiceItems(array, selectedIndex) { dialog, which ->
|
||||
presenter.onSemesterSelected(which)
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setTitle(R.string.grade_switch_semester)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,21 @@ package io.github.wulkanowy.ui.modules.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.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.logEvent
|
||||
import io.reactivex.Completable
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradePresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val sessionRepository: SessionRepository) : BasePresenter<GradeView>(errorHandler) {
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<GradeView>(errorHandler) {
|
||||
|
||||
var selectedIndex = 0
|
||||
private set
|
||||
@ -26,11 +28,11 @@ class GradePresenter @Inject constructor(
|
||||
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
||||
super.onAttachView(view)
|
||||
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
|
||||
.subscribe {
|
||||
selectedIndex = savedIndex ?: 0
|
||||
view.initView()
|
||||
loadData()
|
||||
})
|
||||
.subscribe {
|
||||
selectedIndex = savedIndex ?: 0
|
||||
view.initView()
|
||||
loadData()
|
||||
})
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
@ -71,15 +73,16 @@ class GradePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.doOnSuccess {
|
||||
it.first { item -> item.current }.also { current ->
|
||||
selectedIndex = if (selectedIndex == 0) current.semesterName else selectedIndex
|
||||
semesters = it.filter { semester -> semester.diaryId == current.diaryId }
|
||||
}
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getSemesters(it) }
|
||||
.doOnSuccess {
|
||||
it.first { item -> item.isCurrent }.also { current ->
|
||||
selectedIndex = if (selectedIndex == 0) current.semesterName else selectedIndex
|
||||
semesters = it.filter { semester -> semester.diaryId == current.diaryId }
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.subscribe({ view?.run { loadChild(currentPageIndex) } }) { errorHandler.proceed(it) })
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ class GradeDetailsFragment : BaseFragment(), GradeDetailsView, GradeView.GradeCh
|
||||
gradeDetailsAdapter.run {
|
||||
isAutoCollapseOnExpand = true
|
||||
isAutoScrollOnExpand = true
|
||||
setOnItemClickListener { presenter.onGradeItemSelected(getItem(it)) }
|
||||
setOnItemClickListener { presenter.onGradeItemSelected(it) }
|
||||
}
|
||||
|
||||
gradeDetailsRecycler.run {
|
||||
|
@ -5,7 +5,8 @@ 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.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.calcAverage
|
||||
@ -19,7 +20,8 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val preferencesRepository: PreferencesRepository
|
||||
) : BasePresenter<GradeDetailsView>(errorHandler) {
|
||||
|
||||
@ -29,7 +31,8 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getSemesters(it) }
|
||||
.flatMap { gradeRepository.getGrades(it.first { item -> item.semesterId == semesterId }, forceRefresh) }
|
||||
.map { it.map { item -> item.changeModifier(preferencesRepository.gradeModifier) } }
|
||||
.map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) }
|
||||
|
@ -3,7 +3,9 @@ package io.github.wulkanowy.ui.modules.grade.summary
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.*
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
@ -56,7 +58,7 @@ class GradeSummaryFragment : BaseFragment(), GradeSummaryView, GradeView.GradeCh
|
||||
gradeSummarySwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
}
|
||||
|
||||
override fun updateDataSet(data: List<GradeSummaryItem>, header: GradeSummaryScrollableHeader) {
|
||||
override fun updateData(data: List<GradeSummaryItem>, header: GradeSummaryScrollableHeader) {
|
||||
gradeSummaryAdapter.apply {
|
||||
updateDataSet(data, true)
|
||||
removeAllScrollableHeaders()
|
||||
|
@ -5,7 +5,8 @@ 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.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.calcAverage
|
||||
@ -19,7 +20,8 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val gradeSummaryRepository: GradeSummaryRepository,
|
||||
private val gradeRepository: GradeRepository,
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val preferencesRepository: PreferencesRepository,
|
||||
private val schedulers: SchedulersProvider
|
||||
) : BasePresenter<GradeSummaryView>(errorHandler) {
|
||||
@ -30,7 +32,8 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getSemesters(it) }
|
||||
.map { semester -> semester.first { it.semesterId == semesterId } }
|
||||
.flatMap {
|
||||
gradeSummaryRepository.getGradesSummary(it, forceRefresh)
|
||||
@ -63,7 +66,7 @@ class GradeSummaryPresenter @Inject constructor(
|
||||
view?.run {
|
||||
showEmpty(it.first.isEmpty())
|
||||
showContent(it.first.isNotEmpty())
|
||||
updateDataSet(it.first, it.second)
|
||||
updateData(it.first, it.second)
|
||||
}
|
||||
logEvent("Grade summary load", mapOf("items" to it.first.size, "forceRefresh" to forceRefresh))
|
||||
}) {
|
||||
|
@ -12,7 +12,7 @@ interface GradeSummaryView : BaseView {
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateDataSet(data: List<GradeSummaryItem>, header: GradeSummaryScrollableHeader)
|
||||
fun updateData(data: List<GradeSummaryItem>, header: GradeSummaryScrollableHeader)
|
||||
|
||||
fun resetView()
|
||||
|
||||
|
@ -44,7 +44,7 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView {
|
||||
|
||||
override fun initView() {
|
||||
homeworkAdapter.run {
|
||||
setOnItemClickListener { presenter.onHomeworkItemSelected(getItem(it)) }
|
||||
setOnItemClickListener { presenter.onHomeworkItemSelected(it) }
|
||||
}
|
||||
|
||||
homeworkRecycler.run {
|
||||
|
@ -3,7 +3,8 @@ package io.github.wulkanowy.ui.modules.homework
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.repositories.HomeworkRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.isHolidays
|
||||
@ -20,7 +21,8 @@ class HomeworkPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val homeworkRepository: HomeworkRepository,
|
||||
private val sessionRepository: SessionRepository
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<HomeworkView>(errorHandler) {
|
||||
|
||||
lateinit var currentDate: LocalDate
|
||||
@ -57,9 +59,9 @@ class HomeworkPresenter @Inject constructor(
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
add(studentRepository.getCurrentStudent()
|
||||
.delay(200, TimeUnit.MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { homeworkRepository.getHomework(it, currentDate, forceRefresh) }
|
||||
.map { items -> items.map { HomeworkItem(it) } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
|
@ -1,22 +1,25 @@
|
||||
package io.github.wulkanowy.ui.modules.login
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.database.sqlite.SQLiteConstraintException
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.api.login.BadCredentialsException
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
|
||||
class LoginErrorHandler(resources: Resources) : ErrorHandler(resources) {
|
||||
|
||||
var doOnBadCredentials: () -> Unit = {}
|
||||
var onBadCredentials: () -> Unit = {}
|
||||
|
||||
override fun proceed(error: Throwable) {
|
||||
when (error) {
|
||||
is BadCredentialsException -> doOnBadCredentials()
|
||||
is BadCredentialsException -> onBadCredentials()
|
||||
is SQLiteConstraintException -> showErrorMessage(resources.getString(R.string.login_duplicate_student))
|
||||
else -> super.proceed(error)
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
super.clear()
|
||||
doOnBadCredentials = {}
|
||||
onBadCredentials = {}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.login.form
|
||||
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
@ -12,7 +12,7 @@ import javax.inject.Inject
|
||||
class LoginFormPresenter @Inject constructor(
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val errorHandler: LoginErrorHandler,
|
||||
private val sessionRepository: SessionRepository
|
||||
private val studentRepository: StudentRepository
|
||||
) : BasePresenter<LoginFormView>(errorHandler) {
|
||||
|
||||
private var wasEmpty = false
|
||||
@ -21,7 +21,7 @@ class LoginFormPresenter @Inject constructor(
|
||||
super.onAttachView(view)
|
||||
view.run {
|
||||
initView()
|
||||
errorHandler.doOnBadCredentials = {
|
||||
errorHandler.onBadCredentials = {
|
||||
setErrorPassIncorrect()
|
||||
showSoftKeyboard()
|
||||
Timber.i("Entered wrong username or password")
|
||||
@ -32,7 +32,7 @@ class LoginFormPresenter @Inject constructor(
|
||||
fun attemptLogin(email: String, password: String, symbol: String, endpoint: String) {
|
||||
if (!validateCredentials(email, password, symbol)) return
|
||||
|
||||
disposable.add(sessionRepository.getConnectedStudents(email, password, symbol, endpoint)
|
||||
disposable.add(studentRepository.getStudents(email, password, symbol, endpoint)
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doOnSubscribe {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.login.options
|
||||
|
||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -39,7 +41,7 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
loginAdapter.apply { setOnItemClickListener { presenter.onSelectItem(getItem(it)) } }
|
||||
loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } }
|
||||
|
||||
loginOptionsRecycler.apply {
|
||||
adapter = loginAdapter
|
||||
@ -57,8 +59,8 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView {
|
||||
|
||||
override fun openMainView() {
|
||||
activity?.let {
|
||||
startActivity(MainActivity.getStartIntent(it))
|
||||
it.finish()
|
||||
startActivity(MainActivity.getStartIntent(it)
|
||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,20 @@
|
||||
package io.github.wulkanowy.ui.modules.login.options
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.logRegister
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
|
||||
class LoginOptionsPresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val repository: SessionRepository,
|
||||
private val errorHandler: LoginErrorHandler,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val schedulers: SchedulersProvider
|
||||
) : BasePresenter<LoginOptionsView>(errorHandler) {
|
||||
|
||||
@ -21,25 +24,27 @@ class LoginOptionsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onParentViewLoadData() {
|
||||
disposable.add(repository.cachedStudents
|
||||
disposable.add(studentRepository.cachedStudents
|
||||
.observeOn(schedulers.mainThread)
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.doOnSubscribe { view?.showActionBar(true) }
|
||||
.subscribe({ view?.updateData(it.map { student -> LoginOptionsItem(student) }) }, { errorHandler.proceed(it) }))
|
||||
}
|
||||
|
||||
fun onSelectItem(item: AbstractFlexibleItem<*>?) {
|
||||
fun onItemSelected(item: AbstractFlexibleItem<*>?) {
|
||||
if (item is LoginOptionsItem) {
|
||||
registerStudent(item.student)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerStudent(student: Student) {
|
||||
disposable.add(repository.saveStudent(student)
|
||||
disposable.add(studentRepository.saveStudent(student.apply { isCurrent = true })
|
||||
.andThen(semesterRepository.getSemesters(student, true))
|
||||
.onErrorResumeNext { studentRepository.logoutCurrentStudent().andThen(Single.error(it)) }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
view?.apply {
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
showActionBar(false)
|
||||
@ -48,6 +53,13 @@ class LoginOptionsPresenter @Inject constructor(
|
||||
.subscribe({
|
||||
logRegister("Success", true, student.symbol, student.endpoint)
|
||||
view?.openMainView()
|
||||
}, { errorHandler.proceed(it) }))
|
||||
}, {
|
||||
errorHandler.proceed(it)
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
showContent(true)
|
||||
showActionBar(true)
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package io.github.wulkanowy.ui.modules.main
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState.ALWAYS_SHOW
|
||||
@ -12,6 +14,7 @@ import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.services.notification.GradeNotification
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.modules.account.AccountDialog
|
||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||
@ -58,15 +61,16 @@ class MainActivity : BaseActivity(), MainView {
|
||||
navController.initialize(startMenuIndex, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.action_menu_main, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
presenter.onViewStart()
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return presenter.onUpNavigate()
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
mainBottomNav.run {
|
||||
addItems(
|
||||
@ -103,6 +107,15 @@ class MainActivity : BaseActivity(), MainView {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return if (item?.itemId == R.id.mainMenuAccount) presenter.onAccountManagerSelected()
|
||||
else false
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return presenter.onUpNavigate()
|
||||
}
|
||||
|
||||
override fun switchMenuView(position: Int) {
|
||||
navController.switchTab(position)
|
||||
}
|
||||
@ -115,6 +128,10 @@ class MainActivity : BaseActivity(), MainView {
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(show)
|
||||
}
|
||||
|
||||
override fun showAccountPicker() {
|
||||
navController.showDialogFragment(AccountDialog.newInstance())
|
||||
}
|
||||
|
||||
override fun notifyMenuViewReselected() {
|
||||
(navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected()
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import io.github.wulkanowy.di.scopes.PerActivity
|
||||
import io.github.wulkanowy.di.scopes.PerFragment
|
||||
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
||||
import io.github.wulkanowy.ui.modules.about.AboutModule
|
||||
import io.github.wulkanowy.ui.modules.account.AccountDialog
|
||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||
@ -57,12 +58,19 @@ abstract class MainModule {
|
||||
@ContributesAndroidInjector(modules = [AboutModule::class])
|
||||
abstract fun bindAboutFragment(): AboutFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindSettingsFragment(): SettingsFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindNoteFragment(): NoteFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindHomeworkFragment(): HomeworkFragment
|
||||
|
||||
@PerFragment
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindsAccountDialog(): AccountDialog
|
||||
}
|
||||
|
@ -41,6 +41,11 @@ class MainPresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onAccountManagerSelected(): Boolean {
|
||||
view?.showAccountPicker()
|
||||
return true
|
||||
}
|
||||
|
||||
fun onUpNavigate(): Boolean {
|
||||
view?.popView()
|
||||
return true
|
||||
|
@ -18,6 +18,8 @@ interface MainView : BaseView {
|
||||
|
||||
fun showHomeArrow(show: Boolean)
|
||||
|
||||
fun showAccountPicker()
|
||||
|
||||
fun notifyMenuViewReselected()
|
||||
|
||||
fun setViewTitle(title: String)
|
||||
|
@ -76,7 +76,7 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
moreAdapter.run { setOnItemClickListener { presenter.onItemSelected(getItem(it)) } }
|
||||
moreAdapter.run { setOnItemClickListener { presenter.onItemSelected(it) } }
|
||||
|
||||
moreRecycler.apply {
|
||||
layoutManager = SmoothScrollLinearLayoutManager(context)
|
||||
|
@ -10,8 +10,7 @@ import io.github.wulkanowy.R
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_more.*
|
||||
|
||||
class MoreItem(val title: String, private val drawable: Drawable?)
|
||||
: AbstractFlexibleItem<MoreItem.ViewHolder>() {
|
||||
class MoreItem(val title: String, private val drawable: Drawable?) : AbstractFlexibleItem<MoreItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_more
|
||||
|
||||
@ -19,8 +18,7 @@ class MoreItem(val title: String, private val drawable: Drawable?)
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.apply {
|
||||
moreItemTitle.text = title
|
||||
moreItemImage.setImageDrawable(drawable)
|
||||
@ -42,8 +40,7 @@ class MoreItem(val title: String, private val drawable: Drawable?)
|
||||
return title.hashCode()
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<*>?)
|
||||
: FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<*>?) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
get() = contentView
|
||||
|
@ -46,7 +46,7 @@ class NoteFragment : BaseFragment(), NoteView, MainView.TitledView {
|
||||
|
||||
override fun initView() {
|
||||
noteAdapter.run {
|
||||
setOnItemClickListener { presenter.onNoteItemSelected(getItem(it)) }
|
||||
setOnItemClickListener { presenter.onNoteItemSelected(it) }
|
||||
}
|
||||
|
||||
noteRecycler.run {
|
||||
|
@ -4,7 +4,8 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.logEvent
|
||||
@ -14,8 +15,9 @@ import javax.inject.Inject
|
||||
class NotePresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val noteRepository: NoteRepository
|
||||
private val studentRepository: StudentRepository,
|
||||
private val noteRepository: NoteRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<NoteView>(errorHandler) {
|
||||
|
||||
override fun onAttachView(view: NoteView) {
|
||||
@ -29,8 +31,8 @@ class NotePresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun loadData(forceRefresh: Boolean = false) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { it.single { semester -> semester.current } }
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { noteRepository.getNotes(it, forceRefresh) }
|
||||
.map { items -> items.map { NoteItem(it) } }
|
||||
.map { items -> items.sortedByDescending { it.note.date } }
|
||||
|
@ -1,20 +1,20 @@
|
||||
package io.github.wulkanowy.ui.modules.splash
|
||||
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.logLogin
|
||||
import javax.inject.Inject
|
||||
|
||||
class SplashPresenter @Inject constructor(
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val studentRepository: StudentRepository,
|
||||
errorHandler: ErrorHandler
|
||||
) : BasePresenter<SplashView>(errorHandler) {
|
||||
|
||||
override fun onAttachView(view: SplashView) {
|
||||
super.onAttachView(view)
|
||||
view.run {
|
||||
if (sessionRepository.isSessionSaved) {
|
||||
if (studentRepository.isStudentSaved) {
|
||||
logLogin("Open app")
|
||||
openMainView()
|
||||
} else openLoginView()
|
||||
|
@ -47,7 +47,7 @@ class TimetableFragment : BaseFragment(), TimetableView, MainView.MainChildView,
|
||||
|
||||
override fun initView() {
|
||||
timetableAdapter.run {
|
||||
setOnItemClickListener { presenter.onTimetableItemSelected(getItem(it)) }
|
||||
setOnItemClickListener { presenter.onTimetableItemSelected(it) }
|
||||
}
|
||||
|
||||
timetableRecycler.run {
|
||||
|
@ -2,7 +2,8 @@ package io.github.wulkanowy.ui.modules.timetable
|
||||
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import io.github.wulkanowy.data.ErrorHandler
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
@ -22,7 +23,8 @@ class TimetablePresenter @Inject constructor(
|
||||
private val errorHandler: ErrorHandler,
|
||||
private val schedulers: SchedulersProvider,
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val sessionRepository: SessionRepository
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository
|
||||
) : BasePresenter<TimetableView>(errorHandler) {
|
||||
|
||||
lateinit var currentDate: LocalDate
|
||||
@ -64,9 +66,9 @@ class TimetablePresenter @Inject constructor(
|
||||
currentDate = date
|
||||
disposable.apply {
|
||||
clear()
|
||||
add(sessionRepository.getSemesters()
|
||||
add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.delay(200, MILLISECONDS)
|
||||
.map { it.single { semester -> semester.current } }
|
||||
.flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) }
|
||||
.map { items -> items.map { TimetableItem(it, view?.roomString.orEmpty()) } }
|
||||
.map { items -> items.sortedBy { it.lesson.number } }
|
||||
|
@ -12,7 +12,8 @@ import android.widget.RemoteViewsService
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.SharedPrefHelper
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.repositories.SessionRepository
|
||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
@ -21,7 +22,8 @@ import timber.log.Timber
|
||||
|
||||
class TimetableWidgetFactory(
|
||||
private val timetableRepository: TimetableRepository,
|
||||
private val sessionRepository: SessionRepository,
|
||||
private val studentRepository: StudentRepository,
|
||||
private val semesterRepository: SemesterRepository,
|
||||
private val sharedPref: SharedPrefHelper,
|
||||
private val context: Context,
|
||||
private val intent: Intent?
|
||||
@ -46,9 +48,9 @@ class TimetableWidgetFactory(
|
||||
override fun onDataSetChanged() {
|
||||
intent?.action?.let { LocalDate.ofEpochDay(sharedPref.getLong(it, 0)) }
|
||||
?.let { date ->
|
||||
if (sessionRepository.isSessionSaved) {
|
||||
disposable.add(sessionRepository.getSemesters()
|
||||
.map { it.single { item -> item.current } }
|
||||
if (studentRepository.isStudentSaved) {
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { timetableRepository.getTimetable(it, date, date) }
|
||||
.map { item -> item.sortedBy { it.number } }
|
||||
.subscribe({ lessons = it })
|
||||
|
@ -1,10 +1,11 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
|
||||
inline fun FlexibleAdapter<*>.setOnItemClickListener(crossinline listener: (position: Int) -> Unit) {
|
||||
inline fun FlexibleAdapter<*>.setOnItemClickListener(crossinline listener: (item: AbstractFlexibleItem<*>) -> Unit) {
|
||||
addListener(FlexibleAdapter.OnItemClickListener { _, position ->
|
||||
listener(position)
|
||||
listener(getItem(position) as AbstractFlexibleItem<*>)
|
||||
true
|
||||
})
|
||||
}
|
11
app/src/main/res/drawable/ic_account_add_24dp.xml
Normal file
11
app/src/main/res/drawable/ic_account_add_24dp.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,
|
||||
13v-2h4L11,7h2v4h4v2z" />
|
||||
</vector>
|
8
app/src/main/res/drawable/ic_account_circular_border.xml
Normal file
8
app/src/main/res/drawable/ic_account_circular_border.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<stroke
|
||||
android:width="3dp"
|
||||
android:color="@color/colorPrimary" />
|
||||
</shape>
|
12
app/src/main/res/drawable/ic_all_account_24dp.xml
Normal file
12
app/src/main/res/drawable/ic_all_account_24dp.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#FFF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2
|
||||
12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22
|
||||
0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z" />
|
||||
</vector>
|
50
app/src/main/res/layout/dialog_account.xml
Normal file
50
app/src/main/res/layout/dialog_account.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="280dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/accountDialogTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingRight="24dp"
|
||||
android:text="@string/account_title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:firstBaselineToTopHeight="40dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/accountDialogRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/accountDialogTitle"
|
||||
android:overScrollMode="never"
|
||||
tools:itemCount="3"
|
||||
tools:listitem="@layout/item_account" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/accountDialogAdd"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/accountDialogRecycler"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/account_add_new" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/accountDialogRemove"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/accountDialogRecycler"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/account_logout"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
</RelativeLayout>
|
@ -10,7 +10,6 @@
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attendance_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
|
@ -10,7 +10,6 @@
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exam_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
|
@ -10,7 +10,6 @@
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/homework_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
|
@ -10,7 +10,6 @@
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/note_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
|
@ -10,7 +10,6 @@
|
||||
android:padding="20dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/exam_dialog_details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
|
48
app/src/main/res/layout/item_account.xml
Normal file
48
app/src/main/res/layout/item_account.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?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="56dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingRight="24dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/accountItemImage"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="@drawable/ic_account_circular_border"
|
||||
android:tint="#7E7E7E"
|
||||
app:srcCompat="@drawable/ic_all_account_24dp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/accountItemName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@+id/accountItemImage"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_toEndOf="@id/accountItemImage"
|
||||
android:layout_toRightOf="@id/accountItemImage"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/accountItemSchool"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/accountItemName"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_toEndOf="@id/accountItemImage"
|
||||
android:layout_toRightOf="@id/accountItemImage"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
@ -16,7 +16,7 @@
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:srcCompat="@drawable/ic_more_settings_24dp"
|
||||
android:tint="?android:attr/android:textColorSecondary"/>
|
||||
app:tint="?android:attr/android:textColorSecondary" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/moreItemTitle"
|
||||
@ -27,5 +27,4 @@
|
||||
android:layout_marginLeft="32dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -1,12 +1,10 @@
|
||||
<menu 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"
|
||||
tools:context="io.github.wulkanowy.timetable.MainActivity">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/gradeMenuSemester"
|
||||
android:icon="@drawable/ic_menu_grade_semester_24dp"
|
||||
android:orderInCategory="2"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/grade_switch_semester"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
|
10
app/src/main/res/menu/action_menu_main.xml
Normal file
10
app/src/main/res/menu/action_menu_main.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/mainMenuAccount"
|
||||
android:icon="@drawable/ic_all_account_24dp"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/main_account_picker"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
@ -13,9 +13,10 @@
|
||||
<string name="about_title">O aplikacji</string>
|
||||
<string name="note_title">Uwagi i osiągnięcia</string>
|
||||
<string name="homework_title">Zadania domowe</string>
|
||||
<string name="account_title">Wybierz konto</string>
|
||||
|
||||
|
||||
<!--Login form-->
|
||||
<!--Login-->
|
||||
<string name="login_header_default">Zaloguj się za pomocą konta ucznia lub rodzica</string>
|
||||
<string name="login_header_symbol">Podaj symbol dziennika VULCAN</string>
|
||||
<string name="login_nickname_hint">Email lub nick</string>
|
||||
@ -29,6 +30,11 @@
|
||||
<string name="login_incorrect_password">To hasło jest niepoprawne</string>
|
||||
<string name="login_incorrect_symbol">Nie znaleziono ucznia. Sprwadź symbol</string>
|
||||
<string name="login_field_required">To pole jest wymagane</string>
|
||||
<string name="login_duplicate_student">Ten student jest już zalogowany</string>
|
||||
|
||||
|
||||
<!--Main-->
|
||||
<string name="main_account_picker">Menadżer kont</string>
|
||||
|
||||
|
||||
<!--Grade-->
|
||||
@ -140,6 +146,13 @@
|
||||
<string name="homework_no_items">Brak zadań domowych</string>
|
||||
|
||||
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Dodaj konto</string>
|
||||
<string name="account_logout">Wyloguj</string>
|
||||
<string name="account_confirm">Czy chcesz wylogować aktualnego ucznia?</string>
|
||||
<string name="account_logout_student">Wylogowanie ucznia</string>
|
||||
|
||||
|
||||
<!--Generic-->
|
||||
<string name="all_content">Treść</string>
|
||||
<string name="all_description">Opis</string>
|
||||
@ -151,7 +164,6 @@
|
||||
<string name="all_details">Szczegóły</string>
|
||||
<string name="all_category">Kategoria</string>
|
||||
<string name="all_close">Zamknij</string>
|
||||
<string name="all_cancel">Anuluj</string>
|
||||
<string name="all_no_data">Brak danych</string>
|
||||
<string name="all_subject">Przedmiot</string>
|
||||
<string name="all_prev">Poprzedni</string>
|
||||
|
@ -13,9 +13,10 @@
|
||||
<string name="about_title">About</string>
|
||||
<string name="note_title">Notes and achievements</string>
|
||||
<string name="homework_title">Homework</string>
|
||||
<string name="account_title">Choose account</string>
|
||||
|
||||
|
||||
<!--Login form-->
|
||||
<!--Login-->
|
||||
<string name="login_header_default">Sign in with the student or parent account</string>
|
||||
<string name="login_header_symbol">Enter the VULCAN diary symbol</string>
|
||||
<string name="login_nickname_hint">Email or nick</string>
|
||||
@ -29,6 +30,11 @@
|
||||
<string name="login_incorrect_password">This password is incorrect</string>
|
||||
<string name="login_incorrect_symbol">Student not found. Check the symbol</string>
|
||||
<string name="login_field_required">This field is required</string>
|
||||
<string name="login_duplicate_student">This student has already been logged in</string>
|
||||
|
||||
|
||||
<!--Main-->
|
||||
<string name="main_account_picker">Account manager</string>
|
||||
|
||||
|
||||
<!--Grade-->
|
||||
@ -125,6 +131,13 @@
|
||||
<string name="homework_no_items">No info about homework</string>
|
||||
|
||||
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Add account</string>
|
||||
<string name="account_logout">Logout</string>
|
||||
<string name="account_confirm">Do you want to log out of an active student?</string>
|
||||
<string name="account_logout_student">Student logout</string>
|
||||
|
||||
|
||||
<!--Generic-->
|
||||
<string name="all_content">Content</string>
|
||||
<string name="all_description">Description</string>
|
||||
@ -136,7 +149,6 @@
|
||||
<string name="all_details">Details</string>
|
||||
<string name="all_category">Category</string>
|
||||
<string name="all_close">Close</string>
|
||||
<string name="all_cancel">Cancel</string>
|
||||
<string name="all_no_data">No data</string>
|
||||
<string name="all_subject">Subject</string>
|
||||
<string name="all_prev">Prev</string>
|
||||
|
@ -14,7 +14,6 @@
|
||||
<item name="subtitleTextColor">@android:color/primary_text_dark</item>
|
||||
<item name="android:colorBackground">@android:color/white</item>
|
||||
<item name="bottomNavBackground">@color/bottom_nav_background_inverse</item>
|
||||
<item name="android:windowAnimationStyle">@null</item>
|
||||
|
||||
<!-- AboutLibraries specific values -->
|
||||
<item name="about_libraries_window_background">@color/about_libraries_window_background</item>
|
||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
||||
import io.mockk.impl.annotations.SpyK
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
@ -15,8 +16,8 @@ import java.sql.Date
|
||||
|
||||
class AttendanceRemoteTest {
|
||||
|
||||
@MockK
|
||||
private lateinit var mockApi: Api
|
||||
@SpyK
|
||||
private var mockApi = Api()
|
||||
|
||||
@MockK
|
||||
private lateinit var semesterMock: Semester
|
||||
@ -27,7 +28,7 @@ class AttendanceRemoteTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getExamsTest() {
|
||||
fun getAttendanceTest() {
|
||||
every { mockApi.getAttendance(
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 15)
|
||||
|
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