[Login] Add new login user interface.

This commit is contained in:
Kuba Szczodrzyński 2020-04-16 11:01:53 +02:00
parent 9b13552b73
commit 97dc8d12f1
89 changed files with 2196 additions and 4550 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -135,9 +135,6 @@
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/AppTheme.Light" /> android:theme="@style/AppTheme.Light" />
<activity android:name=".ui.modules.login.LoginLibrusCaptchaActivity"
android:theme="@android:style/Theme.Dialog"
android:excludeFromRecents="true"/>
<activity android:name=".ui.modules.home.CounterActivity" <activity android:name=".ui.modules.home.CounterActivity"
android:theme="@style/AppTheme.Black" /> android:theme="@style/AppTheme.Black" />
<activity android:name=".ui.modules.feedback.FeedbackActivity" <activity android:name=".ui.modules.feedback.FeedbackActivity"

View File

@ -167,6 +167,10 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
db.profileDao().firstId?.let { profileLoadById(it) } db.profileDao().firstId?.let { profileLoadById(it) }
} }
config.ui.language?.let {
setLanguage(it)
}
devMode = BuildConfig.DEBUG devMode = BuildConfig.DEBUG
Signing.getCert(this) Signing.getCert(this)

View File

@ -454,7 +454,7 @@ operator fun MatchResult.get(group: Int): String {
return groupValues[group] return groupValues[group]
} }
fun Activity.setLanguage(language: String) { fun Context.setLanguage(language: String) {
val locale = Locale(language.toLowerCase(Locale.ROOT)) val locale = Locale(language.toLowerCase(Locale.ROOT))
val configuration = resources.configuration val configuration = resources.configuration
Locale.setDefault(locale) Locale.setDefault(locale)
@ -463,7 +463,6 @@ fun Activity.setLanguage(language: String) {
} }
configuration.locale = locale configuration.locale = locale
resources.updateConfiguration(configuration, resources.displayMetrics) resources.updateConfiguration(configuration, resources.displayMetrics)
baseContext.resources.updateConfiguration(configuration, baseContext.resources.displayMetrics)
} }
/* /*

View File

@ -120,7 +120,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiLogin: String? = null private var mApiLogin: String? = null
var apiLogin: String? var apiLogin: String?
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin } get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
set(value) { profile?.putStudentData("accountLogin", value) ?: return; mApiLogin = value } set(value) { profile?.putStudentData("accountLogin", value); mApiLogin = value }
/** /**
* A Synergia password. * A Synergia password.
* Used: for login (API Login Method) in Synergia mode. * Used: for login (API Login Method) in Synergia mode.
@ -129,7 +129,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPassword: String? = null private var mApiPassword: String? = null
var apiPassword: String? var apiPassword: String?
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword } get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
set(value) { profile?.putStudentData("accountPassword", value) ?: return; mApiPassword = value } set(value) { profile?.putStudentData("accountPassword", value); mApiPassword = value }
/** /**
* A JST login Code. * A JST login Code.
@ -138,8 +138,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiCode: String? = null private var mApiCode: String? = null
var apiCode: String? var apiCode: String?
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode } get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
set(value) { set(value) { profile?.putStudentData("accountCode", value); mApiCode = value }
loginStore.putLoginData("accountCode", value); mApiCode = value }
/** /**
* A JST login PIN. * A JST login PIN.
* Used only during first login in JST mode. * Used only during first login in JST mode.
@ -147,8 +146,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPin: String? = null private var mApiPin: String? = null
var apiPin: String? var apiPin: String?
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin } get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
set(value) { set(value) { profile?.putStudentData("accountPin", value); mApiPin = value }
loginStore.putLoginData("accountPin", value); mApiPin = value }
/** /**
* A Synergia API access token. * A Synergia API access token.

View File

@ -116,7 +116,8 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
).apply { ).apply {
studentData["isPremium"] = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true studentData["isPremium"] = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true
studentData["accountId"] = account.getInt("Id") ?: 0 studentData["accountId"] = account.getInt("Id") ?: 0
studentData["accountLogin"] = login studentData["accountLogin"] = data.apiLogin ?: login
studentData["accountPassword"] = data.apiPassword
studentData["accountToken"] = data.apiAccessToken studentData["accountToken"] = data.apiAccessToken
studentData["accountTokenTime"] = data.apiTokenExpiryTime studentData["accountTokenTime"] = data.apiTokenExpiryTime
studentData["accountRefreshToken"] = data.apiRefreshToken studentData["accountRefreshToken"] = data.apiRefreshToken

View File

@ -146,12 +146,14 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
} }
val error = if (response.code() == 200) null else val error = if (response.code() == 200) null else
json.getJsonArray("errors")?.getString(0) json.getJsonArray("errors")?.getString(0)
?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString
error?.let { code -> error?.let { code ->
when { when {
code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED
code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
// this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set // this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set
code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL
code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR
}.let { errorCode -> }.let { errorCode ->
data.error(ApiError(TAG, errorCode) data.error(ApiError(TAG, errorCode)

View File

@ -197,6 +197,13 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
profile.userCode = generateUserCode() profile.userCode = generateUserCode()
// update profile subname with class name, school year and account type
profile.subname = joinNotNullStrings(
" - ",
profile.studentClassName,
"${profile.studentSchoolYearStart}/${profile.studentSchoolYearStart + 1}"
) + " " + app.getString(if (profile.isParent) R.string.account_type_parent else R.string.account_type_child)
db.profileDao().add(profile) db.profileDao().add(profile)
db.loginStoreDao().add(loginStore) db.loginStoreDao().add(loginStore)

View File

@ -27,6 +27,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
import retrofit2.Response import retrofit2.Response
@ -73,7 +74,7 @@ class SzkolnyApi(val app: App) : CoroutineScope {
suspend inline fun <T> runCatching(errorSnackbar: ErrorSnackbar, crossinline block: SzkolnyApi.() -> T?): T? { suspend inline fun <T> runCatching(errorSnackbar: ErrorSnackbar, crossinline block: SzkolnyApi.() -> T?): T? {
return try { return try {
withContext(Dispatchers.Default) { block() } withContext(Dispatchers.Default) { block.invoke(this@SzkolnyApi) }
} }
catch (e: Exception) { catch (e: Exception) {
errorSnackbar.addError(e.toApiError(TAG)).show() errorSnackbar.addError(e.toApiError(TAG)).show()
@ -82,7 +83,7 @@ class SzkolnyApi(val app: App) : CoroutineScope {
} }
suspend inline fun <T> runCatching(activity: AppCompatActivity, crossinline block: SzkolnyApi.() -> T?): T? { suspend inline fun <T> runCatching(activity: AppCompatActivity, crossinline block: SzkolnyApi.() -> T?): T? {
return try { return try {
withContext(Dispatchers.Default) { block() } withContext(Dispatchers.Default) { block.invoke(this@SzkolnyApi) }
} }
catch (e: Exception) { catch (e: Exception) {
ErrorDetailsDialog( ErrorDetailsDialog(
@ -95,7 +96,7 @@ class SzkolnyApi(val app: App) : CoroutineScope {
} }
inline fun <T> runCatching(block: SzkolnyApi.() -> T, onError: (e: Throwable) -> Unit): T? { inline fun <T> runCatching(block: SzkolnyApi.() -> T, onError: (e: Throwable) -> Unit): T? {
return try { return try {
block() block.invoke(this@SzkolnyApi)
} }
catch (e: Exception) { catch (e: Exception) {
onError(e) onError(e)
@ -327,4 +328,11 @@ class SzkolnyApi(val app: App) : CoroutineScope {
return parseResponse(response).message return parseResponse(response).message
} }
@Throws(Exception::class)
fun getPlatforms(registerName: String): List<LoginInfo.Platform> {
val response = api.appLoginPlatforms(registerName).execute()
return parseResponse(response)
}
} }

View File

@ -6,11 +6,9 @@ package pl.szczodrzynski.edziennik.data.api.szkolny
import pl.szczodrzynski.edziennik.data.api.szkolny.request.* import pl.szczodrzynski.edziennik.data.api.szkolny.request.*
import pl.szczodrzynski.edziennik.data.api.szkolny.response.* import pl.szczodrzynski.edziennik.data.api.szkolny.response.*
import pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo
import retrofit2.Call import retrofit2.Call
import retrofit2.http.Body import retrofit2.http.*
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
interface SzkolnyService { interface SzkolnyService {
@ -34,4 +32,7 @@ interface SzkolnyService {
@POST("feedbackMessage") @POST("feedbackMessage")
fun feedbackMessage(@Body request: FeedbackMessageRequest): Call<ApiResponse<FeedbackMessageResponse>> fun feedbackMessage(@Body request: FeedbackMessageRequest): Call<ApiResponse<FeedbackMessageResponse>>
@GET("appLogin/platforms/{registerName}")
fun appLoginPlatforms(@Path("registerName") registerName: String): Call<ApiResponse<List<LoginInfo.Platform>>>
} }

View File

@ -80,7 +80,7 @@ open class Profile(
var dateYearEnd = Date(studentSchoolYearStart + 1, 6, 30) var dateYearEnd = Date(studentSchoolYearStart + 1, 6, 30)
fun getSemesterStart(semester: Int) = if (semester == 1) dateSemester1Start else dateSemester2Start fun getSemesterStart(semester: Int) = if (semester == 1) dateSemester1Start else dateSemester2Start
fun getSemesterEnd(semester: Int) = if (semester == 1) dateSemester2Start.clone().stepForward(0, 0, -1) else dateYearEnd fun getSemesterEnd(semester: Int) = if (semester == 1) dateSemester2Start.clone().stepForward(0, 0, -1) else dateYearEnd
fun dateToSemester(date: Date) = if (date.value >= getSemesterStart(2).value) 2 else 1 fun dateToSemester(date: Date) = if (date >= dateSemester2Start) 2 else 1
@delegate:Ignore @delegate:Ignore
val currentSemester by lazy { dateToSemester(Date.getToday()) } val currentSemester by lazy { dateToSemester(Date.getToday()) }

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
import android.app.Activity import android.app.Activity
@ -14,20 +18,19 @@ import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.databinding.ActivityLoginBinding import pl.szczodrzynski.edziennik.databinding.LoginActivityBinding
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class LoginActivity : AppCompatActivity(), CoroutineScope { class LoginActivity : AppCompatActivity(), CoroutineScope {
companion object { companion object {
private const val TAG = "LoginActivity" private const val TAG = "LoginActivity"
@JvmField
var navOptions: NavOptions? = null
var thisOneIsTricky = 0 var thisOneIsTricky = 0
} }
private val app: App by lazy { applicationContext as App } private val app: App by lazy { applicationContext as App }
private lateinit var b: ActivityLoginBinding private lateinit var b: LoginActivityBinding
lateinit var navOptions: NavOptions
val nav by lazy { Navigation.findNavController(this, R.id.nav_host_fragment) } val nav by lazy { Navigation.findNavController(this, R.id.nav_host_fragment) }
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) } val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
@ -36,7 +39,7 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
var lastError: ApiError? = null var lastError: ApiError? = null
val profiles = mutableListOf<LoginSummaryProfileAdapter.Item>() val profiles = mutableListOf<LoginSummaryAdapter.Item>()
val loginStores = mutableListOf<LoginStore>() val loginStores = mutableListOf<LoginStore>()
override fun onBackPressed() { override fun onBackPressed() {
@ -50,7 +53,9 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
return return
if (destination.id == R.id.loginSyncFragment) if (destination.id == R.id.loginSyncFragment)
return return
if (destination.id == R.id.loginChooserFragment) { if (destination.id == R.id.loginFinishFragment)
return
if (destination.id == R.id.loginChooserFragment && loginStores.isEmpty()) {
setResult(Activity.RESULT_CANCELED) setResult(Activity.RESULT_CANCELED)
finish() finish()
return return
@ -83,7 +88,7 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
.setPopExitAnim(R.anim.slide_out_right) .setPopExitAnim(R.anim.slide_out_right)
.build() .build()
b = ActivityLoginBinding.inflate(layoutInflater) b = LoginActivityBinding.inflate(layoutInflater)
setContentView(b.root) setContentView(b.root)
errorSnackbar.setCoordinator(b.coordinator, b.snackbarAnchor) errorSnackbar.setCoordinator(b.coordinator, b.snackbarAnchor)

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.modules.grades.models.ExpandableItemModel
import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.BindableViewHolder
import pl.szczodrzynski.edziennik.ui.modules.login.viewholder.ModeViewHolder
import pl.szczodrzynski.edziennik.ui.modules.login.viewholder.RegisterViewHolder
import kotlin.coroutines.CoroutineContext
class LoginChooserAdapter(
val activity: AppCompatActivity,
val onModeClick: ((loginType: LoginInfo.Register, loginMode: LoginInfo.Mode) -> Unit)? = null
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), CoroutineScope {
companion object {
private const val TAG = "LoginChooserAdapter"
private const val ITEM_TYPE_REGISTER = 0
private const val ITEM_TYPE_MODE = 1
const val STATE_CLOSED = 0
const val STATE_OPENED = 1
}
private val app = activity.applicationContext as App
// optional: place the manager here
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
var items = mutableListOf<Any>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
ITEM_TYPE_REGISTER -> RegisterViewHolder(inflater, parent)
ITEM_TYPE_MODE -> ModeViewHolder(inflater, parent)
else -> throw IllegalArgumentException("Incorrect viewType")
}
}
override fun getItemViewType(position: Int): Int {
return when (items[position]) {
is LoginInfo.Register -> ITEM_TYPE_REGISTER
is LoginInfo.Mode -> ITEM_TYPE_MODE
else -> throw IllegalArgumentException("Incorrect viewType")
}
}
private val onClickListener = View.OnClickListener { view ->
val model = view.getTag(R.string.tag_key_model)
if (model is LoginInfo.Register && model.loginModes.size == 1) {
onModeClick?.invoke(model, model.loginModes.first())
return@OnClickListener
}
if (model is LoginInfo.Mode) {
val loginInfo = items.firstOrNull {
it is LoginInfo.Register && it.loginModes.contains(model)
} as? LoginInfo.Register
?: return@OnClickListener
onModeClick?.invoke(loginInfo, model)
return@OnClickListener
}
if (model !is LoginInfo.Register)
return@OnClickListener
expandModel(model, view)
}
private fun expandModel(model: LoginInfo.Register, view: View?, notifyAdapter: Boolean = true) {
val position = items.indexOf(model)
if (position == -1)
return
if (model.state == STATE_CLOSED) {
val subItems = model.items
model.state = STATE_OPENED
items.addAll(position + 1, subItems)
if (notifyAdapter) notifyItemRangeInserted(position + 1, subItems.size)
}
else {
val start = position + 1
var end: Int = items.size
for (i in start until items.size) {
val model1 = items[i]
val level = (model1 as? ExpandableItemModel<*>)?.level ?: 3
if (level <= model.level) {
end = i
break
} else {
if (model1 is ExpandableItemModel<*> && model1.state == STATE_OPENED) {
model1.state = STATE_CLOSED
}
}
}
if (end != -1) {
items.subList(start, end).clear()
if (notifyAdapter) notifyItemRangeRemoved(start, end - start)
}
model.state = STATE_CLOSED
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = items[position]
if (holder !is BindableViewHolder<*, *>)
return
holder.itemView.setTag(R.string.tag_key_model, item)
when {
holder is RegisterViewHolder && item is LoginInfo.Register -> holder.onBind(activity, app, item, position, this)
holder is ModeViewHolder && item is LoginInfo.Mode -> holder.onBind(activity, app, item, position, this)
}
holder.itemView.setOnClickListener(onClickListener)
}
override fun getItemCount() = items.size
}

View File

@ -1,78 +1,90 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.Process
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.AnimationUtils import androidx.core.view.isVisible
import android.widget.CompoundButton
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.afollestad.materialdialogs.DialogAction import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog import kotlinx.coroutines.CoroutineScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.Bundle
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.FragmentLoginChooserBinding import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
import pl.szczodrzynski.edziennik.onChange
import pl.szczodrzynski.edziennik.onClick import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.Anim import kotlin.coroutines.CoroutineContext
import kotlin.system.exitProcess
class LoginChooserFragment : Fragment(), CoroutineScope {
class LoginChooserFragment : Fragment() {
companion object { companion object {
private const val TAG = "LoginChooserFragment" private const val TAG = "LoginChooserFragment"
var fakeLogin = false
} }
private lateinit var app: App private lateinit var app: App
private lateinit var activity: LoginActivity private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginChooserBinding private lateinit var b: LoginChooserFragmentBinding
private val nav by lazy { activity.nav } private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null context ?: return null
app = activity.application as App app = activity.application as App
b = FragmentLoginChooserBinding.inflate(inflater) b = LoginChooserFragmentBinding.inflate(inflater)
return b.root return b.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
b.topLogo.onClick { if (!isAdded) return
if (LoginActivity.thisOneIsTricky <= -1) {
LoginActivity.thisOneIsTricky = 999 val adapter = LoginChooserAdapter(activity) { loginType, loginMode ->
} if (loginMode.isPlatformSelection) {
if (LoginActivity.thisOneIsTricky in 0..7) { nav.navigate(R.id.loginPlatformListFragment, Bundle(
LoginActivity.thisOneIsTricky++ "loginType" to loginType.loginType,
if (LoginActivity.thisOneIsTricky == 7) { "loginMode" to loginMode.loginMode
b.topLogo.startAnimation(AnimationUtils.loadAnimation(activity, R.anim.shake)); ), activity.navOptions)
if (b.devMode.visibility != View.VISIBLE) return@LoginChooserAdapter
Anim.expand(b.devMode, 500, null);
LoginActivity.thisOneIsTricky = 3
}
} }
nav.navigate(R.id.loginFormFragment, Bundle(
"loginType" to loginType.loginType,
"loginMode" to loginMode.loginMode
), activity.navOptions)
}
LoginInfo.chooserList = LoginInfo.chooserList
?: LoginInfo.list.toMutableList<Any>()
adapter.items = LoginInfo.chooserList!!
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
} }
b.loginMobidziennikLogo.onClick { nav.navigate(R.id.loginMobidziennikFragment, null, LoginActivity.navOptions) }
b.loginLibrusLogo.onClick { nav.navigate(R.id.loginLibrusFragment, null, LoginActivity.navOptions) }
b.loginVulcanLogo.onClick { nav.navigate(R.id.loginVulcanFragment, null, LoginActivity.navOptions) }
b.loginIuczniowieLogo.onClick { nav.navigate(R.id.loginIuczniowieFragment, null, LoginActivity.navOptions) }
b.loginLibrusJstLogo.onClick { nav.navigate(R.id.loginLibrusJstFragment, null, LoginActivity.navOptions) }
b.loginEdudziennikLogo.onClick { nav.navigate(R.id.loginEdudziennikFragment, null, LoginActivity.navOptions) }
when { when {
activity.loginStores.isNotEmpty() -> { activity.loginStores.isNotEmpty() -> {
// we are navigated here from LoginSummary // we are navigated here from LoginSummary
b.cancelButton.visibility = View.VISIBLE b.cancelButton.isVisible = true
b.cancelButton.onClick { nav.navigateUp() } b.cancelButton.onClick { nav.navigateUp() }
} }
app.config.loginFinished -> { app.config.loginFinished -> {
// we are navigated here from AppDrawer // we are navigated here from AppDrawer
b.cancelButton.visibility = View.VISIBLE b.cancelButton.isVisible = true
b.cancelButton.onClick { b.cancelButton.onClick {
activity.setResult(Activity.RESULT_CANCELED) activity.setResult(Activity.RESULT_CANCELED)
activity.finish() activity.finish()
@ -80,57 +92,8 @@ class LoginChooserFragment : Fragment() {
} }
else -> { else -> {
// there are no profiles // there are no profiles
b.cancelButton.visibility = View.GONE b.cancelButton.isVisible = false
} }
} }
b.devMode.visibility = if (App.debugMode) View.VISIBLE else View.GONE
b.devMode.isChecked = app.config.debugMode
b.devMode.onChange { v, isChecked ->
if (isChecked) {
MaterialDialog.Builder(activity)
.title(R.string.are_you_sure)
.content(R.string.dev_mode_enable_warning)
.positiveText(R.string.yes)
.negativeText(R.string.no)
.onPositive { _: MaterialDialog?, _: DialogAction? ->
app.config.debugMode = true
App.devMode = true
MaterialAlertDialogBuilder(activity)
.setTitle("Restart")
.setMessage("Wymagany restart aplikacji")
.setPositiveButton("OK") { _, _ ->
Process.killProcess(Process.myPid())
Runtime.getRuntime().exit(0)
exitProcess(0)
}
.setCancelable(false)
.show()
}
.onNegative { _: MaterialDialog?, _: DialogAction? ->
app.config.debugMode = false
App.devMode = false
b.devMode.isChecked = app.config.debugMode
b.devMode.jumpDrawablesToCurrentState()
Anim.collapse(b.devMode, 1000, null)
}
.show()
} else {
app.config.debugMode = false
App.devMode = false
/*if (b.devModeLayout.getVisibility() === View.VISIBLE) {
Anim.collapse(b.devModeTitle, 500, null)
Anim.collapse(b.devModeLayout, 500, null)
}*/
}
}
b.fakeLogin.visibility = if (App.devMode) View.VISIBLE else View.GONE
b.fakeLogin.isChecked = fakeLogin
b.fakeLogin.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
fakeLogin = isChecked
}
b.helpButton.onClick { startActivity(Intent(activity, FeedbackActivity::class.java)) }
} }
} }

