1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-20 00:49:10 -05:00

Add teachers (#489)

This commit is contained in:
Dominik Korsa 2019-09-29 18:09:53 +02:00 committed by Mikołaj Pich
parent ed7996299e
commit a45bc0eef6
26 changed files with 2054 additions and 5 deletions

View File

@ -123,7 +123,7 @@ configurations.all {
}
dependencies {
implementation "io.github.wulkanowy:api:0.10.2"
implementation "io.github.wulkanowy:api:23ae9f6"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:1.1.0"

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,8 @@ abstract class AbstractMigrationTest {
Migration12(),
Migration13(),
Migration14(),
Migration15()
Migration15(),
Migration16()
)
.build()
// close the database and release any stream resources when the test finishes

View File

@ -136,4 +136,8 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideMobileDevicesDao(database: AppDatabase) = database.mobileDeviceDao
@Singleton
@Provides
fun provideTeacherDao(database: AppDatabase) = database.teacherDao
}

View File

@ -23,6 +23,7 @@ import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
@ -41,6 +42,7 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.migrations.Migration10
import io.github.wulkanowy.data.db.migrations.Migration11
@ -48,6 +50,7 @@ import io.github.wulkanowy.data.db.migrations.Migration12
import io.github.wulkanowy.data.db.migrations.Migration13
import io.github.wulkanowy.data.db.migrations.Migration14
import io.github.wulkanowy.data.db.migrations.Migration15
import io.github.wulkanowy.data.db.migrations.Migration16
import io.github.wulkanowy.data.db.migrations.Migration2
import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4
@ -78,7 +81,8 @@ import javax.inject.Singleton
CompletedLesson::class,
ReportingUnit::class,
Recipient::class,
MobileDevice::class
MobileDevice::class,
Teacher::class
],
version = AppDatabase.VERSION_SCHEMA,
exportSchema = true
@ -87,7 +91,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 15
const val VERSION_SCHEMA = 16
fun newInstance(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
@ -108,7 +112,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration12(),
Migration13(),
Migration14(),
Migration15()
Migration15(),
Migration16()
)
.build()
}
@ -149,4 +154,6 @@ abstract class AppDatabase : RoomDatabase() {
abstract val recipientDao: RecipientDao
abstract val mobileDeviceDao: MobileDeviceDao
abstract val teacherDao: TeacherDao
}

View File

@ -0,0 +1,23 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Teacher
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
interface TeacherDao {
@Insert
fun insertAll(devices: List<Teacher>)
@Delete
fun deleteAll(devices: List<Teacher>)
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Maybe<List<Teacher>>
}

View File

