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 name="NAME_COUNT_TO_USE_STAR_IMPORT" 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="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<MarkdownNavigatorCodeStyleSettings>
|
||||
<option name="RIGHT_MARGIN" value="72" />
|
||||
</MarkdownNavigatorCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
@ -143,13 +134,11 @@
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<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_CODE" value="1" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||
<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>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
|
@ -131,14 +131,14 @@ play {
|
||||
|
||||
ext {
|
||||
work_manager = "2.5.0"
|
||||
room = "2.2.6"
|
||||
room = "2.3.0-alpha04"
|
||||
chucker = "3.4.0"
|
||||
mockk = "1.10.5"
|
||||
moshi = "1.11.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "io.github.wulkanowy:sdk:a722e777"
|
||||
implementation "io.github.wulkanowy:sdk:b7576e86"
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
||||
|
||||
@ -214,6 +214,7 @@ dependencies {
|
||||
testImplementation "junit:junit:4.13.1"
|
||||
testImplementation "io.mockk:mockk:$mockk"
|
||||
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: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) }
|
||||
|
||||
// for debug only
|
||||
addInterceptor(ChuckerInterceptor.Builder(context)
|
||||
.collector(chuckerCollector)
|
||||
.alwaysReadResponseBody(true)
|
||||
.build(), network = true
|
||||
addInterceptor(
|
||||
ChuckerInterceptor.Builder(context)
|
||||
.collector(chuckerCollector)
|
||||
.alwaysReadResponseBody(true)
|
||||
.build(), network = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
|
||||
fun provideChuckerCollector(
|
||||
@ApplicationContext context: Context,
|
||||
prefRepository: PreferencesRepository
|
||||
): ChuckerCollector {
|
||||
return ChuckerCollector(
|
||||
context = context,
|
||||
showNotification = prefRepository.isDebugNotificationEnable,
|
||||
@ -53,7 +57,10 @@ internal class RepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
|
||||
fun provideDatabase(
|
||||
@ApplicationContext context: Context,
|
||||
sharedPrefProvider: SharedPrefProvider,
|
||||
) = AppDatabase.newInstance(context, sharedPrefProvider)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@ -65,7 +72,8 @@ internal class RepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@ -89,7 +97,8 @@ internal class RepositoryModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideGradeSemesterStatisticsDao(database: AppDatabase) = database.gradeSemesterStatisticsDao
|
||||
fun provideGradeSemesterStatisticsDao(database: AppDatabase) =
|
||||
database.gradeSemesterStatisticsDao
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@ -166,4 +175,8 @@ internal class RepositoryModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
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.SemesterDao
|
||||
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.TeacherDao
|
||||
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.Semester
|
||||
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.Teacher
|
||||
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.Migration3
|
||||
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.Migration5
|
||||
import io.github.wulkanowy.data.db.migrations.Migration6
|
||||
@ -116,6 +119,7 @@ import javax.inject.Singleton
|
||||
School::class,
|
||||
Conference::class,
|
||||
TimetableAdditional::class,
|
||||
StudentInfo::class,
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
@ -124,7 +128,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 30
|
||||
const val VERSION_SCHEMA = 31
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
|
||||
return arrayOf(
|
||||
@ -157,6 +161,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
Migration28(),
|
||||
Migration29(),
|
||||
Migration30(),
|
||||
Migration31()
|
||||
)
|
||||
}
|
||||
|
||||
@ -219,4 +224,6 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract val conferenceDao: ConferenceDao
|
||||
|
||||
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.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(
|
||||
|
||||
@ColumnInfo(name = "scrapper_base_url")
|
||||
@ -52,7 +58,7 @@ data class Student(
|
||||
@ColumnInfo(name = "school_id")
|
||||
val schoolSymbol: String,
|
||||
|
||||
@ColumnInfo(name ="school_short")
|
||||
@ColumnInfo(name = "school_short")
|
||||
val schoolShortName: String,
|
||||
|
||||
@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
|
||||
) {
|
||||
|
||||
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
|
||||
shouldFetch = { it == null || forceRefresh },
|
||||
query = { schoolDb.load(semester.studentId, semester.classId) },
|
||||
fetch = { sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool().mapToEntity(semester) },
|
||||
saveFetchResult = { old, new ->
|
||||
if (new != old && old != null) {
|
||||
schoolDb.deleteAll(listOf(old))
|
||||
schoolDb.insertAll(listOf(new))
|
||||
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
|
||||
networkBoundResource(
|
||||
shouldFetch = { it == null || forceRefresh },
|
||||
query = { schoolDb.load(semester.studentId, semester.classId) },
|
||||
fetch = {
|
||||
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool()
|
||||
.mapToEntity(semester)
|
||||
},
|
||||
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?>?
|
||||
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?>?
|
||||
|
@ -8,16 +8,16 @@ import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.databinding.HeaderAccountBinding
|
||||
import io.github.wulkanowy.databinding.ItemAccountBinding
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import javax.inject.Inject
|
||||
|
||||
class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
var isAccountQuickDialogMode = false
|
||||
|
||||
var items = emptyList<AccountItem<*>>()
|
||||
|
||||
var onClickListener: (StudentWithSemesters) -> Unit = {}
|
||||
@ -30,54 +30,69 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.V
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (viewType) {
|
||||
AccountItem.ViewType.HEADER.id -> HeaderViewHolder(HeaderAccountBinding.inflate(inflater, parent, false))
|
||||
AccountItem.ViewType.ITEM.id -> ItemViewHolder(ItemAccountBinding.inflate(inflater, parent, false))
|
||||
AccountItem.ViewType.HEADER.id -> HeaderViewHolder(
|
||||
HeaderAccountBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
AccountItem.ViewType.ITEM.id -> ItemViewHolder(
|
||||
ItemAccountBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is HeaderViewHolder -> bindHeaderViewHolder(holder.binding, items[position].value as Account)
|
||||
is ItemViewHolder -> bindItemViewHolder(holder.binding, items[position].value as StudentWithSemesters)
|
||||
is HeaderViewHolder -> bindHeaderViewHolder(
|
||||
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) {
|
||||
accountHeaderDivider.visibility = if (position == 0) GONE else VISIBLE
|
||||
accountHeaderEmail.text = account.email
|
||||
accountHeaderType.setText(if (account.isParent) R.string.account_type_parent else R.string.account_type_student)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindItemViewHolder(binding: ItemAccountBinding, studentWithSemesters: StudentWithSemesters) {
|
||||
private fun bindItemViewHolder(
|
||||
binding: ItemAccountBinding,
|
||||
studentWithSemesters: StudentWithSemesters
|
||||
) {
|
||||
val student = studentWithSemesters.student
|
||||
val semesters = studentWithSemesters.semesters
|
||||
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) {
|
||||
accountItemName.text = "${student.studentName} ${diary?.diaryName.orEmpty()}"
|
||||
accountItemSchool.text = studentWithSemesters.student.schoolName
|
||||
with(accountItemLoginMode) {
|
||||
visibility = when (Sdk.Mode.valueOf(student.loginMode)) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
accountItemAccountType.setText(if (student.isParent) R.string.account_type_parent else R.string.account_type_student)
|
||||
accountItemAccountType.visibility = if (isDuplicatedStudent) VISIBLE else GONE
|
||||
|
||||
with(accountItemImage) {
|
||||
val colorImage = if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary)
|
||||
else context.getThemeAttrColor(R.attr.colorOnSurface, 153)
|
||||
val colorImage =
|
||||
if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary)
|
||||
else context.getThemeAttrColor(R.attr.colorOnSurface, 153)
|
||||
|
||||
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.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.utils.afterLoading
|
||||
@ -15,101 +14,85 @@ import javax.inject.Inject
|
||||
class AccountPresenter @Inject constructor(
|
||||
errorHandler: ErrorHandler,
|
||||
studentRepository: StudentRepository,
|
||||
private val syncManager: SyncManager
|
||||
) : BasePresenter<AccountView>(errorHandler, studentRepository) {
|
||||
|
||||
private lateinit var lastError: Throwable
|
||||
|
||||
override fun onAttachView(view: AccountView) {
|
||||
super.onAttachView(view)
|
||||
view.initView()
|
||||
Timber.i("Account dialog view was initialized")
|
||||
Timber.i("Account view was initialized")
|
||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onRetry() {
|
||||
view?.run {
|
||||
showErrorView(false)
|
||||
showProgress(true)
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onDetailsClick() {
|
||||
view?.showErrorDetailsDialog(lastError)
|
||||
}
|
||||
|
||||
fun onAddSelected() {
|
||||
Timber.i("Select add account")
|
||||
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) {
|
||||
Timber.i("Select student item ${studentWithSemesters.student.id}")
|
||||
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")
|
||||
view?.openAccountDetailsView(studentWithSemesters)
|
||||
}
|
||||
|
||||
private fun createAccountItems(items: List<StudentWithSemesters>): List<AccountItem<*>> {
|
||||
return items.groupBy { Account(it.student.email, it.student.isParent) }.map { (account, students) ->
|
||||
listOf(AccountItem(account, AccountItem.ViewType.HEADER)) + students.map { student ->
|
||||
AccountItem(student, AccountItem.ViewType.ITEM)
|
||||
return items.groupBy {
|
||||
Account("${it.student.userName} (${it.student.email})", it.student.isParent)
|
||||
}
|
||||
.map { (account, students) ->
|
||||
listOf(
|
||||
AccountItem(account, AccountItem.ViewType.HEADER)
|
||||
) + students.map { student ->
|
||||
AccountItem(student, AccountItem.ViewType.ITEM)
|
||||
}
|
||||
}
|
||||
}.flatten()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
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!!)
|
||||
flowWithResource { studentRepository.getSavedStudents() }
|
||||
.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!!))
|
||||
view?.run {
|
||||
showContent(true)
|
||||
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
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.ui.base.BaseView
|
||||
|
||||
interface AccountView : BaseView {
|
||||
|
||||
val isViewEmpty: Boolean
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<AccountItem<*>>)
|
||||
|
||||
fun dismissView()
|
||||
|
||||
fun showConfirmDialog()
|
||||
|
||||
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
|
||||
|
||||
private var actionMode: ActionMode? = null
|
||||
|
||||
private val actionModeCallback = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
val inflater = mode.menuInflater
|
||||
|
@ -14,6 +14,7 @@ import android.os.Build.VERSION_CODES.LOLLIPOP
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.ViewCompat
|
||||
@ -28,7 +29,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||
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.exam.ExamFragment
|
||||
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 navController = FragNavController(supportFragmentManager, R.id.mainFragmentContainer)
|
||||
private val navController =
|
||||
FragNavController(supportFragmentManager, R.id.mainFragmentContainer)
|
||||
|
||||
companion object {
|
||||
const val EXTRA_START_MENU = "extraStartMenu"
|
||||
|
||||
fun getStartIntent(context: Context, startMenu: MainView.Section? = null, clear: Boolean = false): Intent {
|
||||
return 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) }
|
||||
}
|
||||
fun getStartIntent(
|
||||
context: Context,
|
||||
startMenu: MainView.Section? = null,
|
||||
clear: Boolean = false
|
||||
) = 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 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
|
||||
|
||||
@ -106,7 +112,10 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
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) {
|
||||
initialize(startMenuIndex, savedInstanceState)
|
||||
@ -132,21 +141,49 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
val shortcutsList = mutableListOf<ShortcutInfo>()
|
||||
|
||||
listOf(
|
||||
Triple(getString(R.string.grade_title), R.drawable.ic_shortcut_grade, MainView.Section.GRADE),
|
||||
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)
|
||||
Triple(
|
||||
getString(R.string.grade_title),
|
||||
R.drawable.ic_shortcut_grade,
|
||||
MainView.Section.GRADE
|
||||
),
|
||||
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) ->
|
||||
shortcutsList.add(ShortcutInfo.Builder(applicationContext, title)
|
||||
.setShortLabel(title)
|
||||
.setLongLabel(title)
|
||||
.setIcon(Icon.createWithResource(applicationContext, icon))
|
||||
.setIntents(arrayOf(
|
||||
Intent(applicationContext, MainActivity::class.java).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())
|
||||
shortcutsList.add(
|
||||
ShortcutInfo.Builder(applicationContext, title)
|
||||
.setShortLabel(title)
|
||||
.setLongLabel(title)
|
||||
.setIcon(Icon.createWithResource(applicationContext, icon))
|
||||
.setIntents(
|
||||
arrayOf(
|
||||
Intent(applicationContext, MainActivity::class.java)
|
||||
.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
|
||||
@ -160,20 +197,33 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
override fun initView() {
|
||||
with(binding.mainToolbar) {
|
||||
if (SDK_INT >= LOLLIPOP) stateListAnimator = null
|
||||
setBackgroundColor(overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f)))
|
||||
setBackgroundColor(
|
||||
overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(4f))
|
||||
)
|
||||
}
|
||||
|
||||
with(binding.mainBottomNav) {
|
||||
addItems(listOf(
|
||||
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_main_grade, 0),
|
||||
AHBottomNavigationItem(R.string.attendance_title, 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)
|
||||
))
|
||||
addItems(
|
||||
listOf(
|
||||
AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_main_grade, 0),
|
||||
AHBottomNavigationItem(
|
||||
R.string.attendance_title,
|
||||
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)
|
||||
inactiveColor = getThemeAttrColor(R.attr.colorOnSurface, 153)
|
||||
defaultBackgroundColor = overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f))
|
||||
defaultBackgroundColor =
|
||||
overlayProvider.compositeOverlayWithThemeSurfaceColorIfNeeded(dpToPx(8f))
|
||||
titleState = ALWAYS_SHOW
|
||||
currentItem = startMenuIndex
|
||||
isBehaviorTranslationEnabled = false
|
||||
@ -183,6 +233,13 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
|
||||
with(navController) {
|
||||
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)
|
||||
presenter.onViewChange(section)
|
||||
}
|
||||
@ -224,7 +281,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
}
|
||||
|
||||
override fun showAccountPicker() {
|
||||
navController.showDialogFragment(AccountDialog.newInstance())
|
||||
navController.showDialogFragment(AccountQuickDialog.newInstance())
|
||||
}
|
||||
|
||||
override fun showActionBarElevation(show: Boolean) {
|
||||
|
@ -64,6 +64,8 @@ interface MainView : BaseView {
|
||||
LUCKY_NUMBER(8),
|
||||
SETTINGS(9),
|
||||
ABOUT(10),
|
||||
SCHOOL(11)
|
||||
SCHOOL(11),
|
||||
ACCOUNT(12),
|
||||
STUDENT_INFO(13)
|
||||
}
|
||||
}
|
||||
|
@ -81,10 +81,7 @@ class SchoolPresenter @Inject constructor(
|
||||
showEmpty(false)
|
||||
showErrorView(false)
|
||||
}
|
||||
analytics.logEvent(
|
||||
"load_item",
|
||||
"type" to "school"
|
||||
)
|
||||
analytics.logEvent("load_item", "type" to "school")
|
||||
} else view?.run {
|
||||
Timber.i("Loading school result: No school info found")
|
||||
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")
|
||||
open val systemLanguage: String
|
||||
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.Status
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
@ -71,24 +72,14 @@ inline fun <ResultType, RequestType, T> networkBoundResource(
|
||||
|
||||
fun <T> flowWithResource(block: suspend () -> T) = flow {
|
||||
emit(Resource.loading())
|
||||
emit(try {
|
||||
Resource.success(block())
|
||||
} catch (e: Throwable) {
|
||||
Resource.error(e)
|
||||
})
|
||||
}
|
||||
emit(Resource.success(block()))
|
||||
}.catch { emit(Resource.error(it)) }
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
fun <T> flowWithResourceIn(block: suspend () -> Flow<Resource<T>>) = flow {
|
||||
emit(Resource.loading())
|
||||
|
||||
block()
|
||||
.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
emitAll(block().filter { it.status != Status.LOADING || (it.status == Status.LOADING && it.data != null) })
|
||||
}.catch { emit(Resource.error(it)) }
|
||||
|
||||
fun <T> Flow<Resource<T>>.afterLoading(callback: () -> Unit) = onEach {
|
||||
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>>.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 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.exam.ExamFragment
|
||||
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.schoolandteachers.SchoolAndTeachersFragment
|
||||
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
|
||||
import io.github.wulkanowy.ui.modules.studentinfo.StudentInfoFragment
|
||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||
|
||||
fun Fragment.toSection(): MainView.Section? {
|
||||
@ -29,6 +32,9 @@ fun Fragment.toSection(): MainView.Section? {
|
||||
is SettingsFragment -> MainView.Section.SETTINGS
|
||||
is AboutFragment -> MainView.Section.ABOUT
|
||||
is SchoolAndTeachersFragment -> MainView.Section.SCHOOL
|
||||
is AccountFragment -> MainView.Section.ACCOUNT
|
||||
is AccountDetailsFragment -> MainView.Section.ACCOUNT
|
||||
is StudentInfoFragment -> MainView.Section.STUDENT_INFO
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accountDialogTitle"
|
||||
android:id="@+id/account_quick_dialog_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingRight="24dp"
|
||||
android:text="@string/account_title"
|
||||
android:text="@string/account_quick_title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:firstBaselineToTopHeight="40dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/accountDialogRecycler"
|
||||
android:id="@+id/account_quick_dialog_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
@ -39,26 +40,12 @@
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/accountDialogAdd"
|
||||
android:id="@+id/account_quick_dialog_manger"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/account_add_new"
|
||||
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" />
|
||||
android:text="@string/account_quick_manager" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</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:layout_width="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:background="?attr/selectableItemBackgroundBorderless"
|
||||
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_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
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
|
||||
android:id="@+id/accountHeaderEmail"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="14sp"
|
||||
tools:text="jan@fakelog.cf" />
|
||||
@ -21,7 +28,6 @@
|
||||
android:id="@+id/accountHeaderType"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
tools:text="Konto ucznia" />
|
||||
|
@ -5,9 +5,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="8dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp"
|
||||
tools:context=".ui.modules.account.AccountAdapter">
|
||||
|
||||
<ImageView
|
||||
@ -49,7 +51,7 @@
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accountItemLoginMode"
|
||||
android:id="@+id/accountItemAccountType"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
@ -58,7 +60,6 @@
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/accountItemImage"
|
||||
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="note_title">Notes and achievements</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-->
|
||||
@ -344,12 +347,19 @@
|
||||
<!--Account-->
|
||||
<string name="account_add_new">Add account</string>
|
||||
<string name="account_logout">Logout</string>
|
||||
<string name="account_confirm">Do you want to log out of an active student?</string>
|
||||
<string name="account_confirm">Do you want to log out this student?</string>
|
||||
<string name="account_logout_student">Student logout</string>
|
||||
<string name="account_type_student">Student account</string>
|
||||
<string name="account_type_parent">Parent account</string>
|
||||
<string name="account_login_mobile_api">Mobile API 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-->
|
||||
@ -382,6 +392,28 @@
|
||||
<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-->
|
||||
<string name="logviewer_share">Share logs</string>
|
||||
<string name="logviewer_refresh">Refresh</string>
|
||||
@ -410,6 +442,8 @@
|
||||
<string name="all_next">Next</string>
|
||||
<string name="all_search">Search</string>
|
||||
<string name="all_search_hint">Search…</string>
|
||||
<string name="all_yes">Yes</string>
|
||||
<string name="all_no">No</string>
|
||||
|
||||
|
||||
<!--Timetable Widget-->
|
||||
@ -508,4 +542,5 @@
|
||||
<string name="error_unknown">An unexpected error occurred</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>
|
||||
|
||||
</resources>
|
||||
|
@ -35,7 +35,9 @@ class StudentTest {
|
||||
|
||||
@Test
|
||||
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", "") }
|
||||
assertEquals(1, students.size)
|
||||
|
@ -41,7 +41,29 @@ class GradeAverageProviderTest {
|
||||
|
||||
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(
|
||||
getSemesterEntity(10, 21, of(2019, 1, 31), of(2019, 6, 23)),
|
||||
|
@ -99,8 +99,32 @@ class LoginFormPresenterTest {
|
||||
|
||||
@Test
|
||||
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 = "")
|
||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(StudentWithSemesters(studentTest, emptyList()))
|
||||
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 = ""
|
||||
)
|
||||
coEvery { repository.getStudentsScrapper(any(), any(), any(), any()) } returns listOf(
|
||||
StudentWithSemesters(studentTest, emptyList())
|
||||
)
|
||||
|
||||
every { loginFormView.formUsernameValue } returns "@"
|
||||
every { loginFormView.formPassValue } returns "123456"
|
||||
|
@ -38,7 +38,31 @@ class LoginStudentSelectPresenterTest {
|
||||
|
||||
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") }
|
||||
|
||||
@ -64,8 +88,24 @@ class LoginStudentSelectPresenterTest {
|
||||
|
||||
@Test
|
||||
fun onSelectedStudentTest() {
|
||||
coEvery { studentRepository.saveStudents(listOf(StudentWithSemesters(testStudent, emptyList()))) } returns listOf(1L)
|
||||
coEvery { studentRepository.switchStudent(StudentWithSemesters(testStudent, emptyList())) } just Runs
|
||||
coEvery {
|
||||
studentRepository.saveStudents(
|
||||
listOf(
|
||||
StudentWithSemesters(
|
||||
testStudent,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
)
|
||||
} returns listOf(1L)
|
||||
coEvery {
|
||||
studentRepository.switchStudent(
|
||||
StudentWithSemesters(
|
||||
testStudent,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
} just Runs
|
||||
every { loginStudentSelectView.openMainView() } just Runs
|
||||
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
||||
presenter.onSignIn()
|
||||
@ -77,7 +117,16 @@ class LoginStudentSelectPresenterTest {
|
||||
|
||||
@Test
|
||||
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
|
||||
presenter.onItemSelected(StudentWithSemesters(testStudent, emptyList()), false)
|
||||
presenter.onSignIn()
|
||||
|
@ -7,10 +7,13 @@
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
kotlin.code.style=official
|
||||
kapt.incremental.apt=true
|
||||
kapt.use.worker.api=true
|
||||
kapt.include.compile.classpath=false
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
|
Loading…
x
Reference in New Issue
Block a user