forked from github/wulkanowy-mirror
Add account manager (#671)
This commit is contained in:
parent
26565b627a
commit
d79b1c9a58
15
.idea/codeStyles/Project.xml
generated
15
.idea/codeStyles/Project.xml
generated
@ -18,18 +18,9 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
<option name="CONTINUATION_INDENT_IN_PARAMETER_LISTS" value="false" />
|
|
||||||
<option name="CONTINUATION_INDENT_IN_ARGUMENT_LISTS" value="false" />
|
|
||||||
<option name="CONTINUATION_INDENT_FOR_EXPRESSION_BODIES" value="false" />
|
|
||||||
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="false" />
|
|
||||||
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" />
|
|
||||||
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" />
|
|
||||||
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
|
|
||||||
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<MarkdownNavigatorCodeStyleSettings>
|
|
||||||
<option name="RIGHT_MARGIN" value="72" />
|
|
||||||
</MarkdownNavigatorCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="XML">
|
<codeStyleSettings language="XML">
|
||||||
<indentOptions>
|
<indentOptions>
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
@ -143,13 +134,11 @@
|
|||||||
</arrangement>
|
</arrangement>
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
<codeStyleSettings language="kotlin">
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
|
||||||
<indentOptions>
|
<indentOptions>
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
</indentOptions>
|
</indentOptions>
|
||||||
|
@ -131,14 +131,14 @@ play {
|
|||||||
|
|
||||||
ext {
|
ext {
|
||||||
work_manager = "2.5.0"
|
work_manager = "2.5.0"
|
||||||
room = "2.2.6"
|
room = "2.3.0-alpha04"
|
||||||
chucker = "3.4.0"
|
chucker = "3.4.0"
|
||||||
mockk = "1.10.5"
|
mockk = "1.10.5"
|
||||||
moshi = "1.11.0"
|
moshi = "1.11.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "io.github.wulkanowy:sdk:a722e777"
|
implementation "io.github.wulkanowy:sdk:b7576e86"
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
||||||
|
|
||||||
@ -214,6 +214,7 @@ dependencies {
|
|||||||
testImplementation "junit:junit:4.13.1"
|
testImplementation "junit:junit:4.13.1"
|
||||||
testImplementation "io.mockk:mockk:$mockk"
|
testImplementation "io.mockk:mockk:$mockk"
|
||||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
|
||||||
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
|
||||||
androidTestImplementation "androidx.test:core:1.3.0"
|
androidTestImplementation "androidx.test:core:1.3.0"
|
||||||
androidTestImplementation "androidx.test:runner:1.3.0"
|
androidTestImplementation "androidx.test:runner:1.3.0"
|
||||||
|
2136
app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json
Normal file
2136
app/schemas/io.github.wulkanowy.data.db.AppDatabase/31.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
|||||||
package io.github.wulkanowy.data
|
|
||||||
|
|
||||||
import io.github.wulkanowy.utils.DispatchersProvider
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
|
|
||||||
class TestDispatchersProvider : DispatchersProvider() {
|
|
||||||
|
|
||||||
override val backgroundThread: CoroutineDispatcher
|
|
||||||
get() = Dispatchers.Unconfined
|
|
||||||
}
|
|
@ -33,17 +33,21 @@ internal class RepositoryModule {
|
|||||||
setSimpleHttpLogger { Timber.d(it) }
|
setSimpleHttpLogger { Timber.d(it) }
|
||||||
|
|
||||||
// for debug only
|
// for debug only
|
||||||
addInterceptor(ChuckerInterceptor.Builder(context)
|
addInterceptor(
|
||||||
.collector(chuckerCollector)
|
ChuckerInterceptor.Builder(context)
|
||||||
.alwaysReadResponseBody(true)
|
.collector(chuckerCollector)
|
||||||
.build(), network = true
|
.alwaysReadResponseBody(true)
|
||||||
|
.build(), network = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
|
fun provideChuckerCollector(
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
prefRepository: PreferencesRepository
|
||||||
|
): ChuckerCollector {
|
||||||
return ChuckerCollector(
|
return ChuckerCollector(
|
||||||
context = context,
|
context = context,
|
||||||
showNotification = prefRepository.isDebugNotificationEnable,
|
showNotification = prefRepository.isDebugNotificationEnable,
|
||||||
@ -53,7 +57,10 @@ internal class RepositoryModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
|
fun provideDatabase(
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
sharedPrefProvider: SharedPrefProvider,
|
||||||
|
) = AppDatabase.newInstance(context, sharedPrefProvider)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
@ -65,7 +72,8 @@ internal class RepositoryModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
@ -89,7 +97,8 @@ internal class RepositoryModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideGradeSemesterStatisticsDao(database: AppDatabase) = database.gradeSemesterStatisticsDao
|
fun provideGradeSemesterStatisticsDao(database: AppDatabase) =
|
||||||
|
database.gradeSemesterStatisticsDao
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
@ -166,4 +175,8 @@ internal class RepositoryModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideTimetableAdditionalDao(database: AppDatabase) = database.timetableAdditionalDao
|
fun provideTimetableAdditionalDao(database: AppDatabase) = database.timetableAdditionalDao
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import io.github.wulkanowy.data.db.dao.ReportingUnitDao
|
|||||||
import io.github.wulkanowy.data.db.dao.SchoolDao
|
import io.github.wulkanowy.data.db.dao.SchoolDao
|
||||||
import io.github.wulkanowy.data.db.dao.SemesterDao
|
import io.github.wulkanowy.data.db.dao.SemesterDao
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
|
import io.github.wulkanowy.data.db.dao.StudentInfoDao
|
||||||
import io.github.wulkanowy.data.db.dao.SubjectDao
|
import io.github.wulkanowy.data.db.dao.SubjectDao
|
||||||
import io.github.wulkanowy.data.db.dao.TeacherDao
|
import io.github.wulkanowy.data.db.dao.TeacherDao
|
||||||
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
|
||||||
@ -53,6 +54,7 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
|
|||||||
import io.github.wulkanowy.data.db.entities.School
|
import io.github.wulkanowy.data.db.entities.School
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
import io.github.wulkanowy.data.db.entities.Subject
|
import io.github.wulkanowy.data.db.entities.Subject
|
||||||
import io.github.wulkanowy.data.db.entities.Teacher
|
import io.github.wulkanowy.data.db.entities.Teacher
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
@ -80,6 +82,7 @@ import io.github.wulkanowy.data.db.migrations.Migration28
|
|||||||
import io.github.wulkanowy.data.db.migrations.Migration29
|
import io.github.wulkanowy.data.db.migrations.Migration29
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration30
|
import io.github.wulkanowy.data.db.migrations.Migration30
|
||||||
|
import io.github.wulkanowy.data.db.migrations.Migration31
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration5
|
import io.github.wulkanowy.data.db.migrations.Migration5
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||||
@ -116,6 +119,7 @@ import javax.inject.Singleton
|
|||||||
School::class,
|
School::class,
|
||||||
Conference::class,
|
Conference::class,
|
||||||
TimetableAdditional::class,
|
TimetableAdditional::class,
|
||||||
|
StudentInfo::class,
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
@ -124,7 +128,7 @@ import javax.inject.Singleton
|
|||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 30
|
const val VERSION_SCHEMA = 31
|
||||||
|
|
||||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
||||||
return arrayOf(
|
return arrayOf(
|
||||||
@ -157,6 +161,7 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration28(),
|
Migration28(),
|
||||||
Migration29(),
|
Migration29(),
|
||||||
Migration30(),
|
Migration30(),
|
||||||
|
Migration31()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,4 +224,6 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
abstract val conferenceDao: ConferenceDao
|
abstract val conferenceDao: ConferenceDao
|
||||||
|
|
||||||
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
abstract val timetableAdditionalDao: TimetableAdditionalDao
|
||||||
|
|
||||||
|
abstract val studentInfoDao: StudentInfoDao
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package io.github.wulkanowy.data.db.dao
|
||||||
|
|
||||||
|
import androidx.room.Dao
|
||||||
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Dao
|
||||||
|
interface StudentInfoDao : BaseDao<StudentInfo> {
|
||||||
|
|
||||||
|
@Query("SELECT * FROM StudentInfo WHERE student_id = :studentId")
|
||||||
|
fun loadStudentInfo(studentId: Int): Flow<StudentInfo?>
|
||||||
|
}
|
@ -7,7 +7,13 @@ import androidx.room.PrimaryKey
|
|||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
|
@Entity(
|
||||||
|
tableName = "Students",
|
||||||
|
indices = [Index(
|
||||||
|
value = ["email", "symbol", "student_id", "school_id", "class_id"],
|
||||||
|
unique = true
|
||||||
|
)]
|
||||||
|
)
|
||||||
data class Student(
|
data class Student(
|
||||||
|
|
||||||
@ColumnInfo(name = "scrapper_base_url")
|
@ColumnInfo(name = "scrapper_base_url")
|
||||||
@ -52,7 +58,7 @@ data class Student(
|
|||||||
@ColumnInfo(name = "school_id")
|
@ColumnInfo(name = "school_id")
|
||||||
val schoolSymbol: String,
|
val schoolSymbol: String,
|
||||||
|
|
||||||
@ColumnInfo(name ="school_short")
|
@ColumnInfo(name = "school_short")
|
||||||
val schoolShortName: String,
|
val schoolShortName: String,
|
||||||
|
|
||||||
@ColumnInfo(name = "school_name")
|
@ColumnInfo(name = "school_name")
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package io.github.wulkanowy.data.db.entities
|
||||||
|
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Entity
|
||||||
|
import androidx.room.PrimaryKey
|
||||||
|
import io.github.wulkanowy.data.enums.Gender
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
@Entity(tableName = "StudentInfo")
|
||||||
|
data class StudentInfo(
|
||||||
|
|
||||||
|
@ColumnInfo(name = "student_id")
|
||||||
|
val studentId: Int,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "full_name")
|
||||||
|
val fullName: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "first_name")
|
||||||
|
val firstName: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "second_name")
|
||||||
|
val secondName: String,
|
||||||
|
|
||||||
|
val surname: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "birth_date")
|
||||||
|
val birthDate: LocalDate,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "birth_place")
|
||||||
|
val birthPlace: String,
|
||||||
|
|
||||||
|
val gender: Gender,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "has_polish_citizenship")
|
||||||
|
val hasPolishCitizenship: Boolean,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "family_name")
|
||||||
|
val familyName: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "parents_names")
|
||||||
|
val parentsNames: String,
|
||||||
|
|
||||||
|
val address: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "registered_address")
|
||||||
|
val registeredAddress: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "correspondence_address")
|
||||||
|
val correspondenceAddress: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "phone_number")
|
||||||
|
val phoneNumber: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "cell_phone_number")
|
||||||
|
val cellPhoneNumber: String,
|
||||||
|
|
||||||
|
val email: String,
|
||||||
|
|
||||||
|
@Embedded(prefix = "first_guardian_")
|
||||||
|
val firstGuardian: StudentGuardian,
|
||||||
|
|
||||||
|
@Embedded(prefix = "second_guardian_")
|
||||||
|
val secondGuardian: StudentGuardian
|
||||||
|
|
||||||
|
) : Serializable {
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
var id: Long = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data class StudentGuardian(
|
||||||
|
|
||||||
|
@ColumnInfo(name = "full_name")
|
||||||
|
val fullName: String,
|
||||||
|
|
||||||
|
val kinship: String,
|
||||||
|
|
||||||
|
val address: String,
|
||||||
|
|
||||||
|
val phones: String,
|
||||||
|
|
||||||
|
val email: String
|
||||||
|
) : Serializable
|
@ -0,0 +1,42 @@
|
|||||||
|
package io.github.wulkanowy.data.db.migrations
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration31 : Migration(30, 31) {
|
||||||
|
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL(
|
||||||
|
"""CREATE TABLE IF NOT EXISTS StudentInfo (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||||
|
student_id INTEGER NOT NULL,
|
||||||
|
full_name TEXT NOT NULL,
|
||||||
|
first_name TEXT NOT NULL,
|
||||||
|
second_name TEXT NOT NULL,
|
||||||
|
surname TEXT NOT NULL,
|
||||||
|
birth_date INTEGER NOT NULL,
|
||||||
|
birth_place TEXT NOT NULL,
|
||||||
|
gender TEXT NOT NULL,
|
||||||
|
has_polish_citizenship INTEGER NOT NULL,
|
||||||
|
family_name TEXT NOT NULL,
|
||||||
|
parents_names TEXT NOT NULL,
|
||||||
|
address TEXT NOT NULL,
|
||||||
|
registered_address TEXT NOT NULL,
|
||||||
|
correspondence_address TEXT NOT NULL,
|
||||||
|
phone_number TEXT NOT NULL,
|
||||||
|
cell_phone_number TEXT NOT NULL,
|
||||||
|
email TEXT NOT NULL,
|
||||||
|
first_guardian_full_name TEXT NOT NULL,
|
||||||
|
first_guardian_kinship TEXT NOT NULL,
|
||||||
|
first_guardian_address TEXT NOT NULL,
|
||||||
|
first_guardian_phones TEXT NOT NULL,
|
||||||
|
first_guardian_email TEXT NOT NULL,
|
||||||
|
second_guardian_full_name TEXT NOT NULL,
|
||||||
|
second_guardian_kinship TEXT NOT NULL,
|
||||||
|
second_guardian_address TEXT NOT NULL,
|
||||||
|
second_guardian_phones TEXT NOT NULL,
|
||||||
|
second_guardian_email TEXT NOT NULL)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
package io.github.wulkanowy.data.enums
|
||||||
|
|
||||||
|
enum class Gender { MALE, FEMALE }
|
@ -0,0 +1,38 @@
|
|||||||
|
package io.github.wulkanowy.data.mappers
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentGuardian
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
|
import io.github.wulkanowy.data.enums.Gender
|
||||||
|
import io.github.wulkanowy.sdk.pojo.StudentGuardian as SdkStudentGuardian
|
||||||
|
import io.github.wulkanowy.sdk.pojo.StudentInfo as SdkStudentInfo
|
||||||
|
|
||||||
|
fun SdkStudentInfo.mapToEntity(semester: Semester) = StudentInfo(
|
||||||
|
studentId = semester.studentId,
|
||||||
|
fullName = fullName,
|
||||||
|
firstName = firstName,
|
||||||
|
secondName = secondName,
|
||||||
|
surname = surname,
|
||||||
|
birthDate = birthDate,
|
||||||
|
birthPlace = birthPlace,
|
||||||
|
gender = Gender.valueOf(gender.name),
|
||||||
|
hasPolishCitizenship = hasPolishCitizenship,
|
||||||
|
familyName = familyName,
|
||||||
|
parentsNames = parentsNames,
|
||||||
|
address = address,
|
||||||
|
registeredAddress = registeredAddress,
|
||||||
|
correspondenceAddress = correspondenceAddress,
|
||||||
|
phoneNumber = phoneNumber,
|
||||||
|
cellPhoneNumber = phoneNumber,
|
||||||
|
email = email,
|
||||||
|
firstGuardian = guardians[0].mapToEntity(),
|
||||||
|
secondGuardian = guardians[1].mapToEntity()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun SdkStudentGuardian.mapToEntity() = StudentGuardian(
|
||||||
|
fullName = fullName,
|
||||||
|
kinship = kinship,
|
||||||
|
address = address,
|
||||||
|
phones = phones,
|
||||||
|
email = email
|
||||||
|
)
|
@ -16,16 +16,23 @@ class SchoolRepository @Inject constructor(
|
|||||||
private val sdk: Sdk
|
private val sdk: Sdk
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
||||||
shouldFetch = { it == null || forceRefresh },
|
networkBoundResource(
|
||||||
query = { schoolDb.load(semester.studentId, semester.classId) },
|
shouldFetch = { it == null || forceRefresh },
|
||||||
fetch = { sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool().mapToEntity(semester) },
|
query = { schoolDb.load(semester.studentId, semester.classId) },
|
||||||
saveFetchResult = { old, new ->
|
fetch = {
|
||||||
if (new != old && old != null) {
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool()
|
||||||
schoolDb.deleteAll(listOf(old))
|
.mapToEntity(semester)
|
||||||
schoolDb.insertAll(listOf(new))
|
},
|
||||||
|
saveFetchResult = { old, new ->
|
||||||
|
if (old != null && new != old) {
|
||||||
|
with(schoolDb) {
|
||||||
|
deleteAll(listOf(old))
|
||||||
|
insertAll(listOf(new))
|
||||||
|
}
|
||||||
|
} else if (old == null) {
|
||||||
|
schoolDb.insertAll(listOf(new))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
schoolDb.insertAll(listOf(new))
|
)
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.dao.StudentInfoDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.mappers.mapToEntity
|
||||||
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
|
import io.github.wulkanowy.utils.init
|
||||||
|
import io.github.wulkanowy.utils.networkBoundResource
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class StudentInfoRepository @Inject constructor(
|
||||||
|
private val studentInfoDao: StudentInfoDao,
|
||||||
|
private val sdk: Sdk
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun getStudentInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
||||||
|
networkBoundResource(
|
||||||
|
shouldFetch = { it == null || forceRefresh },
|
||||||
|
query = { studentInfoDao.loadStudentInfo(student.studentId) },
|
||||||
|
fetch = {
|
||||||
|
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
|
||||||
|
.getStudentInfo().mapToEntity(semester)
|
||||||
|
},
|
||||||
|
saveFetchResult = { old, new ->
|
||||||
|
if (old != null && new != old) {
|
||||||
|
with(studentInfoDao) {
|
||||||
|
deleteAll(listOf(old))
|
||||||
|
insertAll(listOf(new))
|
||||||
|
}
|
||||||
|
} else if (old == null) {
|
||||||
|
studentInfoDao.insertAll(listOf(new))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
@ -65,7 +65,11 @@ class AboutFragment : BaseFragment<FragmentAboutBinding>(R.layout.fragment_about
|
|||||||
|
|
||||||
override val homepageRes: Triple<String, String, Drawable?>?
|
override val homepageRes: Triple<String, String, Drawable?>?
|
||||||
get() = context?.run {
|
get() = context?.run {
|
||||||
Triple(getString(R.string.about_homepage), getString(R.string.about_homepage_summary), getCompatDrawable(R.drawable.ic_about_homepage))
|
Triple(
|
||||||
|
getString(R.string.about_homepage),
|
||||||
|
getString(R.string.about_homepage_summary),
|
||||||
|
getCompatDrawable(R.drawable.ic_all_home)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val licensesRes: Triple<String, String, Drawable?>?
|
override val licensesRes: Triple<String, String, Drawable?>?
|
||||||
|
@ -8,16 +8,16 @@ import android.view.View.VISIBLE
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.databinding.HeaderAccountBinding
|
import io.github.wulkanowy.databinding.HeaderAccountBinding
|
||||||
import io.github.wulkanowy.databinding.ItemAccountBinding
|
import io.github.wulkanowy.databinding.ItemAccountBinding
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
var isAccountQuickDialogMode = false
|
||||||
|
|
||||||
var items = emptyList<AccountItem<*>>()
|
var items = emptyList<AccountItem<*>>()
|
||||||
|
|
||||||
var onClickListener: (StudentWithSemesters) -> Unit = {}
|
var onClickListener: (StudentWithSemesters) -> Unit = {}
|
||||||
@ -30,54 +30,69 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.V
|
|||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
AccountItem.ViewType.HEADER.id -> HeaderViewHolder(HeaderAccountBinding.inflate(inflater, parent, false))
|
AccountItem.ViewType.HEADER.id -> HeaderViewHolder(
|
||||||
AccountItem.ViewType.ITEM.id -> ItemViewHolder(ItemAccountBinding.inflate(inflater, parent, false))
|
HeaderAccountBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
|
AccountItem.ViewType.ITEM.id -> ItemViewHolder(
|
||||||
|
ItemAccountBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is HeaderViewHolder -> bindHeaderViewHolder(holder.binding, items[position].value as Account)
|
is HeaderViewHolder -> bindHeaderViewHolder(
|
||||||
is ItemViewHolder -> bindItemViewHolder(holder.binding, items[position].value as StudentWithSemesters)
|
holder.binding,
|
||||||
|
items[position].value as Account,
|
||||||
|
position
|
||||||
|
)
|
||||||
|
is ItemViewHolder -> bindItemViewHolder(
|
||||||
|
holder.binding,
|
||||||
|
items[position].value as StudentWithSemesters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindHeaderViewHolder(binding: HeaderAccountBinding, account: Account) {
|
private fun bindHeaderViewHolder(
|
||||||
|
binding: HeaderAccountBinding,
|
||||||
|
account: Account,
|
||||||
|
position: Int
|
||||||
|
) {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
|
accountHeaderDivider.visibility = if (position == 0) GONE else VISIBLE
|
||||||
accountHeaderEmail.text = account.email
|
accountHeaderEmail.text = account.email
|
||||||
accountHeaderType.setText(if (account.isParent) R.string.account_type_parent else R.string.account_type_student)
|
accountHeaderType.setText(if (account.isParent) R.string.account_type_parent else R.string.account_type_student)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun bindItemViewHolder(binding: ItemAccountBinding, studentWithSemesters: StudentWithSemesters) {
|
private fun bindItemViewHolder(
|
||||||
|
binding: ItemAccountBinding,
|
||||||
|
studentWithSemesters: StudentWithSemesters
|
||||||
|
) {
|
||||||
val student = studentWithSemesters.student
|
val student = studentWithSemesters.student
|
||||||
val semesters = studentWithSemesters.semesters
|
val semesters = studentWithSemesters.semesters
|
||||||
val diary = semesters.maxByOrNull { it.semesterId }
|
val diary = semesters.maxByOrNull { it.semesterId }
|
||||||
|
val isDuplicatedStudent = items.filter {
|
||||||
|
if (it.value !is StudentWithSemesters) return@filter false
|
||||||
|
val studentToCompare = it.value.student
|
||||||
|
|
||||||
|
studentToCompare.studentId == student.studentId
|
||||||
|
&& studentToCompare.schoolSymbol == student.schoolSymbol
|
||||||
|
&& studentToCompare.symbol == student.symbol
|
||||||
|
}.size > 1 && isAccountQuickDialogMode
|
||||||
|
|
||||||
with(binding) {
|
with(binding) {
|
||||||
accountItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}"
|
accountItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}"
|
||||||
accountItemSchool.text = studentWithSemesters.student.schoolName
|
accountItemSchool.text = studentWithSemesters.student.schoolName
|
||||||
with(accountItemLoginMode) {
|
accountItemAccountType.setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student)
|
||||||
visibility = when (Sdk.Mode.valueOf(student.loginMode)) {
|
accountItemAccountType.visibility = if (isDuplicatedStudent) VISIBLE else GONE
|
||||||
Sdk.Mode.API -> {
|
|
||||||
setText(R.string.account_login_mobile_api)
|
|
||||||
VISIBLE
|
|
||||||
}
|
|
||||||
Sdk.Mode.HYBRID -> {
|
|
||||||
setText(R.string.account_login_hybrid)
|
|
||||||
VISIBLE
|
|
||||||
}
|
|
||||||
Sdk.Mode.SCRAPPER -> {
|
|
||||||
GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(accountItemImage) {
|
with(accountItemImage) {
|
||||||
val colorImage = if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary)
|
val colorImage =
|
||||||
else context.getThemeAttrColor(R.attr.colorOnSurface, 153)
|
if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary)
|
||||||
|
else context.getThemeAttrColor(R.attr.colorOnSurface, 153)
|
||||||
|
|
||||||
setColorFilter(colorImage, PorterDuff.Mode.SRC_IN)
|
setColorFilter(colorImage, PorterDuff.Mode.SRC_IN)
|
||||||
}
|
}
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
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 androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import io.github.wulkanowy.R
|
|
||||||
import io.github.wulkanowy.databinding.DialogAccountBinding
|
|
||||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class AccountDialog : BaseDialogFragment<DialogAccountBinding>(), AccountView {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var presenter: AccountPresenter
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var accountAdapter: AccountAdapter
|
|
||||||
|
|
||||||
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 DialogAccountBinding.inflate(inflater).apply { binding = this }.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
presenter.onAttachView(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun initView() {
|
|
||||||
accountAdapter.onClickListener = presenter::onItemSelected
|
|
||||||
|
|
||||||
with(binding) {
|
|
||||||
accountDialogAdd.setOnClickListener { presenter.onAddSelected() }
|
|
||||||
accountDialogRemove.setOnClickListener { presenter.onRemoveSelected() }
|
|
||||||
accountDialogRecycler.apply {
|
|
||||||
layoutManager = LinearLayoutManager(context)
|
|
||||||
adapter = accountAdapter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateData(data: List<AccountItem<*>>) {
|
|
||||||
with(accountAdapter) {
|
|
||||||
items = data
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {
|
|
||||||
showMessage(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
|
||||||
Toast.makeText(context, text, LENGTH_LONG).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dismissView() {
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openLoginView() {
|
|
||||||
activity?.let {
|
|
||||||
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 recreateMainView() {
|
|
||||||
activity?.recreate()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
presenter.onDetachView()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,111 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.get
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.databinding.FragmentAccountBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class AccountFragment : BaseFragment<FragmentAccountBinding>(R.layout.fragment_account),
|
||||||
|
AccountView, MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: AccountPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var accountAdapter: AccountAdapter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance() = AccountFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val titleStringId = R.string.account_title
|
||||||
|
|
||||||
|
override var subtitleString = ""
|
||||||
|
|
||||||
|
override val isViewEmpty get() = accountAdapter.items.isEmpty()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding = FragmentAccountBinding.bind(view)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
binding.accountErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
|
binding.accountErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
|
|
||||||
|
binding.accountRecycler.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = accountAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
accountAdapter.onClickListener = presenter::onItemSelected
|
||||||
|
|
||||||
|
with(binding) {
|
||||||
|
accountAdd.setOnClickListener { presenter.onAddSelected() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
menu[0].isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<AccountItem<*>>) {
|
||||||
|
with(accountAdapter) {
|
||||||
|
items = data
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openLoginView() {
|
||||||
|
activity?.let {
|
||||||
|
startActivity(LoginActivity.getStartIntent(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters) {
|
||||||
|
(activity as? MainActivity)?.pushView(
|
||||||
|
AccountDetailsFragment.newInstance(
|
||||||
|
studentWithSemesters
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorView(show: Boolean) {
|
||||||
|
binding.accountError.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setErrorDetails(message: String) {
|
||||||
|
binding.accountErrorMessage.text = message
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProgress(show: Boolean) {
|
||||||
|
binding.accountProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContent(show: Boolean) {
|
||||||
|
with(binding) {
|
||||||
|
accountRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
accountAdd.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.account
|
|||||||
import io.github.wulkanowy.data.Status
|
import io.github.wulkanowy.data.Status
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.afterLoading
|
import io.github.wulkanowy.utils.afterLoading
|
||||||
@ -15,101 +14,85 @@ import javax.inject.Inject
|
|||||||
class AccountPresenter @Inject constructor(
|
class AccountPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val syncManager: SyncManager
|
|
||||||
) : BasePresenter<AccountView>(errorHandler, studentRepository) {
|
) : BasePresenter<AccountView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
override fun onAttachView(view: AccountView) {
|
override fun onAttachView(view: AccountView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.initView()
|
view.initView()
|
||||||
Timber.i("Account dialog view was initialized")
|
Timber.i("Account view was initialized")
|
||||||
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onRetry() {
|
||||||
|
view?.run {
|
||||||
|
showErrorView(false)
|
||||||
|
showProgress(true)
|
||||||
|
}
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDetailsClick() {
|
||||||
|
view?.showErrorDetailsDialog(lastError)
|
||||||
|
}
|
||||||
|
|
||||||
fun onAddSelected() {
|
fun onAddSelected() {
|
||||||
Timber.i("Select add account")
|
Timber.i("Select add account")
|
||||||
view?.openLoginView()
|
view?.openLoginView()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRemoveSelected() {
|
|
||||||
Timber.i("Select remove account")
|
|
||||||
view?.showConfirmDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onLogoutConfirm() {
|
|
||||||
flowWithResource {
|
|
||||||
val student = studentRepository.getCurrentStudent(false)
|
|
||||||
studentRepository.logoutStudent(student)
|
|
||||||
|
|
||||||
val students = studentRepository.getSavedStudents(false)
|
|
||||||
if (students.isNotEmpty()) {
|
|
||||||
studentRepository.switchStudent(students[0])
|
|
||||||
}
|
|
||||||
students
|
|
||||||
}.onEach {
|
|
||||||
when (it.status) {
|
|
||||||
Status.LOADING -> Timber.i("Attempt to logout current user ")
|
|
||||||
Status.SUCCESS -> view?.run {
|
|
||||||
if (it.data!!.isEmpty()) {
|
|
||||||
Timber.i("Logout result: Open login view")
|
|
||||||
syncManager.stopSyncWorker()
|
|
||||||
openClearLoginView()
|
|
||||||
} else {
|
|
||||||
Timber.i("Logout result: Switch to another student")
|
|
||||||
recreateMainView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Status.ERROR -> {
|
|
||||||
Timber.i("Logout result: An exception occurred")
|
|
||||||
errorHandler.dispatch(it.error!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.afterLoading {
|
|
||||||
view?.dismissView()
|
|
||||||
}.launch("logout")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onItemSelected(studentWithSemesters: StudentWithSemesters) {
|
fun onItemSelected(studentWithSemesters: StudentWithSemesters) {
|
||||||
Timber.i("Select student item ${studentWithSemesters.student.id}")
|
view?.openAccountDetailsView(studentWithSemesters)
|
||||||
if (studentWithSemesters.student.isCurrent) {
|
|
||||||
view?.dismissView()
|
|
||||||
} else flowWithResource { studentRepository.switchStudent(studentWithSemesters) }.onEach {
|
|
||||||
when (it.status) {
|
|
||||||
Status.LOADING -> Timber.i("Attempt to change a student")
|
|
||||||
Status.SUCCESS -> {
|
|
||||||
Timber.i("Change a student result: Success")
|
|
||||||
view?.recreateMainView()
|
|
||||||
}
|
|
||||||
Status.ERROR -> {
|
|
||||||
Timber.i("Change a student result: An exception occurred")
|
|
||||||
errorHandler.dispatch(it.error!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.afterLoading {
|
|
||||||
view?.dismissView()
|
|
||||||
}.launch("switch")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAccountItems(items: List<StudentWithSemesters>): List<AccountItem<*>> {
|
private fun createAccountItems(items: List<StudentWithSemesters>): List<AccountItem<*>> {
|
||||||
return items.groupBy { Account(it.student.email, it.student.isParent) }.map { (account, students) ->
|
return items.groupBy {
|
||||||
listOf(AccountItem(account, AccountItem.ViewType.HEADER)) + students.map { student ->
|
Account("${it.student.userName} (${it.student.email})", it.student.isParent)
|
||||||
AccountItem(student, AccountItem.ViewType.ITEM)
|
}
|
||||||
|
.map { (account, students) ->
|
||||||
|
listOf(
|
||||||
|
AccountItem(account, AccountItem.ViewType.HEADER)
|
||||||
|
) + students.map { student ->
|
||||||
|
AccountItem(student, AccountItem.ViewType.ITEM)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
flowWithResource { studentRepository.getSavedStudents(false) }.onEach {
|
flowWithResource { studentRepository.getSavedStudents() }
|
||||||
when (it.status) {
|
.onEach {
|
||||||
Status.LOADING -> Timber.i("Loading account data started")
|
when (it.status) {
|
||||||
Status.SUCCESS -> {
|
Status.LOADING -> Timber.i("Loading account data started")
|
||||||
Timber.i("Loading account result: Success")
|
Status.SUCCESS -> {
|
||||||
view?.updateData(createAccountItems(it.data!!))
|
Timber.i("Loading account result: Success")
|
||||||
}
|
view?.updateData(createAccountItems(it.data!!))
|
||||||
Status.ERROR -> {
|
view?.run {
|
||||||
Timber.i("Loading account result: An exception occurred")
|
showContent(true)
|
||||||
errorHandler.dispatch(it.error!!)
|
showErrorView(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Loading account result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.launch()
|
.afterLoading { view?.showProgress(false) }
|
||||||
|
.launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||||
|
view?.run {
|
||||||
|
if (isViewEmpty) {
|
||||||
|
lastError = error
|
||||||
|
setErrorDetails(message)
|
||||||
|
showErrorView(true)
|
||||||
|
showContent(false)
|
||||||
|
showProgress(false)
|
||||||
|
} else showError(message, error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,26 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account
|
package io.github.wulkanowy.ui.modules.account
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
interface AccountView : BaseView {
|
interface AccountView : BaseView {
|
||||||
|
|
||||||
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateData(data: List<AccountItem<*>>)
|
fun updateData(data: List<AccountItem<*>>)
|
||||||
|
|
||||||
fun dismissView()
|
|
||||||
|
|
||||||
fun showConfirmDialog()
|
|
||||||
|
|
||||||
fun openLoginView()
|
fun openLoginView()
|
||||||
|
|
||||||
fun recreateMainView()
|
fun openAccountDetailsView(studentWithSemesters: StudentWithSemesters)
|
||||||
|
|
||||||
|
fun showErrorView(show: Boolean)
|
||||||
|
|
||||||
|
fun setErrorDetails(message: String)
|
||||||
|
|
||||||
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
|
fun showContent(show: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,134 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.get
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.databinding.FragmentAccountDetailsBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class AccountDetailsFragment :
|
||||||
|
BaseFragment<FragmentAccountDetailsBinding>(R.layout.fragment_account_details),
|
||||||
|
AccountDetailsView, MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: AccountDetailsPresenter
|
||||||
|
|
||||||
|
override val titleStringId = R.string.account_details_title
|
||||||
|
|
||||||
|
override var subtitleString = ""
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val ARGUMENT_KEY = "Data"
|
||||||
|
|
||||||
|
fun newInstance(studentWithSemesters: StudentWithSemesters) =
|
||||||
|
AccountDetailsFragment().apply {
|
||||||
|
arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, studentWithSemesters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
arguments?.let {
|
||||||
|
presenter.studentWithSemesters =
|
||||||
|
it.getSerializable(ARGUMENT_KEY) as StudentWithSemesters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding = FragmentAccountDetailsBinding.bind(view)
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
binding.accountDetailsLogout.setOnClickListener { presenter.onRemoveSelected() }
|
||||||
|
binding.accountDetailsSelect.setOnClickListener { presenter.onStudentSelect() }
|
||||||
|
binding.accountDetailsSelect.isEnabled = !presenter.studentWithSemesters.student.isCurrent
|
||||||
|
|
||||||
|
binding.accountDetailsPersonalData.setOnClickListener {
|
||||||
|
presenter.onStudentInfoSelected(StudentInfoView.Type.PERSONAL)
|
||||||
|
}
|
||||||
|
binding.accountDetailsAddressData.setOnClickListener {
|
||||||
|
presenter.onStudentInfoSelected(StudentInfoView.Type.ADDRESS)
|
||||||
|
}
|
||||||
|
binding.accountDetailsContactData.setOnClickListener {
|
||||||
|
presenter.onStudentInfoSelected(StudentInfoView.Type.CONTACT)
|
||||||
|
}
|
||||||
|
binding.accountDetailsFamilyData.setOnClickListener {
|
||||||
|
presenter.onStudentInfoSelected(StudentInfoView.Type.FAMILY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
menu[0].isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
return if (item.itemId == R.id.accountDetailsMenuEdit) {
|
||||||
|
showAccountEditDetailsDialog()
|
||||||
|
return true
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showAccountData(studentWithSemesters: StudentWithSemesters) {
|
||||||
|
with(binding) {
|
||||||
|
accountDetailsName.text = studentWithSemesters.student.studentName
|
||||||
|
accountDetailsSchool.text = studentWithSemesters.student.schoolName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showAccountEditDetailsDialog() {
|
||||||
|
(requireActivity() as MainActivity).showDialogFragment(AccountEditDetailsDialog.newInstance())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showLogoutConfirmDialog() {
|
||||||
|
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 popView() {
|
||||||
|
(requireActivity() as MainActivity).popView(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recreateMainView() {
|
||||||
|
requireActivity().recreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openStudentInfoView(
|
||||||
|
infoType: StudentInfoView.Type,
|
||||||
|
studentWithSemesters: StudentWithSemesters
|
||||||
|
) {
|
||||||
|
(requireActivity() as MainActivity).pushView(
|
||||||
|
StudentInfoFragment.newInstance(
|
||||||
|
infoType,
|
||||||
|
studentWithSemesters
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.Status
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
import io.github.wulkanowy.utils.afterLoading
|
||||||
|
import io.github.wulkanowy.utils.flowWithResource
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AccountDetailsPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val syncManager: SyncManager
|
||||||
|
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
lateinit var studentWithSemesters: StudentWithSemesters
|
||||||
|
|
||||||
|
override fun onAttachView(view: AccountDetailsView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
view.initView()
|
||||||
|
Timber.i("Account details view was initialized")
|
||||||
|
|
||||||
|
view.showAccountData(studentWithSemesters)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onStudentInfoSelected(infoType: StudentInfoView.Type) {
|
||||||
|
view?.openStudentInfoView(infoType, studentWithSemesters)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onStudentSelect() {
|
||||||
|
Timber.i("Select student ${studentWithSemesters.student.id}")
|
||||||
|
|
||||||
|
flowWithResource { studentRepository.switchStudent(studentWithSemesters) }
|
||||||
|
.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Attempt to change a student")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
Timber.i("Change a student result: Success")
|
||||||
|
view?.recreateMainView()
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Change a student result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.afterLoading {
|
||||||
|
view?.popView()
|
||||||
|
}.launch("switch")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRemoveSelected() {
|
||||||
|
Timber.i("Select remove account")
|
||||||
|
view?.showLogoutConfirmDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onLogoutConfirm() {
|
||||||
|
flowWithResource {
|
||||||
|
val studentToLogout = studentWithSemesters.student
|
||||||
|
|
||||||
|
studentRepository.logoutStudent(studentToLogout)
|
||||||
|
val students = studentRepository.getSavedStudents(false)
|
||||||
|
|
||||||
|
if (studentToLogout.isCurrent && students.isNotEmpty()) {
|
||||||
|
studentRepository.switchStudent(students[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return@flowWithResource students
|
||||||
|
}.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Attempt to logout user")
|
||||||
|
Status.SUCCESS -> view?.run {
|
||||||
|
when {
|
||||||
|
it.data!!.isEmpty() -> {
|
||||||
|
Timber.i("Logout result: Open login view")
|
||||||
|
syncManager.stopSyncWorker()
|
||||||
|
openClearLoginView()
|
||||||
|
}
|
||||||
|
studentWithSemesters.student.isCurrent -> {
|
||||||
|
Timber.i("Logout result: Logout student and switch to another")
|
||||||
|
recreateMainView()
|
||||||
|
}
|
||||||
|
else -> Timber.i("Logout result: Logout student")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Logout result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.afterLoading {
|
||||||
|
view?.popView()
|
||||||
|
}.launch("logout")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoView
|
||||||
|
|
||||||
|
interface AccountDetailsView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun showAccountData(studentWithSemesters: StudentWithSemesters)
|
||||||
|
|
||||||
|
fun showAccountEditDetailsDialog()
|
||||||
|
|
||||||
|
fun showLogoutConfirmDialog()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
|
|
||||||
|
fun recreateMainView()
|
||||||
|
|
||||||
|
fun openStudentInfoView(
|
||||||
|
infoType: StudentInfoView.Type,
|
||||||
|
studentWithSemesters: StudentWithSemesters
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import io.github.wulkanowy.databinding.DialogAccountEditDetailsBinding
|
||||||
|
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||||
|
|
||||||
|
class AccountEditDetailsDialog : DialogFragment() {
|
||||||
|
|
||||||
|
private var binding: DialogAccountEditDetailsBinding by lifecycleAwareVariable()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun newInstance() = AccountEditDetailsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return DialogAccountEditDetailsBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
binding.accountEditDetailsCancel.setOnClickListener { dismiss() }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountquick
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.databinding.DialogAccountQuickBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.account.AccountAdapter
|
||||||
|
import io.github.wulkanowy.ui.modules.account.AccountFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.account.AccountItem
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class AccountQuickDialog : BaseDialogFragment<DialogAccountQuickBinding>(), AccountQuickView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var accountAdapter: AccountAdapter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: AccountQuickPresenter
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = AccountQuickDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NO_TITLE, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
) = DialogAccountQuickBinding.inflate(inflater).apply { binding = this }.root
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
presenter.onAttachView(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
binding.accountQuickDialogManger.setOnClickListener { presenter.onManagerSelected() }
|
||||||
|
|
||||||
|
with(accountAdapter) {
|
||||||
|
isAccountQuickDialogMode = true
|
||||||
|
onClickListener = presenter::onStudentSelect
|
||||||
|
}
|
||||||
|
|
||||||
|
with(binding.accountQuickDialogRecycler) {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
adapter = accountAdapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<AccountItem<*>>) {
|
||||||
|
with(accountAdapter) {
|
||||||
|
items = data
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popView() {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun recreateMainView() {
|
||||||
|
activity?.recreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openAccountView() {
|
||||||
|
(requireActivity() as MainActivity).pushView(AccountFragment.newInstance())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountquick
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.Status
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.account.AccountItem
|
||||||
|
import io.github.wulkanowy.utils.afterLoading
|
||||||
|
import io.github.wulkanowy.utils.flowWithResource
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class AccountQuickPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository
|
||||||
|
) : BasePresenter<AccountQuickView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
override fun onAttachView(view: AccountQuickView) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
view.initView()
|
||||||
|
Timber.i("Account quick dialog view was initialized")
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onManagerSelected() {
|
||||||
|
view?.run {
|
||||||
|
openAccountView()
|
||||||
|
popView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onStudentSelect(studentWithSemesters: StudentWithSemesters) {
|
||||||
|
Timber.i("Select student ${studentWithSemesters.student.id}")
|
||||||
|
|
||||||
|
if (studentWithSemesters.student.isCurrent) {
|
||||||
|
view?.popView()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
flowWithResource { studentRepository.switchStudent(studentWithSemesters) }
|
||||||
|
.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Attempt to change a student")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
Timber.i("Change a student result: Success")
|
||||||
|
view?.recreateMainView()
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Change a student result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.afterLoading {
|
||||||
|
view?.popView()
|
||||||
|
}.launch("switch")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
flowWithResource { studentRepository.getSavedStudents(false) }.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Loading account data started")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
Timber.i("Loading account result: Success")
|
||||||
|
view?.updateData(createAccountItems(it.data!!))
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Loading account result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createAccountItems(items: List<StudentWithSemesters>) = items.map {
|
||||||
|
AccountItem(it, AccountItem.ViewType.ITEM)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.account.accountquick
|
||||||
|
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
import io.github.wulkanowy.ui.modules.account.AccountItem
|
||||||
|
|
||||||
|
interface AccountQuickView : BaseView {
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<AccountItem<*>>)
|
||||||
|
|
||||||
|
fun recreateMainView()
|
||||||
|
|
||||||
|
fun popView()
|
||||||
|
|
||||||
|
fun openAccountView()
|
||||||
|
}
|
@ -60,6 +60,7 @@ class AttendanceFragment : BaseFragment<FragmentAttendanceBinding>(R.layout.frag
|
|||||||
override val excuseActionMode: Boolean get() = attendanceAdapter.excuseActionMode
|
override val excuseActionMode: Boolean get() = attendanceAdapter.excuseActionMode
|
||||||
|
|
||||||
private var actionMode: ActionMode? = null
|
private var actionMode: ActionMode? = null
|
||||||
|
|
||||||
private val actionModeCallback = object : ActionMode.Callback {
|
private val actionModeCallback = object : ActionMode.Callback {
|
||||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||||
val inflater = mode.menuInflater
|
val inflater = mode.menuInflater
|
||||||
|
@ -14,6 +14,7 @@ import android.os.Build.VERSION_CODES.LOLLIPOP
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
@ -28,7 +29,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.databinding.ActivityMainBinding
|
import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.account.AccountDialog
|
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
@ -65,17 +66,19 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
|
|
||||||
private val overlayProvider by lazy { ElevationOverlayProvider(this) }
|
private val overlayProvider by lazy { ElevationOverlayProvider(this) }
|
||||||
|
|
||||||
private val navController = FragNavController(supportFragmentManager, R.id.mainFragmentContainer)
|
private val navController =
|
||||||
|
FragNavController(supportFragmentManager, R.id.mainFragmentContainer)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_START_MENU = "extraStartMenu"
|
const val EXTRA_START_MENU = "extraStartMenu"
|
||||||
|
|
||||||
fun getStartIntent(context: Context, startMenu: MainView.Section? = null, clear: Boolean = false): Intent {
|
fun getStartIntent(
|
||||||
return Intent(context, MainActivity::class.java)
|
context: Context,
|
||||||
.apply {
|
startMenu: MainView.Section? = null,
|
||||||
if (clear) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
|
clear: Boolean = false
|
||||||
startMenu?.let { putExtra(EXTRA_START_MENU, it.id) }
|
) = Intent(context, MainActivity::class.java).apply {
|
||||||
}
|
if (clear) flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
startMenu?.let { putExtra(EXTRA_START_MENU, it.id) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +86,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
|
|
||||||
override val currentStackSize get() = navController.currentStack?.size
|
override val currentStackSize get() = navController.currentStack?.size
|
||||||
|
|
||||||
override val currentViewTitle get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId?.let { getString(it) }
|
override val currentViewTitle
|
||||||
|
get() = (navController.currentFrag as? MainView.TitledView)?.titleStringId?.let {
|
||||||
|
getString(it)
|
||||||
|
}
|
||||||
|
|
||||||
override val currentViewSubtitle get() = (navController.currentFrag as? MainView.TitledView)?.subtitleString
|
override val currentViewSubtitle get() = (navController.currentFrag as? MainView.TitledView)?.subtitleString
|
||||||
|
|
||||||
@ -106,7 +112,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
messageContainer = binding.mainFragmentContainer
|
messageContainer = binding.mainFragmentContainer
|
||||||
updateHelper.messageContainer = binding.mainFragmentContainer
|
updateHelper.messageContainer = binding.mainFragmentContainer
|
||||||
|
|
||||||
presenter.onAttachView(this, MainView.Section.values().singleOrNull { it.id == intent.getIntExtra(EXTRA_START_MENU, -1) })
|
val section = MainView.Section.values()
|
||||||
|
.singleOrNull { it.id == intent.getIntExtra(EXTRA_START_MENU, -1) }
|
||||||
|
|
||||||
|
presenter.onAttachView(this, section)
|
||||||
|
|
||||||
with(navController) {
|
with(navController) {
|
||||||
initialize(startMenuIndex, savedInstanceState)
|
initialize(startMenuIndex, savedInstanceState)
|
||||||
@ -132,21 +141,49 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
val shortcutsList = mutableListOf<ShortcutInfo>()
|
val shortcutsList = mutableListOf<ShortcutInfo>()
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
Triple(getString(R.string.grade_title), R.drawable.ic_shortcut_grade, MainView.Section.GRADE),
|
Triple(
|
||||||
Triple(getString(R.string.attendance_title), R.drawable.ic_shortcut_attendance, MainView.Section.ATTENDANCE),
|
getString(R.string.grade_title),
|
||||||
Triple(getString(R.string.exam_title), R.drawable.ic_shortcut_exam, MainView.Section.EXAM),
|
R.drawable.ic_shortcut_grade,
|
||||||
Triple(getString(R.string.timetable_title), R.drawable.ic_shortcut_timetable, MainView.Section.TIMETABLE),
|
MainView.Section.GRADE
|
||||||
Triple(getString(R.string.message_title), R.drawable.ic_shortcut_message, MainView.Section.MESSAGE)
|
),
|
||||||
|
Triple(
|
||||||
|
getString(R.string.attendance_title),
|
||||||
|
R.drawable.ic_shortcut_attendance,
|
||||||
|
MainView.Section.ATTENDANCE
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
getString(R.string.exam_title),
|
||||||
|
R.drawable.ic_shortcut_exam,
|
||||||
|
MainView.Section.EXAM
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
getString(R.string.timetable_title),
|
||||||
|
R.drawable.ic_shortcut_timetable,
|
||||||
|
MainView.Section.TIMETABLE
|
||||||
|
),
|
||||||
|
Triple(
|
||||||
|
getString(R.string.message_title),
|
||||||
|
R.drawable.ic_shortcut_message,
|
||||||
|
MainView.Section.MESSAGE
|
||||||
|
)
|
||||||
).forEach { (title, icon, enum) ->
|
).forEach { (title, icon, enum) ->
|
||||||
shortcutsList.add(ShortcutInfo.Builder(applicationContext, title)
|
shortcutsList.add(
|
||||||
.setShortLabel(title)
|
ShortcutInfo.Builder(applicationContext, title)
|
||||||
.setLongLabel(title)
|
.setShortLabel(title)
|
||||||
.setIcon(Icon.createWithResource(applicationContext, icon))
|
.setLongLabel(title)
|
||||||
.setIntents(arrayOf(
|
.setIcon(Icon.createWithResource(applicationContext, icon))
|
||||||
Intent(applicationContext, MainActivity::class.java).setAction(Intent.ACTION_VIEW),
|
.setIntents(
|
||||||
Intent(applicationContext, MainActivity::class.java).putExtra(EXTRA_START_MENU, enum.id)
|
arrayOf(
|
||||||
.setAction(Intent.ACTION_VIEW).addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)))
|
Intent(applicationContext, MainActivity::class.java)
|
||||||
.build())
|
.setAction(Intent.ACTION_VIEW),
|
||||||
|
Intent(applicationContext, MainActivity::class.java)
|
||||||
|
.putExtra(EXTRA_START_MENU, enum.id)
|
||||||
|
.setAction(Intent.ACTION_VIEW)
|
||||||
|
.addFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getSystemService<ShortcutManager>()?.dynamicShortcuts = shortcutsList
|
getSystemService<ShortcutManager>()?.dynamicShortcuts = shortcutsList
|
||||||
@ -160,20 +197,33 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
override fun initView() {
|
override fun initView() {
|
||||||
with(binding.mainToolbar) {
|
with(binding.mainToolbar) {
|
||||||
if (SDK_INT >= LOLLIPOP) stateListAnimator = null
|
if (SDK_INT >= LOLLIPOP) stateListAnimator = null
|
||||||
setBackgroundColor(overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f)))
|
setBackgroundColor(
|
||||||
|
overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.mainBottomNav) {
|
with(binding.mainBottomNav) {
|
||||||
addItems(listOf(
|
addItems(
|
||||||
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_main_grade, 0),
|
listOf(
|
||||||
AHBottomNavigationItem(R.string.attendance_title, R.drawable.ic_main_attendance, 0),
|
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_main_grade, 0),
|
||||||
AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_main_exam, 0),
|
AHBottomNavigationItem(
|
||||||
AHBottomNavigationItem(R.string.timetable_title, R.drawable.ic_main_timetable, 0),
|
R.string.attendance_title,
|
||||||
AHBottomNavigationItem(R.string.more_title, R.drawable.ic_main_more, 0)
|
R.drawable.ic_main_attendance,
|
||||||
))
|
0
|
||||||
|
),
|
||||||
|
AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_main_exam, 0),
|
||||||
|
AHBottomNavigationItem(
|
||||||
|
R.string.timetable_title,
|
||||||
|
R.drawable.ic_main_timetable,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
AHBottomNavigationItem(R.string.more_title, R.drawable.ic_main_more, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
accentColor = getThemeAttrColor(R.attr.colorPrimary)
|
accentColor = getThemeAttrColor(R.attr.colorPrimary)
|
||||||
inactiveColor = getThemeAttrColor(R.attr.colorOnSurface, 153)
|
inactiveColor = getThemeAttrColor(R.attr.colorOnSurface, 153)
|
||||||
defaultBackgroundColor = overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f))
|
defaultBackgroundColor =
|
||||||
|
overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f))
|
||||||
titleState = ALWAYS_SHOW
|
titleState = ALWAYS_SHOW
|
||||||
currentItem = startMenuIndex
|
currentItem = startMenuIndex
|
||||||
isBehaviorTranslationEnabled = false
|
isBehaviorTranslationEnabled = false
|
||||||
@ -183,6 +233,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
|
|
||||||
with(navController) {
|
with(navController) {
|
||||||
setOnViewChangeListener { section, name ->
|
setOnViewChangeListener { section, name ->
|
||||||
|
binding.mainBottomNav.visibility =
|
||||||
|
if (section == MainView.Section.ACCOUNT || section == MainView.Section.STUDENT_INFO) {
|
||||||
|
View.GONE
|
||||||
|
} else {
|
||||||
|
View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
analytics.setCurrentScreen(this@MainActivity, name)
|
analytics.setCurrentScreen(this@MainActivity, name)
|
||||||
presenter.onViewChange(section)
|
presenter.onViewChange(section)
|
||||||
}
|
}
|
||||||
@ -224,7 +281,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showAccountPicker() {
|
override fun showAccountPicker() {
|
||||||
navController.showDialogFragment(AccountDialog.newInstance())
|
navController.showDialogFragment(AccountQuickDialog.newInstance())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showActionBarElevation(show: Boolean) {
|
override fun showActionBarElevation(show: Boolean) {
|
||||||
|
@ -64,6 +64,8 @@ interface MainView : BaseView {
|
|||||||
LUCKY_NUMBER(8),
|
LUCKY_NUMBER(8),
|
||||||
SETTINGS(9),
|
SETTINGS(9),
|
||||||
ABOUT(10),
|
ABOUT(10),
|
||||||
SCHOOL(11)
|
SCHOOL(11),
|
||||||
|
ACCOUNT(12),
|
||||||
|
STUDENT_INFO(13)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,7 @@ class SchoolPresenter @Inject constructor(
|
|||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
}
|
}
|
||||||
analytics.logEvent(
|
analytics.logEvent("load_item", "type" to "school")
|
||||||
"load_item",
|
|
||||||
"type" to "school"
|
|
||||||
)
|
|
||||||
} else view?.run {
|
} else view?.run {
|
||||||
Timber.i("Loading school result: No school info found")
|
Timber.i("Loading school result: No school info found")
|
||||||
showContent(!isViewEmpty)
|
showContent(!isViewEmpty)
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.studentinfo
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.wulkanowy.databinding.ItemStudentInfoBinding
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class StudentInfoAdapter @Inject constructor() :
|
||||||
|
RecyclerView.Adapter<StudentInfoAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
var items = listOf<Pair<String, String>>()
|
||||||
|
|
||||||
|
var onItemClickListener: (position: Int) -> Unit = {}
|
||||||
|
|
||||||
|
var onItemLongClickListener: (text: String) -> Unit = {}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemStudentInfoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val item = items[position]
|
||||||
|
|
||||||
|
with(holder.binding) {
|
||||||
|
studentInfoItemTitle.text = item.first
|
||||||
|
studentInfoItemSubtitle.text = item.second
|
||||||
|
|
||||||
|
with(root) {
|
||||||
|
setOnClickListener { onItemClickListener(position) }
|
||||||
|
setOnLongClickListener {
|
||||||
|
onItemLongClickListener(studentInfoItemSubtitle.text.toString())
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(val binding: ItemStudentInfoBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
|
}
|
@ -0,0 +1,228 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.studentinfo
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import androidx.core.view.get
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.enums.Gender
|
||||||
|
import io.github.wulkanowy.databinding.FragmentStudentInfoBinding
|
||||||
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class StudentInfoFragment :
|
||||||
|
BaseFragment<FragmentStudentInfoBinding>(R.layout.fragment_student_info), StudentInfoView,
|
||||||
|
MainView.TitledView {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var presenter: StudentInfoPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var studentInfoAdapter: StudentInfoAdapter
|
||||||
|
|
||||||
|
override val titleStringId: Int
|
||||||
|
get() = R.string.student_info_title
|
||||||
|
|
||||||
|
override val isViewEmpty get() = studentInfoAdapter.items.isEmpty()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val INFO_TYPE_ARGUMENT_KEY = "info_type"
|
||||||
|
|
||||||
|
private const val STUDENT_ARGUMENT_KEY = "student_with_semesters"
|
||||||
|
|
||||||
|
fun newInstance(type: StudentInfoView.Type, studentWithSemesters: StudentWithSemesters) =
|
||||||
|
StudentInfoFragment().apply {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putSerializable(INFO_TYPE_ARGUMENT_KEY, type)
|
||||||
|
putSerializable(STUDENT_ARGUMENT_KEY, studentWithSemesters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
binding = FragmentStudentInfoBinding.bind(view)
|
||||||
|
presenter.onAttachView(
|
||||||
|
this,
|
||||||
|
requireArguments().getSerializable(INFO_TYPE_ARGUMENT_KEY) as StudentInfoView.Type,
|
||||||
|
requireArguments().getSerializable(STUDENT_ARGUMENT_KEY) as StudentWithSemesters
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView() {
|
||||||
|
with(binding) {
|
||||||
|
studentInfoSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
|
studentInfoErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
|
studentInfoErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
|
}
|
||||||
|
|
||||||
|
with(studentInfoAdapter) {
|
||||||
|
onItemClickListener = presenter::onItemSelected
|
||||||
|
onItemLongClickListener = presenter::onItemLongClick
|
||||||
|
}
|
||||||
|
|
||||||
|
with(binding.studentInfoRecycler) {
|
||||||
|
layoutManager = LinearLayoutManager(context)
|
||||||
|
addItemDecoration(DividerItemDecoration(context, RecyclerView.VERTICAL))
|
||||||
|
setHasFixedSize(true)
|
||||||
|
adapter = studentInfoAdapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateData(data: List<Pair<String, String>>) {
|
||||||
|
with(studentInfoAdapter) {
|
||||||
|
items = data
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
menu[0].isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showPersonalTypeData(studentInfo: StudentInfo) {
|
||||||
|
updateData(
|
||||||
|
listOf(
|
||||||
|
getString(R.string.student_info_first_name) to studentInfo.firstName,
|
||||||
|
getString(R.string.student_info_second_name) to studentInfo.secondName,
|
||||||
|
getString(R.string.student_info_gender) to getString(if (studentInfo.gender == Gender.MALE) R.string.student_info_male else R.string.student_info_female),
|
||||||
|
getString(R.string.student_info_polish_citizenship) to getString(if (studentInfo.hasPolishCitizenship) R.string.all_yes else R.string.all_no),
|
||||||
|
getString(R.string.student_info_family_name) to studentInfo.familyName,
|
||||||
|
getString(R.string.student_info_parents_name) to studentInfo.parentsNames
|
||||||
|
).map {
|
||||||
|
if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContactTypeData(studentInfo: StudentInfo) {
|
||||||
|
updateData(
|
||||||
|
listOf(
|
||||||
|
getString(R.string.student_info_phone) to studentInfo.phoneNumber,
|
||||||
|
getString(R.string.student_info_cellphone) to studentInfo.cellPhoneNumber,
|
||||||
|
getString(R.string.student_info_email) to studentInfo.email
|
||||||
|
).map {
|
||||||
|
if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
override fun showFamilyTypeData(studentInfo: StudentInfo) {
|
||||||
|
updateData(
|
||||||
|
listOf(
|
||||||
|
studentInfo.firstGuardian.kinship.capitalize() to studentInfo.firstGuardian.fullName,
|
||||||
|
studentInfo.secondGuardian.kinship.capitalize() to studentInfo.secondGuardian.fullName
|
||||||
|
).map {
|
||||||
|
if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showAddressTypeData(studentInfo: StudentInfo) {
|
||||||
|
updateData(
|
||||||
|
listOf(
|
||||||
|
getString(R.string.student_info_address) to studentInfo.address,
|
||||||
|
getString(R.string.student_info_registered_address) to studentInfo.registeredAddress,
|
||||||
|
getString(R.string.student_info_correspondence_address) to studentInfo.correspondenceAddress
|
||||||
|
).map {
|
||||||
|
if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showFirstGuardianTypeData(studentInfo: StudentInfo) {
|
||||||
|
updateData(
|
||||||
|
listOf(
|
||||||
|
getString(R.string.student_info_full_name) to studentInfo.firstGuardian.fullName,
|
||||||
|
getString(R.string.student_info_kinship) to studentInfo.firstGuardian.kinship,
|
||||||
|
getString(R.string.student_info_guardian_address) to studentInfo.firstGuardian.address,
|
||||||
|
getString(R.string.student_info_phones) to studentInfo.firstGuardian.phones,
|
||||||
|
getString(R.string.student_info_email) to studentInfo.firstGuardian.email
|
||||||
|
).map {
|
||||||
|
if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showSecondGuardianTypeData(studentInfo: StudentInfo) {
|
||||||
|
updateData(
|
||||||
|
listOf(
|
||||||
|
getString(R.string.student_info_full_name) to studentInfo.secondGuardian.fullName,
|
||||||
|
getString(R.string.student_info_kinship) to studentInfo.secondGuardian.kinship,
|
||||||
|
getString(R.string.student_info_guardian_address) to studentInfo.secondGuardian.address,
|
||||||
|
getString(R.string.student_info_phones) to studentInfo.secondGuardian.phones,
|
||||||
|
getString(R.string.student_info_email) to studentInfo.secondGuardian.email
|
||||||
|
).map {
|
||||||
|
if (it.second.isBlank()) it.copy(second = getString(R.string.all_no_data)) else it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openStudentInfoView(
|
||||||
|
infoType: StudentInfoView.Type,
|
||||||
|
studentWithSemesters: StudentWithSemesters
|
||||||
|
) {
|
||||||
|
(requireActivity() as MainActivity).pushView(newInstance(infoType, studentWithSemesters))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showEmpty(show: Boolean) {
|
||||||
|
binding.studentInfoEmpty.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showErrorView(show: Boolean) {
|
||||||
|
binding.studentInfoError.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setErrorDetails(message: String) {
|
||||||
|
binding.studentInfoErrorMessage.text = message
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showProgress(show: Boolean) {
|
||||||
|
binding.studentInfoProgress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun enableSwipe(enable: Boolean) {
|
||||||
|
binding.studentInfoSwipe.isEnabled = enable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showContent(show: Boolean) {
|
||||||
|
binding.studentInfoRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hideRefresh() {
|
||||||
|
binding.studentInfoSwipe.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copyToClipboard(text: String) {
|
||||||
|
val clipData = ClipData.newPlainText("student_info_wulkanowy", text)
|
||||||
|
requireActivity().getSystemService<ClipboardManager>()?.setPrimaryClip(clipData)
|
||||||
|
Toast.makeText(context, R.string.all_copied, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
presenter.onDetachView()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.studentinfo
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.Status
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentInfoRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.afterLoading
|
||||||
|
import io.github.wulkanowy.utils.flowWithResourceIn
|
||||||
|
import io.github.wulkanowy.utils.getCurrentOrLast
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class StudentInfoPresenter @Inject constructor(
|
||||||
|
errorHandler: ErrorHandler,
|
||||||
|
studentRepository: StudentRepository,
|
||||||
|
private val studentInfoRepository: StudentInfoRepository,
|
||||||
|
private val analytics: AnalyticsHelper
|
||||||
|
) : BasePresenter<StudentInfoView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
|
private lateinit var infoType: StudentInfoView.Type
|
||||||
|
|
||||||
|
private lateinit var studentWithSemesters: StudentWithSemesters
|
||||||
|
|
||||||
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
|
fun onAttachView(
|
||||||
|
view: StudentInfoView,
|
||||||
|
type: StudentInfoView.Type,
|
||||||
|
studentWithSemesters: StudentWithSemesters
|
||||||
|
) {
|
||||||
|
super.onAttachView(view)
|
||||||
|
infoType = type
|
||||||
|
this.studentWithSemesters = studentWithSemesters
|
||||||
|
view.initView()
|
||||||
|
Timber.i("Student info $infoType view was initialized")
|
||||||
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSwipeRefresh() {
|
||||||
|
loadData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRetry() {
|
||||||
|
view?.run {
|
||||||
|
showErrorView(false)
|
||||||
|
showProgress(true)
|
||||||
|
}
|
||||||
|
loadData(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDetailsClick() {
|
||||||
|
view?.showErrorDetailsDialog(lastError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onItemSelected(position: Int) {
|
||||||
|
if (infoType != StudentInfoView.Type.FAMILY) return
|
||||||
|
|
||||||
|
if (position == 0) {
|
||||||
|
view?.openStudentInfoView(StudentInfoView.Type.FIRST_GUARDIAN, studentWithSemesters)
|
||||||
|
} else {
|
||||||
|
view?.openStudentInfoView(StudentInfoView.Type.SECOND_GUARDIAN, studentWithSemesters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onItemLongClick(text: String) {
|
||||||
|
view?.copyToClipboard(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData(forceRefresh: Boolean = false) {
|
||||||
|
flowWithResourceIn {
|
||||||
|
val semester = studentWithSemesters.semesters.getCurrentOrLast()
|
||||||
|
studentInfoRepository.getStudentInfo(
|
||||||
|
studentWithSemesters.student,
|
||||||
|
semester,
|
||||||
|
forceRefresh
|
||||||
|
)
|
||||||
|
}.onEach {
|
||||||
|
when (it.status) {
|
||||||
|
Status.LOADING -> Timber.i("Loading student info $infoType started")
|
||||||
|
Status.SUCCESS -> {
|
||||||
|
if (it.data != null) {
|
||||||
|
Timber.i("Loading student info $infoType result: Success")
|
||||||
|
showCorrectData(it.data)
|
||||||
|
view?.run {
|
||||||
|
showContent(true)
|
||||||
|
showEmpty(false)
|
||||||
|
showErrorView(false)
|
||||||
|
}
|
||||||
|
analytics.logEvent("load_item", "type" to "student_info")
|
||||||
|
} else {
|
||||||
|
Timber.i("Loading student info $infoType result: No school info found")
|
||||||
|
view?.run {
|
||||||
|
showContent(!isViewEmpty)
|
||||||
|
showEmpty(isViewEmpty)
|
||||||
|
showErrorView(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Status.ERROR -> {
|
||||||
|
Timber.i("Loading student info $infoType result: An exception occurred")
|
||||||
|
errorHandler.dispatch(it.error!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.afterLoading {
|
||||||
|
view?.run {
|
||||||
|
hideRefresh()
|
||||||
|
showProgress(false)
|
||||||
|
enableSwipe(true)
|
||||||
|
}
|
||||||
|
}.launch()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showCorrectData(studentInfo: StudentInfo) {
|
||||||
|
when (infoType) {
|
||||||
|
StudentInfoView.Type.PERSONAL -> view?.showPersonalTypeData(studentInfo)
|
||||||
|
StudentInfoView.Type.CONTACT -> view?.showContactTypeData(studentInfo)
|
||||||
|
StudentInfoView.Type.ADDRESS -> view?.showAddressTypeData(studentInfo)
|
||||||
|
StudentInfoView.Type.FAMILY -> view?.showFamilyTypeData(studentInfo)
|
||||||
|
StudentInfoView.Type.SECOND_GUARDIAN -> view?.showSecondGuardianTypeData(studentInfo)
|
||||||
|
StudentInfoView.Type.FIRST_GUARDIAN -> view?.showFirstGuardianTypeData(studentInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||||
|
view?.run {
|
||||||
|
if (isViewEmpty) {
|
||||||
|
lastError = error
|
||||||
|
setErrorDetails(message)
|
||||||
|
showErrorView(true)
|
||||||
|
showEmpty(false)
|
||||||
|
showContent(false)
|
||||||
|
showProgress(false)
|
||||||
|
} else showError(message, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.studentinfo
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentInfo
|
||||||
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
|
interface StudentInfoView : BaseView {
|
||||||
|
|
||||||
|
enum class Type {
|
||||||
|
PERSONAL, ADDRESS, CONTACT, FAMILY, FIRST_GUARDIAN, SECOND_GUARDIAN
|
||||||
|
}
|
||||||
|
|
||||||
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
|
fun initView()
|
||||||
|
|
||||||
|
fun updateData(data: List<Pair<String, String>>)
|
||||||
|
|
||||||
|
fun showPersonalTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
|
fun showContactTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
|
fun showAddressTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
|
fun showFamilyTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
|
fun showFirstGuardianTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
|
fun showSecondGuardianTypeData(studentInfo: StudentInfo)
|
||||||
|
|
||||||
|
fun openStudentInfoView(infoType: Type, studentWithSemesters: StudentWithSemesters)
|
||||||
|
|
||||||
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
|
fun showErrorView(show: Boolean)
|
||||||
|
|
||||||
|
fun setErrorDetails(message: String)
|
||||||
|
|
||||||
|
fun showProgress(show: Boolean)
|
||||||
|
|
||||||
|
fun enableSwipe(enable: Boolean)
|
||||||
|
|
||||||
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
|
fun hideRefresh()
|
||||||
|
|
||||||
|
fun copyToClipboard(text: String)
|
||||||
|
}
|
@ -28,4 +28,9 @@ open class AppInfo @Inject constructor() {
|
|||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
open val systemLanguage: String
|
open val systemLanguage: String
|
||||||
get() = Resources.getSystem().configuration.locale.language
|
get() = Resources.getSystem().configuration.locale.language
|
||||||
|
|
||||||
|
open val defaultColorsForAvatar = listOf(
|
||||||
|
0xe57373, 0xf06292, 0xba68c8, 0x9575cd, 0x7986cb, 0x64b5f6, 0x4fc3f7, 0x4dd0e1, 0x4db6ac,
|
||||||
|
0x81c784, 0xaed581, 0xff8a65, 0xd4e157, 0xffd54f, 0xffb74d, 0xa1887f, 0x90a4ae
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.utils
|
|||||||
|
|
||||||
import io.github.wulkanowy.data.Resource
|
import io.github.wulkanowy.data.Resource
|
||||||
import io.github.wulkanowy.data.Status
|
import io.github.wulkanowy.data.Status
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
@ -71,24 +72,14 @@ inline fun <ResultType, RequestType, T> networkBoundResource(
|
|||||||
|
|
||||||
fun <T> flowWithResource(block: suspend () -> T) = flow {
|
fun <T> flowWithResource(block: suspend () -> T) = flow {
|
||||||
emit(Resource.loading())
|
emit(Resource.loading())
|
||||||
emit(try {
|
emit(Resource.success(block()))
|
||||||
Resource.success(block())
|
}.catch { emit(Resource.error(it)) }
|
||||||
} catch (e: Throwable) {
|
|
||||||
Resource.error(e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@OptIn(FlowPreview::class)
|
||||||
fun <T> flowWithResourceIn(block: suspend () -> Flow<Resource<T>>) = flow {
|
fun <T> flowWithResourceIn(block: suspend () -> Flow<Resource<T>>) = flow {
|
||||||
emit(Resource.loading())
|
emit(Resource.loading())
|
||||||
|
emitAll(block().filter { it.status != Status.LOADING || (it.status == Status.LOADING && it.data != null) })
|
||||||
block()
|
}.catch { emit(Resource.error(it)) }
|
||||||
.catch { emit(Resource.error(it)) }
|
|
||||||
.collect {
|
|
||||||
if (it.status != Status.LOADING || (it.status == Status.LOADING && it.data != null)) { // LOADING without data is already emitted
|
|
||||||
emit(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach {
|
fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach {
|
||||||
if (it.status != Status.LOADING) callback()
|
if (it.status != Status.LOADING) callback()
|
||||||
@ -96,4 +87,5 @@ fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach {
|
|||||||
|
|
||||||
suspend fun <T> Flow<Resource<T>>.toFirstResult() = filter { it.status != Status.LOADING }.first()
|
suspend fun <T> Flow<Resource<T>>.toFirstResult() = filter { it.status != Status.LOADING }.first()
|
||||||
|
|
||||||
suspend fun <T> Flow<Resource<T>>.waitForResult() = takeWhile { it.status == Status.LOADING }.collect()
|
suspend fun <T> Flow<Resource<T>>.waitForResult() =
|
||||||
|
takeWhile { it.status == Status.LOADING }.collect()
|
||||||
|
@ -2,6 +2,8 @@ package io.github.wulkanowy.utils
|
|||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.account.AccountFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||||
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
|
||||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
@ -13,6 +15,7 @@ import io.github.wulkanowy.ui.modules.more.MoreFragment
|
|||||||
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
import io.github.wulkanowy.ui.modules.note.NoteFragment
|
||||||
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
import io.github.wulkanowy.ui.modules.schoolandteachers.SchoolAndTeachersFragment
|
||||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
|
|
||||||
fun Fragment.toSection(): MainView.Section? {
|
fun Fragment.toSection(): MainView.Section? {
|
||||||
@ -29,6 +32,9 @@ fun Fragment.toSection(): MainView.Section? {
|
|||||||
is SettingsFragment -> MainView.Section.SETTINGS
|
is SettingsFragment -> MainView.Section.SETTINGS
|
||||||
is AboutFragment -> MainView.Section.ABOUT
|
is AboutFragment -> MainView.Section.ABOUT
|
||||||
is SchoolAndTeachersFragment -> MainView.Section.SCHOOL
|
is SchoolAndTeachersFragment -> MainView.Section.SCHOOL
|
||||||
|
is AccountFragment -> MainView.Section.ACCOUNT
|
||||||
|
is AccountDetailsFragment -> MainView.Section.ACCOUNT
|
||||||
|
is StudentInfoFragment -> MainView.Section.STUDENT_INFO
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
app/src/main/res/drawable/ic_account_details_family.xml
Normal file
9
app/src/main/res/drawable/ic_account_details_family.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M16,4c0,-1.11 0.89,-2 2,-2s2,0.89 2,2s-0.89,2 -2,2S16,5.11 16,4zM20,22v-6h2.5l-2.54,-7.63C19.68,7.55 18.92,7 18.06,7h-0.12c-0.86,0 -1.63,0.55 -1.9,1.37l-0.86,2.58C16.26,11.55 17,12.68 17,14v8H20zM12.5,11.5c0.83,0 1.5,-0.67 1.5,-1.5s-0.67,-1.5 -1.5,-1.5S11,9.17 11,10S11.67,11.5 12.5,11.5zM5.5,6c1.11,0 2,-0.89 2,-2s-0.89,-2 -2,-2s-2,0.89 -2,2S4.39,6 5.5,6zM7.5,22v-7H9V9c0,-1.1 -0.9,-2 -2,-2H4C2.9,7 2,7.9 2,9v6h1.5v7H7.5zM14,22v-4h1v-4c0,-0.82 -0.68,-1.5 -1.5,-1.5h-2c-0.82,0 -1.5,0.68 -1.5,1.5v4h1v4H14z" />
|
||||||
|
</vector>
|
82
app/src/main/res/layout/dialog_account_edit_details.xml
Normal file
82
app/src/main/res/layout/dialog_account_edit_details.xml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="280dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/accountEditDetailsHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="Modify data"
|
||||||
|
android:textSize="21sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/accountEditDetailsNick"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="28dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:hint="Nick"
|
||||||
|
app:errorEnabled="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountEditDetailsHeader">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:inputType="textPersonName" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/accountEditDetailsSave"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
|
||||||
|
android:layout_width="88dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="Save"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountEditDetailsNick" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/accountEditDetailsCancel"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
|
||||||
|
android:layout_width="88dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="@android:string/cancel"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/accountEditDetailsSave"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountEditDetailsNick" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -8,23 +8,24 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/accountDialogTitle"
|
android:id="@+id/account_quick_dialog_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="24dp"
|
android:paddingStart="24dp"
|
||||||
android:paddingLeft="24dp"
|
android:paddingLeft="24dp"
|
||||||
android:paddingEnd="24dp"
|
android:paddingEnd="24dp"
|
||||||
android:paddingRight="24dp"
|
android:paddingRight="24dp"
|
||||||
android:text="@string/account_title"
|
android:text="@string/account_quick_title"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:firstBaselineToTopHeight="40dp" />
|
app:firstBaselineToTopHeight="40dp" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/accountDialogRecycler"
|
android:id="@+id/account_quick_dialog_recycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
@ -39,26 +40,12 @@
|
|||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/accountDialogAdd"
|
android:id="@+id/account_quick_dialog_manger"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:text="@string/account_add_new"
|
android:text="@string/account_quick_manager" />
|
||||||
android:textColor="?android:textColorPrimary" />
|
|
||||||
|
|
||||||
<Space
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/accountDialogRemove"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:text="@string/account_logout" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
91
app/src/main/res/layout/fragment_account.xml
Normal file
91
app/src/main/res/layout/fragment_account.xml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
android:id="@+id/account_progress"
|
||||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:indeterminate="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/accountRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/accountAdd"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:listitem="@layout/item_account" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/accountAdd"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="@string/account_add_new"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/account_error"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible"
|
||||||
|
tools:ignore="UseCompoundDrawables"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
app:srcCompat="@drawable/ic_all_account"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/account_error_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/error_unknown"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/account_error_details"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:text="@string/all_details" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/account_error_retry"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/all_retry" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
206
app/src/main/res/layout/fragment_account_details.xml
Normal file
206
app/src/main/res/layout/fragment_account_details.xml
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:fillViewport="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/accountDetailsSelect"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/accountDetailsAvatar"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_all_account"
|
||||||
|
app:tint="?colorPrimary"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/accountDetailsName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="24sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountDetailsAvatar"
|
||||||
|
tools:text="Jan Kowalski" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/accountDetailsSchool"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountDetailsName"
|
||||||
|
tools:text="Szkoła FakeLog" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/accountDetailsPersonalData"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountDetailsSchool"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:srcCompat="@drawable/ic_all_account"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/account_personal_data"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/accountDetailsAddressData"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountDetailsPersonalData"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:srcCompat="@drawable/ic_all_home"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/account_address"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/accountDetailsContactData"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountDetailsAddressData"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:srcCompat="@drawable/ic_all_phone"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/account_contact"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/accountDetailsFamilyData"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/accountDetailsContactData"
|
||||||
|
tools:ignore="UseCompoundDrawables">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:srcCompat="@drawable/ic_account_details_family"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="32dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:text="@string/account_family"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/accountDetailsSelect"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="@string/account_select_student"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/accountDetailsLogout" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/accountDetailsLogout"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:insetLeft="0dp"
|
||||||
|
android:insetTop="0dp"
|
||||||
|
android:insetRight="0dp"
|
||||||
|
android:insetBottom="0dp"
|
||||||
|
android:text="@string/account_logout"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -140,7 +140,7 @@
|
|||||||
android:id="@+id/schoolTelephoneButton"
|
android:id="@+id/schoolTelephoneButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:srcCompat="@drawable/ic_school_phone"
|
app:srcCompat="@drawable/ic_all_phone"
|
||||||
android:contentDescription="@string/school_telephone_button"
|
android:contentDescription="@string/school_telephone_button"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:tint="?colorPrimary"
|
android:tint="?colorPrimary"
|
||||||
|
108
app/src/main/res/layout/fragment_student_info.xml
Normal file
108
app/src/main/res/layout/fragment_student_info.xml
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
|
android:id="@+id/student_info_progress"
|
||||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminate="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:id="@+id/student_info_swipe"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/student_info_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/student_info_empty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="UseCompoundDrawables"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
app:srcCompat="@drawable/ic_all_about"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/student_info_empty"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/student_info_error"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="invisible"
|
||||||
|
tools:ignore="UseCompoundDrawables"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
app:srcCompat="@drawable/ic_error"
|
||||||
|
app:tint="?colorOnBackground"
|
||||||
|
tools:ignore="contentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/student_info_error_message"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/error_unknown"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/student_info_error_details"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:text="@string/all_details" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/student_info_error_retry"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/all_retry" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -4,15 +4,22 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="24dp"
|
android:paddingHorizontal="16dp"
|
||||||
android:paddingTop="8dp"
|
android:paddingBottom="16dp"
|
||||||
android:paddingBottom="8dp"
|
|
||||||
tools:context=".ui.modules.account.AccountAdapter">
|
tools:context=".ui.modules.account.AccountAdapter">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:id="@+id/accountHeaderDivider"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@color/colorDivider" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/accountHeaderEmail"
|
android:id="@+id/accountHeaderEmail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
android:textColor="?android:textColorPrimary"
|
android:textColor="?android:textColorPrimary"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
tools:text="jan@fakelog.cf" />
|
tools:text="jan@fakelog.cf" />
|
||||||
@ -21,7 +28,6 @@
|
|||||||
android:id="@+id/accountHeaderType"
|
android:id="@+id/accountHeaderType"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
tools:text="Konto ucznia" />
|
tools:text="Konto ucznia" />
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?selectableItemBackground"
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingVertical="8dp"
|
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="8dp"
|
||||||
tools:context=".ui.modules.account.AccountAdapter">
|
tools:context=".ui.modules.account.AccountAdapter">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@ -49,7 +51,7 @@
|
|||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/accountItemLoginMode"
|
android:id="@+id/accountItemAccountType"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
@ -58,7 +60,6 @@
|
|||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="?android:textColorSecondary"
|
android:textColor="?android:textColorSecondary"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/accountItemImage"
|
app:layout_constraintStart_toEndOf="@id/accountItemImage"
|
||||||
app:layout_constraintTop_toBottomOf="@id/accountItemSchool"
|
app:layout_constraintTop_toBottomOf="@id/accountItemSchool"
|
||||||
|
41
app/src/main/res/layout/item_student_info.xml
Normal file
41
app/src/main/res/layout/item_student_info.xml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/student_info_item_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/student_info_item_subtitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?android:textColorSecondary"
|
||||||
|
android:textSize="12sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/student_info_item_title"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
11
app/src/main/res/menu/action_menu_account_details.xml
Normal file
11
app/src/main/res/menu/action_menu_account_details.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?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/accountDetailsMenuEdit"
|
||||||
|
android:icon="@drawable/ic_menu_message_write"
|
||||||
|
android:orderInCategory="1"
|
||||||
|
android:title="@string/account_details_edit"
|
||||||
|
app:iconTint="@color/material_on_surface_emphasis_medium"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
</menu>
|
@ -17,7 +17,10 @@
|
|||||||
<string name="send_message_title">New message</string>
|
<string name="send_message_title">New message</string>
|
||||||
<string name="note_title">Notes and achievements</string>
|
<string name="note_title">Notes and achievements</string>
|
||||||
<string name="homework_title">Homework</string>
|
<string name="homework_title">Homework</string>
|
||||||
<string name="account_title">Choose account</string>
|
<string name="account_title">Accounts manager</string>
|
||||||
|
<string name="account_quick_title">Select account</string>
|
||||||
|
<string name="account_details_title">Account details</string>
|
||||||
|
<string name="student_info_title">Student info</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Subtitles-->
|
<!--Subtitles-->
|
||||||
@ -344,12 +347,19 @@
|
|||||||
<!--Account-->
|
<!--Account-->
|
||||||
<string name="account_add_new">Add account</string>
|
<string name="account_add_new">Add account</string>
|
||||||
<string name="account_logout">Logout</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_confirm">Do you want to log out this student?</string>
|
||||||
<string name="account_logout_student">Student logout</string>
|
<string name="account_logout_student">Student logout</string>
|
||||||
<string name="account_type_student">Student account</string>
|
<string name="account_type_student">Student account</string>
|
||||||
<string name="account_type_parent">Parent account</string>
|
<string name="account_type_parent">Parent account</string>
|
||||||
<string name="account_login_mobile_api">Mobile API mode</string>
|
<string name="account_login_mobile_api">Mobile API mode</string>
|
||||||
<string name="account_login_hybrid">Hybrid mode</string>
|
<string name="account_login_hybrid">Hybrid mode</string>
|
||||||
|
<string name="account_details_edit">Edit data</string>
|
||||||
|
<string name="account_quick_manager">Accounts manager</string>
|
||||||
|
<string name="account_select_student">Select student</string>
|
||||||
|
<string name="account_family">Family</string>
|
||||||
|
<string name="account_contact">Contact</string>
|
||||||
|
<string name="account_address">Residence details</string>
|
||||||
|
<string name="account_personal_data">Personal information</string>
|
||||||
|
|
||||||
|
|
||||||
<!--About-->
|
<!--About-->
|
||||||
@ -382,6 +392,28 @@
|
|||||||
<string name="contributor_see_more">See more on GitHub</string>
|
<string name="contributor_see_more">See more on GitHub</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!--Student info-->
|
||||||
|
<string name="student_info_empty">No info about student</string>
|
||||||
|
<string name="student_info_first_name">Name</string>
|
||||||
|
<string name="student_info_second_name">Second name</string>
|
||||||
|
<string name="student_info_gender">Gender</string>
|
||||||
|
<string name="student_info_polish_citizenship">Polish citizenship</string>
|
||||||
|
<string name="student_info_family_name">Family name</string>
|
||||||
|
<string name="student_info_parents_name">Mother\'s and father\'s names</string>
|
||||||
|
<string name="student_info_phone">Phone</string>
|
||||||
|
<string name="student_info_cellphone">Cellphone</string>
|
||||||
|
<string name="student_info_email">E-mail</string>
|
||||||
|
<string name="student_info_address">Address of residence</string>
|
||||||
|
<string name="student_info_registered_address">Address of registration</string>
|
||||||
|
<string name="student_info_correspondence_address">Correspondence address</string>
|
||||||
|
<string name="student_info_full_name">Surname and first name</string>
|
||||||
|
<string name="student_info_kinship">Degree of kinship</string>
|
||||||
|
<string name="student_info_guardian_address">Address</string>
|
||||||
|
<string name="student_info_phones">Phones</string>
|
||||||
|
<string name="student_info_male">Male</string>
|
||||||
|
<string name="student_info_female">Female</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Log viewer-->
|
<!--Log viewer-->
|
||||||
<string name="logviewer_share">Share logs</string>
|
<string name="logviewer_share">Share logs</string>
|
||||||
<string name="logviewer_refresh">Refresh</string>
|
<string name="logviewer_refresh">Refresh</string>
|
||||||
@ -410,6 +442,8 @@
|
|||||||
<string name="all_next">Next</string>
|
<string name="all_next">Next</string>
|
||||||
<string name="all_search">Search</string>
|
<string name="all_search">Search</string>
|
||||||
<string name="all_search_hint">Search…</string>
|
<string name="all_search_hint">Search…</string>
|
||||||
|
<string name="all_yes">Yes</string>
|
||||||
|
<string name="all_no">No</string>
|
||||||
|
|
||||||
|
|
||||||
<!--Timetable Widget-->
|
<!--Timetable Widget-->
|
||||||
@ -508,4 +542,5 @@
|
|||||||
<string name="error_unknown">An unexpected error occurred</string>
|
<string name="error_unknown">An unexpected error occurred</string>
|
||||||
<string name="error_feature_disabled">Feature disabled by your school</string>
|
<string name="error_feature_disabled">Feature disabled by your school</string>
|
||||||
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -35,7 +35,9 @@ class StudentTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testRemoteAll() {
|
fun testRemoteAll() {
|
||||||
coEvery { mockSdk.getStudentsFromScrapper(any(), any(), any(), any()) } returns listOf(getStudent("test"))
|
coEvery { mockSdk.getStudentsFromScrapper(any(), any(), any(), any()) } returns listOf(
|
||||||
|
getStudent("test")
|
||||||
|
)
|
||||||
|
|
||||||
val students = runBlocking { studentRepository.getStudentsScrapper("", "", "http://fakelog.cf", "") }
|
val students = runBlocking { studentRepository.getStudentsScrapper("", "", "http://fakelog.cf", "") }
|
||||||
assertEquals(1, students.size)
|
assertEquals(1, students.size)
|
||||||
|
@ -41,7 +41,29 @@ class GradeAverageProviderTest {
|
|||||||
|
|
||||||
private lateinit var gradeAverageProvider: GradeAverageProvider
|
private lateinit var gradeAverageProvider: GradeAverageProvider
|
||||||
|
|
||||||
private val student = Student("", "", "", "SCRAPPER", "", "", false, "", "", "", 101, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now())
|
private val student = Student(
|
||||||
|
scrapperBaseUrl = "",
|
||||||
|
mobileBaseUrl = "",
|
||||||
|
loginType = "",
|
||||||
|
loginMode = "SCRAPPER",
|
||||||
|
certificateKey = "",
|
||||||
|
privateKey = "",
|
||||||
|
isParent = false,
|
||||||
|
email = "",
|
||||||
|
password = "",
|
||||||
|
symbol = "",
|
||||||
|
studentId = 101,
|
||||||
|
userLoginId = 0,
|
||||||
|
userName = "",
|
||||||
|
studentName = "",
|
||||||
|
schoolSymbol = "",
|
||||||
|
schoolShortName = "",
|
||||||
|
schoolName = "",
|
||||||
|
className = "",
|
||||||
|
classId = 1,
|
||||||
|
isCurrent = true,
|
||||||
|
registrationDate = LocalDateTime.now()
|
||||||
|
)
|
||||||
|
|
||||||
private val semesters = mutableListOf(
|
private val semesters = mutableListOf(
|
||||||
getSemesterEntity(10, 21, of(2019, 1, 31), of(2019, 6, 23)),
|
getSemesterEntity(10, 21, of(2019, 1, 31), of(2019, 6, 23)),
|
||||||
|
@ -99,8 +99,32 @@ class LoginFormPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun loginTest() {
|
fun loginTest() {
|
||||||
val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf/", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, schoolShortName = "", isParent = false, userName = "")
|
val studentTest = Student(
|
||||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(StudentWithSemesters(studentTest, emptyList()))
|
email = "test@",
|
||||||
|
password = "123",
|
||||||
|
scrapperBaseUrl = "https://fakelog.cf/",
|
||||||
|
loginType = "AUTO",
|
||||||
|
studentName = "",
|
||||||
|
schoolSymbol = "",
|
||||||
|
schoolName = "",
|
||||||
|
studentId = 0,
|
||||||
|
classId = 1,
|
||||||
|
isCurrent = false,
|
||||||
|
symbol = "",
|
||||||
|
registrationDate = now(),
|
||||||
|
className = "",
|
||||||
|
mobileBaseUrl = "",
|
||||||
|
privateKey = "",
|
||||||
|
certificateKey = "",
|
||||||
|
loginMode = "",
|
||||||
|
userLoginId = 0,
|
||||||
|
schoolShortName = "",
|
||||||
|
isParent = false,
|
||||||
|
userName = ""
|
||||||
|
)
|
||||||
|
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(
|
||||||
|
StudentWithSemesters(studentTest, emptyList())
|
||||||
|
)
|
||||||
|
|
||||||
every { loginFormView.formUsernameValue } returns "@"
|
every { loginFormView.formUsernameValue } returns "@"
|
||||||
every { loginFormView.formPassValue } returns "123456"
|
every { loginFormView.formPassValue } returns "123456"
|
||||||
|
@ -38,7 +38,31 @@ class LoginStudentSelectPresenterTest {
|
|||||||
|
|
||||||
private lateinit var presenter: LoginStudentSelectPresenter
|
private lateinit var presenter: LoginStudentSelectPresenter
|
||||||
|
|
||||||
private val testStudent by lazy { Student(email = "test", password = "test123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "", loginMode = "", certificateKey = "", privateKey = "", mobileBaseUrl = "", schoolShortName = "", userLoginId = 1, isParent = false, userName = "") }
|
private val testStudent by lazy {
|
||||||
|
Student(
|
||||||
|
email = "test",
|
||||||
|
password = "test123",
|
||||||
|
scrapperBaseUrl = "https://fakelog.cf",
|
||||||
|
loginType = "AUTO",
|
||||||
|
symbol = "",
|
||||||
|
isCurrent = false,
|
||||||
|
studentId = 0,
|
||||||
|
schoolName = "",
|
||||||
|
schoolSymbol = "",
|
||||||
|
classId = 1,
|
||||||
|
studentName = "",
|
||||||
|
registrationDate = now(),
|
||||||
|
className = "",
|
||||||
|
loginMode = "",
|
||||||
|
certificateKey = "",
|
||||||
|
privateKey = "",
|
||||||
|
mobileBaseUrl = "",
|
||||||
|
schoolShortName = "",
|
||||||
|
userLoginId = 1,
|
||||||
|
isParent = false,
|
||||||
|
userName = ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val testException by lazy { RuntimeException("Problem") }
|
private val testException by lazy { RuntimeException("Problem") }
|
||||||
|
|
||||||
@ -64,8 +88,24 @@ class LoginStudentSelectPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onSelectedStudentTest() {
|
fun onSelectedStudentTest() {
|
||||||
coEvery { studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) } returns listOf(1L)
|
coEvery {
|
||||||
coEvery { studentRepository.switchStudent(StudentWithSemesters(testStudent, emptyList())) } just Runs
|
studentRepository.saveStudents(
|
||||||
|
listOf(
|
||||||
|
StudentWithSemesters(
|
||||||
|
testStudent,
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} returns listOf(1L)
|
||||||
|
coEvery {
|
||||||
|
studentRepository.switchStudent(
|
||||||
|
StudentWithSemesters(
|
||||||
|
testStudent,
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} just Runs
|
||||||
every { loginStudentSelectView.openMainView() } just Runs
|
every { loginStudentSelectView.openMainView() } just Runs
|
||||||
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
||||||
presenter.onSignIn()
|
presenter.onSignIn()
|
||||||
@ -77,7 +117,16 @@ class LoginStudentSelectPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onSelectedStudentErrorTest() {
|
fun onSelectedStudentErrorTest() {
|
||||||
coEvery { studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) } throws testException
|
coEvery {
|
||||||
|
studentRepository.saveStudents(
|
||||||
|
listOf(
|
||||||
|
StudentWithSemesters(
|
||||||
|
testStudent,
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} throws testException
|
||||||
coEvery { studentRepository.logoutStudent(testStudent) } just Runs
|
coEvery { studentRepository.logoutStudent(testStudent) } just Runs
|
||||||
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
||||||
presenter.onSignIn()
|
presenter.onSignIn()
|
||||||
|
@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
org.gradle.jvmargs=-Xmx1536m
|
kotlin.code.style=official
|
||||||
kapt.incremental.apt=true
|
kapt.incremental.apt=true
|
||||||
|
kapt.use.worker.api=true
|
||||||
|
kapt.include.compile.classpath=false
|
||||||
|
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
Loading…
x
Reference in New Issue
Block a user