grades ui polishing & sorting fix
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
42d938b0bc
commit
638c321798
|
@ -11,7 +11,7 @@ android {
|
|||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 15
|
||||
versionName "0.5.92"
|
||||
versionName "0.5.93-RC1"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
resValue "string", "build_time", buildTime()
|
||||
setProperty("archivesBaseName", "projectlaogai-$versionName")
|
||||
|
|
|
@ -35,34 +35,33 @@ import org.mosad.seil0.projectlaogai.util.gradeSubject
|
|||
import java.security.KeyStore
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* TODO context in constructor?
|
||||
* Parse the qispos site the get all needed data for the grades fragment
|
||||
*/
|
||||
class QISPOSParser {
|
||||
class QISPOSParser(val context: Context) {
|
||||
|
||||
private val className = this.javaClass.name
|
||||
private val baseURL = "https://notenverwaltung.hs-offenburg.de"
|
||||
private val loginPath = "/qispos/rds?state=user&type=1&category=auth.login&startpage=portal.vm&breadCrumbSource=portal"
|
||||
//private val rootPath = "/qispos/rds?state=change&type=1&moduleParameter=studyPOSMenu&nextdir=change&next=menu.vm&subdir=applications&xml=menu&purge=y&navigationPosition=functions%2CstudyPOSMenu&breadcrumb=studyPOSMenu&topitem=functions&subitem=studyPOSMenu"
|
||||
|
||||
|
||||
fun parseGrades(context: Context): HashMap<String, ArrayList<gradeSubject>> {
|
||||
/**
|
||||
* parse the html from readGrades()
|
||||
* @return a SortedMap, each entry is a semester, each semester has a ArrayList with subjects
|
||||
*/
|
||||
fun parseGrades(): SortedMap<String, ArrayList<gradeSubject>> {
|
||||
val gradesMap = HashMap<String, ArrayList<gradeSubject>>()
|
||||
val gradesListHtml = readGrades(context)
|
||||
val gradesListHtml = readGrades()
|
||||
|
||||
gradesListHtml?.select("table > tbody > tr")?.forEach {
|
||||
//val row = it.select("td.qis_konto")
|
||||
|
||||
val row = it.select("td.tabelle1_alignleft,td.tabelle1_aligncenter,td.tabelle1_alignright")
|
||||
|
||||
//println("-----------------------------------------------------------")
|
||||
//println(it.select("td.qis_konto"))
|
||||
|
||||
//if(row.size >= 6) {
|
||||
// only real subjects will be selected
|
||||
if(row.size >= 6 && row[0].text().length >=7) {
|
||||
val subject = gradeSubject(
|
||||
|
@ -75,39 +74,30 @@ class QISPOSParser {
|
|||
|
||||
if (gradesMap.containsKey(subject.semester)) {
|
||||
gradesMap[subject.semester]!!.add(subject)
|
||||
println(subject.name)
|
||||
} else {
|
||||
gradesMap[subject.semester] = arrayListOf(subject)
|
||||
println(subject.name)
|
||||
}
|
||||
|
||||
println("ID: ${row[0].text()}")
|
||||
println("Subject Name: ${row[1].text()}")
|
||||
println("Semester: ${row[2].text()}")
|
||||
println("Grade: ${row[3].text()}")
|
||||
println("Credits: ${row[5].text()}")
|
||||
println("------------------------------------------------------")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
println(gradesMap)
|
||||
gradesMap.forEach {
|
||||
println("${it.key}: ${it.value}")
|
||||
|
||||
// return the sorted map
|
||||
return gradesMap.toSortedMap(compareBy<String>{
|
||||
val oText = it.substringAfter(" ")
|
||||
|
||||
if (oText.contains("/")) {
|
||||
oText.substringBefore("/").toInt() + 0.5
|
||||
} else {
|
||||
oText.toDouble()
|
||||
}
|
||||
|
||||
// TODO sort
|
||||
|
||||
println("finished parsing!")
|
||||
|
||||
return gradesMap
|
||||
}.thenBy { it })
|
||||
}
|
||||
|
||||
/**
|
||||
* read the grades html from qispos
|
||||
* @return the grades list as html element or null
|
||||
*/
|
||||
private fun readGrades(context: Context): Element?{
|
||||
private fun readGrades(): Element?{
|
||||
|
||||
val credentials = EncryptedPreferences.readCredentials(context)
|
||||
val username = credentials.first.substringBefore("@")
|
||||
|
@ -116,10 +106,7 @@ class QISPOSParser {
|
|||
return runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
println("querying qispos ...")
|
||||
println("using $username with ********")
|
||||
|
||||
val socketFactory = createSSLSocketFactory(context)
|
||||
val socketFactory = createSSLSocketFactory()
|
||||
|
||||
// login, asdf = username, fdsa = password, wtf
|
||||
val list = mapOf(
|
||||
|
@ -136,16 +123,13 @@ class QISPOSParser {
|
|||
.data(list)
|
||||
.postDataCharset("UTF-8")
|
||||
.execute()
|
||||
Log.i(className, "login status is: ${res.statusMessage()}: ${res.statusCode()}")
|
||||
|
||||
val loginCookies = res.cookies()
|
||||
|
||||
println("cookies: $loginCookies")
|
||||
println("status is: ${res.statusMessage()}: ${res.statusCode()}")
|
||||
|
||||
// grades root document and url
|
||||
val rootHtml =Jsoup.parse(res.body())
|
||||
val gradesRootLink = rootHtml.select("li.menueListStyle > a.auflistung").last().attr("abs:href")
|
||||
println(gradesRootLink)
|
||||
|
||||
// parse grades url
|
||||
val gradesHtml = Jsoup.connect(gradesRootLink)
|
||||
|
@ -156,7 +140,6 @@ class QISPOSParser {
|
|||
.get()
|
||||
|
||||
val gradesNextLink = gradesHtml.select("li.treelist > a.regular").attr("abs:href")
|
||||
println(gradesNextLink)
|
||||
|
||||
val gradesNextHtml = Jsoup.connect(gradesNextLink)
|
||||
.sslSocketFactory(socketFactory)
|
||||
|
@ -166,7 +149,6 @@ class QISPOSParser {
|
|||
.get()
|
||||
|
||||
val gradesListLink = gradesNextHtml.selectFirst("li.treelist > ul > li").selectFirst("a").attr("abs:href")
|
||||
println(gradesListLink)
|
||||
|
||||
// get the grades list
|
||||
val gradesListHtml = Jsoup.connect(gradesListLink)
|
||||
|
@ -179,7 +161,7 @@ class QISPOSParser {
|
|||
//println(gradesListHtml.body())
|
||||
gradesListHtml.body()
|
||||
} catch (ex: Exception) {
|
||||
Log.e(className, "could not load qispos", ex)
|
||||
Log.e(className, "error while loading qispos", ex)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +169,10 @@ class QISPOSParser {
|
|||
|
||||
}
|
||||
|
||||
private fun createSSLSocketFactory(context: Context): SSLSocketFactory {
|
||||
/**
|
||||
* since the HS has a fucked up tls setup we need to work around that
|
||||
*/
|
||||
private fun createSSLSocketFactory(): SSLSocketFactory {
|
||||
// Load CAs from an InputStream
|
||||
// (could be from a resource or ByteArrayInputStream or ...)
|
||||
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
|
||||
|
@ -195,7 +180,6 @@ class QISPOSParser {
|
|||
val ca = caInput.use {
|
||||
cf.generateCertificate(it) as X509Certificate
|
||||
}
|
||||
println("ca=" + ca.subjectDN)
|
||||
|
||||
// Create a KeyStore containing our trusted CAs
|
||||
val keyStoreType = KeyStore.getDefaultType()
|
||||
|
|
|
@ -71,8 +71,7 @@ object EncryptedPreferences {
|
|||
fun load(context: Context) {
|
||||
with(getEncryptedPreferences(context)) {
|
||||
email = this?.getString(
|
||||
context.getString(R.string.save_key_user_email),
|
||||
context.getString(R.string.sample_user)
|
||||
context.getString(R.string.save_key_user_email), ""
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.mosad.seil0.projectlaogai.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import kotlinx.android.synthetic.main.fragment_grades.*
|
||||
|
@ -36,11 +36,14 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.QISPOSParser
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.GradeLinearLayout
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoginDialog
|
||||
|
||||
/**
|
||||
* A simple [Fragment] subclass.
|
||||
* The grades fragment class
|
||||
* contains all needed parts to display and the grades screen
|
||||
*/
|
||||
class GradesFragment : Fragment() {
|
||||
|
||||
|
@ -52,20 +55,51 @@ class GradesFragment : Fragment() {
|
|||
refreshLayoutGrades = view.findViewById(R.id.refreshLayout_Grades)
|
||||
refreshLayoutGrades.isEnabled = false // disable swipe
|
||||
|
||||
if (checkCredentials()) {
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
addGrades()
|
||||
}
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the credentials are set, if not show a login dialog
|
||||
*/
|
||||
private fun checkCredentials(): Boolean {
|
||||
val credentials = EncryptedPreferences.readCredentials(context!!)
|
||||
var credentialsPresent = false
|
||||
|
||||
// if there is no password set, show the login dialog
|
||||
if (credentials.first.isEmpty() || credentials.second.isEmpty()) {
|
||||
LoginDialog(this.context!!)
|
||||
.positiveButton {
|
||||
EncryptedPreferences.saveCredentials(email, password, context)
|
||||
addGrades()
|
||||
}
|
||||
.negativeButton {
|
||||
txtView_Loading.text = resources.getString(R.string.credentials_missing)
|
||||
}
|
||||
.show {
|
||||
email = EncryptedPreferences.email
|
||||
password = ""
|
||||
}
|
||||
} else {
|
||||
credentialsPresent = true
|
||||
}
|
||||
|
||||
return credentialsPresent
|
||||
}
|
||||
|
||||
// add the grades to the layout, async
|
||||
private fun addGrades() = GlobalScope.launch(Dispatchers.Default) {
|
||||
withContext(Dispatchers.Main) {
|
||||
refreshLayout_Grades.isRefreshing = true
|
||||
}
|
||||
|
||||
val parser = QISPOSParser()
|
||||
val grades = parser.parseGrades(context!!)
|
||||
val parser = QISPOSParser(context!!)
|
||||
val grades = parser.parseGrades()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
linLayout_Grades.removeAllViews() // clear layout
|
||||
|
@ -73,16 +107,40 @@ class GradesFragment : Fragment() {
|
|||
|
||||
// for each semester add a new card
|
||||
grades.forEach { semester ->
|
||||
val usedSubjects = ArrayList<String>()
|
||||
val semesterCard = DayCardView(context!!)
|
||||
semesterCard.setDayHeading(semester.key)
|
||||
|
||||
// for each subject add a new linLayout
|
||||
semester.value.forEachIndexed { index, subject ->
|
||||
if (usedSubjects.contains(subject.name)) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
// get the first sub subjects
|
||||
val subSubject = semester.value.firstOrNull {
|
||||
it.name.contains(subject.name) && it.name != subject.name
|
||||
}
|
||||
|
||||
// if sub subject is not null, add it to used subjects
|
||||
subSubject?.let {
|
||||
usedSubjects.add(it.name)
|
||||
}
|
||||
|
||||
val subjectLayout = GradeLinearLayout(context).set {
|
||||
subjectName = subject.name
|
||||
grade = subject.grade
|
||||
subSubjectName = subSubject?.name.toString()
|
||||
subGrade = subSubject?.grade.toString()
|
||||
}
|
||||
|
||||
// disable sub-subject if not set
|
||||
if (subSubject == null)
|
||||
subjectLayout.disableSubSubject()
|
||||
|
||||
// FIXME this is broken
|
||||
// disable divider if last element
|
||||
//if (index == semester.value.lastIndex || semester.value.indexOf(subSubject) == semester.value.lastIndex)
|
||||
if (index == semester.value.lastIndex)
|
||||
subjectLayout.disableDivider()
|
||||
|
||||
|
@ -94,11 +152,17 @@ class GradesFragment : Fragment() {
|
|||
linLayout_Grades.addView(semesterCard)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
refreshLayout_Grades.isRefreshing = false
|
||||
|
||||
val txtViewLegal = TextView(context).apply {
|
||||
text = resources.getString(R.string.without_guarantee)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
}
|
||||
|
||||
//refreshLayoutGrades.isRefreshing = false
|
||||
// stop refreshing and show legal warning
|
||||
withContext(Dispatchers.Main) {
|
||||
linLayout_Grades.addView(txtViewLegal)
|
||||
refreshLayout_Grades.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -105,7 +105,7 @@ class SettingsFragment : Fragment() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// initialize the settings gui
|
||||
txtView_User.text = EncryptedPreferences.email
|
||||
txtView_User.text = EncryptedPreferences.email.ifEmpty { resources.getString(R.string.sample_user) }
|
||||
txtView_Course.text = cCourse.courseName
|
||||
txtView_AboutDesc.text = resources.getString(R.string.about_version, BuildConfig.VERSION_NAME, getString(R.string.build_time))
|
||||
switch_buffet.isChecked = cShowBuffet // init switch
|
||||
|
@ -140,7 +140,6 @@ class SettingsFragment : Fragment() {
|
|||
// open a new dialog
|
||||
LoginDialog(context!!)
|
||||
.positiveButton {
|
||||
println("Test: $password")
|
||||
EncryptedPreferences.saveCredentials(email, password, context)
|
||||
}
|
||||
.show {
|
||||
|
|
|
@ -33,6 +33,8 @@ class GradeLinearLayout(context: Context?): LinearLayout(context) {
|
|||
|
||||
var subjectName = ""
|
||||
var grade = ""
|
||||
var subSubjectName = ""
|
||||
var subGrade = ""
|
||||
|
||||
init {
|
||||
CardView.inflate(context, R.layout.linearlayout_grade, this)
|
||||
|
@ -43,9 +45,15 @@ class GradeLinearLayout(context: Context?): LinearLayout(context) {
|
|||
|
||||
txtView_subject.text = subjectName
|
||||
txtView_grade.text = grade
|
||||
txtView_sub_subject.text = subSubjectName
|
||||
txtView_sub_grade.text = subGrade
|
||||
}
|
||||
|
||||
fun disableDivider() {
|
||||
divider_grades.visibility = View.GONE
|
||||
divider_grade.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun disableSubSubject() {
|
||||
linLayout_sub_subject.visibility = View.GONE
|
||||
}
|
||||
}
|
|
@ -45,8 +45,8 @@ class LoginDialog(val context: Context) {
|
|||
var password = ""
|
||||
|
||||
init {
|
||||
dialog.title(R.string.grades_heading)
|
||||
.message(R.string.grades_desc_on)
|
||||
dialog.title(R.string.login_heading)
|
||||
.message(R.string.login_desc_on)
|
||||
.customView(R.layout.dialog_login)
|
||||
.positiveButton(R.string.save)
|
||||
.negativeButton(R.string.cancel)
|
||||
|
@ -69,6 +69,12 @@ class LoginDialog(val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun negativeButton(func: LoginDialog.() -> Unit): LoginDialog = apply {
|
||||
dialog.negativeButton {
|
||||
func()
|
||||
}
|
||||
}
|
||||
|
||||
fun show(func: LoginDialog.() -> Unit): LoginDialog = apply {
|
||||
func()
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,7h16v2H4V7zM4,13h16v-2H4V13zM4,17h7v-2H4V17zM4,21h7v-2H4V21zM15.41,18.17L14,16.75l-1.41,1.41L15.41,21L20,16.42L18.58,15L15.41,18.17zM4,3v2h16V3H4z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
|
@ -10,6 +10,7 @@
|
|||
android:paddingBottom="3dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linLayout_subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
@ -19,23 +20,51 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Mathematik 1"
|
||||
android:text="@string/sample_subject"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtView_grade"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:text="2,0"
|
||||
android:text="@string/sample_grade"
|
||||
android:textAlignment="textEnd"
|
||||
android:textSize="15sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linLayout_sub_subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="7dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingEnd="0dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtView_sub_subject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/sample_sub_subject" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtView_sub_grade"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/sample_grade_state"
|
||||
android:textAlignment="textEnd" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider_grades"
|
||||
android:id="@+id/divider_grade"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?dividerColor" />
|
||||
</LinearLayout>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
android:id="@+id/txtView_Grades"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/grades_heading"
|
||||
android:text="@string/login_heading"
|
||||
android:textAlignment="center"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold" />
|
||||
|
@ -49,7 +49,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="7dp"
|
||||
android:text="@string/grades_desc_on"
|
||||
android:text="@string/login_desc_on"
|
||||
android:textAlignment="center"
|
||||
android:textSize="18sp" />
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
android:id="@+id/txtView_UserDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/user" />
|
||||
android:text="@string/user_desc" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
android:title="@string/moodle"/>
|
||||
<item
|
||||
android:id="@+id/nav_grades"
|
||||
android:icon="@drawable/icon_checkmark_black"
|
||||
android:icon="@drawable/ic_grading_black_24dp"
|
||||
android:title="@string/grades" />
|
||||
<item
|
||||
android:id="@+id/nav_settings"
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<string name="get_started">los geht\'s</string>
|
||||
<string name="course_heading">Studiengang</string>
|
||||
<string name="course_desc_on">Wähle deinen aktuellen Studiengang.\nZusätzliche Vorlesungen können später hinzugefügt werden.</string>
|
||||
<string name="grades_heading">Noten</string>
|
||||
<string name="grades_desc_on">Project Laogai kann auf die Notenverwaltung zugreifen. Deine Login-Daten werden verschlüsselt auf deinem Gerät gespeichert. Diese Funktion wird "as is" und ohne Garantie bereitgestellt.</string>
|
||||
<string name="login_heading">Login</string>
|
||||
<string name="login_desc_on">Project Laogai kann auf die Notenverwaltung zugreifen. Deine Login-Daten werden verschlüsselt auf deinem Gerät gespeichert. Diese Funktion wird "as is" und ohne Garantie bereitgestellt.</string>
|
||||
<string name="email">E-Mail</string>
|
||||
<string name="password">Passwort</string>
|
||||
<string name="login">login</string>
|
||||
|
@ -41,10 +41,12 @@
|
|||
|
||||
<!-- fragment_grades -->
|
||||
<string name="loading_from_hs">Lade Daten von den Hochschul Servern.\nDas kann eine Weile dauern.</string>
|
||||
<string name="credentials_missing">Diese Funktion benötigt deine Login-Daten. Bitte logge dich über die Einstellungen ein.</string>
|
||||
<string name="without_guarantee">Alle Angaben ohne Gewähr.</string>
|
||||
|
||||
<!-- fragment_settings -->
|
||||
<string name="info">Info</string>
|
||||
<string name="user">Benutzer</string>
|
||||
<string name="user_desc">Zum bearbeiten tippen</string>
|
||||
<string name="course_desc">Tippe um den Kurs zu ändern</string>
|
||||
<string name="manage_lessons">Bearbeite Zusätzliche Vorlesungen</string>
|
||||
<string name="manage_lessons_desc">Tippe um zusätzliche Vorlesungen zu bearbeiten</string>
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
<string name="get_started">get started</string>
|
||||
<string name="course_heading">Course</string>
|
||||
<string name="course_desc_on">Select your current course.\nAdditional lessons can be added later.</string>
|
||||
<string name="grades_heading">Grades</string>
|
||||
<string name="grades_desc_on">Project Laogai can connect to the HIS Online-Portal. Your Login-Data will be stored encrypted on your device. This feature is provided "as is", without any warranty.</string>
|
||||
<string name="login_heading">Login</string>
|
||||
<string name="login_desc_on">Project Laogai can connect to the HIS Online-Portal. Your Login-Data will be stored encrypted on your device. This feature is provided "as is", without any guarantee.</string>
|
||||
<string name="email">E-Mail</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="login">login</string>
|
||||
|
@ -43,10 +43,12 @@
|
|||
|
||||
<!-- fragment_grades -->
|
||||
<string name="loading_from_hs">Loading data from the university servers.\nThis may take a while.</string>
|
||||
<string name="credentials_missing">This feature needs your Login-Data to work. Please login via the settings.</string>
|
||||
<string name="without_guarantee">All information is supplied without guarantee.</string>
|
||||
|
||||
<!-- fragment_settings -->
|
||||
<string name="info">Info</string>
|
||||
<string name="user">User</string>
|
||||
<string name="user_desc">Tap to edit</string>
|
||||
<string name="course_desc">Tap to change course</string>
|
||||
<string name="manage_lessons">Manage Additional Lessons</string>
|
||||
<string name="manage_lessons_desc">Tap to manage additional lessons</string>
|
||||
|
@ -79,8 +81,12 @@
|
|||
|
||||
<!-- sample strings -->
|
||||
<string name="sample_user" translatable="false">spinefield@stud.hs-offenburg.de</string>
|
||||
<string name="sample_course" translatable="false">SampleCourse 3</string>
|
||||
<string name="sample_date" translatable="false">Montag, 30.02</string>
|
||||
<string name="sample_course" translatable="false">Everything</string>
|
||||
<string name="sample_subject" translatable="false">Earthbending</string>
|
||||
<string name="sample_sub_subject" translatable="false">Applied Earthbending</string>
|
||||
<string name="sample_grade" translatable="false">1,0</string>
|
||||
<string name="sample_grade_state" translatable="false">passed</string>
|
||||
<string name="sample_date" translatable="false">Monday, 30.02</string>
|
||||
<string name="a_time" translatable="false">0.00 – 23.59</string>
|
||||
|
||||
<!-- errors -->
|
||||
|
|
Loading…
Reference in New Issue