View File

@ -1,121 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.animation.ArgbEvaluator
import android.animation.ObjectAnimator
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_EDUDZIENNIK
import pl.szczodrzynski.edziennik.databinding.FragmentLoginEdudziennikBinding
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginEdudziennikFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginEdudziennikFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginEdudziennikBinding
private val nav by lazy { activity.nav }
private var hehe = 0
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginEdudziennikBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN ->
b.loginPasswordLayout.error = getString(R.string.login_error_incorrect_login_or_password)
}
}
}
b.topText.onClick {
if (LoginActivity.thisOneIsTricky != -1)
return@onClick
hehe++
if (hehe >= 5) {
LoginActivity.thisOneIsTricky = 3
val colorAnim = ObjectAnimator.ofInt(
b.topText,
"textColor",
Color.BLACK,
Color.RED,
Color.BLACK,
Color.RED,
Color.BLACK,
Color.RED,
Color.BLACK
)
colorAnim.setEvaluator(ArgbEvaluator())
colorAnim.duration = 1500L
colorAnim.start()
}
}
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginEmailLayout.error = null
b.loginPasswordLayout.error = null
val email = b.loginEmail.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val password = b.loginPassword.text?.toString() ?: ""
if (email.isBlank()) {
b.loginEmailLayout.error = getString(R.string.login_error_no_email)
errors = true
}
if (password.isBlank()) {
b.loginPasswordLayout.error = getString(R.string.login_error_no_password)
errors = true
}
if (errors) return@onClick
errors = false
b.loginEmail.setText(email)
if (!"([\\w.\\-_+]+)?\\w+@[\\w-_]+(\\.\\w+)+".toRegex().matches(email)) {
b.loginEmailLayout.error = getString(R.string.login_error_incorrect_email)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_EDUDZIENNIK,
"email" to email,
"password" to password
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) Kuba Szczodrzyński 2020-1-4. * Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/ */
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
@ -14,7 +14,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.databinding.FragmentLoginFinishBinding import pl.szczodrzynski.edziennik.databinding.LoginFinishFragmentBinding
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class LoginFinishFragment : Fragment(), CoroutineScope { class LoginFinishFragment : Fragment(), CoroutineScope {
@ -24,27 +24,29 @@ class LoginFinishFragment : Fragment(), CoroutineScope {
private lateinit var app: App private lateinit var app: App
private lateinit var activity: LoginActivity private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginFinishBinding private lateinit var b: LoginFinishFragmentBinding
private val nav by lazy { activity.nav } private val nav by lazy { activity.nav }
private val job: Job = Job() private val job: Job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null context ?: return null
app = activity.application as App app = activity.application as App
b = FragmentLoginFinishBinding.inflate(inflater) b = LoginFinishFragmentBinding.inflate(inflater)
return b.root return b.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val firstRun = !App.config.loginFinished val firstRun = !app.config.loginFinished
App.config.loginFinished = true app.config.loginFinished = true
if (!firstRun) { if (!firstRun) {
b.loginFinishSubtitle.setText(R.string.login_finish_subtitle_not_first_run) b.subTitle.setText(R.string.login_finish_subtitle_not_first_run)
} }
b.finishButton.onClick { b.finishButton.onClick {
@ -74,4 +76,4 @@ class LoginFinishFragment : Fragment(), CoroutineScope {
} }
} }
} }
} }

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.annotation.SuppressLint
import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import com.google.android.material.textfield.TextInputLayout
import com.google.gson.JsonParser
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.utils.paddingDp
import com.mikepenz.iconics.utils.sizeDp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.databinding.LoginFormFragmentBinding
import pl.szczodrzynski.edziennik.databinding.LoginFormItemBinding
import pl.szczodrzynski.navlib.colorAttr
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginFormFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginFormFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: LoginFormFragmentBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = LoginFormFragmentBinding.inflate(inflater)
return b.root
}
@SuppressLint("ResourceType")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded) return
b.backButton.onClick { nav.navigateUp() }
b.errorLayout.isVisible = false
b.errorLayout.background?.setTintColor(R.attr.colorError.resolveAttr(activity))
val loginType = arguments?.getInt("loginType") ?: return
val register = LoginInfo.list.firstOrNull { it.loginType == loginType } ?: return
val loginMode = arguments?.getInt("loginMode") ?: return
val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return
val platformName = arguments?.getString("platformName")
val platformGuideText = arguments?.getString("platformGuideText")
val platformDescription = arguments?.getString("platformDescription")
val platformFormFields = arguments?.getString("platformFormFields")?.split(";")
val platformApiData = arguments?.getString("platformApiData")?.let { JsonParser().parse(it)?.asJsonObject }
b.title.setText(R.string.login_form_title_format, app.getString(register.registerName))
b.subTitle.text = platformName ?: app.getString(mode.name)
b.text.text = platformGuideText ?: app.getString(mode.guideText)
val credentials = mutableMapOf<LoginInfo.Credential, LoginFormItemBinding>()
for (credential in mode.credentials) {
if (platformFormFields?.contains(credential.keyName) == false)
continue
val b = LoginFormItemBinding.inflate(layoutInflater)
b.textLayout.hint = app.getString(credential.name)
if (credential.hideText) {
b.textEdit.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD
b.textLayout.endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE
}
b.textEdit.addTextChangedListener {
b.textLayout.error = null
}
b.textEdit.id = credential.name
b.textEdit.setText(arguments?.getString(credential.keyName) ?: "")
b.textLayout.startIconDrawable = IconicsDrawable(activity)
.icon(credential.icon)
.sizeDp(24)
.paddingDp(2)
.colorAttr(activity, R.attr.colorOnBackground)
this.b.formContainer.addView(b.root)
credentials[credential] = b
}
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 200L) {
for (credential in credentials) {
credential.key.errorCodes[error.errorCode]?.let {
credential.value.textLayout.error = app.getString(it)
return@startCoroutineTimer
}
}
mode.errorCodes[error.errorCode]?.let {
b.errorText.text = app.getString(it)
b.errorLayout.isVisible = true
return@startCoroutineTimer
}
}
}
b.loginButton.onClick {
val payload = Bundle(
"loginType" to loginType,
"loginMode" to loginMode
)
if (App.devMode && b.fakeLogin.isChecked) {
payload.putBoolean("fakeLogin", true)
}
platformApiData?.entrySet()?.forEach {
payload.putString(it.key, it.value.asString)
}
var hasErrors = false
credentials.forEach { (credential, b) ->
var text = b.textEdit.text?.toString() ?: return@forEach
if (!credential.hideText)
text = text.trim()
if (credential.caseMode == LoginInfo.Credential.CaseMode.UPPER_CASE)
text = text.toUpperCase(Locale.getDefault())
if (credential.caseMode == LoginInfo.Credential.CaseMode.LOWER_CASE)
text = text.toLowerCase(Locale.getDefault())
credential.stripTextRegex?.let {
text = text.replace(it.toRegex(), "")
}
b.textEdit.setText(text)
if (credential.isRequired && text.isBlank()) {
b.textLayout.error = app.getString(credential.emptyText)
hasErrors = true
return@forEach
}
if (!text.matches(credential.validationRegex.toRegex())) {
b.textLayout.error = app.getString(credential.invalidText)
hasErrors = true
return@forEach
}
payload.putString(credential.keyName, text)
arguments?.putString(credential.keyName, text)
}
if (hasErrors)
return@onClick
nav.navigate(R.id.loginProgressFragment, payload, activity.navOptions)
}
}
}

View File

