2023-04-12 18:58:10 +02:00
|
|
|
package com.denizk0461.studip.activity
|
|
|
|
|
|
|
|
|
|
import android.annotation.SuppressLint
|
|
|
|
|
import android.os.Bundle
|
2023-05-05 11:53:44 +02:00
|
|
|
import android.view.View
|
2023-04-12 18:58:10 +02:00
|
|
|
import android.webkit.WebResourceRequest
|
|
|
|
|
import android.webkit.WebView
|
|
|
|
|
import android.webkit.WebViewClient
|
2023-05-02 22:35:19 +02:00
|
|
|
import androidx.fragment.app.FragmentActivity
|
2023-04-12 18:58:10 +02:00
|
|
|
import androidx.lifecycle.ViewModelProvider
|
|
|
|
|
import com.denizk0461.studip.R
|
2023-04-29 10:56:52 +02:00
|
|
|
import com.denizk0461.studip.data.showErrorSnackBar
|
2023-05-02 22:35:19 +02:00
|
|
|
import com.denizk0461.studip.data.showToast
|
2023-04-12 18:58:10 +02:00
|
|
|
import com.denizk0461.studip.databinding.ActivityFetcherBinding
|
2023-05-02 22:35:19 +02:00
|
|
|
import com.denizk0461.studip.sheet.TextSheet
|
2023-04-12 18:58:10 +02:00
|
|
|
import com.denizk0461.studip.viewmodel.FetcherViewModel
|
2023-04-25 12:02:25 +02:00
|
|
|
import java.io.IOException
|
2023-04-12 18:58:10 +02:00
|
|
|
import java.net.URLDecoder
|
|
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
/**
|
|
|
|
|
* Activity for allowing the user to log in to access and fetch their schedule from their Stud.IP
|
|
|
|
|
* profile. Launched through a button in the app's settings.
|
|
|
|
|
*/
|
2023-05-02 22:35:19 +02:00
|
|
|
class FetcherActivity : FragmentActivity() {
|
2023-04-12 18:58:10 +02:00
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
// View binding
|
2023-04-12 18:58:10 +02:00
|
|
|
private lateinit var binding: ActivityFetcherBinding
|
2023-05-04 08:32:12 +02:00
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
// View model
|
2023-04-12 18:58:10 +02:00
|
|
|
private lateinit var viewModel: FetcherViewModel
|
|
|
|
|
|
2023-05-05 11:53:44 +02:00
|
|
|
// URL of the schedule
|
|
|
|
|
private val scheduleUrl: String = "https://elearning.uni-bremen.de/dispatch.php/calendar/schedule"
|
|
|
|
|
|
2023-04-27 20:27:42 +02:00
|
|
|
/**
|
2023-04-12 18:58:10 +02:00
|
|
|
* Enabling JavaScript is necessary to get the HTML source in this context. As the HTML can only
|
|
|
|
|
* be accessed once the user has logged in, a simple HTML request would not suffice here.
|
|
|
|
|
*/
|
|
|
|
|
@SuppressLint("SetJavaScriptEnabled")
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
// Instantiate view model
|
2023-05-04 08:32:12 +02:00
|
|
|
viewModel = ViewModelProvider.AndroidViewModelFactory(application)
|
|
|
|
|
.create(FetcherViewModel::class.java)
|
|
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
// Inflate view binding and bind to this activity
|
2023-04-12 18:58:10 +02:00
|
|
|
binding = ActivityFetcherBinding.inflate(layoutInflater)
|
|
|
|
|
setContentView(binding.root)
|
|
|
|
|
|
2023-05-05 11:53:44 +02:00
|
|
|
// Remind the user of the help button
|
|
|
|
|
showToast(this, getString(R.string.toast_info_reminder))
|
|
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
// Enabling JavaScript. See comment above lint suppression for reason why this is done.
|
2023-04-12 18:58:10 +02:00
|
|
|
binding.webview.settings.apply {
|
|
|
|
|
javaScriptEnabled = true
|
|
|
|
|
}
|
2023-05-05 11:53:44 +02:00
|
|
|
|
2023-04-12 18:58:10 +02:00
|
|
|
binding.webview.webViewClient = object : WebViewClient() {
|
2023-04-21 15:42:21 +02:00
|
|
|
// Disallow redirecting to prevent the app from launching Chrome after the user logs in
|
2023-04-12 18:58:10 +02:00
|
|
|
override fun shouldOverrideUrlLoading(
|
|
|
|
|
view: WebView,
|
|
|
|
|
request: WebResourceRequest
|
|
|
|
|
): Boolean {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2023-05-05 11:53:44 +02:00
|
|
|
|
|
|
|
|
override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
|
|
|
|
|
// Check whether the button to save the timetable should be shown
|
|
|
|
|
if (url?.contains(scheduleUrl) == true) {
|
|
|
|
|
binding.fab.visibility = View.VISIBLE
|
|
|
|
|
} else {
|
|
|
|
|
binding.fab.visibility = View.GONE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Super call
|
|
|
|
|
super.doUpdateVisitedHistory(view, url, isReload)
|
|
|
|
|
}
|
2023-04-12 18:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-02 22:35:19 +02:00
|
|
|
// Set up bottom app bar for various actions
|
|
|
|
|
binding.bottomAppBar.setOnMenuItemClickListener { item ->
|
|
|
|
|
when (item.itemId) {
|
|
|
|
|
R.id.close -> {
|
|
|
|
|
// Close the activity
|
|
|
|
|
finish()
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
R.id.refresh -> {
|
|
|
|
|
// Refresh the currently opened page
|
|
|
|
|
binding.webview.reload()
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
R.id.help -> {
|
|
|
|
|
// Present the user with a small tutorial on how to fetch their timetable
|
|
|
|
|
TextSheet().also { sheet ->
|
|
|
|
|
val bundle = Bundle()
|
|
|
|
|
bundle.putString("header", getString(R.string.fetch_bar_help_sheet_title))
|
|
|
|
|
bundle.putString("content", getString(R.string.fetch_bar_help_sheet_content))
|
2023-05-05 11:53:44 +02:00
|
|
|
bundle.putBoolean("isCancellable", true)
|
2023-05-02 22:35:19 +02:00
|
|
|
sheet.arguments = bundle
|
|
|
|
|
}.show(supportFragmentManager, TextSheet::class.java.simpleName)
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
else -> false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-21 15:42:21 +02:00
|
|
|
/*
|
|
|
|
|
* Attempt to load the user-set Stud.IP front page. Redirects to login page if user is
|
|
|
|
|
* not logged in.
|
|
|
|
|
*/
|
2023-04-12 18:58:10 +02:00
|
|
|
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
|
|
|
|
|
|
2023-05-04 13:29:34 +02:00
|
|
|
binding.webview
|
|
|
|
|
|
2023-05-02 22:35:19 +02:00
|
|
|
binding.fab.setOnClickListener {
|
2023-04-29 22:26:26 +02:00
|
|
|
|
|
|
|
|
if (binding.webview.url?.contains(
|
2023-05-05 11:53:44 +02:00
|
|
|
scheduleUrl
|
2023-04-29 22:26:26 +02:00
|
|
|
) == true) {
|
|
|
|
|
/*
|
|
|
|
|
* Retrieve encoded HTML via JavaScript function. Encoding is done as otherwise not all
|
|
|
|
|
* symbols will be accurately fetched.
|
|
|
|
|
*/
|
|
|
|
|
binding.webview.evaluateJavascript(
|
|
|
|
|
"(function(){return encodeURI(document.getElementsByTagName('html')[0].innerHTML)})();"
|
|
|
|
|
) { p0 ->
|
|
|
|
|
try {
|
|
|
|
|
// Decode HTML and parse it into a list of StudIPEvent.kt
|
2023-05-03 11:10:34 +02:00
|
|
|
val elementsNotFetched = viewModel.parse(URLDecoder.decode(p0, "UTF-8"))
|
2023-04-29 22:26:26 +02:00
|
|
|
|
2023-05-03 11:10:34 +02:00
|
|
|
/*
|
|
|
|
|
* Notify the user that the fetch was successful, and tell the user how many
|
|
|
|
|
* items could not be fetched.
|
|
|
|
|
*/
|
|
|
|
|
showToast(this, when (elementsNotFetched) {
|
|
|
|
|
0 -> getString(R.string.toast_fetch_finished_zero)
|
|
|
|
|
1 -> getString(R.string.toast_fetch_finished_one)
|
|
|
|
|
else -> getString(R.string.toast_fetch_finished_other, elementsNotFetched)
|
|
|
|
|
})
|
2023-04-29 22:26:26 +02:00
|
|
|
|
|
|
|
|
// Close the activity
|
|
|
|
|
finish()
|
|
|
|
|
|
|
|
|
|
} catch (e: IOException) {
|
|
|
|
|
// Let the user know that an error occurred
|
2023-05-02 22:35:19 +02:00
|
|
|
theme.showErrorSnackBar(binding.rootView, getString(R.string.fetch_error_snack), binding.bottomAppBar)
|
2023-04-29 22:26:26 +02:00
|
|
|
}
|
2023-04-12 18:58:10 +02:00
|
|
|
}
|
2023-04-29 22:26:26 +02:00
|
|
|
} else {
|
2023-05-02 22:35:19 +02:00
|
|
|
// Tell the user that they must navigate to their timetable
|
|
|
|
|
theme.showErrorSnackBar(binding.rootView, getString(R.string.fetch_error_webpage_snack), binding.bottomAppBar)
|
2023-04-12 18:58:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|