@ -0,0 +1,27 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity(tableName = "Teachers")
data class Teacher(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "class_id")
val classId: Int,
val subject: String,
val name: String,
@ColumnInfo(name = "short_name")
val shortName: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration16 : Migration(15, 16) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS Teachers (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
class_id INTEGER NOT NULL,
subject TEXT NOT NULL,
name TEXT NOT NULL,
short_name TEXT NOT NULL
)
""")
}
}

View File

@ -0,0 +1,21 @@
package io.github.wulkanowy.data.repositories.teacher
import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Teacher
import io.reactivex.Maybe
import javax.inject.Inject
class TeacherLocal @Inject constructor(private val teacherDb: TeacherDao) {
fun saveTeachers(teachers: List<Teacher>) {
teacherDb.insertAll(teachers)
}
fun deleteTeachers(teachers: List<Teacher>) {
teacherDb.deleteAll(teachers)
}
fun getTeachers(semester: Semester): Maybe<List<Teacher>> {
return teacherDb.loadAll(semester.studentId, semester.classId).filter { it.isNotEmpty() }
}
}

View File

@ -0,0 +1,28 @@
package io.github.wulkanowy.data.repositories.teacher
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Teacher
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class TeacherRemote @Inject constructor(private val api: Api) {
fun getTeachers(semester: Semester): Single<List<Teacher>> {
return Single.just(api.apply { diaryId = semester.diaryId })
.flatMap { it.getTeachers() }
.map { teachers ->
teachers.map {
Teacher(
studentId = semester.studentId,
name = it.name,
subject = it.subject,
shortName = it.short,
classId = semester.classId
)
}
}
}
}

View File

@ -0,0 +1,33 @@
package io.github.wulkanowy.data.repositories.teacher
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class TeacherRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: TeacherLocal,
private val remote: TeacherRemote
) {
fun getTeachers(semester: Semester, forceRefresh: Boolean = false): Single<List<Teacher>> {
return local.getTeachers(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getTeachers(semester)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getTeachers(semester).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteTeachers(old.uniqueSubtract(new))
local.saveTeachers(new.uniqueSubtract(old))
}
}.flatMap { local.getTeachers(semester).toSingle(emptyList()) })
}
}

View File

@ -21,6 +21,7 @@ import io.github.wulkanowy.services.sync.works.LuckyNumberWork
import io.github.wulkanowy.services.sync.works.MessageWork
import io.github.wulkanowy.services.sync.works.NoteWork
import io.github.wulkanowy.services.sync.works.RecipientWork
import io.github.wulkanowy.services.sync.works.TeacherWork
import io.github.wulkanowy.services.sync.works.TimetableWork
import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.services.widgets.TimetableWidgetService
@ -75,6 +76,10 @@ abstract class ServicesModule {
@IntoSet
abstract fun provideTimetableWork(work: TimetableWork): Work
@Binds
@IntoSet
abstract fun provideTeacherWork(work: TeacherWork): Work
@Binds
@IntoSet
abstract fun provideLuckyNumberWork(work: LuckyNumberWork): Work

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.teacher.TeacherRepository
import io.reactivex.Completable
import javax.inject.Inject
class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return teacherRepository.getTeachers(semester, true).ignoreElement()
}
}

View File

@ -27,6 +27,7 @@ import io.github.wulkanowy.ui.modules.mobiledevice.token.MobileDeviceTokenDialog
import io.github.wulkanowy.ui.modules.more.MoreFragment
import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
import io.github.wulkanowy.ui.modules.teacher.TeacherFragment
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
import io.github.wulkanowy.ui.modules.timetable.completed.CompletedLessonsFragment
@ -120,4 +121,8 @@ abstract class MainModule {
@PerFragment
@ContributesAndroidInjector(modules = [LicenseModule::class])
abstract fun bindLicenseFragment(): LicenseFragment
@PerFragment
@ContributesAndroidInjector
abstract fun bindTeacherFragment(): TeacherFragment
}

View File

@ -19,6 +19,7 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.mobiledevice.MobileDeviceFragment
import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.settings.SettingsFragment
import io.github.wulkanowy.ui.modules.teacher.TeacherFragment
import io.github.wulkanowy.utils.getCompatDrawable
import io.github.wulkanowy.utils.setOnItemClickListener
import kotlinx.android.synthetic.main.fragment_more.*
@ -54,6 +55,9 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
override val mobileDevicesRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.mobile_devices_title) to getCompatDrawable(R.drawable.ic_more_mobile_devices) }
override val teachersRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.teachers_title) to getCompatDrawable((R.drawable.ic_more_teacher)) }
override val settingsRes: Pair<String, Drawable?>?
get() = context?.run { getString(R.string.settings_title) to getCompatDrawable(R.drawable.ic_more_settings) }
@ -106,6 +110,10 @@ class MoreFragment : BaseFragment(), MoreView, MainView.TitledView, MainView.Mai
(activity as? MainActivity)?.pushView(MobileDeviceFragment.newInstance())
}
override fun openTeachersView() {
(activity as? MainActivity)?.pushView(TeacherFragment.newInstance())
}
override fun openSettingsView() {
(activity as? MainActivity)?.pushView(SettingsFragment.newInstance())
}

View File

@ -31,6 +31,7 @@ class MorePresenter @Inject constructor(
noteRes?.first -> openNoteView()
luckyNumberRes?.first -> openLuckyNumberView()
mobileDevicesRes?.first -> openMobileDevicesView()
teachersRes?.first -> openTeachersView()
settingsRes?.first -> openSettingsView()
aboutRes?.first -> openAboutView()
}
@ -51,6 +52,7 @@ class MorePresenter @Inject constructor(
noteRes?.let { MoreItem(it.first, it.second) },
luckyNumberRes?.let { MoreItem(it.first, it.second) },
mobileDevicesRes?.let { MoreItem(it.first, it.second) },
teachersRes?.let { MoreItem(it.first, it.second) },
settingsRes?.let { MoreItem(it.first, it.second) },
aboutRes?.let { MoreItem(it.first, it.second) })
)

View File

@ -15,6 +15,8 @@ interface MoreView : BaseView {
val mobileDevicesRes: Pair<String, Drawable?>?
val teachersRes: Pair<String, Drawable?>?
val settingsRes: Pair<String, Drawable?>?
val aboutRes: Pair<String, Drawable?>?
@ -38,4 +40,6 @@ interface MoreView : BaseView {
fun openLuckyNumberView()
fun openMobileDevicesView()
fun openTeachersView()
}

View File

@ -0,0 +1,93 @@
package io.github.wulkanowy.ui.modules.teacher
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainView
import kotlinx.android.synthetic.main.fragment_teacher.*
import javax.inject.Inject
class TeacherFragment : BaseFragment(), TeacherView, MainView.TitledView {
@Inject
lateinit var presenter: TeacherPresenter
@Inject
lateinit var teacherAdapter: FlexibleAdapter<AbstractFlexibleItem<*>>
companion object {
fun newInstance() = TeacherFragment()
}
override val titleStringId: Int
get() = R.string.teachers_title
override val noSubjectString get() = getString(R.string.teacher_no_subject)
override val isViewEmpty: Boolean
get() = teacherAdapter.isEmpty
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_teacher, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
presenter.onAttachView(this)
}
override fun initView() {
teacherRecycler.run {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = teacherAdapter
addItemDecoration(FlexibleItemDecoration(context)
.withDefaultDivider()
.withDrawDividerOnLastItem(false)
)
}
teacherSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
}
override fun updateData(data: List<TeacherItem>) {
teacherAdapter.updateDataSet(data, true)
}
override fun updateItem(item: AbstractFlexibleItem<*>) {
teacherAdapter.updateItem(item)
}
override fun clearData() {
teacherAdapter.clear()
}
override fun showEmpty(show: Boolean) {
teacherEmpty.visibility = if (show) View.VISIBLE else View.GONE
}
override fun showProgress(show: Boolean) {
teacherProgress.visibility = if (show) View.VISIBLE else View.GONE
}
override fun enableSwipe(enable: Boolean) {
teacherSwipe.isEnabled = enable
}
override fun showContent(show: Boolean) {
teacherRecycler.visibility = if (show) View.VISIBLE else View.GONE
}
override fun hideRefresh() {
teacherSwipe.isRefreshing = false
}
override fun onDestroyView() {
presenter.onDetachView()
super.onDestroyView()
}
}

View File

@ -0,0 +1,59 @@
package io.github.wulkanowy.ui.modules.teacher
import android.annotation.SuppressLint
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Teacher
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.item_teacher.*
class TeacherItem(val teacher: Teacher, private val noSubjectText: String) : AbstractFlexibleItem<TeacherItem.ViewHolder>() {
override fun getLayoutRes() = R.layout.item_teacher
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): TeacherItem.ViewHolder {
return TeacherItem.ViewHolder(view, adapter)
}
@SuppressLint("SetTextI18n")
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: TeacherItem.ViewHolder, position: Int, payloads: MutableList<Any>?) {
holder.apply {
teacherItemName.text = teacher.name
teacherItemSubject.text = if (teacher.subject.isNotBlank()) teacher.subject else noSubjectText
if (teacher.shortName.isNotBlank()) {
teacherItemShortName.visibility = VISIBLE
teacherItemShortName.text = "[${teacher.shortName}]"
} else {
teacherItemShortName.visibility = GONE
}
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as TeacherItem
if (teacher != other.teacher) return false
if (teacher.id != other.teacher.id) return false
return true
}
override fun hashCode(): Int {
var result = teacher.hashCode()
result = 31 * result + teacher.id.toInt()
return result
}
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
override val containerView: View
get() = contentView
}
}

View File

@ -0,0 +1,62 @@
package io.github.wulkanowy.ui.modules.teacher
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.data.repositories.teacher.TeacherRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import timber.log.Timber
import javax.inject.Inject
class TeacherPresenter @Inject constructor(
schedulers: SchedulersProvider,
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val semesterRepository: SemesterRepository,
private val teacherRepository: TeacherRepository,
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter<TeacherView>(errorHandler, studentRepository, schedulers) {
override fun onAttachView(view: TeacherView) {
super.onAttachView(view)
view.initView()
Timber.i("Teacher view was initialized")
loadData()
}
fun onSwipeRefresh() {
loadData(true)
}
private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading teachers data started")
disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { teacherRepository.getTeachers(it, forceRefresh) }
.map { it.filter { teacher -> teacher.name.isNotBlank() } }
.map { items -> items.map { TeacherItem(it, view?.noSubjectString.orEmpty()) } }
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doFinally {
view?.run {
hideRefresh()
showProgress(false)
enableSwipe(true)
}
}.subscribe({
Timber.i("Loading teachers result: Success")
view?.run {
updateData(it)
showContent(it.isNotEmpty())
showEmpty(it.isEmpty())
}
analytics.logEvent("load_teachers", "items" to it.size, "force_refresh" to forceRefresh)
}) {
Timber.i("Loading teachers result: An exception occurred")
errorHandler.dispatch(it)
})
}
}

View File

@ -0,0 +1,29 @@
package io.github.wulkanowy.ui.modules.teacher
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.ui.base.BaseView
interface TeacherView : BaseView {
val isViewEmpty: Boolean
val noSubjectString: String
fun initView()
fun updateData(data: List<TeacherItem>)
fun updateItem(item: AbstractFlexibleItem<*>)
fun hideRefresh()
fun clearData()
fun showProgress(show: Boolean)
fun enableSwipe(enable: Boolean)
fun showContent(show: Boolean)
fun showEmpty(show: Boolean)
}

View File

@ -0,0 +1,7 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path android:fillColor="#fff" android:pathData="M16.36 12.76C18.31 13.42 20 14.5 20 16V21H4V16C4 14.5 5.69 13.42 7.65 12.76L8.27 14L8.5 14.5C7 14.96 5.9 15.62 5.9 16V19.1H10.12L11 14.03L10.06 12.15C10.68 12.08 11.33 12.03 12 12.03C12.67 12.03 13.32 12.08 13.94 12.15L13 14.03L13.88 19.1H18.1V16C18.1 15.62 17 14.96 15.5 14.5L15.73 14L16.36 12.76M12 5C10.9 5 10 5.9 10 7C10 8.1 10.9 9 12 9C13.1 9 14 8.1 14 7C14 5.9 13.1 5 12 5M12 11C9.79 11 8 9.21 8 7C8 4.79 9.79 3 12 3C14.21 3 16 4.79 16 7C16 9.21 14.21 11 12 11Z" />
</vector>

View File

@ -0,0 +1,51 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/teacherProgress"
style="@style/Widget.MaterialProgressBar.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/teacherSwipe"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/teacherRecycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/teacherEmpty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
app:srcCompat="@drawable/ic_more_teacher"
app:tint="?colorOnBackground"
tools:ignore="contentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="@string/teacher_no_items"
android:textSize="20sp" />
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,54 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:paddingStart="12dp"
android:paddingLeft="12dp"
android:paddingTop="7dp"
android:paddingEnd="12dp"
android:paddingRight="12dp"
android:paddingBottom="7dp"
tools:context=".ui.modules.teacher.TeacherItem">
<TextView
android:id="@+id/teacherItemName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="17sp"
tools:text="@tools:sample/full_names" />
<TextView
android:id="@+id/teacherItemShortName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:layout_marginEnd="40dp"
android:layout_marginRight="40dp"
android:layout_toEndOf="@+id/teacherItemName"
android:layout_toRightOf="@+id/teacherItemName"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="17sp"
tools:text="[LI]" />
<TextView
android:id="@+id/teacherItemSubject"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/teacherItemName"
android:layout_alignStart="@id/teacherItemName"
android:layout_alignLeft="@id/teacherItemName"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
tools:text="11:11-12:00" />
</RelativeLayout>

View File

@ -216,6 +216,12 @@
<string name="mobile_device_pin">PIN</string>
<!--Teacher-->
<string name="teachers_title">Nauczyciele</string>
<string name="teacher_no_items">Brak informacji o nauczycielach</string>
<string name="teacher_no_subject">Brak przedmiotu</string>
<!--Account-->
<string name="account_add_new">Dodaj konto</string>
<string name="account_logout">Wyloguj</string>

View File

@ -200,6 +200,12 @@
<string name="mobile_device_pin">PIN</string>
<!--Teacher-->
<string name="teachers_title">Teachers</string>
<string name="teacher_no_items">No info about teachers</string>
<string name="teacher_no_subject">No subject</string>
<!--Account-->
<string name="account_add_new">Add account</string>
<string name="account_logout">Logout</string>