@ -0,0 +1,358 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.google.gson.JsonObject
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.ui.modules.grades.models.ExpandableItemModel
object LoginInfo {
private fun getEmailCredential(keyName: String) = Credential(
keyName = keyName,
name = R.string.login_hint_email,
icon = CommunityMaterial.Icon.cmd_at,
emptyText = R.string.login_error_no_email,
invalidText = R.string.login_error_incorrect_email,
errorCodes = mapOf(),
isRequired = true,
validationRegex = "([\\w.\\-_+]+)?\\w+@[\\w-_]+(\\.\\w+)+",
caseMode = Credential.CaseMode.LOWER_CASE
)
private fun getPasswordCredential(keyName: String) = Credential(
keyName = keyName,
name = R.string.login_hint_password,
icon = CommunityMaterial.Icon2.cmd_lock_outline,
emptyText = R.string.login_error_no_password,
invalidText = R.string.login_error_incorrect_login_or_password,
errorCodes = mapOf(),
isRequired = true,
validationRegex = ".*",
hideText = true
)
val list by lazy { listOf(
Register(
loginType = LOGIN_TYPE_LIBRUS,
internalName = "librus",
registerName = R.string.login_register_librus,
registerLogo = R.drawable.login_logo_librus,
loginModes = listOf(
Mode(
loginMode = LOGIN_MODE_LIBRUS_EMAIL,
name = R.string.login_mode_librus_email,
icon = R.drawable.login_mode_librus_email,
hintText = R.string.login_mode_librus_email_hint,
guideText = R.string.login_mode_librus_email_guide,
isRecommended = true,
credentials = listOf(
getEmailCredential("email"),
getPasswordCredential("password")
),
errorCodes = mapOf(
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED to R.string.login_error_account_not_activated,
ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password,
ERROR_CAPTCHA_LIBRUS_PORTAL to R.string.error_3001_reason
)
),
Mode(
loginMode = LOGIN_MODE_LIBRUS_SYNERGIA,
name = R.string.login_mode_librus_synergia,
icon = R.drawable.login_mode_librus_synergia,
hintText = R.string.login_mode_librus_synergia_hint,
guideText = R.string.login_mode_librus_synergia_guide,
credentials = listOf(
Credential(
keyName = "accountLogin",
name = R.string.login_hint_login,
icon = CommunityMaterial.Icon.cmd_account_outline,
emptyText = R.string.login_error_no_login,
invalidText = R.string.login_error_incorrect_login,
errorCodes = mapOf(),
isRequired = true,
validationRegex = "[A-z0-9._\\-+]+",
caseMode = Credential.CaseMode.LOWER_CASE
),
getPasswordCredential("accountPassword")
),
errorCodes = mapOf(
ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password,
ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST to R.string.login_error_incorrect_login_or_password
)
),
Mode(
loginMode = LOGIN_MODE_LIBRUS_JST,
name = R.string.login_mode_librus_jst,
icon = R.drawable.login_mode_librus_jst,
hintText = R.string.login_mode_librus_jst_hint,
guideText = R.string.login_mode_librus_jst_guide,
credentials = listOf(
Credential(
keyName = "accountCode",
name = R.string.login_hint_token,
icon = CommunityMaterial.Icon.cmd_code_braces,
emptyText = R.string.login_error_no_token,
invalidText = R.string.login_error_incorrect_token,
errorCodes = mapOf(),
isRequired = true,
validationRegex = "[A-Z0-9_]+",
caseMode = Credential.CaseMode.UPPER_CASE
),
Credential(
keyName = "accountPin",
name = R.string.login_hint_pin,
icon = CommunityMaterial.Icon2.cmd_lock,
emptyText = R.string.login_error_no_pin,
invalidText = R.string.login_error_incorrect_pin,
errorCodes = mapOf(),
isRequired = true,
validationRegex = "[a-z0-9_]+",
caseMode = Credential.CaseMode.LOWER_CASE
)
),
errorCodes = mapOf(
ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN to R.string.login_error_incorrect_code_or_pin,
ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST to R.string.login_error_incorrect_code_or_pin
)
)
)
),
Register(
loginType = LOGIN_TYPE_VULCAN,
internalName = "vulcan",
registerName = R.string.login_type_vulcan,
registerLogo = R.drawable.login_logo_vulcan,
loginModes = listOf(
Mode(
loginMode = LOGIN_MODE_VULCAN_API,
name = R.string.login_mode_vulcan_api,
icon = R.drawable.login_mode_vulcan_api,
hintText = R.string.login_mode_vulcan_api_hint,
guideText = R.string.login_mode_vulcan_api_guide,
isRecommended = true,
credentials = listOf(
Credential(
keyName = "deviceToken",
name = R.string.login_hint_token,
icon = CommunityMaterial.Icon.cmd_code_braces,
emptyText = R.string.login_error_no_token,
invalidText = R.string.login_error_incorrect_token,
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_INVALID_TOKEN to R.string.login_error_incorrect_token
),
isRequired = true,
validationRegex = "[A-Z0-9]{5,12}",
caseMode = Credential.CaseMode.UPPER_CASE
),
Credential(
keyName = "deviceSymbol",
name = R.string.login_hint_symbol,
icon = CommunityMaterial.Icon2.cmd_school,
emptyText = R.string.login_error_no_symbol,
invalidText = R.string.login_error_incorrect_symbol,
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_INVALID_SYMBOL to R.string.login_error_incorrect_symbol
),
isRequired = true,
validationRegex = "[a-z0-9_-]+",
caseMode = Credential.CaseMode.LOWER_CASE
),
Credential(
keyName = "devicePin",
name = R.string.login_hint_pin,
icon = CommunityMaterial.Icon2.cmd_lock,
emptyText = R.string.login_error_no_pin,
invalidText = R.string.login_error_incorrect_pin,
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_INVALID_PIN to R.string.login_error_incorrect_pin
),
isRequired = true,
validationRegex = "[0-9]+",
caseMode = Credential.CaseMode.LOWER_CASE
)
),
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_EXPIRED_TOKEN to R.string.login_error_expired_token
)
),
Mode(
loginMode = LOGIN_MODE_VULCAN_WEB,
name = R.string.login_mode_vulcan_web,
icon = R.drawable.login_mode_vulcan_web,
hintText = R.string.login_mode_vulcan_web_hint,
guideText = R.string.login_mode_vulcan_web_guide,
isTesting = true,
isPlatformSelection = true,
credentials = listOf(
getEmailCredential("webEmail"),
Credential(
keyName = "webUsername",
name = R.string.login_hint_username,
icon = CommunityMaterial.Icon.cmd_account_outline,
emptyText = R.string.login_error_no_username,
invalidText = R.string.login_error_incorrect_username,
errorCodes = mapOf(),
isRequired = true,
validationRegex = "[A-Z]{7}[0-9]+",
caseMode = Credential.CaseMode.UPPER_CASE
),
Credential(
keyName = "webPassword",
name = R.string.login_hint_password,
icon = CommunityMaterial.Icon2.cmd_lock_outline,
emptyText = R.string.login_error_no_password,
invalidText = R.string.login_error_incorrect_login_or_password,
errorCodes = mapOf(),
isRequired = true,
validationRegex = ".*",
hideText = true
)
),
errorCodes = mapOf()
)
)
),
Register(
loginType = LOGIN_TYPE_MOBIDZIENNIK,
internalName = "mobidziennik",
registerName = R.string.login_type_mobidziennik,
registerLogo = R.drawable.login_logo_mobidziennik,
loginModes = listOf(
Mode(
loginMode = LOGIN_MODE_MOBIDZIENNIK_WEB,
name = R.string.login_mode_mobidziennik_web,
icon = R.drawable.login_mode_mobidziennik_web,
hintText = R.string.login_mode_mobidziennik_web_hint,
guideText = R.string.login_mode_mobidziennik_web_guide,
credentials = listOf(
Credential(
keyName = "username",
name = R.string.login_hint_login_email,
icon = CommunityMaterial.Icon.cmd_account_outline,
emptyText = R.string.login_error_no_login,
invalidText = R.string.login_error_incorrect_login,
errorCodes = mapOf(),
isRequired = true,
validationRegex = "^[a-z0-9_\\-@+.]+$",
caseMode = Credential.CaseMode.LOWER_CASE
),
Credential(
keyName = "password",
name = R.string.login_hint_password,
icon = CommunityMaterial.Icon2.cmd_lock_outline,
emptyText = R.string.login_error_no_password,
invalidText = R.string.login_error_incorrect_login_or_password,
errorCodes = mapOf(
ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD to R.string.login_error_old_password
),
isRequired = true,
validationRegex = ".*",
hideText = true
),
Credential(
keyName = "serverName",
name = R.string.login_hint_address,
icon = CommunityMaterial.Icon2.cmd_web,
emptyText = R.string.login_error_no_address,
invalidText = R.string.login_error_incorrect_address,
errorCodes = mapOf(
ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS to R.string.login_error_incorrect_address
),
isRequired = true,
validationRegex = "^[a-z0-9_\\-]+\$",
caseMode = Credential.CaseMode.LOWER_CASE
)
),
errorCodes = mapOf(
ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password,
ERROR_LOGIN_MOBIDZIENNIK_WEB_ARCHIVED to R.string.sync_error_archived
)
)
)
)
/*Register(
loginType = LOGIN_TYPE_IDZIENNIK,
)*/
) }
data class Register(
val loginType: Int,
val internalName: String,
val registerName: Int,
@DrawableRes
val registerLogo: Int,
val loginModes: List<Mode>
) : ExpandableItemModel<Mode>(loginModes.toMutableList()) {
override var level = 1
}
data class Mode(
val loginMode: Int,
@StringRes
val name: Int,
@DrawableRes
val icon: Int,
@StringRes
val hintText: Int? = null,
@StringRes
val guideText: Int,
val isRecommended: Boolean = false,
val isTesting: Boolean = false,
val isPlatformSelection: Boolean = false,
val credentials: List<Credential>,
val errorCodes: Map<Int, Int>
)
data class Platform(
val id: Int,
val loginType: Int,
val loginMode: Int,
val name: String,
val description: String?,
val guideText: String?,
val icon: String,
val screenshot: String?,
val formFields: List<String>,
val apiData: JsonObject
)
data class Credential(
val keyName: String,
@StringRes
val name: Int,
val icon: IIcon,
@StringRes
val placeholder: Int? = null,
@StringRes
val emptyText: Int,
@StringRes
val invalidText: Int,
val errorCodes: Map<Int, Int>,
@StringRes
val hintText: Int? = null,
val isRequired: Boolean = true,
val validationRegex: String,
val caseMode: CaseMode = CaseMode.UNCHANGED,
val hideText: Boolean = false,
val stripTextRegex: String? = null
) {
enum class CaseMode { UNCHANGED, UPPER_CASE, LOWER_CASE }
}
var chooserList: MutableList<Any>? = null
var platformList: MutableMap<Int, List<Platform>> = mutableMapOf()
}

View File

@ -1,109 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_IDZIENNIK
import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieBinding
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginIuczniowieFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginIuczniowieFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginIuczniowieBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginIuczniowieBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME ->
b.loginSchoolNameLayout.error = getString(R.string.login_error_incorrect_school_name)
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED ->
b.loginPasswordLayout.error = getString(R.string.login_error_incorrect_login_or_password)
}
}
}
b.helpButton.onClick { nav.navigate(R.id.loginIuczniowieHelpFragment, null, LoginActivity.navOptions) }
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginSchoolNameLayout.error = null
b.loginUsernameLayout.error = null
b.loginPasswordLayout.error = null
val schoolName = b.loginSchoolName.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val username = b.loginUsername.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val password = b.loginPassword.text?.toString() ?: ""
if (schoolName.isBlank()) {
b.loginSchoolNameLayout.error = getString(R.string.login_error_no_school_name)
errors = true
}
if (username.isBlank()) {
b.loginUsernameLayout.error = getString(R.string.login_error_no_username)
errors = true
}
if (password.isBlank()) {
b.loginPasswordLayout.error = getString(R.string.login_error_no_password)
errors = true
}
if (errors) return@onClick
errors = false
b.loginSchoolName.setText(schoolName)
b.loginUsername.setText(username)
if (!"[a-z0-9_\\-]+".toRegex().matches(schoolName)) {
b.loginSchoolNameLayout.error = getString(R.string.login_error_incorrect_school_name)
errors = true
}
if (!"[a-z0-9_\\-]+".toRegex().matches(username)) {
b.loginUsernameLayout.error = getString(R.string.login_error_incorrect_username)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_IDZIENNIK,
"schoolName" to schoolName,
"username" to username,
"password" to password
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,48 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.login;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieHelpBinding;
public class LoginIuczniowieHelpFragment extends Fragment {
private App app;
private NavController nav;
private FragmentLoginIuczniowieHelpBinding b;
private static final String TAG = "LoginIuczniowieHelp";
public LoginIuczniowieHelpFragment() { }
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (getActivity() != null) {
app = (App) getActivity().getApplicationContext();
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
}
else {
return null;
}
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_iuczniowie_help, container, false);
return b.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
assert getContext() != null;
assert getActivity() != null;
b.backButton.setOnClickListener((v) -> nav.navigateUp());
}
}

View File

@ -1,116 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.login
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.util.Base64
import android.webkit.JavascriptInterface
import android.webkit.WebView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.afollestad.materialdialogs.MaterialDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.LIBRUS_USER_AGENT
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.Utils.hexFromColorInt
import java.nio.charset.Charset
class LoginLibrusCaptchaActivity : AppCompatActivity() {
companion object {
private const val TAG = "LoginLibrusCaptchaActivity"
}
private lateinit var webView: WebView
private lateinit var dialog: AlertDialog
private lateinit var jsInterface: CaptchaCallbackInterface
@SuppressLint("AddJavascriptInterface", "SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTheme(Themes.appThemeNoDisplay)
setFinishOnTouchOutside(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true)
}
val base64Content = """
PCFET0NUWVBFIGh0bWw+PGh0bWw+PGhlYWQ+PHNjcmlwdCBzcmM9Imh0dHBzOi8vd3d3Lmdvb2ds
ZS5jb20vcmVjYXB0Y2hhL2FwaS5qcz9vbmxvYWQ9cmVhZHkmcmVuZGVyPWV4cGxpY2l0Ij48L3Nj
cmlwdD48L2hlYWQ+PGJvZHk+PGJyPjxjZW50ZXIgaWQ9ImdyIj48L2NlbnRlcj48YnI+PHNjcmlw
dD5mdW5jdGlvbiByZWFkeSgpe2dyZWNhcHRjaGEucmVuZGVyKCdncicse3NpdGVrZXk6JzZMZjQ4
bW9VQUFBQUFCOUNsaGR2SHI0NmdSV1ItQ04zMUNYUVBHMlUnLHRoZW1lOidUSEVNRScsY2FsbGJh
Y2s6ZnVuY3Rpb24oZSl7d2luZG93LmlmLmNhbGxiYWNrKGUpO30sImV4cGlyZWQtY2FsbGJhY2si
OmZ1bmN0aW9uKCl7d2luZG93LmlmLmV4cGlyZWRDYWxsYmFjayhlKTt9LCJlcnJvci1jYWxsYmFj
ayI6ZnVuY3Rpb24oKXt3aW5kb3cuaWYuZXJyb3JDYWxsYmFjayhlKTt9fSk7fTwvc2NyaXB0Pjwv
Ym9keT48L2h0bWw+"""
val backgroundColor = if (Themes.isDark) 0x424242 else 0xffffff
val backgroundColorString = hexFromColorInt(backgroundColor)
val htmlContent = Base64.decode(base64Content, Base64.DEFAULT)
.toString(Charset.defaultCharset())
.replace("COLOR", backgroundColorString, true)
.replace("THEME", if (Themes.isDark) "dark" else "light")
jsInterface = object : CaptchaCallbackInterface {
@JavascriptInterface
override fun callback(recaptchaResponse: String) {
MaterialDialog.Builder(this@LoginLibrusCaptchaActivity)
.title("Captcha checked")
.content("Response: $recaptchaResponse")
.positiveText("OK")
.show()
}
@JavascriptInterface
override fun expiredCallback() {
MaterialDialog.Builder(this@LoginLibrusCaptchaActivity)
.title("Captcha expired")
.content("Captcha expired")
.positiveText("OK")
.show()
}
@JavascriptInterface
override fun errorCallback() {
MaterialDialog.Builder(this@LoginLibrusCaptchaActivity)
.title("Captcha error")
.content("Captcha error")
.positiveText("OK")
.show()
}
}
webView = WebView(this).apply {
//setBackgroundColor((backgroundColor.toLong() or 0xff000000).toInt())
setBackgroundColor(Color.TRANSPARENT)
settings.javaScriptEnabled = true
settings.userAgentString = LIBRUS_USER_AGENT
addJavascriptInterface(jsInterface, "if")
loadDataWithBaseURL("https://portal.librus.pl/rodzina/login/", htmlContent, "text/html", "UTF-8", null)
setLayerType(WebView.LAYER_TYPE_SOFTWARE, null)
}
dialog = MaterialAlertDialogBuilder(this)
.setTitle(R.string.login_librus_captcha_title)
.setView(webView)
.setNegativeButton(R.string.cancel) { dialog, _ ->
dialog.dismiss()
finish()
}
.setCancelable(false)
.show()
}
interface CaptchaCallbackInterface {
@JavascriptInterface
fun callback(recaptchaResponse: String)
@JavascriptInterface
fun expiredCallback()
@JavascriptInterface
fun errorCallback()
}
}

