diff --git a/app/build.gradle b/app/build.gradle
index e4af4a9..0edf59e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
applicationId "com.nareshkumarrao.eiweblog"
minSdkVersion 16
targetSdkVersion 30
- versionCode 4
- versionName "0.9.3"
+ versionCode 5
+ versionName "0.10.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -42,12 +42,13 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.android.volley:volley:1.2.0'
implementation "androidx.work:work-runtime-ktx:2.5.0"
-
-
+ implementation 'org.jsoup:jsoup:1.13.1'
+ implementation 'com.google.code.gson:gson:2.8.6'
}
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
index 6e7cb04..bcbfcbc 100644
Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index ed7cac1..97322b7 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -10,8 +10,8 @@
{
"type": "SINGLE",
"filters": [],
- "versionCode": 4,
- "versionName": "0.9.3",
+ "versionCode": 5,
+ "versionName": "0.10.1",
"outputFile": "app-release.apk"
}
]
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2669787..533a159 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,14 +11,18 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.EIWeblog">
+
+ android:parentActivityName=".MainActivity"
+ android:theme="@style/Theme.EIWeblog.NoActionBar" />
+ android:parentActivityName=".MainActivity"
+ android:theme="@style/Theme.EIWeblog.NoActionBar" />
(R.id.grades_toolbar) as Toolbar
+ setSupportActionBar(myToolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ supportActionBar?.setDisplayShowTitleEnabled(false)
+
+ findViewById(R.id.grades_recycler).apply {
+ layoutManager = LinearLayoutManager(this@GradesActivity)
+ adapter = ItemArticleAdapter(listOf())
+ }
+ findViewById(R.id.grades_recycler).addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
+ val swipeRefreshLayout = findViewById(R.id.grades_swipe_refresh)
+ swipeRefreshLayout?.setOnRefreshListener {
+ HISUtility.fetchExamRows(this, ::updateExamRows)
+ }
+
+ val sharedPref = getSharedPreferences(
+ getString(R.string.preference_file_key),
+ Context.MODE_PRIVATE
+ )
+
+ val username = sharedPref?.getString(getString(R.string.username_key), null)
+ if( username == null ){
+ val loginDialog = LoginDialogFragment(this, false) {
+ HISUtility.fetchExamRows(this, ::updateExamRows)
+ }
+ loginDialog.show(supportFragmentManager, "loginDialog")
+ }else{
+ val savedRows = HISUtility.getSavedExamRows(this)
+ if(savedRows == null){
+ HISUtility.fetchExamRows(this, ::updateExamRows)
+ }else{
+ updateExamRows(savedRows)
+ }
+ }
+ }
+
+ private fun updateExamRows(examRows: List?){
+ examRows ?: run {
+ val loginDialog = LoginDialogFragment(this, true){
+ HISUtility.fetchExamRows(this, ::updateExamRows)
+ }
+ loginDialog.show(supportFragmentManager, "loginDialog")
+ return
+ }
+ this@GradesActivity.runOnUiThread {
+ findViewById(R.id.grades_recycler)?.apply {
+ layoutManager = LinearLayoutManager(this@GradesActivity)
+ adapter = ItemGradesAdapter(examRows)
+ }
+ findViewById(R.id.grades_swipe_refresh).isRefreshing=false
+ findViewById(R.id.gradesProgressBar).visibility=View.GONE
+ }
+ }
+}
+
+class LoginDialogFragment(val context: GradesActivity, private val isError: Boolean, val loginCallback: () -> Unit?) : DialogFragment() {
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ return activity?.let {
+ val builder = AlertDialog.Builder(it)
+ val inflater = requireActivity().layoutInflater
+ val dialogView = inflater.inflate(R.layout.dialog_login, null)
+ if(isError){
+ dialogView.findViewById(R.id.errorText).visibility=View.VISIBLE
+ }else{
+ dialogView.findViewById(R.id.errorText).visibility=View.INVISIBLE
+ }
+ builder.setView(dialogView)
+ .setPositiveButton(
+ R.string.login
+ ) { _, _ ->
+ val username = dialogView.findViewById(R.id.loginUsername).text.toString()
+ val password = dialogView.findViewById(R.id.loginPassword).text.toString()
+ HISUtility.setUsernamePassword(context, username, password)
+ loginCallback()
+ }
+ .setNegativeButton(
+ R.string.cancel
+ ) { _, _ ->
+ dialog?.cancel()
+ context.finish()
+ }
+ builder.create()
+ } ?: throw IllegalStateException("Activity cannot be null")
+
+ }
+}
diff --git a/app/src/main/java/com/nareshkumarrao/eiweblog/HISUtility.kt b/app/src/main/java/com/nareshkumarrao/eiweblog/HISUtility.kt
new file mode 100644
index 0000000..5ee8d9a
--- /dev/null
+++ b/app/src/main/java/com/nareshkumarrao/eiweblog/HISUtility.kt
@@ -0,0 +1,173 @@
+package com.nareshkumarrao.eiweblog
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import org.jsoup.Connection
+import org.jsoup.Jsoup
+
+data class ExamRow(val name: String, val grade: String, val attempt: String, val date: String)
+
+internal object HISUtility {
+
+ fun setUsernamePassword(context: Context?, username: String, password: String) {
+ val sharedPref = context?.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+ if (sharedPref != null) {
+ with(sharedPref.edit()) {
+ putString(context.getString(R.string.username_key), username)
+ putString(context.getString(R.string.password_key), password)
+ apply()
+ }
+ }
+ }
+
+ fun checkForUpdates(context: Context?, callback: (examRows: List?) -> Unit) {
+ val savedRows = getSavedExamRows(context) ?: run {
+ callback(null)
+ return
+ }
+
+ val newRows: MutableList = mutableListOf()
+ fetchExamRows(context) { examRows ->
+ if (examRows != null) {
+ for (examRow in examRows) {
+ if (!savedRows.contains(examRow)) {
+ newRows.add(examRow)
+ }
+ }
+ }
+ callback(newRows)
+ }
+
+
+ }
+
+ fun getSavedExamRows(context: Context?): List? {
+ val sharedPref = context?.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+ val examRowsJson = sharedPref?.getString(context.getString(R.string.exam_rows_key), null)
+ ?: return null
+ val examRowsType = object : TypeToken>() {}.type
+ return Gson().fromJson(examRowsJson, examRowsType)
+ }
+
+ private fun saveExamRows(context: Context?, examRows: List) {
+ val examRowsJson = Gson().toJson(examRows)
+ val sharedPref = context?.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+ if (sharedPref != null) {
+ with(sharedPref.edit()) {
+ putString(context.getString(R.string.exam_rows_key), examRowsJson)
+ apply()
+ }
+ }
+ }
+
+ @Throws(LoginFailedException::class)
+ fun fetchExamRows(context: Context?, callback: (examRows: List?) -> Unit): Unit? {
+ val sharedPref = context?.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+ val username = sharedPref?.getString(context.getString(R.string.username_key), null)
+ ?: return null
+ val password = sharedPref.getString(context.getString(R.string.password_key), null)
+ ?: return null
+
+ val runnable = Runnable {
+ val postData: MutableMap = mutableMapOf()
+ postData["asdf"] = username
+ postData["fdsa"] = password
+
+ val loginPage = Jsoup.connect(context.getString(R.string.ossc_login_post))
+ .method(Connection.Method.POST)
+ .userAgent("Mozilla")
+ .data(postData)
+ .execute()
+
+ val selectNotenspiegel = Jsoup.connect(context.getString(R.string.ossc_select_noten))
+ .userAgent("Mozilla")
+ .cookies(loginPage.cookies())
+ .get()
+
+ val notenspiegelURL = selectNotenspiegel.select("a[href]:containsOwn(Notenspiegel)").first()?.attr("href")
+ ?: kotlin.run {
+ callback(null)
+ return@Runnable
+ }
+
+ val selectStudiengangUnhide = Jsoup.connect(notenspiegelURL)
+ .userAgent("Mozilla")
+ .cookies(loginPage.cookies())
+ .get()
+ val selectStudiengangUnhideURL = selectStudiengangUnhide.select("a[href]:containsOwn(Abschluss)").first().attr("href")
+
+ val selectStudiengang = Jsoup.connect(selectStudiengangUnhideURL)
+ .userAgent("Mozilla")
+ .cookies(loginPage.cookies())
+ .get()
+ val studiengangURL = selectStudiengang.select("a[href]:containsOwn(Leistungen anzeigen)").first().attr("href")
+
+
+ val notenSpiegelPage = Jsoup.connect(studiengangURL)
+ .userAgent("Mozilla")
+ .cookies(loginPage.cookies())
+ .get()
+
+ val allGradesRows = notenSpiegelPage.select("div.fixedContainer > table > tbody > tr")
+ val examRows: MutableList = mutableListOf()
+ for (row in allGradesRows) {
+ if (row.select("td.tabelle1_alignleft").size < 1) {
+ continue
+ }
+ val columns = row.select("td")
+ if (columns.size < 1) {
+ continue
+ }
+ val examRow = ExamRow(columns[1].text(), columns[3].text(), columns[6].text(), columns[7].text())
+ examRows.add(examRow)
+ }
+ saveExamRows(context, examRows)
+ callback(examRows)
+ }
+
+ return Thread(runnable).start()
+ }
+ fun sendNotification(context: Context?, examRow: ExamRow, id:Int) {
+ val intent = Intent(context, NotificationSettingsActivity::class.java).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ }
+ val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
+
+ val builder = NotificationCompat.Builder(context!!, context.getString(R.string.grades_notification_channel_id))
+ .setSmallIcon(R.drawable.ic_stat_name)
+ .setContentTitle(context.getString(R.string.exam_results_notification))
+ .setStyle(NotificationCompat.BigTextStyle()
+ .bigText("${examRow.name}: ${examRow.grade}"))
+ .setContentIntent(pendingIntent)
+ .setPriority(NotificationCompat.PRIORITY_DEFAULT)
+ .setAutoCancel(true)
+ with(NotificationManagerCompat.from(context)) {
+ notify(id, builder.build())
+ }
+
+ }
+
+ fun createNotificationChannel(context: Context?){
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val name = context?.getString(R.string.grades_notification_channel_name)
+ val descriptionText = context?.getString(R.string.grades_notification_channel_description)
+ val importance = NotificationManager.IMPORTANCE_DEFAULT
+ val channel = NotificationChannel(context?.getString(R.string.grades_notification_channel_id), name, importance).apply {
+ description = descriptionText
+ }
+ val notificationManager: NotificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.createNotificationChannel(channel)
+ }
+ }
+}
+
+
+class LoginFailedException : Throwable()
diff --git a/app/src/main/java/com/nareshkumarrao/eiweblog/MainActivity.kt b/app/src/main/java/com/nareshkumarrao/eiweblog/MainActivity.kt
index 839c1e7..a04e440 100644
--- a/app/src/main/java/com/nareshkumarrao/eiweblog/MainActivity.kt
+++ b/app/src/main/java/com/nareshkumarrao/eiweblog/MainActivity.kt
@@ -35,6 +35,7 @@ class MainActivity : AppCompatActivity() {
setSupportActionBar(myToolbar)
Utilities.createNotificationChannel(this)
+ HISUtility.createNotificationChannel(this)
val uploadWorkRequest: WorkRequest =
PeriodicWorkRequestBuilder(1, TimeUnit.HOURS)
@@ -42,8 +43,6 @@ class MainActivity : AppCompatActivity() {
WorkManager.getInstance(this).enqueue(uploadWorkRequest)
Utilities.fetchRepoReleaseInformation(this, ::repoReleaseCallback)
-
-
}
private fun repoReleaseCallback(version: String, log: String, url: String?){
@@ -97,4 +96,8 @@ class MainActivity : AppCompatActivity() {
val intent = Intent(this, AboutActivity::class.java)
startActivity(intent)
}
+
+ fun showGrades(item: MenuItem){
+ startActivity(Intent(this, GradesActivity::class.java))
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/nareshkumarrao/eiweblog/NotificationSettingsActivity.kt b/app/src/main/java/com/nareshkumarrao/eiweblog/NotificationSettingsActivity.kt
index b4069bd..06e69ed 100644
--- a/app/src/main/java/com/nareshkumarrao/eiweblog/NotificationSettingsActivity.kt
+++ b/app/src/main/java/com/nareshkumarrao/eiweblog/NotificationSettingsActivity.kt
@@ -18,16 +18,25 @@ class NotificationSettingsActivity : AppCompatActivity() {
supportActionBar?.setDisplayShowTitleEnabled(false)
val sharedPref = getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE)
- val weblogResponse = sharedPref?.getBoolean(getString(R.string.enable_notifications_key), true)
- val notificationSwitch = findViewById(R.id.notification_switch)
- notificationSwitch.isChecked = weblogResponse!!
- notificationSwitch.setOnCheckedChangeListener { _, isChecked ->
+ val weblogResponse = sharedPref?.getBoolean(getString(R.string.enable_weblog_notifications_key), true)
+ val weblogNotificationSwitch = findViewById(R.id.weblog_notification_switch)
+ weblogNotificationSwitch.isChecked = weblogResponse!!
+ weblogNotificationSwitch.setOnCheckedChangeListener { _, isChecked ->
with(sharedPref.edit()) {
- putBoolean(getString(R.string.enable_notifications_key), isChecked)
+ putBoolean(getString(R.string.enable_weblog_notifications_key), isChecked)
+ apply()
+ }
+ }
+
+ val gradeResponse = sharedPref.getBoolean(getString(R.string.enable_grades_notifications_key), true)
+ val gradeNotificationSwitch = findViewById(R.id.grades_notification_switch)
+ gradeNotificationSwitch.isChecked = gradeResponse
+ gradeNotificationSwitch.setOnCheckedChangeListener { _, isChecked ->
+ with(sharedPref.edit()) {
+ putBoolean(getString(R.string.enable_grades_notifications_key), isChecked)
apply()
}
- //Toast.makeText(this, "Notifications are set to $isChecked", Toast.LENGTH_SHORT).show()
}
diff --git a/app/src/main/java/com/nareshkumarrao/eiweblog/UpdateWorker.kt b/app/src/main/java/com/nareshkumarrao/eiweblog/UpdateWorker.kt
index 52b3cb2..773e171 100644
--- a/app/src/main/java/com/nareshkumarrao/eiweblog/UpdateWorker.kt
+++ b/app/src/main/java/com/nareshkumarrao/eiweblog/UpdateWorker.kt
@@ -10,23 +10,34 @@ class UpdateWorker(private val context: Context, workerParams: WorkerParameters)
override fun doWork(): Result {
val sharedPref = context.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
- val notificationsEnabled = sharedPref?.getBoolean(context.getString(R.string.enable_notifications_key), true)
- if(!notificationsEnabled!!){
- return Result.success()
- }
- Utilities.weblogList(context) { articles ->
- val lastArticle = Utilities.getLatestRelevantArticle(articles)!!
- val hashString = lastArticle.title + lastArticle.content + lastArticle.date
- val oldHash = md5(hashString)
+ val weblogNotificationsEnabled = sharedPref?.getBoolean(context.getString(R.string.enable_weblog_notifications_key), true)
+ val gradesNotificationsEnabled = sharedPref?.getBoolean(context.getString(R.string.enable_grades_notifications_key), true)
+
+ if(weblogNotificationsEnabled!!){
+ Utilities.weblogList(context) { articles ->
+ val lastArticle = Utilities.getLatestRelevantArticle(articles)!!
+ val hashString = lastArticle.title + lastArticle.content + lastArticle.date
+ val oldHash = md5(hashString)
+
+ Utilities.fetchWeblogXML(applicationContext){newArticles ->
+ val lastNewArticle = Utilities.getLatestRelevantArticle(newArticles)!!
+ val newHashString = lastNewArticle.title + lastNewArticle.content + lastNewArticle.date
+ val newHash = md5(newHashString)
- Utilities.fetchWeblogXML(applicationContext){newArticles ->
- val lastNewArticle = Utilities.getLatestRelevantArticle(newArticles)!!
- val newHashString = lastNewArticle.title + lastNewArticle.content + lastNewArticle.date
- val newHash = md5(newHashString)
+ if(oldHash != newHash){
+ Utilities.sendNotification(context, lastNewArticle, newArticles.size)
+ }
+ }
+ }
+ }
- if(oldHash != newHash){
- Utilities.sendNotification(context, lastNewArticle, newArticles.size)
+ if(gradesNotificationsEnabled!!){
+ HISUtility.checkForUpdates(context) { gradeUpdates ->
+ if (gradeUpdates != null) {
+ for (grade in gradeUpdates) {
+ HISUtility.sendNotification(context, grade, gradeUpdates.indexOf(grade))
+ }
}
}
}
diff --git a/app/src/main/java/com/nareshkumarrao/eiweblog/Utilities.kt b/app/src/main/java/com/nareshkumarrao/eiweblog/Utilities.kt
index 74646c3..08a544e 100644
--- a/app/src/main/java/com/nareshkumarrao/eiweblog/Utilities.kt
+++ b/app/src/main/java/com/nareshkumarrao/eiweblog/Utilities.kt
@@ -55,8 +55,6 @@ internal object Utilities {
}
}
-
-
val parser: XmlPullParser = Xml.newPullParser()
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
//Log.d("XMLLIST", responseStr )
@@ -140,7 +138,7 @@ internal object Utilities {
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
- val builder = NotificationCompat.Builder(context!!, context.getString(R.string.channel_id))
+ val builder = NotificationCompat.Builder(context!!, context.getString(R.string.weblog_notification_channel_id))
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(article.title)
.setStyle(NotificationCompat.BigTextStyle()
@@ -158,10 +156,10 @@ internal object Utilities {
fun createNotificationChannel(context: Context?){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val name = context?.getString(R.string.channel_name)
- val descriptionText = context?.getString(R.string.channel_description)
+ val name = context?.getString(R.string.weblog_notification_channel_name)
+ val descriptionText = context?.getString(R.string.weblog_notification_channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
- val channel = NotificationChannel(context?.getString(R.string.channel_id), name, importance).apply {
+ val channel = NotificationChannel(context?.getString(R.string.weblog_notification_channel_id), name, importance).apply {
description = descriptionText
}
val notificationManager: NotificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
diff --git a/app/src/main/java/com/nareshkumarrao/eiweblog/ui/main/ItemGradesAdapter.kt b/app/src/main/java/com/nareshkumarrao/eiweblog/ui/main/ItemGradesAdapter.kt
new file mode 100644
index 0000000..6560729
--- /dev/null
+++ b/app/src/main/java/com/nareshkumarrao/eiweblog/ui/main/ItemGradesAdapter.kt
@@ -0,0 +1,46 @@
+package com.nareshkumarrao.eiweblog.ui.main
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import com.nareshkumarrao.eiweblog.ExamRow
+import com.nareshkumarrao.eiweblog.R
+
+class ItemGradesAdapter(private val examRows: List) : RecyclerView.Adapter() {
+ inner class ViewHolder(inflater: LayoutInflater, parent: ViewGroup) : RecyclerView.ViewHolder(inflater.inflate(R.layout.item_grades, parent, false)) {
+ private var name: TextView? = null
+ private var attempt: TextView? = null
+ private var date: TextView? = null
+ private var grade: TextView? = null
+
+ init {
+ name = itemView.findViewById(R.id.examNameText)
+ attempt = itemView.findViewById(R.id.versuchText)
+ date = itemView.findViewById(R.id.examDateText)
+ grade = itemView.findViewById(R.id.gradeText)
+ }
+
+ fun bind(examRow: ExamRow) {
+ name?.text = examRow.name
+ attempt?.text = examRow.attempt
+ grade?.text = examRow.grade
+ date?.text = examRow.date
+ }
+
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemGradesAdapter.ViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ return ViewHolder(inflater, parent)
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val examRow = examRows[position]
+ holder.bind(examRow)
+ }
+
+ override fun getItemCount(): Int {
+ return examRows.size
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index 1110b8e..b846f0a 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -15,8 +15,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_notification_settings.xml b/app/src/main/res/layout/activity_notification_settings.xml
index 175418b..5431d6d 100644
--- a/app/src/main/res/layout/activity_notification_settings.xml
+++ b/app/src/main/res/layout/activity_notification_settings.xml
@@ -15,8 +15,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
-
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_login.xml b/app/src/main/res/layout/dialog_login.xml
new file mode 100644
index 0000000..366baf9
--- /dev/null
+++ b/app/src/main/res/layout/dialog_login.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_grades.xml b/app/src/main/res/layout/item_grades.xml
new file mode 100644
index 0000000..29b8fb7
--- /dev/null
+++ b/app/src/main/res/layout/item_grades.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/toolbar_menu.xml b/app/src/main/res/menu/toolbar_menu.xml
index bd7cc32..b5c6f88 100644
--- a/app/src/main/res/menu/toolbar_menu.xml
+++ b/app/src/main/res/menu/toolbar_menu.xml
@@ -9,4 +9,9 @@
android:onClick="showAbout"
android:title="@string/about"
app:showAsAction="never" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 78eda5d..92e3a2a 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -4,7 +4,7 @@
Info
Shick mir €5 für ein Bier über PayPal
Benachrichtigung
- Benachrichtige mich über Neuerungen auf der Weblog
+ Benachrichtige mich über Neuerungen auf der Weblog
Ich bin Naresh und mache gerade mein Master in Automatisierungstechnik hier an der HSD.\n
\nIch habe diese App geschrieben, da die EI-Weblog für mich unzufriedenstellend war. Ich vergesse
@@ -20,4 +20,16 @@
Herunterladen
Abbrechen
Neues App-Version verfügbar
+ Benutzername
+ Passwort
+ Notenspiegel
+ Versuch:
+ Prüfungsdatum:
+ Anmelden
+ Neues Klausurergebnis!
+ Klausurergebnis
+ Benachrichtigung bei neuem Klausurergebnis
+ Benachrichtige mich bei neuem Klausurergebnis
+ Anmelden bei OSSC
+ FEHLER!
\ No newline at end of file
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index 6a8cfff..a067e29 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -9,7 +9,7 @@
About
Send me €5 for beer on PayPal
Notifications
- Notify me when new updates are posted to the weblog
+ Notify me when new updates are posted to the weblog
My name is Naresh and I am doing my Master\'s in Automation at the HSD.\n
\nI wrote this app because I was unsatisfied with the EI weblog that was always silently being
@@ -21,4 +21,16 @@
Download
Cancel
New version of app available
+ Username
+ Password
+ Grades
+ Attempt:
+ Exam date:
+ Login
+ New exam results out!
+ Exam Results
+ Notification when you get a new exam result
+ Notify me when I get new grades
+ Login to OSSC
+ ERROR!
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8f4dff5..9eb4847 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,7 +1,6 @@
#E60028
- #FF6200EE
#FF3700B3
#FF03DAC5
#FF018786
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1ed5774..fc2a8e1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -24,15 +24,34 @@
as contained within the terms of the GPLv3 license. More information about the license and the
source code of this project can be found on its GitHub repository.
- EI Weblog Notifications
- Latest updates from the EI Weblog
- com.nareshkumarrao.eiweblog.update
+ EI Weblog Notifications
+ Latest updates from the EI Weblog
+ com.nareshkumarrao.eiweblog.weblogupdate
Benachrichtigung
- Notify me when new updates are posted to the weblog
- com.nareshkumarrao.notifications.key
+ Notify me when new updates are posted to the weblog
+ com.nareshkumarrao.weblog_notifications.key
GitHub Repository
https://api.github.com/repos/naresh97/ei-weblog-android/releases
New version of app available
Download
Cancel
+
+
+ exam_rows
+ username_key
+ password_key
+ Username
+ Password
+ Notenspiegel
+ Versuch:
+ Prüfungsdatum:
+ Anmelden
+ New exam results out!
+ Exam Results
+ Notification when you get a new exam result
+ com.nareshkumarrao.eiweblog.grades
+ Notify me when I get new grades
+ com.nareshkumarrao.eiweblog.grades_notifications.key
+ Login to OSSC
+ ERROR!
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 917b396..01368f3 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -2,7 +2,7 @@