View File

@ -1,97 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusBinding
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginLibrusFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginLibrusFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginLibrusBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginLibrusBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN ->
b.loginPasswordLayout.error = getString(R.string.login_error_incorrect_login_or_password)
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED ->
b.loginEmailLayout.error = getString(R.string.login_error_account_not_activated)
}
}
}
b.helpButton.onClick { nav.navigate(R.id.loginLibrusHelpFragment, null, LoginActivity.navOptions) }
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginEmailLayout.error = null
b.loginPasswordLayout.error = null
val email = b.loginEmail.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val password = b.loginPassword.text?.toString() ?: ""
if (email.isBlank()) {
b.loginEmailLayout.error = getString(R.string.login_error_no_email)
errors = true
}
if (password.isBlank()) {
b.loginPasswordLayout.error = getString(R.string.login_error_no_password)
errors = true
}
if (errors) return@onClick
errors = false
b.loginEmail.setText(email)
if (!"([\\w.\\-_+]+)?\\w+@[\\w-_]+(\\.\\w+)+".toRegex().matches(email)) {
b.loginEmailLayout.error = getString(R.string.login_error_incorrect_email)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_LIBRUS,
"email" to email,
"password" to password
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,48 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.login;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusHelpBinding;
public class LoginLibrusHelpFragment extends Fragment {
private App app;
private NavController nav;
private FragmentLoginLibrusHelpBinding b;
private static final String TAG = "LoginLibrusHelp";
public LoginLibrusHelpFragment() { }
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (getActivity() != null) {
app = (App) getActivity().getApplicationContext();
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
}
else {
return null;
}
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_librus_help, container, false);
return b.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
assert getContext() != null;
assert getActivity() != null;
b.backButton.setOnClickListener((v) -> nav.navigateUp());
}
}

View File

@ -1,122 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.fragment.app.Fragment
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST
import pl.szczodrzynski.edziennik.data.api.LOGIN_MODE_LIBRUS_JST
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusJstBinding
import pl.szczodrzynski.edziennik.ui.dialogs.QrScannerDialog
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginLibrusJstFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginLibrusJstFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginLibrusJstBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginLibrusJstBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN,
ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST ->
b.loginCodeLayout.error = getString(R.string.login_error_incorrect_code_or_pin)
}
}
}
b.loginQrScan.setImageDrawable(IconicsDrawable(activity)
.icon(CommunityMaterial.Icon2.cmd_qrcode_scan)
.colorInt(Color.BLACK)
.sizeDp(72))
b.loginQrScan.onClick {
QrScannerDialog(activity, { code ->
b.loginCode.setText(code)
if (b.loginPin.requestFocus()) {
activity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
})
}
b.helpButton.onClick { nav.navigate(R.id.loginLibrusHelpFragment, null, LoginActivity.navOptions) }
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginCodeLayout.error = null
b.loginPinLayout.error = null
val code = b.loginCode.text?.toString()?.toUpperCase(Locale.ROOT) ?: ""
val pin = b.loginPin.text?.toString() ?: ""
if (code.isBlank()) {
b.loginCodeLayout.error = getString(R.string.login_error_no_code)
errors = true
}
if (pin.isBlank()) {
b.loginPinLayout.error = getString(R.string.login_error_no_pin)
errors = true
}
if (errors) return@onClick
errors = false
b.loginCode.setText(code)
if (!"[A-Z0-9_]+".toRegex().matches(code)) {
b.loginCodeLayout.error = getString(R.string.login_error_incorrect_code)
errors = true
}
if (!"[a-z0-9_]+".toRegex().matches(pin)) {
b.loginPinLayout.error = getString(R.string.login_error_incorrect_pin)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_LIBRUS,
"loginMode" to LOGIN_MODE_LIBRUS_JST,
"accountCode" to code,
"accountPin" to pin
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,114 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikBinding
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginMobidziennikFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginMobidziennikFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginMobidziennikBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginMobidziennikBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN ->
b.loginPasswordLayout.error = getString(R.string.login_error_incorrect_login_or_password)
ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD ->
b.loginPasswordLayout.error = getString(R.string.login_error_old_password)
ERROR_LOGIN_MOBIDZIENNIK_WEB_ARCHIVED ->
b.loginUsernameLayout.error = getString(R.string.sync_error_archived)
ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS ->
b.loginServerAddressLayout.error = getString(R.string.login_error_incorrect_address)
}
}
}
b.helpButton.onClick { nav.navigate(R.id.loginMobidziennikHelpFragment, null, LoginActivity.navOptions) }
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginServerAddressLayout.error = null
b.loginUsernameLayout.error = null
b.loginPasswordLayout.error = null
val serverName = b.loginServerAddress.text
?.toString()
?.toLowerCase(Locale.ROOT)
?.replace("(?:http://|www.|mobidziennik\\.pl|wizja\\.net|\\.)".toRegex(), "") ?: ""
val username = b.loginUsername.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val password = b.loginPassword.text?.toString() ?: ""
if (serverName.isBlank()) {
b.loginServerAddressLayout.error = getString(R.string.login_error_no_address)
errors = true
}
if (username.isBlank()) {
b.loginUsernameLayout.error = getString(R.string.login_error_no_login)
errors = true
}
if (password.isBlank()) {
b.loginPasswordLayout.error = getString(R.string.login_error_no_password)
errors = true
}
if (errors) return@onClick
errors = false
b.loginServerAddress.setText(serverName)
b.loginUsername.setText(username)
if (!"^[a-z0-9_\\-]+$".toRegex().matches(serverName)) {
b.loginServerAddressLayout.error = getString(R.string.login_error_incorrect_address)
errors = true
}
if (!"^[a-z0-9_\\-@+.]+$".toRegex().matches(username)) {
b.loginUsernameLayout.error = getString(R.string.login_error_incorrect_login)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_MOBIDZIENNIK,
"serverName" to serverName,
"username" to username,
"password" to password
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,48 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.login;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikHelpBinding;
public class LoginMobidziennikHelpFragment extends Fragment {
private App app;
private NavController nav;
private FragmentLoginMobidziennikHelpBinding b;
private static final String TAG = "LoginMobidziennikHelp";
public LoginMobidziennikHelpFragment() { }
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (getActivity() != null) {
app = (App) getActivity().getApplicationContext();
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
}
else {
return null;
}
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_mobidziennik_help, container, false);
return b.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
assert getContext() != null;
assert getActivity() != null;
b.backButton.setOnClickListener((v) -> nav.navigateUp());
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.ui.modules.login.viewholder.PlatformViewHolder
import kotlin.coroutines.CoroutineContext
class LoginPlatformAdapter(
val activity: AppCompatActivity,
val onPlatformClick: ((platform: LoginInfo.Platform) -> Unit)? = null
) : RecyclerView.Adapter<PlatformViewHolder>(), CoroutineScope {
companion object {
private const val TAG = "LoginPlatformAdapter"
}
private val app = activity.applicationContext as App
// optional: place the manager here
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
var items = listOf<LoginInfo.Platform>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlatformViewHolder {
val inflater = LayoutInflater.from(parent.context)
return PlatformViewHolder(inflater, parent)
}
override fun onBindViewHolder(holder: PlatformViewHolder, position: Int) {
val item = items[position]
holder.onBind(activity, app, item, position, this)
onPlatformClick?.let {
holder.b.root.onClick { _ -> it(item) }
}
}
override fun getItemCount() = items.size
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.databinding.LoginPlatformListFragmentBinding
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
class LoginPlatformListFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginPlatformListFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: LoginPlatformListFragmentBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
private val api by lazy { SzkolnyApi(app) }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = LoginPlatformListFragmentBinding.inflate(inflater)
return b.root
}
private lateinit var timeoutJob: Job
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded) return
b.backButton.onClick { nav.navigateUp() }
val loginType = arguments?.getInt("loginType") ?: return
val register = LoginInfo.list.firstOrNull { it.loginType == loginType } ?: return
val loginMode = arguments?.getInt("loginMode") ?: return
val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return
timeoutJob = startCoroutineTimer(5000L) {
b.timeoutText.isVisible = true
timeoutJob.cancel()
}
val adapter = LoginPlatformAdapter(activity) { platform ->
nav.navigate(R.id.loginFormFragment, Bundle(
"loginType" to platform.loginType,
"loginMode" to platform.loginMode,
"platformName" to platform.name,
"platformDescription" to platform.description,
"platformFormFields" to platform.formFields.joinToString(";"),
"platformApiData" to platform.apiData.toString()
), activity.navOptions)
}
launch {
val platforms = LoginInfo.platformList[mode.name]
?: run {
api.runCatching(activity) {
getPlatforms(register.internalName)
} ?: run {
nav.navigateUp()
return@launch
}
}
LoginInfo.platformList[mode.name] = platforms
adapter.items = platforms
b.list.adapter = adapter
b.list.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
}
timeoutJob.cancel()
b.loadingLayout.isVisible = false
b.list.isVisible = true
}
}
}

View File

@ -1,29 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.login;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore;
import pl.szczodrzynski.edziennik.data.db.entity.Profile;
public class LoginProfileObject {
LoginStore loginStore = null;
List<Profile> profileList = new ArrayList<>();
List<Boolean> selectedList = new ArrayList<>();
public LoginProfileObject(@NonNull LoginStore loginStore, @NonNull List<Profile> profileList) {
this.loginStore = loginStore;
this.profileList = profileList;
for (Profile ignored : profileList) {
selectedList.add(true);
}
}
public LoginProfileObject addProfile(Profile profile) {
profileList.add(profile);
selectedList.add(true);
return this;
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) Kuba Szczodrzyński 2020-1-3. * Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/ */
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
@ -27,8 +27,10 @@ import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.databinding.FragmentLoginProgressBinding import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding
import pl.szczodrzynski.edziennik.joinNotNullStrings
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.math.max
class LoginProgressFragment : Fragment(), CoroutineScope { class LoginProgressFragment : Fragment(), CoroutineScope {
companion object { companion object {
@ -37,22 +39,26 @@ class LoginProgressFragment : Fragment(), CoroutineScope {
private lateinit var app: App private lateinit var app: App
private lateinit var activity: LoginActivity private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginProgressBinding private lateinit var b: LoginProgressFragmentBinding
private val nav by lazy { activity.nav } private val nav by lazy { activity.nav }
private val job: Job = Job() private val job: Job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null context ?: return null
app = activity.application as App app = activity.application as App
b = FragmentLoginProgressBinding.inflate(inflater) b = LoginProgressFragmentBinding.inflate(inflater)
return b.root return b.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded) return
val args = arguments ?: run { val args = arguments ?: run {
activity.error(ApiError(TAG, LOGIN_NO_ARGUMENTS)) activity.error(ApiError(TAG, LOGIN_NO_ARGUMENTS))
nav.navigateUp() nav.navigateUp()
@ -66,19 +72,21 @@ class LoginProgressFragment : Fragment(), CoroutineScope {
launch { launch {
activity.errorSnackbar.dismiss() activity.errorSnackbar.dismiss()
val firstProfileId = (app.db.profileDao().lastId ?: 0) + 1 val maxProfileId = max(
app.db.profileDao().lastId ?: 0,
activity.profiles.maxBy { it.profile.id }?.profile?.id ?: 0
)
val loginType = args.getInt("loginType", -1) val loginType = args.getInt("loginType", -1)
val loginMode = args.getInt("loginMode", 0) val loginMode = args.getInt("loginMode", 0)
val loginStore = LoginStore( val loginStore = LoginStore(
id = firstProfileId, id = maxProfileId + 1,
type = loginType, type = loginType,
mode = loginMode mode = loginMode
) )
loginStore.copyFrom(args) loginStore.copyFrom(args)
if (App.devMode && LoginChooserFragment.fakeLogin) { loginStore.removeLoginData("loginType")
loginStore.putLoginData("fakeLogin", true) loginStore.removeLoginData("loginMode")
}
EdziennikTask.firstLogin(loginStore).enqueue(activity) EdziennikTask.firstLogin(loginStore).enqueue(activity)
} }
} }
@ -94,10 +102,21 @@ class LoginProgressFragment : Fragment(), CoroutineScope {
.show() .show()
return return
} }
// update subnames with school years and class name
for (profile in event.profileList) {
val schoolYearName = "${profile.studentSchoolYearStart}/${profile.studentSchoolYearStart + 1}"
profile.subname = joinNotNullStrings(
" - ",
profile.studentClassName,
schoolYearName
)
}
activity.loginStores += event.loginStore activity.loginStores += event.loginStore
activity.profiles += event.profileList.map { LoginSummaryProfileAdapter.Item(it) } activity.profiles += event.profileList.map { LoginSummaryAdapter.Item(it) }
activity.errorSnackbar.dismiss() activity.errorSnackbar.dismiss()
nav.navigate(R.id.loginSummaryFragment, null, LoginActivity.navOptions) nav.navigate(R.id.loginSummaryFragment, null, activity.navOptions)
} }
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true) @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.databinding.LoginSummaryItemBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.trigger
import kotlin.coroutines.CoroutineContext
class LoginSummaryAdapter(
val activity: LoginActivity,
val onSelectionChanged: ((item: Item) -> Unit)? = null
) : RecyclerView.Adapter<LoginSummaryAdapter.ViewHolder>(), CoroutineScope {
companion object {
private const val TAG = "LoginSummaryAdapter"
}
private val app = activity.applicationContext as App
// optional: place the manager here
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
var items = listOf<Item>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return ViewHolder(LoginSummaryItemBinding.inflate(inflater, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
val b = holder.b
val profile = item.profile
val loginStore = activity.loginStores.firstOrNull { it.id == profile.loginStoreId }
?: return
val loginType = loginStore.type
val register = LoginInfo.list.firstOrNull { it.loginType == loginType } ?: return
val loginMode = loginStore.mode
val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return
b.profileName.text = profile.name
b.profileDetails.text = profile.subname
b.checkBox.isChecked = item.isSelected
b.modeIcon.setImageResource(mode.icon)
if (profile.isParent) {
b.accountType.setText(R.string.account_type_parent)
} else {
b.accountType.setText(R.string.account_type_child)
}
b.root.onClick {
b.checkBox.trigger()
}
b.checkBox.setOnCheckedChangeListener { _, isChecked ->
item.isSelected = isChecked
onSelectionChanged?.invoke(item)
}
}
override fun getItemCount() = items.size
class ViewHolder(val b: LoginSummaryItemBinding) : RecyclerView.ViewHolder(b.root)
class Item(val profile: Profile, var isSelected: Boolean = true)
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) Kuba Szczodrzyński 2020-1-3. * Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/ */
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
@ -16,7 +16,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSummaryBinding import pl.szczodrzynski.edziennik.databinding.LoginSummaryFragmentBinding
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -27,27 +27,32 @@ class LoginSummaryFragment : Fragment(), CoroutineScope {
private lateinit var app: App private lateinit var app: App
private lateinit var activity: LoginActivity private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginSummaryBinding private lateinit var b: LoginSummaryFragmentBinding
private val nav by lazy { activity.nav } private val nav by lazy { activity.nav }
private val job: Job = Job() private val job: Job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null context ?: return null
app = activity.application as App app = activity.application as App
b = FragmentLoginSummaryBinding.inflate(inflater) b = LoginSummaryFragmentBinding.inflate(inflater)
return b.root return b.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
b.profileListView.apply { val adapter = LoginSummaryAdapter(activity) { _ ->
adapter = LoginSummaryProfileAdapter(activity, activity.profiles) { item -> b.finishButton.isEnabled = activity.profiles.any { it.isSelected }
b.finishButton.isEnabled = activity.profiles.any { it.isSelected } }
}
adapter.items = activity.profiles
b.list.adapter = adapter
b.list.apply {
isNestedScrollingEnabled = false isNestedScrollingEnabled = false
setHasFixedSize(true) setHasFixedSize(true)
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
@ -66,7 +71,7 @@ class LoginSummaryFragment : Fragment(), CoroutineScope {
} }
b.anotherButton.onClick { b.anotherButton.onClick {
nav.navigate(R.id.loginChooserFragment, null, LoginActivity.navOptions) nav.navigate(R.id.loginChooserFragment, null, activity.navOptions)
} }
b.finishButton.onClick { b.finishButton.onClick {
@ -86,7 +91,7 @@ class LoginSummaryFragment : Fragment(), CoroutineScope {
val args = Bundle( val args = Bundle(
"registrationAllowed" to b.registerMeSwitch.isChecked "registrationAllowed" to b.registerMeSwitch.isChecked
) )
nav.navigate(R.id.loginSyncFragment, args, LoginActivity.navOptions) nav.navigate(R.id.loginSyncFragment, args, activity.navOptions)
} }
} }
} }

View File

@ -1,81 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.databinding.RowLoginProfileListItemBinding
class LoginSummaryProfileAdapter(
val context: Context,
val items: List<Item>,
val onSelectionChanged: ((item: Item) -> Unit)? = null
) : RecyclerView.Adapter<LoginSummaryProfileAdapter.ViewHolder>() {
private val app by lazy { context.applicationContext as App }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = RowLoginProfileListItemBinding.inflate(inflater, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
val profile = item.profile
val b = holder.b
b.textView.text = profile.name
b.checkBox.isChecked = item.isSelected
val registerIcon = when (profile.loginStoreType) {
LOGIN_TYPE_MOBIDZIENNIK -> R.drawable.logo_mobidziennik
LOGIN_TYPE_LIBRUS -> R.drawable.logo_librus
LOGIN_TYPE_IDZIENNIK -> R.drawable.logo_idziennik
LOGIN_TYPE_VULCAN -> R.drawable.logo_vulcan
LOGIN_TYPE_EDUDZIENNIK -> R.drawable.logo_edudziennik
else -> null
}
if (registerIcon == null)
b.registerIcon.visibility = View.GONE
else {
b.registerIcon.visibility = View.VISIBLE
b.registerIcon.setImageResource(registerIcon)
}
if (profile.isParent) {
b.accountType.setText(R.string.login_summary_account_parent)
} else {
b.accountType.setText(R.string.login_summary_account_child)
}
val schoolYearName = "${profile.studentSchoolYearStart}/${profile.studentSchoolYearStart+1}"
b.textDetails.text = joinNotNullStrings(
" - ",
profile.studentClassName,
schoolYearName
)
b.root.onClick {
b.checkBox.trigger()
}
b.checkBox.setOnCheckedChangeListener { _, isChecked ->
item.isSelected = isChecked
onSelectionChanged?.invoke(item)
}
}
override fun getItemCount() = items.size
class ViewHolder(val b: RowLoginProfileListItemBinding) : RecyclerView.ViewHolder(b.root)
class Item(val profile: Profile, var isSelected: Boolean = true)
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) Kuba Szczodrzyński 2020-1-3. * Copyright (c) Kuba Szczodrzyński 2020-4-14.
*/ */
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
@ -14,7 +14,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSyncErrorBinding import pl.szczodrzynski.edziennik.databinding.LoginSyncErrorFragmentBinding
import pl.szczodrzynski.edziennik.onClick import pl.szczodrzynski.edziennik.onClick
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -25,18 +25,20 @@ class LoginSyncErrorFragment : Fragment(), CoroutineScope {
private lateinit var app: App private lateinit var app: App
private lateinit var activity: LoginActivity private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginSyncErrorBinding private lateinit var b: LoginSyncErrorFragmentBinding
private val nav by lazy { activity.nav } private val nav by lazy { activity.nav }
private val job: Job = Job() private val job: Job = Job()
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null context ?: return null
app = activity.application as App app = activity.application as App
b = FragmentLoginSyncErrorBinding.inflate(inflater) b = LoginSyncErrorFragmentBinding.inflate(inflater)
return b.root return b.root
} }
@ -44,7 +46,7 @@ class LoginSyncErrorFragment : Fragment(), CoroutineScope {
b.errorDetails.text = activity.lastError?.getStringReason(activity) b.errorDetails.text = activity.lastError?.getStringReason(activity)
activity.lastError = null activity.lastError = null
b.nextButton.onClick { b.nextButton.onClick {
nav.navigate(R.id.loginFinishFragment, arguments, LoginActivity.navOptions) nav.navigate(R.id.loginFinishFragment, arguments, activity.navOptions)
} }
} }
} }

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-16.
*/
package pl.szczodrzynski.edziennik.ui.modules.login package pl.szczodrzynski.edziennik.ui.modules.login
import android.os.Bundle import android.os.Bundle
@ -19,9 +23,8 @@ import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskProgressEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskProgressEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskStartedEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskStartedEvent
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_DISABLED import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.REGISTRATION_ENABLED import pl.szczodrzynski.edziennik.databinding.LoginSyncFragmentBinding
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSyncBinding
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -32,7 +35,7 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
private lateinit var app: App private lateinit var app: App
private lateinit var activity: LoginActivity private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginSyncBinding private lateinit var b: LoginSyncFragmentBinding
private val nav: NavController by lazy { Navigation.findNavController(activity, R.id.nav_host_fragment) } private val nav: NavController by lazy { Navigation.findNavController(activity, R.id.nav_host_fragment) }
private val job: Job = Job() private val job: Job = Job()
@ -45,7 +48,7 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
activity = (getActivity() as LoginActivity?) ?: return null activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null context ?: return null
app = activity.application as App app = activity.application as App
b = FragmentLoginSyncBinding.inflate(inflater) b = LoginSyncFragmentBinding.inflate(inflater)
return b.root return b.root
} }
@ -56,9 +59,9 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
val registrationAllowed = arguments?.getBoolean("registrationAllowed") ?: false val registrationAllowed = arguments?.getBoolean("registrationAllowed") ?: false
profiles.forEach { profiles.forEach {
it.registration = if (registrationAllowed) it.registration = if (registrationAllowed)
REGISTRATION_ENABLED Profile.REGISTRATION_ENABLED
else else
REGISTRATION_DISABLED Profile.REGISTRATION_DISABLED
app.db.eventTypeDao().addDefaultTypes(activity, it.id) app.db.eventTypeDao().addDefaultTypes(activity, it.id)
} }
@ -84,13 +87,13 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onSyncFinishedEvent(event: ApiTaskAllFinishedEvent) { fun onSyncFinishedEvent(event: ApiTaskAllFinishedEvent) {
nav.navigate(R.id.loginFinishFragment, finishArguments, LoginActivity.navOptions) nav.navigate(R.id.loginFinishFragment, finishArguments, activity.navOptions)
} }
@Subscribe(threadMode = ThreadMode.MAIN) @Subscribe(threadMode = ThreadMode.MAIN)
fun onSyncProgressEvent(event: ApiTaskProgressEvent) { fun onSyncProgressEvent(event: ApiTaskProgressEvent) {
b.loginSyncProgressBar.progress = event.progress.roundToInt() b.loginSyncProgressBar.progress = event.progress.roundToInt()
b.loginSyncProgressBar.isIndeterminate = event.progress < 0f b.loginSyncProgressBar.isIndeterminate = event.progress <= 0f
b.loginSyncSubtitle2.text = event.progressText b.loginSyncSubtitle2.text = event.progressText
} }
@ -98,7 +101,7 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
fun onSyncErrorEvent(event: ApiTaskErrorEvent) { fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
EventBus.getDefault().removeStickyEvent(event) EventBus.getDefault().removeStickyEvent(event)
activity.error(event.error) activity.error(event.error)
nav.navigate(R.id.loginSyncErrorFragment, finishArguments, LoginActivity.navOptions) nav.navigate(R.id.loginSyncErrorFragment, finishArguments, activity.navOptions)
} }
override fun onStart() { override fun onStart() {

View File

@ -1,97 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_TEMPLATE
import pl.szczodrzynski.edziennik.databinding.FragmentLoginTemplateBinding
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginTemplateFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginTemplateFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginTemplateBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginTemplateBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN ->
b.loginPasswordLayout.error = getString(R.string.login_error_incorrect_login_or_password)
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED ->
b.loginEmailLayout.error = getString(R.string.login_error_account_not_activated)
}
}
}
b.helpButton.onClick { nav.navigate(R.id.loginLibrusHelpFragment, null, LoginActivity.navOptions) }
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginEmailLayout.error = null
b.loginPasswordLayout.error = null
val email = b.loginEmail.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val password = b.loginPassword.text?.toString() ?: ""
if (email.isBlank()) {
b.loginEmailLayout.error = getString(R.string.login_error_no_email)
errors = true
}
if (password.isBlank()) {
b.loginPasswordLayout.error = getString(R.string.login_error_no_password)
errors = true
}
if (errors) return@onClick
errors = false
b.loginEmail.setText(email)
if (!"([\\w.\\-_+]+)?\\w+@[\\w-_]+(\\.\\w+)+".toRegex().matches(email)) {
b.loginEmailLayout.error = getString(R.string.login_error_incorrect_email)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_TEMPLATE,
"email" to email,
"password" to password
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,144 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-1-3.
*/
package pl.szczodrzynski.edziennik.ui.modules.login
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.fragment.app.Fragment
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanBinding
import pl.szczodrzynski.edziennik.ui.dialogs.QrScannerDialog
import pl.szczodrzynski.edziennik.utils.Utils
import java.util.*
import kotlin.coroutines.CoroutineContext
class LoginVulcanFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "LoginVulcanFragment"
}
private lateinit var app: App
private lateinit var activity: LoginActivity
private lateinit var b: FragmentLoginVulcanBinding
private val nav by lazy { activity.nav }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as LoginActivity?) ?: return null
context ?: return null
app = activity.application as App
b = FragmentLoginVulcanBinding.inflate(inflater)
return b.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
activity.lastError?.let { error ->
activity.lastError = null
startCoroutineTimer(delayMillis = 100) {
when (error.errorCode) {
ERROR_LOGIN_VULCAN_INVALID_TOKEN ->
b.loginTokenLayout.error = getString(R.string.login_error_incorrect_token)
ERROR_LOGIN_VULCAN_EXPIRED_TOKEN ->
b.loginTokenLayout.error = getString(R.string.login_error_expired_token)
ERROR_LOGIN_VULCAN_INVALID_SYMBOL ->
b.loginSymbolLayout.error = getString(R.string.login_error_incorrect_symbol)
ERROR_LOGIN_VULCAN_INVALID_PIN ->
b.loginPinLayout.error = getString(R.string.login_error_incorrect_pin)
}
}
}
b.loginQrScan.setImageDrawable(IconicsDrawable(activity)
.icon(CommunityMaterial.Icon2.cmd_qrcode_scan)
.colorInt(Color.BLACK)
.sizeDp(72))
b.loginQrScan.onClick {
QrScannerDialog(activity, { code ->
try {
val data = Utils.VulcanQrEncryptionUtils.decode(code)
"CERT#https?://.+?/([A-z]+)/mobile-api#([A-z0-9]+)#ENDCERT".toRegex().find(data)?.let {
b.loginToken.setText(it[2])
b.loginSymbol.setText(it[1])
if (b.loginPin.requestFocus()) {
activity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
}
}
catch (_: Exception) {}
})
}
b.helpButton.onClick { nav.navigate(R.id.loginVulcanHelpFragment, null, LoginActivity.navOptions) }
b.backButton.onClick { nav.navigateUp() }
b.loginButton.onClick {
var errors = false
b.loginTokenLayout.error = null
b.loginSymbolLayout.error = null
b.loginPinLayout.error = null
val token = b.loginToken.text?.toString()?.toUpperCase(Locale.ROOT) ?: ""
val symbol = b.loginSymbol.text?.toString()?.toLowerCase(Locale.ROOT) ?: ""
val pin = b.loginPin.text?.toString() ?: ""
if (token.isBlank()) {
b.loginTokenLayout.error = getString(R.string.login_error_no_token)
errors = true
}
if (symbol.isBlank()) {
b.loginSymbolLayout.error = getString(R.string.login_error_no_symbol)
errors = true
}
if (pin.isBlank()) {
b.loginPinLayout.error = getString(R.string.login_error_no_pin)
errors = true
}
if (errors) return@onClick
errors = false
b.loginToken.setText(token)
b.loginSymbol.setText(symbol)
b.loginPin.setText(pin)
if (!"[A-Z0-9]{5,12}".toRegex().matches(token)) {
b.loginTokenLayout.error = getString(R.string.login_error_incorrect_token)
errors = true
}
if (!"[a-z0-9_-]+".toRegex().matches(symbol)) {
b.loginSymbolLayout.error = getString(R.string.login_error_incorrect_symbol)
errors = true
}
if (!"[a-z0-9_]+".toRegex().matches(pin)) {
b.loginPinLayout.error = getString(R.string.login_error_incorrect_pin)
errors = true
}
if (errors) return@onClick
val args = Bundle(
"loginType" to LOGIN_TYPE_VULCAN,
"deviceToken" to token,
"deviceSymbol" to symbol,
"devicePin" to pin
)
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions)
}
}
}

View File

@ -1,48 +0,0 @@
package pl.szczodrzynski.edziennik.ui.modules.login;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanHelpBinding;
public class LoginVulcanHelpFragment extends Fragment {
private App app;
private NavController nav;
private FragmentLoginVulcanHelpBinding b;
private static final String TAG = "LoginVulcanHelp";
public LoginVulcanHelpFragment() { }
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (getActivity() != null) {
app = (App) getActivity().getApplicationContext();
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
}
else {
return null;
}
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_vulcan_help, container, false);
return b.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
assert getContext() != null;
assert getActivity() != null;
b.backButton.setOnClickListener((v) -> nav.navigateUp());
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-10.
*/
package pl.szczodrzynski.edziennik.ui.modules.login.viewholder
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.databinding.LoginChooserModeItemBinding
import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.BindableViewHolder
import pl.szczodrzynski.edziennik.ui.modules.login.LoginChooserAdapter
import pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo
class ModeViewHolder(
inflater: LayoutInflater,
parent: ViewGroup,
val b: LoginChooserModeItemBinding = LoginChooserModeItemBinding.inflate(inflater, parent, false)
) : RecyclerView.ViewHolder(b.root), BindableViewHolder<LoginInfo.Mode, LoginChooserAdapter> {
companion object {
private const val TAG = "ModeViewHolder"
}
override fun onBind(activity: AppCompatActivity, app: App, item: LoginInfo.Mode, position: Int, adapter: LoginChooserAdapter) {
b.logo.setImageResource(item.icon)
b.name.setText(item.name)
if (item.hintText == null) {
b.description.isVisible = false
}
else {
b.description.isVisible = true
b.description.setText(item.hintText)
}
b.hint.isVisible = false
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-10.
*/
package pl.szczodrzynski.edziennik.ui.modules.login.viewholder
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import coil.api.load
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.databinding.LoginPlatformItemBinding
import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.BindableViewHolder
import pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo
import pl.szczodrzynski.edziennik.ui.modules.login.LoginPlatformAdapter
class PlatformViewHolder(
inflater: LayoutInflater,
parent: ViewGroup,
val b: LoginPlatformItemBinding = LoginPlatformItemBinding.inflate(inflater, parent, false)
) : RecyclerView.ViewHolder(b.root), BindableViewHolder<LoginInfo.Platform, LoginPlatformAdapter> {
companion object {
private const val TAG = "PlatformViewHolder"
}
override fun onBind(activity: AppCompatActivity, app: App, item: LoginInfo.Platform, position: Int, adapter: LoginPlatformAdapter) {
b.logo.load(item.icon)
b.name.text = item.name
b.description.text = item.description
b.description.isVisible = item.description != null
b.screenshotButton.isVisible = false
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-10.
*/
package pl.szczodrzynski.edziennik.ui.modules.login.viewholder
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.databinding.LoginChooserItemBinding
import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.BindableViewHolder
import pl.szczodrzynski.edziennik.ui.modules.login.LoginChooserAdapter
import pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo
class RegisterViewHolder(
inflater: LayoutInflater,
parent: ViewGroup,
val b: LoginChooserItemBinding = LoginChooserItemBinding.inflate(inflater, parent, false)
) : RecyclerView.ViewHolder(b.root), BindableViewHolder<LoginInfo.Register, LoginChooserAdapter> {
companion object {
private const val TAG = "RegisterViewHolder"
}
override fun onBind(activity: AppCompatActivity, app: App, item: LoginInfo.Register, position: Int, adapter: LoginChooserAdapter) {
b.logo.setImageResource(item.registerLogo)
b.name.setText(item.registerName)
b.description.isVisible = false
}
}

View File

@ -55,6 +55,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog; import pl.szczodrzynski.edziennik.ui.dialogs.sync.NotificationFilterDialog;
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity;
import pl.szczodrzynski.edziennik.utils.Themes; import pl.szczodrzynski.edziennik.utils.Themes;
import pl.szczodrzynski.edziennik.utils.Utils; import pl.szczodrzynski.edziennik.utils.Utils;
import pl.szczodrzynski.edziennik.utils.models.Date; import pl.szczodrzynski.edziennik.utils.models.Date;
@ -161,7 +162,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
profileCardTitleItem = new MaterialAboutProfileItem( profileCardTitleItem = new MaterialAboutProfileItem(
app.getProfile().getName(), app.getProfile().getName(),
getString(R.string.settings_profile_subtitle_format, app.getProfile().getSubname()), app.getProfile().getSubname(),
getProfileDrawable() getProfileDrawable()
); );
profileCardTitleItem.setOnClickAction(() -> { profileCardTitleItem.setOnClickAction(() -> {
@ -218,6 +219,20 @@ public class SettingsNewFragment extends MaterialAboutFragment {
}) })
);*/ );*/
items.add(
new MaterialAboutActionItem(
getString(R.string.settings_add_student_text),
getString(R.string.settings_add_student_subtext),
new IconicsDrawable(activity)
.icon(CommunityMaterial.Icon.cmd_account_plus_outline)
.size(IconicsSize.dp(iconSizeDp))
.color(IconicsColor.colorInt(iconColor))
)
.setOnClickAction(() -> {
startActivity(new Intent(activity, LoginActivity.class));
})
);
items.add( items.add(
new MaterialAboutActionItem( new MaterialAboutActionItem(
getString(R.string.settings_profile_notifications_text), getString(R.string.settings_profile_notifications_text),
@ -232,6 +247,20 @@ public class SettingsNewFragment extends MaterialAboutFragment {
}) })
); );
items.add(
new MaterialAboutActionItem(
getString(R.string.settings_profile_remove_text),
getString(R.string.settings_profile_remove_subtext),
new IconicsDrawable(activity)
.icon(SzkolnyFont.Icon.szf_delete_empty_outline)
.size(IconicsSize.dp(iconSizeDp))
.color(IconicsColor.colorInt(iconColor))
)
.setOnClickAction(() -> {
new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName());
})
);
items.add(getMoreItem(() -> addCardItems(CARD_PROFILE, getProfileCard(true)))); items.add(getMoreItem(() -> addCardItems(CARD_PROFILE, getProfileCard(true))));
} }
else { else {
@ -253,20 +282,6 @@ public class SettingsNewFragment extends MaterialAboutFragment {
})) }))
); );
items.add(
new MaterialAboutActionItem(
getString(R.string.settings_profile_remove_text),
getString(R.string.settings_profile_remove_subtext),
new IconicsDrawable(activity)
.icon(SzkolnyFont.Icon.szf_delete_empty_outline)
.size(IconicsSize.dp(iconSizeDp))
.color(IconicsColor.colorInt(iconColor))
)
.setOnClickAction(() -> {
new ProfileRemoveDialog(activity, app.getProfile().getId(), app.getProfile().getName());
})
);
} }
return items; return items;
} }

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,194 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<TextView
android:id="@+id/subjectName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:textAppearance="@style/NavView.TextView.Title"
android:textSize="24sp"
tools:text="geografia" />
<TextView
android:id="@+id/semesterName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:textAppearance="@style/NavView.TextView.Subtitle"
tools:text="Semestr 1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@string/grades_editor_semester_average_before" />
<TextView
android:id="@+id/averageBefore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="@drawable/bg_rounded_4dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textColor="@color/black"
android:textStyle="bold"
tools:text="0.63" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_marginTop="4dp"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@string/grades_editor_semester_average_after" />
<TextView
android:id="@+id/averageAfter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="@drawable/bg_rounded_4dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textColor="@color/black"
android:textStyle="bold"
tools:text="2.75" />
</LinearLayout>
<LinearLayout
android:id="@+id/yearAverageContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@string/grades_editor_semester_year_average_before" />
<TextView
android:id="@+id/yearAverageBefore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="@drawable/bg_rounded_4dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textColor="@color/black"
android:textStyle="bold"
tools:text="0.63" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@string/grades_editor_semester_year_average_after" />
<TextView
android:id="@+id/yearAverageAfter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_marginRight="5dp"
android:background="@drawable/bg_rounded_4dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textColor="@color/black"
android:textStyle="bold"
tools:text="2.75" />
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:text="@string/grades_editor_modify_help"
android:textStyle="italic" />
<Button
android:id="@+id/addGrade"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:minHeight="0dp"
android:text="@string/grades_editor_add_grade" />
<Button
android:id="@+id/restoreGrades"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:minHeight="0dp"
android:text="@string/grades_editor_restore" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</layout>

View File

@ -1,87 +0,0 @@
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent"
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">
<LinearLayout
android:id="@+id/mainActivityRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
tools:title="Szkolny.eu"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<!--app:popupTheme="@style/ThemeOverlay.AppCompat.Light"-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/fixed_drawer_container"
android:layout_width="300dp"
android:layout_height="match_parent"
android:visibility="gone">
</FrameLayout>
<FrameLayout
android:id="@+id/fragment_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
android:id="@+id/fragment_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch>
<View
android:id="@+id/fragment_elevation"
android:layout_width="5dp"
android:layout_height="match_parent"
android:background="@drawable/shadow_right"
android:visibility="visible" />
</FrameLayout>
</LinearLayout>
<View
android:id="@+id/toolbar_elevation"
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="@drawable/shadow_top"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_collapseMode="pin"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
</FrameLayout>

View File

@ -34,4 +34,4 @@
</FrameLayout> </FrameLayout>
</layout> </layout>

View File

@ -1,178 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<LinearLayout
android:id="@+id/mainActivityRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<ScrollView
android:id="@+id/webPushConfig"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/textView8"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Przekazywanie powiadomień pozwala przesyłać wszystkie powiadomienia z tego urządzenia na wszystkie sparowane komputery, widoczne poniżej.\n\nPowiadomienia będą się wyświetlać w przeglądarce, w okienku pop-up, w prawym dolnym rogu ekranu.\n\nLista komputerów docelowych jest niezależna od wybranego profilu ucznia." />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="@dimen/section_margin_top"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/web_push_configured_browsers"
android:textAllCaps="true"
android:textColor="?attr/colorSection"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/section_underline_height"
android:layout_marginTop="2dp"
android:background="?attr/colorSection" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableLayout
android:id="@+id/browserList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:shrinkColumns="0"
android:stretchColumns="0">
<!--<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="end">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:gravity="center_vertical"
android:text="Chrome 70.0.3538.102 @ Windows 7 64-bit" />
<Button
android:id="@+id/button6"
style="@style/Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="0dp"
android:minWidth="0dp"
android:text="Usuń" />
</TableRow>-->
</TableLayout>
<ProgressBar
android:id="@+id/browserListProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible" />
<TextView
android:id="@+id/browserListErrorText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="18sp"
android:textStyle="italic"
android:visibility="visible"
android:text="@string/web_push_no_browsers" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="@dimen/section_margin_top"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/web_push_pair_browser"
android:textAllCaps="true"
android:textColor="?attr/colorSection"
android:textStyle="bold" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/section_underline_height"
android:layout_marginTop="2dp"
android:background="?attr/colorSection" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="W przeglądarce na komputerze wejdź na stronę\n\nhttp://edziennik.szczodrzynski.pl/wp\n\nUdziel zgody na wysyłanie powiadomień, następnie zeskanuj wygenerowany kod QR.\n\nPod tym samym adresem możesz zarządzać listą sparowanych z przeglądarką urządzeń.\n\nJeśli sparujesz kilka urządzeń z tą samą przeglądarką, możesz otrzymywać te same powiadomienia kilkukrotnie." />
<Button
android:id="@+id/webPushScanNewButton"
style="@style/Widget.AppCompat.Button.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="Skanuj..." />
</LinearLayout>
</LinearLayout>
</ScrollView>
<me.dm7.barcodescanner.zxing.ZXingScannerView
android:id="@+id/qrCodeScanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
</me.dm7.barcodescanner.zxing.ZXingScannerView>
</LinearLayout>
</layout>

View File

@ -1,262 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/topLogo"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-school"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_startpage_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_startpage_subtitle" />
<CheckBox
android:id="@+id/devMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
android:text="@string/developer_mode"
tools:visibility="visible"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="32dp"
android:layout_marginRight="24dp"
android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1">
<ImageView
android:id="@+id/loginMobidziennikLogo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_rounded_ripple"
android:padding="16dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/login_logo_mobidziennik" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_weight="1">
<ImageView
android:id="@+id/loginLibrusLogo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_rounded_ripple"
android:padding="16dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/login_logo_librus" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1">
<ImageView
android:id="@+id/loginVulcanLogo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_rounded_ripple"
android:padding="16dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/login_logo_vulcan" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_weight="1">
<ImageView
android:id="@+id/loginIuczniowieLogo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_rounded_ripple"
android:padding="16dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/login_logo_iuczniowie" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1">
<ImageView
android:id="@+id/loginLibrusJstLogo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_rounded_ripple"
android:padding="16dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/login_logo_oswiata" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_weight="1">
<ImageView
android:id="@+id/loginEdudziennikLogo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_rounded_ripple"
android:padding="16dp"
android:scaleType="fitCenter"
app:srcCompat="@drawable/login_logo_edudziennik" />
</FrameLayout>
</LinearLayout>
<Switch
android:id="@+id/fakeLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="Fake login"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/cancelButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/cancel"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android:text="@string/help"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,174 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kacper Ziubryniewicz 2019-12-23
-->
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/topText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_edudziennik_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_edudziennik_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginEmailLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_email"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPasswordLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_password"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<!--<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false" />-->
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-flag-checkered"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_finish_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/loginFinishSubtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_finish_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/finishButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:text="@string/done"
android:textAllCaps="false"
android:layout_marginEnd="20dp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,189 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd_account_circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_iuczniowie_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_iuczniowie_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginSchoolNameLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_school_name"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginSchoolName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginUsernameLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_username"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPasswordLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_password"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-help-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_iuczniowie_help_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:autoLink="web"
android:text="@string/login_iuczniowie_help_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/login_iuczniowie_help_subtitle"
android:src="@drawable/login_help_iuczniowie" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginEmailLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_email"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPasswordLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_password"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-help-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_help_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:autoLink="web"
android:text="@string/login_librus_help_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/login_librus_help_subtitle"
android:src="@drawable/login_help_librus" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,194 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_jst_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_jst_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/login_code_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_weight="1"
android:hint="@string/login_hint_token"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/login_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<ImageButton
android:id="@+id/loginQrScan"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:padding="4dp"
android:layout_marginRight="16dp"
android:layout_marginLeft="8dp"
android:scaleType="centerInside"
tools:srcCompat="@tools:sample/avatars"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/login_vulcan_qr" />
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPinLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_pin"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false"
android:visibility="gone"/>
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-sync"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_sync_title"
android:textSize="24sp" />
<ProgressBar
android:id="@+id/loginSyncProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="8dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="8dp"
android:indeterminate="false" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/loginSyncSubtitle1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
tools:text="@string/login_sync_subtitle_1_format" />
<TextView
android:id="@+id/loginSyncSubtitle2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
tools:text="@string/login_sync_subtitle_2_format" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,191 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd_account_circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_mobidziennik_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_mobidziennik_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginUsernameLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_login_email"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPasswordLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_password"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginServerAddressLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_address"
app:errorEnabled="true"
app:helperText="@string/login_helper_address"
app:helperTextEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginServerAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-help-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_mobidziennik_help_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_mobidziennik_help_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:text="@string/login_mobidziennik_help_address"
android:textSize="18sp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/login_mobidziennik_help_address"
android:src="@drawable/login_help_mobidziennik_address" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:text="@string/login_mobidziennik_help_login"
android:textSize="18sp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/login_mobidziennik_help_login"
android:src="@drawable/login_help_mobidziennik_login" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/imageView2"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-login"
app:iiv_size="32dp"
tools:srcCompat="@android:drawable/stat_sys_phone_call_forward" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:textSize="24sp"
android:text="@string/login_progress_title" />
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="8dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="8dp"
android:indeterminate="true" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-check"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_summary_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_summary_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/profileListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:clipToPadding="false"
tools:listitem="@layout/row_login_profile_list_item"
tools:itemCount="10">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/registerMeSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:checked="true"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:text="@string/login_allow_registration" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/anotherButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:text="@string/login_summary_add_student"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/finishButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android:text="@string/done"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,99 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-sync"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_sync_title"
android:textSize="24sp" />
<ProgressBar
android:id="@+id/loginSyncProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="8dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="8dp"
android:max="100"
android:indeterminate="false" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/loginSyncSubtitle1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
tools:text="@string/login_sync_subtitle_1_format" />
<TextView
android:id="@+id/loginSyncSubtitle2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
tools:text="@string/login_sync_subtitle_2_format" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_librus_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginEmailLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_email"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPasswordLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_password"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,213 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd_account_circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_vulcan_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_vulcan_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginTokenLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_weight="1"
android:hint="@string/login_hint_token"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
android:layout_marginStart="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginToken"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<ImageButton
android:id="@+id/loginQrScan"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:padding="4dp"
android:layout_marginRight="16dp"
android:layout_marginLeft="8dp"
android:scaleType="centerInside"
tools:srcCompat="@tools:sample/avatars"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/login_vulcan_qr" />
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginSymbolLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_symbol"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginSymbol"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginPinLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:hint="@string/login_hint_pin"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/loginPin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="@string/login_help_button"
android:textAllCaps="false" />
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View File

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-help-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_vulcan_help_title"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
android:text="@string/login_vulcan_help_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:text="@string/login_vulcan_help_register"
android:textSize="18sp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/login_vulcan_help_register"
android:src="@drawable/login_help_vulcan_register" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:text="@string/login_vulcan_help_token"
android:textSize="18sp" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:adjustViewBounds="true"
android:contentDescription="@string/login_vulcan_help_token"
android:src="@drawable/login_help_vulcan_token" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@string/back"
android:textAllCaps="false"
android:layout_marginStart="8dp" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-9.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
@ -8,11 +12,6 @@
android:orientation="vertical" android:orientation="vertical"
android:visibility="visible"> android:visibility="visible">
<Space
android:layout_width="0dp"
android:layout_height="32dp"
android:visibility="gone" />
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator" android:id="@+id/coordinator"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -26,23 +25,15 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:defaultNavHost="false" app:defaultNavHost="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_login" /> app:navGraph="@navigation/nav_login" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/snackbarAnchor" android:id="@+id/snackbarAnchor"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:text="@string/done" android:layout_marginBottom="16dp"
android:visibility="invisible"/> android:visibility="invisible" />
</FrameLayout> </FrameLayout>
</layout> </layout>

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-9.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/topLogo"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-school"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/login_chooser_title"
android:textSize="24sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="2dp"
android:text="@string/login_chooser_subtitle" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_weight="1"
tools:itemCount="5"
tools:listitem="@layout/login_chooser_item" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/cancelButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/cancel"
android:textAllCaps="false" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/help"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-10.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="12dp">
<ImageView
android:id="@+id/logo"
android:layout_width="100dp"
android:layout_height="60dp"
android:adjustViewBounds="true"
tools:src="@drawable/login_logo_vulcan" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:background="@drawable/divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Vulcan UONET+" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="Dziennik Uczniowie Optivum NET+" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-10.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="12dp">
<ImageView
android:id="@+id/logo"
android:layout_width="36dp"
android:layout_height="36dp"
android:adjustViewBounds="true"
tools:src="@drawable/login_mode_librus_email" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:background="@drawable/divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Zaloguj używając e-maila" />
<TextView
android:id="@+id/hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
tools:text="(zalecane)" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="Musisz posiadać konto Librus Rodzina" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -1,7 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto" <!--
xmlns:tools="http://schemas.android.com/tools" ~ Copyright (c) Kuba Szczodrzyński 2020-4-14.
xmlns:android="http://schemas.android.com/apk/res/android"> -->
<layout 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">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -9,71 +14,49 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:orientation="vertical"> android:layout_weight="1"
android:orientation="vertical"
android:paddingHorizontal="24dp">
<com.mikepenz.iconics.view.IconicsImageView <com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_marginStart="24dp" android:layout_marginTop="32dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary" app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-cellphone-arrow-down" app:iiv_icon="cmd-flag-checkered"
app:iiv_size="32dp" app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" /> tools:srcCompat="@android:drawable/stat_sys_phone_call_forward" />
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginRight="24dp" android:text="@string/login_finish_title"
android:text="@string/login_migration_title"
android:textSize="24sp" /> android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView <TextView
android:id="@+id/subTitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:layout_marginRight="24dp" tools:text="@string/login_finish_subtitle" />
android:text="@string/login_migration_subtitle" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:gravity="end"
android:orientation="horizontal"> android:orientation="horizontal">
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/doneButton" android:id="@+id/finishButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginRight="20dp" android:layout_marginHorizontal="16dp"
android:text="@string/done" android:text="@string/done"
android:textAllCaps="false" /> android:textAllCaps="false" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</layout> </layout>

View File

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-11.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:id="@+id/formContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-circle"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textSize="24sp"
tools:text="Zaloguj się - Vulcan UONET+" />
<TextView
android:id="@+id/subTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Opolska eSzkoła" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginVertical="4dp"
android:background="@drawable/divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="16dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:text="Podaj dane logowania, jakich używasz podczas logowania na stronie internetowej swojego e-dziennika." />
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?selectableItemBackgroundBorderless"
app:iiv_color="?colorOnBackground"
app:iiv_icon="cmd-help-circle-outline"
app:iiv_size="24dp"
tools:src="@android:drawable/ic_menu_help" />
</LinearLayout>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/fakeLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Fake login" />
<LinearLayout
android:id="@+id/errorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="@drawable/bg_rounded_8dp"
android:gravity="center_vertical"
android:minHeight="40dp"
android:orientation="horizontal"
android:paddingHorizontal="8dp"
android:visibility="gone"
tools:backgroundTint="?colorError"
tools:visibility="visible">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="24dp"
android:layout_height="24dp"
app:iiv_color="?colorOnError"
app:iiv_icon="cmd-alert-circle-outline"
app:iiv_size="20dp" />
<TextView
android:id="@+id/errorText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="4dp"
android:layout_weight="1"
android:textColor="?colorOnError"
android:textStyle="bold"
tools:text="Nieprawidłowy login lub hasło, konto nie zostało aktywowane, lub dziennik ma problemy egzystencjalne" />
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/back"
android:textAllCaps="false" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/login_button"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-11.
-->
<layout 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">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
tools:hint="Hint"
tools:startIconDrawable="@android:drawable/ic_menu">
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
android:id="@+id/textEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
</layout>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-11.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:errorEnabled="true"
app:hintAnimationEnabled="true"
app:hintEnabled="true"
tools:hint="Hint">
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
android:id="@+id/textEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<ImageButton
android:id="@+id/qrButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/transparent"
android:padding="4dp"
android:scaleType="centerInside"
tools:srcCompat="@tools:sample/avatars" />
</LinearLayout>
</layout>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-10.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="12dp">
<ImageView
android:id="@+id/logo"
android:layout_width="100dp"
android:layout_height="60dp"
android:adjustViewBounds="true"
tools:src="@sample/vulcan" />
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:background="@drawable/divider" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Lubelski Portal Oświatowy" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="edu.lublin.eu" />
</LinearLayout>
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/screenshotButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="?selectableItemBackgroundBorderless"
app:iiv_color="?colorOnBackground"
app:iiv_icon="cmd-image-search-outline"
app:iiv_size="36dp" />
</LinearLayout>
</layout>

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-10.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/topLogo"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-tooltip-account"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/login_platform_list_title"
android:textSize="24sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="2dp"
android:text="@string/login_platform_list_subtitle" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_weight="1"
android:visibility="gone"
tools:itemCount="5"
tools:listitem="@layout/login_platform_item" />
<LinearLayout
android:id="@+id/loadingLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:paddingHorizontal="16dp">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/login_platform_list_loading"
android:textAppearance="@style/NavView.TextView.Medium" />
<TextView
android:id="@+id/timeoutText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/login_platform_list_loading_timeout"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/backButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/back"
android:textAllCaps="false" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/help"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-13.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:id="@+id/imageView2"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-login"
app:iiv_size="32dp"
tools:srcCompat="@android:drawable/stat_sys_phone_call_forward" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/login_progress_title"
android:textSize="24sp" />
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:indeterminate="true" />
</LinearLayout>
</layout>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-13.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-account-check"
app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="@string/login_summary_title"
android:textSize="24sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="2dp"
android:text="@string/login_summary_subtitle" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:clipToPadding="false"
tools:itemCount="10"
tools:listitem="@layout/login_summary_item" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/registerMeSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:checked="true"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:text="@string/login_allow_registration" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/anotherButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/login_summary_add_student"
android:textAllCaps="false" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/finishButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="@string/done"
android:textAllCaps="false" />
</LinearLayout>
</LinearLayout>
</layout>

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-13.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="8dp">
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="0dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/profileName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_weight="1"
android:ellipsize="middle"
android:singleLine="true"
android:textSize="16sp"
tools:text="Jan Kowalski Bardzo długi" />
<TextView
android:id="@+id/accountType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginLeft="4dp"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="(rodzic)" />
</LinearLayout>
<TextView
android:id="@+id/profileDetails"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:textAppearance="@style/NavView.TextView.Helper"
tools:text="2B3T - 2019/2020" />
</LinearLayout>
<ImageView
android:id="@+id/modeIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
tools:srcCompat="@drawable/login_mode_mobidziennik_web" />
</LinearLayout>
</layout>

View File

@ -1,7 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto" <!--
xmlns:tools="http://schemas.android.com/tools" ~ Copyright (c) Kuba Szczodrzyński 2020-4-13.
xmlns:android="http://schemas.android.com/apk/res/android"> -->
<layout 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">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -9,80 +14,55 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:orientation="vertical"> android:layout_weight="1"
android:orientation="vertical"
android:paddingHorizontal="24dp">
<com.mikepenz.iconics.view.IconicsImageView <com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_marginStart="24dp" android:layout_marginTop="32dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="48dp"
app:iiv_color="@color/colorPrimary" app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-alert-circle" app:iiv_icon="cmd-alert-circle-outline"
app:iiv_size="32dp" app:iiv_size="32dp"
tools:srcCompat="@tools:sample/avatars" /> tools:srcCompat="@android:drawable/stat_sys_phone_call_forward" />
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginRight="24dp"
android:text="@string/login_sync_error_title" android:text="@string/login_sync_error_title"
android:textSize="24sp" /> android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:layout_marginRight="24dp" tools:text="@string/login_sync_error_subtitle" />
android:text="@string/login_sync_error_subtitle" />
<TextView <TextView
android:id="@+id/errorDetails" android:id="@+id/errorDetails"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:layout_marginRight="24dp"
tools:text="Error details" /> tools:text="Error details" />
<Space
android:layout_width="match_parent"
android:layout_height="16dp" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:gravity="end"
android:orientation="horizontal"> android:orientation="horizontal">
<Space
android:layout_width="0.0dip"
android:layout_height="0.0dip"
android:layout_weight="1.0" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/nextButton" android:id="@+id/nextButton"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginRight="20dp" android:layout_marginHorizontal="16dp"
android:text="@string/next" android:text="@string/next"
android:textAllCaps="false" /> android:textAllCaps="false" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</layout> </layout>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-13.
-->
<layout 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:orientation="vertical">
<com.mikepenz.iconics.view.IconicsImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="32dp"
app:iiv_color="@color/colorPrimary"
app:iiv_icon="cmd-sync"
app:iiv_size="32dp"
tools:srcCompat="@android:drawable/stat_sys_phone_call_forward" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/login_sync_title"
android:textSize="24sp" />
<ProgressBar
android:id="@+id/loginSyncProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:max="100"
android:indeterminate="true" />
<TextView
android:id="@+id/loginSyncSubtitle1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
tools:text="@string/login_sync_subtitle_1_format" />
<TextView
android:id="@+id/loginSyncSubtitle2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
tools:text="@string/login_sync_subtitle_2_format" />
</LinearLayout>
</layout>

View File

@ -66,7 +66,7 @@
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
tools:srcCompat="@drawable/logo_mobidziennik" /> tools:srcCompat="@drawable/login_mode_mobidziennik_web" />
</LinearLayout> </LinearLayout>
</layout> </layout>

View File

@ -1,164 +1,80 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2020-4-9.
-->
<navigation xmlns:android="http://schemas.android.com/apk/res/android" <navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_login_new"
app:startDestination="@id/loginChooserFragment"> app:startDestination="@id/loginChooserFragment">
<fragment <fragment
android:id="@+id/loginChooserFragment" android:id="@+id/loginChooserFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginChooserFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginChooserFragment"
android:label="fragment_login_type" android:label="LoginChooserFragment">
tools:layout="@layout/fragment_login_chooser" >
<action <action
android:id="@+id/action_loginTypeFragment_to_loginMobidziennikFragment" android:id="@+id/action_loginChooserFragment_to_loginPlatformListFragment"
app:destination="@id/loginMobidziennikFragment" /> app:destination="@id/loginPlatformListFragment" />
<action <action
android:id="@+id/action_loginTypeFragment_to_loginLibrusFragment" android:id="@+id/action_loginChooserFragment_to_loginFormFragment"
app:destination="@id/loginLibrusFragment" /> app:destination="@id/loginFormFragment" />
<action
android:id="@+id/action_loginTypeFragment_to_loginLibrusJstFragment"
app:destination="@id/loginLibrusJstFragment" />
<action
android:id="@+id/action_loginTypeFragment_to_loginVulcanFragment"
app:destination="@id/loginVulcanFragment" />
<action
android:id="@+id/action_loginTypeFragment_to_loginIuczniowieFragment"
app:destination="@id/loginIuczniowieFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/loginMobidziennikFragment" android:id="@+id/loginPlatformListFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginMobidziennikFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginPlatformListFragment"
android:label="fragment_login_mobidziennik" android:label="LoginPlatformListFragment">
tools:layout="@layout/fragment_login_mobidziennik" >
<action <action
android:id="@+id/action_loginMobidziennikFragment_to_loginMobidziennikHelpFragment" android:id="@+id/action_loginPlatformListFragment_to_loginFormFragment"
app:destination="@id/loginMobidziennikHelpFragment" /> app:destination="@id/loginFormFragment" />
<action
android:id="@+id/action_loginMobidziennikFragment_to_loginProgressFragment"
app:destination="@id/loginProgressFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/loginLibrusFragment" android:id="@+id/loginFormFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginLibrusFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginFormFragment"
android:label="fragment_login_librus" android:label="LoginFormFragment">
tools:layout="@layout/fragment_login_librus" >
<action <action
android:id="@+id/action_loginLibrusFragment_to_loginLibrusHelpFragment" android:id="@+id/action_loginFormFragment_to_loginProgressFragment"
app:destination="@id/loginLibrusHelpFragment" />
<action
android:id="@+id/action_loginLibrusFragment_to_loginProgressFragment"
app:destination="@id/loginProgressFragment" />
</fragment>
<fragment
android:id="@+id/loginLibrusJstFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginLibrusJstFragment"
android:label="fragment_login_librus_jst"
tools:layout="@layout/fragment_login_librus_jst" >
<action
android:id="@+id/action_loginLibrusJstFragment_to_loginProgressFragment"
app:destination="@id/loginProgressFragment" /> app:destination="@id/loginProgressFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/loginProgressFragment" android:id="@+id/loginProgressFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginProgressFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginProgressFragment"
android:label="fragment_login_progress" android:label="LoginProgressFragment">
tools:layout="@layout/fragment_login_progress" >
<action <action
android:id="@+id/action_loginProgressFragment_to_loginSummaryFragment" android:id="@+id/action_loginProgressFragment_to_loginSummaryFragment2"
app:destination="@id/loginSummaryFragment" /> app:destination="@id/loginSummaryFragment" />
</fragment> </fragment>
<fragment
android:id="@+id/loginMobidziennikHelpFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginMobidziennikHelpFragment"
android:label="fragment_login_mobidziennik_help"
tools:layout="@layout/fragment_login_mobidziennik_help" />
<fragment
android:id="@+id/loginLibrusHelpFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginLibrusHelpFragment"
android:label="fragment_login_librus_help"
tools:layout="@layout/fragment_login_librus_help" />
<fragment <fragment
android:id="@+id/loginSummaryFragment" android:id="@+id/loginSummaryFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginSummaryFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginSummaryFragment"
android:label="fragment_login_summary" android:label="LoginSummaryFragment">
tools:layout="@layout/fragment_login_summary" >
<action <action
android:id="@+id/action_loginSummaryFragment_to_loginTypeFragment" android:id="@+id/action_loginSummaryFragment_to_loginChooserFragment"
app:destination="@id/loginChooserFragment" /> app:destination="@id/loginChooserFragment" />
<action <action
android:id="@+id/action_loginSummaryFragment_to_loginSyncFragment" android:id="@+id/action_loginSummaryFragment_to_loginSyncFragment2"
app:destination="@id/loginSyncFragment" /> app:destination="@id/loginSyncFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/loginSyncFragment" android:id="@+id/loginSyncFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginSyncFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginSyncFragment"
android:label="fragment_login_sync" android:label="LoginSyncFragment">
tools:layout="@layout/fragment_login_sync" >
<action <action
android:id="@+id/action_loginSyncFragment_to_loginFinishFragment" android:id="@+id/action_loginSyncFragment_to_loginSyncErrorFragment2"
app:destination="@id/loginFinishFragment" />
<action
android:id="@+id/action_loginSyncFragment_to_loginSyncErrorFragment"
app:destination="@id/loginSyncErrorFragment" /> app:destination="@id/loginSyncErrorFragment" />
<action
android:id="@+id/action_loginSyncFragment_to_loginFinishFragment2"
app:destination="@id/loginFinishFragment" />
</fragment> </fragment>
<fragment
android:id="@+id/loginIuczniowieFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginIuczniowieFragment"
android:label="fragment_login_iuczniowie"
tools:layout="@layout/fragment_login_iuczniowie" >
<action
android:id="@+id/action_loginIuczniowieFragment_to_loginIuczniowieHelpFragment"
app:destination="@id/loginIuczniowieHelpFragment" />
<action
android:id="@+id/action_loginIuczniowieFragment_to_loginProgressFragment"
app:destination="@id/loginProgressFragment" />
</fragment>
<fragment
android:id="@+id/loginVulcanFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginVulcanFragment"
android:label="fragment_login_vulcan"
tools:layout="@layout/fragment_login_vulcan" >
<action
android:id="@+id/action_loginVulcanFragment_to_loginVulcanHelpFragment"
app:destination="@id/loginVulcanHelpFragment" />
<action
android:id="@+id/action_loginVulcanFragment_to_loginProgressFragment"
app:destination="@id/loginProgressFragment" />
</fragment>
<fragment
android:id="@+id/loginEdudziennikFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginEdudziennikFragment"
android:label="fragment_login_edudziennik"
tools:layout="@layout/fragment_login_edudziennik" >
<!--<action
android:id="@+id/action_loginLibrusFragment_to_loginLibrusHelpFragment"
app:destination="@id/loginLibrusHelpFragment" />-->
<action
android:id="@+id/action_loginEdudziennikFragment_to_loginProgressFragment"
app:destination="@id/loginProgressFragment" />
</fragment>
<fragment
android:id="@+id/loginVulcanHelpFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginVulcanHelpFragment"
android:label="fragment_login_vulcan_help"
tools:layout="@layout/fragment_login_vulcan_help" />
<fragment
android:id="@+id/loginIuczniowieHelpFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginIuczniowieHelpFragment"
android:label="fragment_login_iuczniowie_help"
tools:layout="@layout/fragment_login_iuczniowie_help" />
<fragment
android:id="@+id/loginFinishFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginFinishFragment"
android:label="fragment_login_finish"
tools:layout="@layout/fragment_login_finish" />
<fragment <fragment
android:id="@+id/loginSyncErrorFragment" android:id="@+id/loginSyncErrorFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginSyncErrorFragment" android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginSyncErrorFragment"
android:label="fragment_login_sync_error" android:label="LoginSyncErrorFragment">
tools:layout="@layout/fragment_login_sync_error" >
<action <action
android:id="@+id/action_loginSyncErrorFragment_to_loginFinishFragment" android:id="@+id/action_loginSyncErrorFragment_to_loginFinishFragment2"
app:destination="@id/loginFinishFragment" /> app:destination="@id/loginFinishFragment" />
</fragment> </fragment>
<fragment
android:id="@+id/loginFinishFragment"
android:name="pl.szczodrzynski.edziennik.ui.modules.login.LoginFinishFragment"
android:label="LoginFinishFragment" />
</navigation> </navigation>

View File

@ -592,8 +592,8 @@
<string name="login_progress_title">Logging in…</string> <string name="login_progress_title">Logging in…</string>
<string name="login_startpage_subtitle">Choose the e-register which your school uses. Later you\'ll be able to add more accounts using different e-registers.</string> <string name="login_startpage_subtitle">Choose the e-register which your school uses. Later you\'ll be able to add more accounts using different e-registers.</string>
<string name="login_startpage_title">Which e-register do you use?</string> <string name="login_startpage_title">Which e-register do you use?</string>
<string name="login_summary_account_child">(child)</string> <string name="account_type_child">(child)</string>
<string name="login_summary_account_parent">(parent)</string> <string name="account_type_parent">(parent)</string>
<string name="login_summary_add_student">Add a student</string> <string name="login_summary_add_student">Add a student</string>
<string name="login_summary_no_profiles_text">You have to select at least one profile to save in the app.</string> <string name="login_summary_no_profiles_text">You have to select at least one profile to save in the app.</string>
<string name="login_summary_no_profiles_title">No profile selected</string> <string name="login_summary_no_profiles_title">No profile selected</string>

View File

@ -626,8 +626,8 @@
<string name="login_progress_title">Loguję…</string> <string name="login_progress_title">Loguję…</string>
<string name="login_startpage_subtitle">Wybierz z jakiego e-dziennika korzysta Twoja szkoła. W późniejszych etapach będziesz mógł dodać kilka kont z różnych e-dzienników.</string> <string name="login_startpage_subtitle">Wybierz z jakiego e-dziennika korzysta Twoja szkoła. W późniejszych etapach będziesz mógł dodać kilka kont z różnych e-dzienników.</string>
<string name="login_startpage_title">Z jakiego e-dziennika korzystasz?</string> <string name="login_startpage_title">Z jakiego e-dziennika korzystasz?</string>
<string name="login_summary_account_child">(uczeń)</string> <string name="account_type_child">(uczeń)</string>
<string name="login_summary_account_parent">(rodzic)</string> <string name="account_type_parent">(rodzic)</string>
<string name="login_summary_add_student">Dodaj ucznia</string> <string name="login_summary_add_student">Dodaj ucznia</string>
<string name="login_summary_no_profiles_text">Musisz wybrać przynajmniej jeden profil, który chcesz zapisać w aplikacji.</string> <string name="login_summary_no_profiles_text">Musisz wybrać przynajmniej jeden profil, który chcesz zapisać w aplikacji.</string>
<string name="login_summary_no_profiles_title">Nie wybrałeś żadnego profilu</string> <string name="login_summary_no_profiles_title">Nie wybrałeś żadnego profilu</string>
@ -1286,4 +1286,34 @@
<string name="yesterday">wczoraj</string> <string name="yesterday">wczoraj</string>
<string name="you_are_offline_text">Jesteś offline. Spróbuj włączyć Wi-Fi lub dane komórkowe.</string> <string name="you_are_offline_text">Jesteś offline. Spróbuj włączyć Wi-Fi lub dane komórkowe.</string>
<string name="you_are_offline_title">Połączenie sieciowe</string> <string name="you_are_offline_title">Połączenie sieciowe</string>
<string name="login_chooser_title">Jaki masz e-dziennik w szkole?</string>
<string name="login_chooser_subtitle">Wybierz z jakiego e-dziennika korzysta Twoja szkoła. Jeśli masz kilka kont w różnych dziennikach, będziesz mógł je dodać później.</string>
<string name="login_register_librus">Librus/Synergia</string>
<string name="login_mode_librus_email">Zaloguj używając e-maila</string>
<string name="login_mode_librus_email_hint">Musisz posiadać konto Librus Rodzina</string>
<string name="login_mode_librus_synergia">Zaloguj używając loginu i hasła</string>
<string name="login_mode_librus_synergia_hint">Użyj loginu w postaci \"9874123u\"</string>
<string name="login_mode_librus_jst">Logowanie przez platformę VULCAN</string>
<string name="login_mode_librus_jst_hint">Oświata w Radomiu oraz Innowacyjny Tarnobrzeg</string>
<string name="login_type_vulcan">Vulcan UONET+</string>
<string name="login_mode_vulcan_api">Użyj tokenu, symbolu i kodu PIN</string>
<string name="login_mode_vulcan_api_hint">Zarejestruj urządzenie na stronie dziennika Vulcan</string>
<string name="login_mode_vulcan_web">Użyj e-maila/nazwy użytkownika i hasła</string>
<string name="login_mode_vulcan_web_hint">Zaloguj danymi, które podajesz na stronie e-dziennika VULCAN</string>
<string name="login_type_mobidziennik">MobiDziennik</string>
<string name="login_mode_mobidziennik_web">Zaloguj nazwą serwera, loginem i hasłem</string>
<string name="login_mode_mobidziennik_web_hint">Podaj dane, których używasz na stronie e-dziennika</string>
<string name="login_platform_list_title">W jaki sposób się logujesz do dziennika?</string>
<string name="login_platform_list_subtitle">Wybierz, który obrazek odpowiada temu, który widzisz podczas logowania na stronie internetowej swojego dziennika.\n\nJeżeli Twoja szkoła nie korzysta z żadnej z tych platform miejskich, wybierz pierwszą opcję.</string>
<string name="login_platform_list_loading">Ładowanie listy e-dzienników…</string>
<string name="login_platform_list_loading_timeout">Jeśli trwa to za długo, sprawdź swoje połączenie internetowe i zrestartuj aplikację.</string>
<string name="login_form_title_format">Zaloguj się - %s</string>
<string name="login_mode_librus_email_guide">Zaloguj się swoim kontem Librus, które działa w oficjalnej aplikacji Librus oraz na stronie portal.librus.pl, w niebieskim formularzu.\n\nJeśli nie masz konta Librus, możesz je założyć na stronie https://portal.librus.pl/rodzina/register.</string>
<string name="login_mode_librus_synergia_guide">Podaj login otrzymany od szkoły, którym logujesz się do Synergii (fioletowy formularz).\n\nZalecane jest logowanie kontem Portal Librus (używając e-maila) w poprzednim kroku.</string>
<string name="login_mode_librus_jst_guide">Zaloguj się do Librusa na komputerze, wybierz zakładkę Aplikacje Mobilne, następnie wpisz otrzymany Token i PIN poniżej.</string>
<string name="login_mode_vulcan_api_guide">Zaloguj się do dziennika Vulcan na komputerze, wybierz zakładkę Dostęp Mobilny, kliknij przycisk Zarejestruj urządzenie mobilne. Podaj otrzymany Token, Symbol i PIN w polach poniżej.</string>
<string name="login_mode_vulcan_web_guide">Podaj dane, którymi logujesz się na stronie internetowej dziennika VULCAN lub na miejskiej platformie.</string>
<string name="login_mode_mobidziennik_web_guide">Podaj dane, których używasz do logowania na stronie MobiDziennika. Jako adres serwera możesz wpisać adres strony internetowej, na której masz MobiDziennik.</string>
<string name="settings_add_student_text">Dodaj nowego ucznia</string>
<string name="settings_add_student_subtext">Zaloguj konto ucznia/rodzica w aplikacji</string>
</resources> </resources>