Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Jannik | 28520bee74 |
|
@ -2,7 +2,8 @@ kind: pipeline
|
|||
name: default
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
- name: assembleRelease
|
||||
image: nextcloudci/android10:android-56
|
||||
commands:
|
||||
- ./gradlew build
|
||||
- ./gradlew assembleRelease
|
||||
|
||||
|
|
12
README.md
12
README.md
|
@ -3,7 +3,7 @@
|
|||
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
# Project Laogai
|
||||
Project Laogai is an app to access the timetable, grades (qispos) and the canteen menu of Hochschule Offenburg. Laogai uses the TCoR-API for timetables and the canteen menu, wich makes acessing them super fast. To get the grades from Qispos, Laogai will ask for your login data, wich are stored encrypted on your device.
|
||||
Project Laogai is an app to access the timetable, grades (qispos) and the canteen menu of Hochschule Offenburg. Laogai uses the TCoR-API fot timetables and the canteen menu, wich makes acessing them super fast. To get the grades from Qispos, Laogai will ask for your login data, wich are stored encrypted on your device.
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="75">](https://f-droid.org/packages/org.mosad.seil0.projectlaogai/)
|
||||
[<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" height="75">](https://play.google.com/store/apps/details?id=org.mosad.seil0.projectlaogai)
|
||||
|
@ -18,10 +18,10 @@ Project Laogai is an app to access the timetable, grades (qispos) and the cantee
|
|||
Please report bugs and issues to support@mosad.xyz
|
||||
|
||||
## Screenshots
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_HomeScreen.webp" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_HomeScreen.webp)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Mensa.webp" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Mensa.webp)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Timetable.webp" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Timetable.webp)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Settings.webp" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Settings.webp)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_dark_Mensa.webp" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_dark_Mensa.webp)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_HomeScreen.png" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_HomeScreen.png)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Mensa.png" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Mensa.png)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Timetable.png" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Timetable.png)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Settings.png" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Settings.png)
|
||||
[<img src="https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Mensa_dark.png" width=180>](https://www.mosad.xyz/images/Project_Laogai/ProjectLaogai_Mensa_dark.png)
|
||||
|
||||
ProjectLaogai © 2019-2020 [@Seil0](https://git.mosad.xyz/Seil0), a [mosad.xyz](http://www.mosad.xyz) Project
|
||||
|
|
|
@ -1,35 +1,22 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain 11
|
||||
sourceSets.configureEach {
|
||||
languageSettings.optIn("kotlin.RequiresOptIn")
|
||||
}
|
||||
}
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
|
||||
compileSdk 34
|
||||
buildToolsVersion = '34.0.0'
|
||||
|
||||
signingConfigs {
|
||||
}
|
||||
compileSdkVersion 29
|
||||
defaultConfig {
|
||||
applicationId "org.mosad.seil0.projectlaogai"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 33
|
||||
versionCode 6100 // 00.06.100
|
||||
versionName "0.6.1"
|
||||
targetSdkVersion 29
|
||||
versionCode 6000 // 0006000
|
||||
versionName "0.6.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
resValue "string", "build_time", buildTime()
|
||||
setProperty("archivesBaseName", "projectlaogai-$versionName")
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
|
@ -38,6 +25,11 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
res.srcDirs =
|
||||
|
@ -50,44 +42,32 @@ android {
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
testOptions.unitTests.all {
|
||||
useJUnitPlatform()
|
||||
|
||||
testLogging {
|
||||
events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
|
||||
}
|
||||
}
|
||||
namespace 'org.mosad.seil0.projectlaogai'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
||||
implementation 'androidx.core:core-ktx:1.12.0'
|
||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
|
||||
implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
|
||||
implementation 'androidx.core:core:1.3.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
|
||||
implementation "androidx.work:work-runtime-ktx:2.9.0"
|
||||
implementation 'com.google.android.material:material:1.11.0'
|
||||
implementation 'com.google.code.gson:gson:2.10'
|
||||
// implementation 'com.afollestad:aesthetic:1.0.0-beta05'
|
||||
implementation 'androidx.security:security-crypto:1.1.0-alpha02'
|
||||
implementation 'com.google.android.material:material:1.2.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.6'
|
||||
implementation 'com.afollestad:aesthetic:1.0.0-beta05'
|
||||
implementation 'com.afollestad.material-dialogs:core:3.3.0'
|
||||
implementation 'com.afollestad.material-dialogs:color:3.3.0'
|
||||
implementation 'com.afollestad.material-dialogs:bottomsheets:3.3.0'
|
||||
implementation 'de.psdev.licensesdialog:licensesdialog:2.1.0'
|
||||
|
||||
implementation 'org.apache.commons:commons-lang3:3.11'
|
||||
implementation 'org.jsoup:jsoup:1.15.3'
|
||||
implementation 'org.jsoup:jsoup:1.13.1'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
|
||||
androidTestImplementation 'androidx.test:core:1.5.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
}
|
||||
|
||||
static def buildTime() {
|
||||
|
|
|
@ -26,9 +26,5 @@
|
|||
-keepattributes Signature
|
||||
-dontwarn sun.misc.**
|
||||
|
||||
# com.google.crypto
|
||||
-dontwarn javax.annotation.Nullable
|
||||
-dontwarn javax.annotation.concurrent.GuardedBy
|
||||
|
||||
#misc
|
||||
-dontwarn java.lang.instrument.ClassFileTransformer
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mosad.seil0.projectlaogai">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
|
||||
|
@ -15,40 +15,40 @@
|
|||
|
||||
<activity
|
||||
android:name=".SplashActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/SplashTheme"
|
||||
android:exported="true">
|
||||
android:screenOrientation="portrait">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
<meta-data android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".OnboardingActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.Light"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme.Light" />
|
||||
android:launchMode="singleTop">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.Light"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme.Light">
|
||||
android:launchMode="singleTop">
|
||||
|
||||
<!-- nfc stuff -->
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.nfc.action.TECH_DISCOVERED"
|
||||
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
|
||||
android:resource="@xml/nfc_tech_filter" />
|
||||
|
||||
</activity>
|
||||
|
|
|
@ -34,23 +34,23 @@ import android.util.Log
|
|||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.fragment.app.commit
|
||||
//import com.afollestad.aesthetic.Aesthetic
|
||||
//import com.afollestad.aesthetic.NavigationViewMode
|
||||
import com.afollestad.aesthetic.Aesthetic
|
||||
import com.afollestad.aesthetic.NavigationViewMode
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import org.mosad.seil0.projectlaogai.controller.NFCMensaCard
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.databinding.ActivityMainBinding
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cColorAccent
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cColorPrimary
|
||||
import org.mosad.seil0.projectlaogai.fragments.*
|
||||
import org.mosad.seil0.projectlaogai.util.NotificationUtils
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
/**
|
||||
|
@ -58,8 +58,8 @@ import kotlin.system.measureTimeMillis
|
|||
*/
|
||||
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private var activeFragment: Fragment = HomeFragment() // the currently active fragment, home at the start
|
||||
private val className = "MainActivity"
|
||||
|
||||
private lateinit var adapter: NfcAdapter
|
||||
private lateinit var pendingIntent: PendingIntent
|
||||
|
@ -68,12 +68,12 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
private var useNFC = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Aesthetic.attach(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
val fragmentTransaction: FragmentTransaction = supportFragmentManager.beginTransaction()
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setSupportActionBar(binding.appBar.toolbar)
|
||||
Aesthetic.attach(this)
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
// load mensa, timetable and color
|
||||
load()
|
||||
|
@ -81,31 +81,24 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
initForegroundDispatch()
|
||||
|
||||
val toggle = ActionBarDrawerToggle(
|
||||
this, binding.drawerLayout, binding.appBar.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close
|
||||
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close
|
||||
)
|
||||
binding.drawerLayout.addDrawerListener(toggle)
|
||||
drawer_layout.addDrawerListener(toggle)
|
||||
toggle.syncState()
|
||||
|
||||
binding.navView.setNavigationItemSelectedListener(this)
|
||||
nav_view.setNavigationItemSelectedListener(this)
|
||||
|
||||
// based on the intent we get, call readBalance or open a Fragment
|
||||
when (intent.action) {
|
||||
NfcAdapter.ACTION_TECH_DISCOVERED -> NFCMensaCard.readBalance(intent, this)
|
||||
getString(R.string.intent_action_mensaFragment) -> activeFragment = MensaFragment()
|
||||
getString(R.string.intent_action_timetableFragment) -> activeFragment = TimetableFragment()
|
||||
getString(R.string.intent_action_moodleFragment) -> activeFragment = MoodleFragment()
|
||||
else -> activeFragment = HomeFragment()
|
||||
"org.mosad.seil0.projectlaogai.fragments.MensaFragment" -> activeFragment = MensaFragment()
|
||||
"org.mosad.seil0.projectlaogai.fragments.TimeTableFragment" -> activeFragment = TimeTableFragment()
|
||||
"org.mosad.seil0.projectlaogai.fragments.MoodleFragment" -> activeFragment = MoodleFragment()
|
||||
}
|
||||
|
||||
supportFragmentManager.commit {
|
||||
replace(R.id.fragment_container, activeFragment, activeFragment.javaClass.simpleName)
|
||||
}
|
||||
|
||||
onBackPressedDispatcher.addCallback {
|
||||
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
}
|
||||
}
|
||||
// open the activeFragment, default is the HomeFragment
|
||||
fragmentTransaction.replace(R.id.fragment_container, activeFragment)
|
||||
fragmentTransaction.commit()
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
|
@ -118,7 +111,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
// Aesthetic.resume(this)
|
||||
Aesthetic.resume(this)
|
||||
if(useNFC)
|
||||
adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray)
|
||||
|
||||
|
@ -126,11 +119,20 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
// Aesthetic.pause(this)
|
||||
Aesthetic.pause(this)
|
||||
if(useNFC)
|
||||
adapter.disableForegroundDispatch(this)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
|
||||
drawer_layout.closeDrawer(GravityCompat.START)
|
||||
} else {
|
||||
// TODO only call on double tap
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
menuInflater.inflate(R.menu.main, menu)
|
||||
|
@ -152,8 +154,9 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
activeFragment = when(item.itemId) {
|
||||
R.id.nav_home -> HomeFragment()
|
||||
R.id.nav_mensa -> MensaFragment()
|
||||
R.id.nav_timetable -> TimetableFragment()
|
||||
R.id.nav_timetable -> TimeTableFragment()
|
||||
R.id.nav_moodle -> MoodleFragment()
|
||||
R.id.nav_grades -> GradesFragment()
|
||||
R.id.nav_settings -> SettingsFragment()
|
||||
else -> HomeFragment()
|
||||
}
|
||||
|
@ -162,7 +165,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
fragmentTransaction.replace(R.id.fragment_container, activeFragment)
|
||||
fragmentTransaction.commit()
|
||||
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
drawer_layout.closeDrawer(GravityCompat.START)
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -175,32 +178,31 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
Preferences.load(this) // load the settings, must be finished before doing anything else
|
||||
CacheController(this) // load the cache
|
||||
EncryptedPreferences.load(this)
|
||||
NotificationUtils(this)
|
||||
}
|
||||
Log.i(javaClass.simpleName, "Startup completed in $startupTime ms")
|
||||
Log.i(className, "startup completed in $startupTime ms")
|
||||
}
|
||||
|
||||
private fun initAesthetic() {
|
||||
// If we haven't set any defaults, do that now
|
||||
// if (Aesthetic.isFirstTime) {
|
||||
// // set the default theme at the first app start
|
||||
// Aesthetic.config {
|
||||
// activityTheme(R.style.AppTheme_Light)
|
||||
// apply()
|
||||
// }
|
||||
// // TODO needs to be shown on first start
|
||||
// // show the onboarding activity
|
||||
// startActivity(Intent(this, OnboardingActivity::class.java))
|
||||
// finish()
|
||||
// }
|
||||
//
|
||||
// Aesthetic.config {
|
||||
// colorPrimary(Preferences.colorPrimary)
|
||||
// colorPrimaryDark(Preferences.colorPrimary)
|
||||
// colorAccent(Preferences.colorAccent)
|
||||
// navigationViewMode(NavigationViewMode.SELECTED_ACCENT)
|
||||
// apply()
|
||||
// }
|
||||
if (Aesthetic.isFirstTime) {
|
||||
// set the default theme at the first app start
|
||||
Aesthetic.config {
|
||||
activityTheme(R.style.AppTheme_Light)
|
||||
apply()
|
||||
}
|
||||
|
||||
// show the onboarding activity
|
||||
startActivity(Intent(this, OnboardingActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
|
||||
Aesthetic.config {
|
||||
colorPrimary(cColorPrimary)
|
||||
colorPrimaryDark(cColorPrimary)
|
||||
colorAccent(cColorAccent)
|
||||
navigationViewMode(NavigationViewMode.SELECTED_ACCENT)
|
||||
apply()
|
||||
}
|
||||
|
||||
// set theme color values
|
||||
val out = TypedValue()
|
||||
|
@ -222,8 +224,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
adapter = NfcAdapter.getDefaultAdapter(this)
|
||||
pendingIntent = PendingIntent.getActivity(
|
||||
this, 0,
|
||||
Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,20 +31,15 @@ import android.widget.LinearLayout
|
|||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import kotlinx.coroutines.*
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController
|
||||
import com.afollestad.materialdialogs.callbacks.onDismiss
|
||||
import kotlinx.android.synthetic.main.activity_onboarding.*
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.databinding.ActivityOnboardingBinding
|
||||
import org.mosad.seil0.projectlaogai.fragments.SettingsFragment
|
||||
import org.mosad.seil0.projectlaogai.onboarding.ViewPagerAdapter
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.CourseSelectionDialog
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoadingDialog
|
||||
|
||||
class OnboardingActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityOnboardingBinding
|
||||
companion object {
|
||||
val layouts = intArrayOf(R.layout.fragment_on_welcome, R.layout.fragment_on_course, R.layout.fragment_on_login)
|
||||
}
|
||||
|
@ -59,9 +54,7 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityOnboardingBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setContentView(R.layout.activity_onboarding)
|
||||
|
||||
viewPager = findViewById(R.id.viewPager)
|
||||
linLayoutDots = findViewById(R.id.linLayout_Dots)
|
||||
|
@ -73,7 +66,7 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
viewPager.addOnPageChangeListener(viewPagerPageChangeListener)
|
||||
|
||||
// we don't use the skip button, instead we use the start button to skip the last fragment
|
||||
binding.btnSkip.visibility = View.GONE
|
||||
btn_Skip.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun btnNextClick(@Suppress("UNUSED_PARAMETER")v: View) {
|
||||
|
@ -88,28 +81,8 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
launchHomeScreen()
|
||||
}
|
||||
|
||||
fun btnSelectCourseClick(v: View) {
|
||||
CourseSelectionDialog(this).show {
|
||||
list = CacheController.coursesList.map { it.courseName }
|
||||
listItems {
|
||||
val loadingDialog = LoadingDialog(context)
|
||||
loadingDialog.show()
|
||||
|
||||
lifecycleScope.launch(Dispatchers.Default) {
|
||||
Preferences.saveCourse(context, CacheController.coursesList[selectedIndex]) // save the course
|
||||
|
||||
// update current & next weeks timetable
|
||||
val threads = listOf(
|
||||
CacheController.updateTimetable(Preferences.course.courseName, 0, context),
|
||||
CacheController.updateTimetable(Preferences.course.courseName, 1, context)
|
||||
)
|
||||
threads.joinAll() // blocking since we want the new data
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
fun btnSelectCourseClick(@Suppress("UNUSED_PARAMETER")v: View) {
|
||||
SettingsFragment().selectCourse(this).show {
|
||||
onDismiss {
|
||||
btnNextClick(v) // show the next fragment
|
||||
}
|
||||
|
@ -156,12 +129,12 @@ class OnboardingActivity : AppCompatActivity() {
|
|||
addBottomDots(position)
|
||||
// changing the next button text to skip for the login fragment
|
||||
if (position == layouts.size - 1) {
|
||||
binding.btnNext.text = getString(R.string.skip)
|
||||
binding.btnNext.visibility = View.VISIBLE
|
||||
binding.btnSkip.visibility = View.GONE
|
||||
btn_Next.text = getString(R.string.skip)
|
||||
btn_Next.visibility = View.VISIBLE
|
||||
btn_Skip.visibility = View.GONE
|
||||
} else {
|
||||
binding.btnNext.visibility = View.GONE
|
||||
binding.btnSkip.visibility = View.GONE
|
||||
btn_Next.visibility = View.GONE
|
||||
btn_Skip.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,12 +28,12 @@ import android.nfc.NfcAdapter
|
|||
import android.nfc.Tag
|
||||
import android.nfc.tech.IsoDep
|
||||
import android.util.Log
|
||||
import android.widget.TextView
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.codebutler.farebot.Utils
|
||||
import com.codebutler.farebot.card.desfire.DesfireFileSettings
|
||||
import com.codebutler.farebot.card.desfire.DesfireProtocol
|
||||
import kotlinx.android.synthetic.main.dialog_mensa_credit.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import java.lang.Exception
|
||||
|
@ -97,8 +97,8 @@ class NFCMensaCard {
|
|||
String.format("%.4f shm", (lastRaw.toFloat() * 0.0000075))
|
||||
}
|
||||
|
||||
dialog.findViewById<TextView>(R.id.txtView_current).text = current
|
||||
dialog.findViewById<TextView>(R.id.txtView_last).text = context.resources.getString(R.string.mensa_last, last)
|
||||
dialog.txtView_current.text = current
|
||||
dialog.txtView_last.text = context.resources.getString(R.string.mensa_last, last)
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/**
|
||||
* ProjectLaogai
|
||||
*
|
||||
* Copyright 2019-2020 <seil0@mosad.xyz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.mosad.seil0.projectlaogai.controller
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jsoup.HttpStatusException
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
|
||||
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
|
||||
|
||||
/**
|
||||
* Parse the qispos site the get all needed data for the grades fragment
|
||||
*/
|
||||
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"
|
||||
|
||||
/**
|
||||
* check if qispos is available
|
||||
* @return a http status code, 999 if no HttpStatusException supplied
|
||||
*/
|
||||
fun checkQISPOSStatus(): Int {
|
||||
return runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
val socketFactory = createSSLSocketFactory()
|
||||
|
||||
try {
|
||||
val res = Jsoup.connect(baseURL + loginPath)
|
||||
.sslSocketFactory(socketFactory)
|
||||
.followRedirects(true)
|
||||
.referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0")
|
||||
.execute()
|
||||
|
||||
res.statusCode()
|
||||
} catch (exHttp: HttpStatusException) {
|
||||
exHttp.statusCode
|
||||
} catch (ex: Exception) {
|
||||
Log.e(className, "Error while checking status", ex)
|
||||
999
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
|
||||
gradesListHtml?.select("table > tbody > tr")?.forEach {
|
||||
val row = it.select("td.tabelle1_alignleft,td.tabelle1_aligncenter,td.tabelle1_alignright")
|
||||
|
||||
// only real subjects will be selected
|
||||
if(row.size >= 6 && row[0].text().length >=7) {
|
||||
val subject = GradeSubject(
|
||||
id = row[0].text(),
|
||||
name = row[1].text(),
|
||||
semester = row[2].text(),
|
||||
grade = if (row[3].text().isNotEmpty()) row[3].text() else row[4].text(),
|
||||
credits = row[5].text()
|
||||
)
|
||||
|
||||
if (gradesMap.containsKey(subject.semester)) {
|
||||
gradesMap[subject.semester]!!.add(subject)
|
||||
} else {
|
||||
gradesMap[subject.semester] = arrayListOf(subject)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// return the sorted map
|
||||
return gradesMap.toSortedMap(compareBy<String>{
|
||||
val oText = it.substringAfter(" ")
|
||||
|
||||
if (oText.contains("/")) {
|
||||
oText.substringBefore("/").toInt() + 0.5
|
||||
} else {
|
||||
oText.toDouble()
|
||||
}
|
||||
}.thenBy { it })
|
||||
}
|
||||
|
||||
/**
|
||||
* read the grades html from qispos
|
||||
* @return the grades list as html element or null
|
||||
*/
|
||||
private fun readGrades(): Element?{
|
||||
|
||||
val credentials = EncryptedPreferences.readCredentials(context)
|
||||
val username = credentials.first.substringBefore("@")
|
||||
val password = credentials.second
|
||||
|
||||
return runBlocking {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val socketFactory = createSSLSocketFactory()
|
||||
|
||||
// login, asdf = username, fdsa = password, wtf
|
||||
val list = mapOf(
|
||||
Pair("asdf", username),
|
||||
Pair("fdsa", password),
|
||||
Pair("submit", "Anmelden")
|
||||
)
|
||||
|
||||
// login and get session cookies
|
||||
val res = Jsoup.connect(baseURL + loginPath)
|
||||
.sslSocketFactory(socketFactory)
|
||||
.followRedirects(true)
|
||||
.referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0")
|
||||
.data(list)
|
||||
.postDataCharset("UTF-8")
|
||||
.execute()
|
||||
Log.i(className, "login status is: ${res.statusMessage()}: ${res.statusCode()}")
|
||||
|
||||
val loginCookies = res.cookies()
|
||||
|
||||
// grades root document and url
|
||||
val rootHtml =Jsoup.parse(res.body())
|
||||
val gradesRootLink = rootHtml.select("li.menueListStyle > a.auflistung").last().attr("abs:href")
|
||||
|
||||
// parse grades url
|
||||
val gradesHtml = Jsoup.connect(gradesRootLink)
|
||||
.sslSocketFactory(socketFactory)
|
||||
.followRedirects(true)
|
||||
.cookies(loginCookies)
|
||||
.referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0")
|
||||
.get()
|
||||
|
||||
val gradesNextLink = gradesHtml.select("li.treelist > a.regular").attr("abs:href")
|
||||
|
||||
val gradesNextHtml = Jsoup.connect(gradesNextLink)
|
||||
.sslSocketFactory(socketFactory)
|
||||
.followRedirects(true)
|
||||
.cookies(loginCookies)
|
||||
.referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0")
|
||||
.get()
|
||||
|
||||
val gradesListLink = gradesNextHtml.selectFirst("li.treelist > ul > li").selectFirst("a").attr("abs:href")
|
||||
|
||||
// get the grades list
|
||||
val gradesListHtml = Jsoup.connect(gradesListLink)
|
||||
.sslSocketFactory(socketFactory)
|
||||
.followRedirects(true)
|
||||
.cookies(loginCookies)
|
||||
.referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0")
|
||||
.get()
|
||||
|
||||
gradesListHtml.body()
|
||||
} catch (ex: Exception) {
|
||||
Log.e(className, "error while loading qispos", ex)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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")
|
||||
val caInput = context.resources.openRawResource(R.raw.notenverwaltung_hs_offenburg_de)
|
||||
val ca = caInput.use {
|
||||
cf.generateCertificate(it) as X509Certificate
|
||||
}
|
||||
|
||||
// Create a KeyStore containing our trusted CAs
|
||||
val keyStoreType = KeyStore.getDefaultType()
|
||||
val keyStore = KeyStore.getInstance(keyStoreType).apply {
|
||||
load(null, null)
|
||||
setCertificateEntry("ca", ca)
|
||||
}
|
||||
|
||||
// Create a TrustManager that trusts the CAs inputStream our KeyStore
|
||||
val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
|
||||
val tmf = TrustManagerFactory.getInstance(tmfAlgorithm).apply {
|
||||
init(keyStore)
|
||||
}
|
||||
|
||||
// Create an SSLContext that uses our TrustManager
|
||||
val sslContext = SSLContext.getInstance("TLS").apply {
|
||||
init(null, tmf.trustManagers, null)
|
||||
}
|
||||
|
||||
return sslContext.socketFactory
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -84,7 +84,7 @@ class TCoRAPIController {
|
|||
fun getSubjectListAsync(courseName: String, week: Int): Deferred<ArrayList<String>> {
|
||||
val url = URL("$tcorBaseURL/subjectList?course=$courseName&week=$week")
|
||||
|
||||
return CoroutineScope(Dispatchers.IO).async {
|
||||
return GlobalScope.async {
|
||||
Gson().fromJson(url.readText(), ArrayList<String>()::class.java)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.google.gson.reflect.TypeToken
|
|||
import kotlinx.coroutines.*
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.controller.TCoRAPIController
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cCourse
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.coursesCacheTime
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.mensaCacheTime
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.timetableCacheTime
|
||||
|
@ -38,16 +39,16 @@ import org.mosad.seil0.projectlaogai.util.*
|
|||
import java.io.*
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* The cacheController reads and updates the cache files.
|
||||
* It contains the courseList and mensaMenu object, all timetable objects
|
||||
* are located in TimetableController.
|
||||
*/
|
||||
class CacheController(private val context: Context) {
|
||||
class CacheController(cont: Context) {
|
||||
|
||||
private val className = this.javaClass.name
|
||||
private val className = "CacheController"
|
||||
private val context = cont
|
||||
|
||||
init {
|
||||
val cal = Calendar.getInstance()
|
||||
|
@ -58,9 +59,9 @@ class CacheController(private val context: Context) {
|
|||
cal.time = Date(mensaCacheTime * 1000)
|
||||
|
||||
// if a) it's monday and the last cache update was on sunday or b) the cache is older than 24hr, update blocking
|
||||
if ((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - mensaCacheTime) > 86400) {
|
||||
Log.i(className, "Update mensa blocking")
|
||||
CoroutineScope(Dispatchers.Default).launch { updateMensaMenu(context).join() }
|
||||
if ((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - mensaMenu.meta.updateTime) > 86400) {
|
||||
Log.i(className, "update mensa blocking")
|
||||
GlobalScope.launch(Dispatchers.Default) { updateMensaMenu(context).join() }
|
||||
}
|
||||
|
||||
// check if we need to update the timetable before displaying it
|
||||
|
@ -68,12 +69,12 @@ class CacheController(private val context: Context) {
|
|||
|
||||
// if a) it`s monday and the last cache update was not on a sunday or b) the cache is older than 24hr, update blocking
|
||||
if ((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - timetableCacheTime) > 86400) {
|
||||
Log.i(className, "Updating timetable after sunday!")
|
||||
Log.i(className, "updating timetable after sunday!")
|
||||
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
val threads = listOf(
|
||||
updateTimetable(Preferences.course.courseName, 0, context),
|
||||
updateTimetable(Preferences.course.courseName, 1, context)
|
||||
updateTimetable(cCourse.courseName, 0, context),
|
||||
updateTimetable(cCourse.courseName, 1, context)
|
||||
)
|
||||
threads.joinAll()
|
||||
}
|
||||
|
@ -81,7 +82,7 @@ class CacheController(private val context: Context) {
|
|||
|
||||
updateCourseList(context)
|
||||
|
||||
readStartCache(Preferences.course.courseName) // initially read values from cache
|
||||
readStartCache(cCourse.courseName) // initially read values from cache
|
||||
|
||||
// check if an update is necessary, not blocking
|
||||
if (currentTime - coursesCacheTime > 86400)
|
||||
|
@ -90,10 +91,12 @@ class CacheController(private val context: Context) {
|
|||
if (currentTime - mensaCacheTime > 10800)
|
||||
updateMensaMenu(context)
|
||||
|
||||
if (currentTime - timetableCacheTime > 10800)
|
||||
if (currentTime - timetableCacheTime > 10800) {
|
||||
TimetableController.update(context)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val className = "CacheController"
|
||||
var coursesList = ArrayList<Course>()
|
||||
|
@ -106,7 +109,7 @@ class CacheController(private val context: Context) {
|
|||
val file = File(context.filesDir, "courses.json")
|
||||
var courseListUp = CoursesList()
|
||||
|
||||
return CoroutineScope(Dispatchers.IO).launch {
|
||||
return GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
courseListUp = TCoRAPIController.getCourseListNEW()
|
||||
} catch (ex: Exception) {
|
||||
|
@ -129,7 +132,7 @@ class CacheController(private val context: Context) {
|
|||
fun updateMensaMenu(context: Context): Job {
|
||||
val file = File(context.filesDir, "mensa.json")
|
||||
|
||||
return CoroutineScope(Dispatchers.IO).launch {
|
||||
return GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
mensaMenu = TCoRAPIController.getMensaMenu()
|
||||
} catch (ex: Exception) {
|
||||
|
@ -153,7 +156,7 @@ class CacheController(private val context: Context) {
|
|||
var timetable = TimetableWeek()
|
||||
|
||||
// try to update timetable from tcor, async
|
||||
return CoroutineScope(Dispatchers.IO).launch {
|
||||
return GlobalScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
timetable = TCoRAPIController.getTimetable(courseName, week)
|
||||
} catch (ex: Exception) {
|
||||
|
@ -180,7 +183,7 @@ class CacheController(private val context: Context) {
|
|||
fun updateAdditionalLessons(context: Context): Job {
|
||||
val fileLessons = File(context.filesDir, "additional_lessons.json")
|
||||
|
||||
return CoroutineScope(Dispatchers.IO).launch {
|
||||
return GlobalScope.launch(Dispatchers.IO) {
|
||||
TimetableController.subjectMap.forEach { (courseName, subjects) ->
|
||||
// update all subjects for a course
|
||||
subjects.forEach {subject ->
|
||||
|
@ -219,6 +222,7 @@ class CacheController(private val context: Context) {
|
|||
Log.e(className, "failed to write file \"${file.absoluteFile}\"", ex)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,7 +275,7 @@ class CacheController(private val context: Context) {
|
|||
}
|
||||
|
||||
coursesList = FileReader(file).use {
|
||||
GsonBuilder().create().fromJson(it, CoursesList().javaClass).courses
|
||||
GsonBuilder().create().fromJson(BufferedReader(it).readLine(), CoursesList().javaClass).courses
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,7 +293,7 @@ class CacheController(private val context: Context) {
|
|||
}
|
||||
|
||||
mensaMenu = FileReader(file).use {
|
||||
GsonBuilder().create().fromJson(it, MensaMenu().javaClass)
|
||||
GsonBuilder().create().fromJson(BufferedReader(it).readLine(), MensaMenu().javaClass)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,14 +354,14 @@ class CacheController(private val context: Context) {
|
|||
FileReader(fileLessons).use {
|
||||
TimetableController.lessonMap.putAll(
|
||||
GsonBuilder().create()
|
||||
.fromJson(it, object : TypeToken<HashMap<String, Lesson>>() {}.type)
|
||||
.fromJson(BufferedReader(it).readLine(), object : TypeToken<HashMap<String, Lesson>>() {}.type)
|
||||
)
|
||||
}
|
||||
|
||||
FileReader(fileSubjects).use {
|
||||
TimetableController.subjectMap.putAll(
|
||||
GsonBuilder().create()
|
||||
.fromJson(it, HashMap<String, ArrayList<String>>().javaClass)
|
||||
.fromJson(BufferedReader(it).readLine(), HashMap<String, ArrayList<String>>().javaClass)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ package org.mosad.seil0.projectlaogai.controller.cache
|
|||
import android.content.Context
|
||||
import kotlinx.coroutines.Job
|
||||
import org.mosad.seil0.projectlaogai.controller.TCoRAPIController
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cCourse
|
||||
import org.mosad.seil0.projectlaogai.util.Lesson
|
||||
import org.mosad.seil0.projectlaogai.util.TimetableWeek
|
||||
|
||||
|
@ -38,8 +38,9 @@ import org.mosad.seil0.projectlaogai.util.TimetableWeek
|
|||
* * add second week
|
||||
* * add configurable week to addSubject() and removeSubject(), updateAdditionalLessons()
|
||||
*/
|
||||
object TimetableController {
|
||||
class TimetableController {
|
||||
|
||||
companion object {
|
||||
val timetable = ArrayList<TimetableWeek>()
|
||||
val lessonMap = HashMap<String, Lesson>() // the key is courseName-subject-lessonID
|
||||
val subjectMap = HashMap<String, ArrayList<String>>() // the key is courseName
|
||||
|
@ -49,8 +50,8 @@ object TimetableController {
|
|||
*/
|
||||
fun update(context: Context): List<Job> {
|
||||
return listOf(
|
||||
CacheController.updateTimetable(Preferences.course.courseName, 0, context),
|
||||
CacheController.updateTimetable(Preferences.course.courseName, 1, context),
|
||||
CacheController.updateTimetable(cCourse.courseName, 0, context),
|
||||
CacheController.updateTimetable(cCourse.courseName, 1, context),
|
||||
CacheController.updateAdditionalLessons(context)
|
||||
)
|
||||
}
|
||||
|
@ -126,3 +127,5 @@ object TimetableController {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -36,15 +36,13 @@ object Preferences {
|
|||
var coursesCacheTime: Long = 0
|
||||
var mensaCacheTime: Long = 0
|
||||
var timetableCacheTime: Long = 0
|
||||
var gradesCacheTime: Long = 0
|
||||
var colorPrimary: Int = Color.parseColor("#009688")
|
||||
var colorAccent: Int = Color.parseColor("#0096ff")
|
||||
var gradesSyncInterval = 0
|
||||
var course = Course(
|
||||
var cColorPrimary: Int = Color.parseColor("#009688")
|
||||
var cColorAccent: Int = Color.parseColor("#0096ff")
|
||||
var cCourse = Course(
|
||||
"https://www.hs-offenburg.de/index.php?id=6627&class=class&iddV=DA64F6FE-9DDB-429E-A677-05D0D40CB636&week=0",
|
||||
"AI3"
|
||||
)
|
||||
var showBuffet = true
|
||||
var cShowBuffet = true
|
||||
var oGiants = false
|
||||
|
||||
// TODO move!
|
||||
|
@ -69,9 +67,6 @@ object Preferences {
|
|||
putLong(context.getString(R.string.save_key_timetableCacheTime),
|
||||
timetableCacheTime
|
||||
)
|
||||
putLong(context.getString(R.string.save_key_gradesCacheTime),
|
||||
gradesCacheTime
|
||||
)
|
||||
apply()
|
||||
}
|
||||
|
||||
|
@ -92,7 +87,7 @@ object Preferences {
|
|||
apply()
|
||||
}
|
||||
|
||||
this.course = course
|
||||
cCourse = course
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,7 +106,7 @@ object Preferences {
|
|||
apply()
|
||||
}
|
||||
|
||||
this.colorPrimary = colorPrimary
|
||||
cColorPrimary = colorPrimary
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,23 +125,7 @@ object Preferences {
|
|||
apply()
|
||||
}
|
||||
|
||||
this.colorAccent = colorAccent
|
||||
}
|
||||
|
||||
fun saveGradesSync(context: Context, interval: Int) {
|
||||
val sharedPref = context.getSharedPreferences(
|
||||
context.getString(R.string.preference_file_key),
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
|
||||
with (sharedPref.edit()) {
|
||||
putInt(context.getString(R.string.save_key_gradesSyncInterval),
|
||||
interval
|
||||
)
|
||||
apply()
|
||||
}
|
||||
|
||||
gradesSyncInterval = interval
|
||||
cColorAccent = colorAccent
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,7 +144,7 @@ object Preferences {
|
|||
apply()
|
||||
}
|
||||
|
||||
this.showBuffet = showBuffet
|
||||
cShowBuffet = showBuffet
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,42 +157,36 @@ object Preferences {
|
|||
)
|
||||
|
||||
// load the update times (cache)
|
||||
coursesCacheTime = sharedPref.getLong(
|
||||
context.getString(R.string.save_key_coursesCacheTime),0
|
||||
)
|
||||
mensaCacheTime = sharedPref.getLong(
|
||||
context.getString(R.string.save_key_mensaCacheTime),0
|
||||
)
|
||||
timetableCacheTime = sharedPref.getLong(
|
||||
context.getString(R.string.save_key_timetableCacheTime),0
|
||||
)
|
||||
gradesCacheTime = sharedPref.getLong(
|
||||
context.getString(R.string.save_key_gradesCacheTime), 0
|
||||
)
|
||||
coursesCacheTime = sharedPref.getLong(context.getString(
|
||||
R.string.save_key_coursesCacheTime
|
||||
), 0)
|
||||
mensaCacheTime = sharedPref.getLong(context.getString(
|
||||
R.string.save_key_mensaCacheTime
|
||||
), 0)
|
||||
timetableCacheTime = sharedPref.getLong(context.getString(
|
||||
R.string.save_key_timetableCacheTime
|
||||
), 0)
|
||||
|
||||
// load saved course
|
||||
course = Course(
|
||||
sharedPref.getString(context.getString(R.string.save_key_courseTTLink),"https://www.hs-offenburg.de/index.php?id=6627&class=class&iddV=DA64F6FE-9DDB-429E-A677-05D0D40CB636&week=0")!!,
|
||||
cCourse = Course(
|
||||
sharedPref.getString(context.getString(R.string.save_key_courseTTLink),
|
||||
"https://www.hs-offenburg.de/index.php?id=6627&class=class&iddV=DA64F6FE-9DDB-429E-A677-05D0D40CB636&week=0"
|
||||
)!!,
|
||||
sharedPref.getString(context.getString(R.string.save_key_course), "AI3")!!
|
||||
)
|
||||
|
||||
// load saved colors
|
||||
colorPrimary = sharedPref.getInt(
|
||||
context.getString(R.string.save_key_colorPrimary), colorPrimary
|
||||
)
|
||||
colorAccent = sharedPref.getInt(
|
||||
context.getString(R.string.save_key_colorAccent), colorAccent
|
||||
)
|
||||
|
||||
// load grades sync interval
|
||||
gradesSyncInterval = sharedPref.getInt(
|
||||
context.getString(R.string.save_key_gradesSyncInterval), gradesSyncInterval
|
||||
)
|
||||
cColorPrimary = sharedPref.getInt(context.getString(
|
||||
R.string.save_key_colorPrimary
|
||||
), cColorPrimary)
|
||||
cColorAccent = sharedPref.getInt(context.getString(
|
||||
R.string.save_key_colorAccent
|
||||
), cColorAccent)
|
||||
|
||||
// load showBuffet
|
||||
showBuffet = sharedPref.getBoolean(
|
||||
context.getString(R.string.save_key_showBuffet), true
|
||||
)
|
||||
cShowBuffet = sharedPref.getBoolean(context.getString(
|
||||
R.string.save_key_showBuffet
|
||||
), true)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
* ProjectLaogai
|
||||
*
|
||||
* Copyright 2019-2020 <seil0@mosad.xyz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.mosad.seil0.projectlaogai.fragments
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import kotlinx.android.synthetic.main.fragment_grades.*
|
||||
import kotlinx.coroutines.*
|
||||
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.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.GradeLinearLayout
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoginDialog
|
||||
|
||||
/**
|
||||
* The grades fragment class
|
||||
* contains all needed parts to display and the grades screen
|
||||
*/
|
||||
class GradesFragment : Fragment() {
|
||||
|
||||
private lateinit var refreshLayoutGrades: SwipeRefreshLayout
|
||||
|
||||
private lateinit var parser: QISPOSParser
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_grades, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
refreshLayoutGrades = view.findViewById(R.id.refreshLayout_Grades)
|
||||
refreshLayoutGrades.isEnabled = false // disable swipe
|
||||
refreshLayoutGrades.setProgressBackgroundColorSchemeColor(Preferences.themeSecondary)
|
||||
|
||||
parser = QISPOSParser(context!!)// init the parser
|
||||
|
||||
if (checkCredentials() && checkQisposStatus()) {
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
addGrades()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
/**
|
||||
* check if qispos is available, if not show an error
|
||||
*/
|
||||
private fun checkQisposStatus(): Boolean {
|
||||
val statusCode = parser.checkQISPOSStatus()
|
||||
|
||||
// show error if the status code is not 200
|
||||
if (statusCode != 200) {
|
||||
val infoText = resources.getString(when(statusCode) {
|
||||
503 -> R.string.qispos_unavailable
|
||||
else -> R.string.qispos_generic_error
|
||||
})
|
||||
|
||||
val img = ResourcesCompat.getDrawable(resources, R.drawable.ic_error_outline_black_24dp, null)?.apply {
|
||||
bounds = Rect(0, 0, 75, 75)
|
||||
}
|
||||
|
||||
txtView_Loading?.apply {
|
||||
text = infoText
|
||||
setCompoundDrawables(null, null, null, img)
|
||||
}
|
||||
}
|
||||
|
||||
return statusCode == 200
|
||||
}
|
||||
|
||||
// add the grades to the layout, async
|
||||
private fun addGrades() = GlobalScope.launch(Dispatchers.Default) {
|
||||
withContext(Dispatchers.Main) {
|
||||
refreshLayout_Grades.isRefreshing = true
|
||||
}
|
||||
|
||||
val grades = parser.parseGrades()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
linLayout_Grades.removeAllViews() // clear layout
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
// disable divider if last element
|
||||
if (index == semester.value.lastIndex || semester.value.indexOf(subSubject) == semester.value.lastIndex)
|
||||
subjectLayout.disableDivider()
|
||||
|
||||
semesterCard.getLinLayoutDay().addView(subjectLayout)
|
||||
}
|
||||
|
||||
// without context we can't access the view
|
||||
withContext(Dispatchers.Main) {
|
||||
linLayout_Grades.addView(semesterCard)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
val txtViewLegal = TextView(context).apply {
|
||||
text = resources.getString(R.string.without_guarantee)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
}
|
||||
|
||||
// stop refreshing and show legal warning
|
||||
withContext(Dispatchers.Main) {
|
||||
linLayout_Grades.addView(txtViewLegal)
|
||||
refreshLayout_Grades.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -30,12 +30,11 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController.Companion.mensaMenu
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.TimetableController
|
||||
import org.mosad.seil0.projectlaogai.databinding.FragmentHomeBinding
|
||||
import org.mosad.seil0.projectlaogai.util.Meal
|
||||
import org.mosad.seil0.projectlaogai.util.TimetableDay
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
|
||||
|
@ -52,11 +51,9 @@ class HomeFragment : Fragment() {
|
|||
|
||||
private val className = "HomeFragment"
|
||||
private val formatter = SimpleDateFormat("E dd.MM", Locale.getDefault())
|
||||
private lateinit var binding: FragmentHomeBinding
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_home, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -69,22 +66,22 @@ class HomeFragment : Fragment() {
|
|||
/**
|
||||
* add the current mensa meal to the home screens
|
||||
*/
|
||||
private fun addMensaMenu() = lifecycleScope.launch(Dispatchers.Default) {
|
||||
private fun addMensaMenu() = GlobalScope.launch(Dispatchers.Default) {
|
||||
|
||||
var dayMeals: ArrayList<Meal>
|
||||
val cal = Calendar.getInstance()
|
||||
val mensaCardView = DayCardView(requireContext())
|
||||
val mensaCardView = DayCardView(context!!)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
if (isAdded) {
|
||||
if (cal.get(Calendar.HOUR_OF_DAY) < 15) {
|
||||
dayMeals = mensaMenu.currentWeek.days[NotRetardedCalendar.getDayOfWeekIndex()].meals
|
||||
mensaCardView.setDayHeading(getString(R.string.today_date, formatter.format(cal.time)))
|
||||
mensaCardView.setDayHeading(activity!!.resources.getString(R.string.today_date, formatter.format(cal.time)))
|
||||
} else {
|
||||
dayMeals = mensaMenu.currentWeek.days[NotRetardedCalendar.getTomorrowWeekIndex()].meals
|
||||
cal.add(Calendar.DATE, 1)
|
||||
mensaCardView.setDayHeading(getString(R.string.tomorrow_date, formatter.format(cal.time)))
|
||||
mensaCardView.setDayHeading(activity!!.resources.getString(R.string.tomorrow_date, formatter.format(cal.time)))
|
||||
}
|
||||
|
||||
if (dayMeals.size >= 2) {
|
||||
|
@ -109,7 +106,7 @@ class HomeFragment : Fragment() {
|
|||
mensaCardView.getLinLayoutDay().addView(getNoCard(resources.getString(R.string.mensa_closed)))
|
||||
}
|
||||
|
||||
binding.linLayoutHome.addView(mensaCardView)
|
||||
linLayout_Home.addView(mensaCardView)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -119,17 +116,22 @@ class HomeFragment : Fragment() {
|
|||
/**
|
||||
* add the current timetable to the home screen
|
||||
*/
|
||||
private fun addTimeTable() = lifecycleScope.launch(Dispatchers.Main) {
|
||||
private fun addTimeTable() = GlobalScope.launch(Dispatchers.Default) {
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
if (isAdded && TimetableController.timetable.isNotEmpty()) {
|
||||
try {
|
||||
val dayCardView = findNextDay(NotRetardedCalendar.getDayOfWeekIndex())
|
||||
binding.linLayoutHome.addView(dayCardView)
|
||||
linLayout_Home.addView(dayCardView)
|
||||
} catch (ex: Exception) {
|
||||
Log.e(className, "could not load timetable", ex) // TODO send feedback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* find the next day with a lesson
|
||||
* start at week 0, startDayIndex and search every cached week until we find a) a day with a timetable
|
||||
|
@ -138,7 +140,7 @@ class HomeFragment : Fragment() {
|
|||
* @return a DayCardView with all lessons added
|
||||
*/
|
||||
private fun findNextDay(startDayIndex: Int): DayCardView {
|
||||
val dayCardView = DayCardView(requireContext())
|
||||
val dayCardView = DayCardView(context!!)
|
||||
var dayTimetable: TimetableDay? = null
|
||||
var dayIndexSearch = startDayIndex
|
||||
var weekIndexSearch = 0
|
||||
|
|
|
@ -27,15 +27,16 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.android.synthetic.main.fragment_mensa.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController.Companion.mensaMenu
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.databinding.FragmentMensaBinding
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cShowBuffet
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.MealLinearLayout
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.TextViewInfo
|
||||
|
@ -48,34 +49,31 @@ import org.mosad.seil0.projectlaogai.util.NotRetardedCalendar
|
|||
*/
|
||||
class MensaFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentMensaBinding
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
binding = FragmentMensaBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_mensa, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.refreshLayoutMensa.setProgressBackgroundColorSchemeColor(Preferences.themeSecondary)
|
||||
refreshLayout_Mensa.setProgressBackgroundColorSchemeColor(Preferences.themeSecondary)
|
||||
|
||||
initActions() // init actions
|
||||
refreshAction() // init actions
|
||||
|
||||
lifecycleScope.launch(Dispatchers.Default) {
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
val dayCurrent = if(NotRetardedCalendar.getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar.getDayOfWeekIndex()
|
||||
|
||||
// add the current and next week
|
||||
addWeek(mensaMenu.currentWeek, dayCurrent).join()
|
||||
addWeek(mensaMenu.nextWeek, 0).join()
|
||||
|
||||
// add the next week
|
||||
addWeek(mensaMenu.nextWeek, 0)
|
||||
}
|
||||
|
||||
// show a info if there are no more menus
|
||||
if (binding.linLayoutMensa.childCount == 0) {
|
||||
val txtViewInfo = TextViewInfo(requireContext()).set {
|
||||
if (linLayout_Mensa.childCount == 0) {
|
||||
val txtViewInfo = TextViewInfo(context!!).set {
|
||||
txt = resources.getString(R.string.no_more_meals)
|
||||
}
|
||||
withContext(Dispatchers.Main) { binding.linLayoutMensa.addView(txtViewInfo) }
|
||||
}
|
||||
linLayout_Mensa.addView(txtViewInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,13 +82,13 @@ class MensaFragment : Fragment() {
|
|||
* @param menusWeek menu of type MensaWeek you want to add
|
||||
* @param dayStart the first day of the week to add
|
||||
*/
|
||||
private fun addWeek(menusWeek: MensaWeek, dayStart: Int) = lifecycleScope.launch(Dispatchers.Default) {
|
||||
private fun addWeek(menusWeek: MensaWeek, dayStart: Int) = GlobalScope.launch(Dispatchers.Default) {
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
// only add the days dayStart to Fri since the mensa is closed on Sat/Sun
|
||||
for (dayIndex in dayStart..4) {
|
||||
var helpMeal = MealLinearLayout(context)
|
||||
val dayCardView = DayCardView(requireContext())
|
||||
val dayCardView = DayCardView(context!!)
|
||||
|
||||
if(menusWeek.days[dayIndex].meals.isNotEmpty())
|
||||
dayCardView.setDayHeading(menusWeek.days[dayIndex].meals[0].day)
|
||||
|
@ -99,7 +97,7 @@ class MensaFragment : Fragment() {
|
|||
val mealLayout = MealLinearLayout(context)
|
||||
mealLayout.setMeal(meal)
|
||||
|
||||
if(meal.heading != "Buffet" || Preferences.showBuffet) {
|
||||
if(meal.heading != "Buffet" || cShowBuffet) {
|
||||
dayCardView.getLinLayoutDay().addView(mealLayout)
|
||||
helpMeal = mealLayout
|
||||
}
|
||||
|
@ -108,47 +106,50 @@ class MensaFragment : Fragment() {
|
|||
helpMeal.disableDivider()
|
||||
|
||||
if(dayCardView.getLinLayoutDay().childCount > 2)
|
||||
binding.linLayoutMensa.addView(dayCardView)
|
||||
linLayout_Mensa.addView(dayCardView)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the actions
|
||||
* initialize the refresh action
|
||||
*/
|
||||
private fun initActions() {
|
||||
private fun refreshAction() = GlobalScope.launch(Dispatchers.Default) {
|
||||
withContext(Dispatchers.Main) {
|
||||
// set the refresh listener
|
||||
binding.refreshLayoutMensa.setOnRefreshListener {
|
||||
refreshLayout_Mensa.setOnRefreshListener {
|
||||
updateMensaScreen()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh the mensa cache and update the mensa screen
|
||||
*/
|
||||
private fun updateMensaScreen() = lifecycleScope.launch(Dispatchers.Default) {
|
||||
CacheController.updateMensaMenu(requireContext()).join() // blocking since we want the new data
|
||||
private fun updateMensaScreen() = GlobalScope.launch(Dispatchers.Default) {
|
||||
CacheController.updateMensaMenu(context!!).join() // blocking since we want the new data
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
// remove all menus from the layout
|
||||
binding.linLayoutMensa.removeAllViews()
|
||||
linLayout_Mensa.removeAllViews()
|
||||
|
||||
// add the refreshed menus
|
||||
val dayCurrent = if (NotRetardedCalendar.getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar.getDayOfWeekIndex()
|
||||
|
||||
// add the current and next week
|
||||
addWeek(mensaMenu.currentWeek, dayCurrent).join()
|
||||
addWeek(mensaMenu.nextWeek, 0).join()
|
||||
|
||||
binding.refreshLayoutMensa.isRefreshing = false
|
||||
// add the next week
|
||||
addWeek(mensaMenu.nextWeek, 0)
|
||||
|
||||
refreshLayout_Mensa.isRefreshing = false
|
||||
|
||||
// show a info if there are no more menus
|
||||
if (binding.linLayoutMensa.childCount == 0) {
|
||||
val txtViewInfo = TextViewInfo(requireContext()).set {
|
||||
if (linLayout_Mensa.childCount == 0) {
|
||||
val txtViewInfo = TextViewInfo(context!!).set {
|
||||
txt = resources.getString(R.string.no_more_meals)
|
||||
}
|
||||
binding.linLayoutMensa.addView(txtViewInfo)
|
||||
linLayout_Mensa.addView(txtViewInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,35 +22,43 @@
|
|||
|
||||
package org.mosad.seil0.projectlaogai.fragments
|
||||
|
||||
//import com.afollestad.aesthetic.Aesthetic
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.afollestad.aesthetic.Aesthetic
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.WhichButton
|
||||
import com.afollestad.materialdialogs.actions.getActionButton
|
||||
import com.afollestad.materialdialogs.callbacks.onDismiss
|
||||
import com.afollestad.materialdialogs.color.colorChooser
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
import com.afollestad.materialdialogs.list.listItemsMultiChoice
|
||||
import com.afollestad.materialdialogs.list.listItemsSingleChoice
|
||||
import de.psdev.licensesdialog.LicensesDialog
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.android.synthetic.main.fragment_settings.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.mosad.seil0.projectlaogai.BuildConfig
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.CacheController.Companion.coursesList
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.TimetableController
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.databinding.FragmentSettingsBinding
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.CourseSelectionDialog
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoadingDialog
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cColorAccent
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cColorPrimary
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cCourse
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences.cShowBuffet
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoginDialog
|
||||
import org.mosad.seil0.projectlaogai.util.DataTypes
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* The settings controller class
|
||||
|
@ -58,13 +66,21 @@ import org.mosad.seil0.projectlaogai.util.DataTypes
|
|||
*/
|
||||
class SettingsFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentSettingsBinding
|
||||
private lateinit var linLayoutUser: LinearLayout
|
||||
private lateinit var linLayoutCourse: LinearLayout
|
||||
private lateinit var linLayoutManageLessons: LinearLayout
|
||||
private lateinit var linLayoutAbout: LinearLayout
|
||||
private lateinit var linLayoutLicence: LinearLayout
|
||||
private lateinit var linLayoutTheme: LinearLayout
|
||||
private lateinit var linLayoutPrimaryColor: LinearLayout
|
||||
private lateinit var linLayoutAccentColor: LinearLayout
|
||||
private lateinit var switchBuffet: SwitchCompat
|
||||
private lateinit var txtViewCourse: TextView
|
||||
|
||||
private var selectedTheme = DataTypes.Theme.Light
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
binding = FragmentSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_settings, container, false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,42 +89,56 @@ class SettingsFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
linLayoutUser = view.findViewById(R.id.linLayout_User)
|
||||
linLayoutCourse = view.findViewById(R.id.linLayout_Course)
|
||||
linLayoutManageLessons = view.findViewById(R.id.linLayout_ManageLessons)
|
||||
linLayoutAbout = view.findViewById(R.id.linLayout_About)
|
||||
linLayoutLicence = view.findViewById(R.id.linLayout_Licence)
|
||||
linLayoutTheme = view.findViewById(R.id.linLayout_Theme)
|
||||
linLayoutPrimaryColor = view.findViewById(R.id.linLayout_PrimaryColor)
|
||||
linLayoutAccentColor = view.findViewById(R.id.linLayout_AccentColor)
|
||||
switchBuffet = view.findViewById(R.id.switch_buffet)
|
||||
|
||||
// if we call txtView_Course via KAE view binding it'll result in a NPE in the onDismissed call
|
||||
txtViewCourse = view.findViewById(R.id.txtView_Course)
|
||||
|
||||
initActions()
|
||||
|
||||
binding.textUser.text = EncryptedPreferences.email.ifEmpty { resources.getString(R.string.sample_user) }
|
||||
binding.textCourse.text = Preferences.course.courseName
|
||||
binding.textAboutDesc.text = resources.getString(R.string.about_version, BuildConfig.VERSION_NAME, getString(R.string.build_time))
|
||||
binding.switchBuffet.isChecked = Preferences.showBuffet // init switch
|
||||
|
||||
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
|
||||
|
||||
val outValue = TypedValue()
|
||||
requireActivity().theme.resolveAttribute(R.attr.themeName, outValue, true)
|
||||
activity!!.theme.resolveAttribute(R.attr.themeName, outValue, true)
|
||||
when(outValue.string) {
|
||||
"light" -> {
|
||||
binding.switchBuffet.setTextColor(requireActivity().resources.getColor(R.color.textPrimaryLight, requireActivity().theme))
|
||||
switch_buffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryLight, activity!!.theme))
|
||||
selectedTheme = DataTypes.Theme.Light
|
||||
selectedTheme.string = resources.getString(R.string.themeLight)
|
||||
}
|
||||
"dark" -> {
|
||||
binding.switchBuffet.setTextColor(requireActivity().resources.getColor(R.color.textPrimaryDark, requireActivity().theme))
|
||||
switch_buffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryDark, activity!!.theme))
|
||||
selectedTheme = DataTypes.Theme.Dark
|
||||
selectedTheme.string = resources.getString(R.string.themeDark)
|
||||
}
|
||||
"black" -> {
|
||||
binding.switchBuffet.setTextColor(requireActivity().resources.getColor(R.color.textPrimaryDark, requireActivity().theme))
|
||||
switch_buffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryDark, activity!!.theme))
|
||||
selectedTheme = DataTypes.Theme.Black
|
||||
selectedTheme.string = resources.getString(R.string.themeBlack)
|
||||
}
|
||||
}
|
||||
binding.textThemeSelected.text = selectedTheme.string
|
||||
txtView_SelectedTheme.text = selectedTheme.string
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize some actions for SettingsFragment elements
|
||||
*/
|
||||
private fun initActions() {
|
||||
binding.linLayoutUser.setOnClickListener {
|
||||
linLayoutUser.setOnClickListener {
|
||||
// open a new dialog
|
||||
LoginDialog(requireContext())
|
||||
LoginDialog(context!!)
|
||||
.positiveButton {
|
||||
EncryptedPreferences.saveCredentials(email, password, context)
|
||||
}
|
||||
|
@ -118,40 +148,20 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
binding.linLayoutUser.setOnLongClickListener {
|
||||
linLayoutUser.setOnLongClickListener {
|
||||
Preferences.oGiants = true // enable easter egg
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
binding.linLayoutCourse.setOnClickListener {
|
||||
CourseSelectionDialog(requireContext()).show {
|
||||
list = coursesList.map { it.courseName }
|
||||
listItems {
|
||||
val loadingDialog = LoadingDialog(context)
|
||||
loadingDialog.show()
|
||||
|
||||
lifecycleScope.launch(Dispatchers.Default) {
|
||||
Preferences.saveCourse(context, coursesList[selectedIndex]) // save the course
|
||||
|
||||
// update current & next weeks timetable
|
||||
val threads = listOf(
|
||||
CacheController.updateTimetable(Preferences.course.courseName, 0, context),
|
||||
CacheController.updateTimetable(Preferences.course.courseName, 1, context)
|
||||
)
|
||||
threads.joinAll() // blocking since we want the new data
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
linLayoutCourse.setOnClickListener {
|
||||
selectCourse(context!!).show {
|
||||
onDismiss {
|
||||
binding.textCourse.text = Preferences.course.courseName // update txtView after the dialog is dismissed
|
||||
txtViewCourse.text = cCourse.courseName // update txtView after the dialog is dismissed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.linLayoutManageLessons.setOnClickListener {
|
||||
linLayoutManageLessons.setOnClickListener {
|
||||
val lessons = ArrayList<String>()
|
||||
TimetableController.subjectMap.forEach { pair ->
|
||||
pair.value.forEach {
|
||||
|
@ -159,12 +169,12 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
MaterialDialog(requireContext()).show {
|
||||
MaterialDialog(context!!).show {
|
||||
title(R.string.manage_lessons)
|
||||
positiveButton(R.string.delete)
|
||||
negativeButton(R.string.cancel)
|
||||
getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
|
||||
getActionButton(WhichButton.NEGATIVE).updateTextColor(Preferences.colorAccent)
|
||||
getActionButton(WhichButton.POSITIVE).updateTextColor(cColorAccent)
|
||||
getActionButton(WhichButton.NEGATIVE).updateTextColor(cColorAccent)
|
||||
|
||||
listItemsMultiChoice(items = lessons) { _, _, items ->
|
||||
items.forEach {
|
||||
|
@ -175,18 +185,18 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
binding.linLayoutAbout.setOnClickListener {
|
||||
linLayoutAbout.setOnClickListener {
|
||||
// open a new info dialog
|
||||
MaterialDialog(requireContext())
|
||||
MaterialDialog(context!!)
|
||||
.title(R.string.about_dialog_heading)
|
||||
.message(R.string.about_dialog_text)
|
||||
.show()
|
||||
}
|
||||
|
||||
binding.linLayoutLicence.setOnClickListener {
|
||||
linLayoutLicence.setOnClickListener {
|
||||
// do the theme magic, as the lib's theme support is broken
|
||||
val outValue = TypedValue()
|
||||
requireContext().theme.resolveAttribute(R.attr.themeName, outValue, true)
|
||||
context!!.theme.resolveAttribute(R.attr.themeName, outValue, true)
|
||||
|
||||
val dialogCss = when (outValue.string) {
|
||||
"light" -> R.string.license_dialog_style_light
|
||||
|
@ -199,7 +209,7 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
|
||||
// open a new license dialog
|
||||
LicensesDialog.Builder(requireContext())
|
||||
LicensesDialog.Builder(context!!)
|
||||
.setNotices(R.raw.notices)
|
||||
.setTitle(R.string.licenses)
|
||||
.setIncludeOwnLicense(true)
|
||||
|
@ -209,72 +219,106 @@ class SettingsFragment : Fragment() {
|
|||
.show()
|
||||
}
|
||||
|
||||
// binding.linLayoutTheme.setOnClickListener {
|
||||
// val themes = listOf(
|
||||
// resources.getString(R.string.themeLight),
|
||||
// resources.getString(R.string.themeDark),
|
||||
// resources.getString(R.string.themeBlack)
|
||||
// )
|
||||
//
|
||||
// MaterialDialog(requireContext()).show {
|
||||
// title(R.string.theme)
|
||||
// listItemsSingleChoice(items = themes, initialSelection = selectedTheme.ordinal) { _, index, _ ->
|
||||
// Aesthetic.config {
|
||||
// when (index) {
|
||||
// 0 -> activityTheme(R.style.AppTheme_Light)
|
||||
// 1 -> activityTheme(R.style.AppTheme_Dark)
|
||||
// 2 -> activityTheme(R.style.AppTheme_Black)
|
||||
// else -> activityTheme(R.style.AppTheme_Light)
|
||||
// }
|
||||
// apply()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
linLayoutTheme.setOnClickListener {
|
||||
val themes = listOf(
|
||||
resources.getString(R.string.themeLight),
|
||||
resources.getString(R.string.themeDark),
|
||||
resources.getString(R.string.themeBlack)
|
||||
)
|
||||
|
||||
// binding.linLayoutPrimaryColor.setOnClickListener {
|
||||
// // open a new color chooser dialog
|
||||
// MaterialDialog(requireContext())
|
||||
// .colorChooser(DataTypes().primaryColors, allowCustomArgb = true, initialSelection = Preferences.colorPrimary) { _, color ->
|
||||
// binding.viewPrimaryColor.setBackgroundColor(color)
|
||||
// Aesthetic.config {
|
||||
// colorPrimary(color)
|
||||
// colorPrimaryDark(color)
|
||||
// apply()
|
||||
// }
|
||||
// Preferences.saveColorPrimary(requireContext(), color)
|
||||
// }
|
||||
// .show {
|
||||
// title(R.string.primary_color)
|
||||
// positiveButton(R.string.select)
|
||||
// getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
MaterialDialog(context!!).show {
|
||||
title(R.string.theme)
|
||||
listItemsSingleChoice(items = themes, initialSelection = selectedTheme.ordinal) { _, index, _ ->
|
||||
Aesthetic.config {
|
||||
when (index) {
|
||||
0 -> activityTheme(R.style.AppTheme_Light)
|
||||
1 -> activityTheme(R.style.AppTheme_Dark)
|
||||
2 -> activityTheme(R.style.AppTheme_Black)
|
||||
else -> activityTheme(R.style.AppTheme_Light)
|
||||
}
|
||||
apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// binding.linLayoutAccentColor.setOnClickListener {
|
||||
// // open a new color chooser dialog
|
||||
// MaterialDialog(requireContext())
|
||||
// .colorChooser(DataTypes().accentColors, allowCustomArgb = true, initialSelection = Preferences.colorAccent) { _, color ->
|
||||
// binding.viewAccentColor.setBackgroundColor(color)
|
||||
// Aesthetic.config {
|
||||
// colorAccent(color)
|
||||
// apply()
|
||||
// }
|
||||
//
|
||||
// Preferences.saveColorAccent(requireContext(), color)
|
||||
// }
|
||||
// .show{
|
||||
// title(R.string.accent_color)
|
||||
// positiveButton(R.string.select)
|
||||
// getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
|
||||
// }
|
||||
// }
|
||||
|
||||
binding.switchBuffet.setOnClickListener {
|
||||
Preferences.saveShowBuffet(requireContext(), binding.switchBuffet.isChecked)
|
||||
linLayoutPrimaryColor.setOnClickListener {
|
||||
// open a new color chooser dialog
|
||||
MaterialDialog(context!!)
|
||||
.colorChooser(DataTypes().primaryColors, allowCustomArgb = true, initialSelection = cColorPrimary) { _, color ->
|
||||
view_PrimaryColor.setBackgroundColor(color)
|
||||
Aesthetic.config {
|
||||
colorPrimary(color)
|
||||
colorPrimaryDark(color)
|
||||
apply()
|
||||
}
|
||||
Preferences.saveColorPrimary(context!!, color)
|
||||
}
|
||||
.show {
|
||||
title(R.string.primary_color)
|
||||
positiveButton(R.string.select)
|
||||
getActionButton(WhichButton.POSITIVE).updateTextColor(cColorAccent)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
linLayoutAccentColor.setOnClickListener {
|
||||
// open a new color chooser dialog
|
||||
MaterialDialog(context!!)
|
||||
.colorChooser(DataTypes().accentColors, allowCustomArgb = true, initialSelection = cColorAccent) { _, color ->
|
||||
view_AccentColor.setBackgroundColor(color)
|
||||
Aesthetic.config {
|
||||
colorAccent(color)
|
||||
apply()
|
||||
}
|
||||
|
||||
Preferences.saveColorAccent(context!!, color)
|
||||
}
|
||||
.show{
|
||||
title(R.string.accent_color)
|
||||
positiveButton(R.string.select)
|
||||
getActionButton(WhichButton.POSITIVE).updateTextColor(cColorAccent)
|
||||
}
|
||||
}
|
||||
|
||||
switchBuffet.setOnClickListener {
|
||||
Preferences.saveShowBuffet(context!!, switchBuffet.isChecked)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun selectCourse(context: Context) : MaterialDialog {
|
||||
val courseNameList = ArrayList<String>()
|
||||
coursesList.forEach { (_, courseName) ->
|
||||
courseNameList.add(courseName)
|
||||
}
|
||||
|
||||
// return a new course selection dialog
|
||||
return MaterialDialog(context)
|
||||
.title(R.string.select_course)
|
||||
.listItems(items = courseNameList) { _, index, _ ->
|
||||
|
||||
val loadingDialog = MaterialDialog(context).cancelable(false)
|
||||
.cancelOnTouchOutside(false)
|
||||
.customView(R.layout.dialog_loading)
|
||||
loadingDialog.show()
|
||||
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
Preferences.saveCourse(context, coursesList[index]) // save the course
|
||||
|
||||
// update current & next weeks timetable
|
||||
val threads = listOf(
|
||||
CacheController.updateTimetable(cCourse.courseName, 0, context),
|
||||
CacheController.updateTimetable(cCourse.courseName, 1, context)
|
||||
)
|
||||
threads.joinAll() // blocking since we want the new data
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,14 +26,15 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ScrollView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import kotlinx.android.synthetic.main.fragment_timetable.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.TimetableController
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.TimetableController.timetable
|
||||
import org.mosad.seil0.projectlaogai.controller.cache.TimetableController.Companion.timetable
|
||||
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
|
||||
import org.mosad.seil0.projectlaogai.databinding.FragmentTimetableBinding
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.AddSubjectDialog
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
|
||||
import org.mosad.seil0.projectlaogai.uicomponents.TextViewInfo
|
||||
|
@ -43,45 +44,47 @@ import org.mosad.seil0.projectlaogai.util.NotRetardedCalendar
|
|||
* The timetable controller class
|
||||
* contains all needed parts to display and the timetable detail screen
|
||||
*/
|
||||
class TimetableFragment : Fragment() {
|
||||
class TimeTableFragment : Fragment() {
|
||||
|
||||
private lateinit var binding: FragmentTimetableBinding
|
||||
private lateinit var scrollViewTimetable: ScrollView
|
||||
private lateinit var faBtnAddSubject: FloatingActionButton
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
binding = FragmentTimetableBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_timetable, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
binding.refreshLayoutTimetable.setProgressBackgroundColorSchemeColor(Preferences.themeSecondary)
|
||||
scrollViewTimetable = view.findViewById(R.id.scrollView_Timetable)
|
||||
faBtnAddSubject = view.findViewById(R.id.faBtnAddSubject)
|
||||
refreshLayout_Timetable.setProgressBackgroundColorSchemeColor(Preferences.themeSecondary)
|
||||
|
||||
initActions() // init actions
|
||||
|
||||
if (timetable.size > 1 && timetable[0].days.isNotEmpty() && timetable[1].days.isNotEmpty()) {
|
||||
initTimetable()
|
||||
} else {
|
||||
val txtViewInfo = TextViewInfo(requireContext()).set {
|
||||
val txtViewInfo = TextViewInfo(context!!).set {
|
||||
txt = resources.getString(R.string.timetable_generic_error)
|
||||
}.showImage()
|
||||
binding.linLayoutTimetable.addView(txtViewInfo)
|
||||
linLayout_Timetable.addView(txtViewInfo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the actions
|
||||
*/
|
||||
private fun initActions() {
|
||||
private fun initActions() = GlobalScope.launch(Dispatchers.Main) {
|
||||
|
||||
binding.refreshLayoutTimetable.setOnRefreshListener {
|
||||
runBlocking { TimetableController.update(requireContext()).joinAll() }
|
||||
refreshLayout_Timetable.setOnRefreshListener {
|
||||
runBlocking { TimetableController.update(context!!).joinAll() }
|
||||
reloadTimetableUI()
|
||||
}
|
||||
|
||||
// show the AddLessonDialog if the ftaBtn is clicked
|
||||
binding.faBtnAddSubject.setOnClickListener {
|
||||
AddSubjectDialog(requireContext())
|
||||
faBtnAddSubject.setOnClickListener {
|
||||
AddSubjectDialog(context!!)
|
||||
.positiveButton {
|
||||
TimetableController.addSubject(selectedCourse, selectedSubject, context)
|
||||
runBlocking { reloadTimetableUI() }
|
||||
|
@ -89,11 +92,11 @@ class TimetableFragment : Fragment() {
|
|||
}
|
||||
|
||||
// hide the btnCardValue if the user is scrolling down
|
||||
binding.scrollViewTimetable.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
scrollViewTimetable.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
if (scrollY > oldScrollY) {
|
||||
binding.faBtnAddSubject.hide()
|
||||
faBtnAddSubject.hide()
|
||||
} else {
|
||||
binding.faBtnAddSubject.show()
|
||||
faBtnAddSubject.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,16 +105,16 @@ class TimetableFragment : Fragment() {
|
|||
/**
|
||||
* add the current and next weeks lessons
|
||||
*/
|
||||
private fun initTimetable() = lifecycleScope.launch(Dispatchers.Default) {
|
||||
private fun initTimetable() = GlobalScope.launch(Dispatchers.Default) {
|
||||
val currentDayIndex = NotRetardedCalendar.getDayOfWeekIndex()
|
||||
|
||||
addTimetableWeek(currentDayIndex, 5, 0).join() // add current week
|
||||
addTimetableWeek(0, currentDayIndex - 1, 1) // add next week
|
||||
}
|
||||
|
||||
private fun addTimetableWeek(dayBegin: Int, dayEnd: Int, week: Int) = lifecycleScope.launch(Dispatchers.Main) {
|
||||
private fun addTimetableWeek(dayBegin: Int, dayEnd: Int, week: Int) = GlobalScope.launch(Dispatchers.Main) {
|
||||
for (dayIndex in dayBegin..dayEnd) {
|
||||
val dayCardView = DayCardView(requireContext())
|
||||
val dayCardView = DayCardView(context!!)
|
||||
|
||||
// some wired calendar magic, calculate the correct date to be shown
|
||||
// ((timetable week - current week * 7) + (dayIndex - dayIndex of current week)
|
||||
|
@ -121,7 +124,7 @@ class TimetableFragment : Fragment() {
|
|||
|
||||
// if there are no lessons don't show the dayCardView
|
||||
if (dayCardView.getLinLayoutDay().childCount > 1)
|
||||
binding.linLayoutTimetable.addView(dayCardView)
|
||||
linLayout_Timetable.addView(dayCardView)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -129,10 +132,10 @@ class TimetableFragment : Fragment() {
|
|||
/**
|
||||
* clear linLayout_Timetable, add the updated timetable
|
||||
*/
|
||||
private fun reloadTimetableUI() = lifecycleScope.launch(Dispatchers.Default) {
|
||||
private fun reloadTimetableUI() = GlobalScope.launch(Dispatchers.Default) {
|
||||
withContext(Dispatchers.Main) {
|
||||
// remove all lessons from the layout
|
||||
binding.linLayoutTimetable.removeAllViews()
|
||||
linLayout_Timetable.removeAllViews()
|
||||
|
||||
// add the refreshed timetables
|
||||
val dayIndex = NotRetardedCalendar.getDayOfWeekIndex()
|
||||
|
@ -140,7 +143,7 @@ class TimetableFragment : Fragment() {
|
|||
addTimetableWeek(dayIndex, 5, 0).join() // add current week
|
||||
addTimetableWeek(0, dayIndex - 1, 1) // add next week
|
||||
|
||||
binding.refreshLayoutTimetable.isRefreshing = false
|
||||
refreshLayout_Timetable.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
|
@ -24,10 +24,10 @@ package org.mosad.seil0.projectlaogai.uicomponents
|
|||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import androidx.cardview.widget.CardView
|
||||
import org.mosad.seil0.projectlaogai.databinding.CardviewDayBinding
|
||||
import kotlinx.android.synthetic.main.cardview_day.view.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.util.DataTypes
|
||||
import org.mosad.seil0.projectlaogai.util.TimetableDay
|
||||
import java.text.SimpleDateFormat
|
||||
|
@ -35,19 +35,21 @@ import java.util.*
|
|||
|
||||
class DayCardView(context: Context) : CardView(context) {
|
||||
|
||||
private var binding = CardviewDayBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
private val formatter = SimpleDateFormat("E dd.MM", Locale.getDefault())
|
||||
|
||||
init {
|
||||
this.setBackgroundColor(Color.TRANSPARENT) // workaround to prevent a white border
|
||||
inflate(context, R.layout.cardview_day,this)
|
||||
|
||||
// workaround to prevent a white border
|
||||
this.setBackgroundColor(Color.TRANSPARENT)
|
||||
}
|
||||
|
||||
fun getLinLayoutDay() : LinearLayout {
|
||||
return binding.linearDay
|
||||
return linLayout_Day
|
||||
}
|
||||
|
||||
fun setDayHeading(heading: String) {
|
||||
binding.textDayHeading.text = heading
|
||||
txtView_DayHeading.text = heading
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,7 +62,7 @@ class DayCardView(context: Context) : CardView(context) {
|
|||
// set the heading
|
||||
val cal = Calendar.getInstance()
|
||||
cal.add(Calendar.DATE, daysToAdd)
|
||||
binding.textDayHeading.text = formatter.format(cal.time)
|
||||
txtView_DayHeading.text = formatter.format(cal.time)
|
||||
|
||||
// for every timeslot of that timetable
|
||||
timetable.timeslots.forEachIndexed { tsIndex, timeslot ->
|
||||
|
@ -69,7 +71,7 @@ class DayCardView(context: Context) : CardView(context) {
|
|||
|
||||
val lessonLayout = LessonLinearLayout(context)
|
||||
lessonLayout.setLesson(lesson, DataTypes().times[tsIndex])
|
||||
binding.linearDay.addView(lessonLayout)
|
||||
linLayout_Day.addView(lessonLayout)
|
||||
|
||||
if (lesson != timeslot.last()) {
|
||||
lessonLayout.disableDivider()
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* ProjectLaogai
|
||||
*
|
||||
* Copyright 2019-2020 <seil0@mosad.xyz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.mosad.seil0.projectlaogai.uicomponents
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.linearlayout_grade.view.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
|
||||
class GradeLinearLayout(context: Context?): LinearLayout(context) {
|
||||
|
||||
var subjectName = ""
|
||||
var grade = ""
|
||||
var subSubjectName = ""
|
||||
var subGrade = ""
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.linearlayout_grade, this)
|
||||
}
|
||||
|
||||
fun set(func: GradeLinearLayout.() -> Unit): GradeLinearLayout = apply {
|
||||
func()
|
||||
|
||||
txtView_subject.text = subjectName
|
||||
txtView_grade.text = grade
|
||||
txtView_sub_subject.text = subSubjectName
|
||||
txtView_sub_grade.text = subGrade
|
||||
}
|
||||
|
||||
fun disableDivider() {
|
||||
divider_grade.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun disableSubSubject() {
|
||||
linLayout_sub_subject.visibility = View.GONE
|
||||
}
|
||||
}
|
|
@ -23,25 +23,27 @@
|
|||
package org.mosad.seil0.projectlaogai.uicomponents
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import org.mosad.seil0.projectlaogai.databinding.LinearlayoutLessonBinding
|
||||
import kotlinx.android.synthetic.main.linearlayout_lesson.view.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.util.Lesson
|
||||
|
||||
class LessonLinearLayout(context: Context?) : LinearLayout(context) {
|
||||
|
||||
private val binding = LinearlayoutLessonBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
init {
|
||||
inflate(context, R.layout.linearlayout_lesson, this)
|
||||
}
|
||||
|
||||
fun setLesson(lesson: Lesson, time: String) {
|
||||
binding.textLessonTime.text = time
|
||||
binding.textLessonSubject.text = lesson.lessonSubject
|
||||
binding.textLessonTeacher.text = lesson.lessonTeacher
|
||||
binding.textLessonRoom.text = lesson.lessonRoom
|
||||
txtView_lessonTime.text = time
|
||||
txtView_lessonSubject.text = lesson.lessonSubject
|
||||
txtView_lessonTeacher.text = lesson.lessonTeacher
|
||||
txtView_lessonRoom.text = lesson.lessonRoom
|
||||
}
|
||||
|
||||
fun disableDivider() {
|
||||
binding.dividerLesson.visibility = View.GONE
|
||||
divider_lesson.visibility = View.GONE
|
||||
}
|
||||
|
||||
}
|
|
@ -23,28 +23,30 @@
|
|||
package org.mosad.seil0.projectlaogai.uicomponents
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import org.mosad.seil0.projectlaogai.databinding.LinearlayoutMealBinding
|
||||
import kotlinx.android.synthetic.main.linearlayout_meal.view.*
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
import org.mosad.seil0.projectlaogai.util.Meal
|
||||
|
||||
class MealLinearLayout(context: Context?): LinearLayout(context) {
|
||||
|
||||
private val binding = LinearlayoutMealBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
init {
|
||||
inflate(context, R.layout.linearlayout_meal, this)
|
||||
}
|
||||
|
||||
fun setMeal(meal: Meal) {
|
||||
binding.textMealHeading.text = meal.heading
|
||||
txtView_MealHeading.text = meal.heading
|
||||
|
||||
meal.parts.forEachIndexed { partIndex, part ->
|
||||
binding.textMeal.append(part)
|
||||
txtView_Meal.append(part)
|
||||
if(partIndex < (meal.parts.size - 1))
|
||||
binding.textMeal.append("\n")
|
||||
txtView_Meal.append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
fun disableDivider() {
|
||||
binding.dividerMeal.visibility = View.GONE
|
||||
divider_meal.visibility = View.GONE
|
||||
}
|
||||
|
||||
}
|
|
@ -41,6 +41,7 @@ class TextViewInfo(context: Context?): AppCompatTextView(context!!) {
|
|||
|
||||
init {
|
||||
params.setMargins(0,200,0,0)
|
||||
|
||||
}
|
||||
|
||||
fun set(func: TextViewInfo.() -> Unit): TextViewInfo = apply {
|
||||
|
|
|
@ -71,8 +71,8 @@ class AddSubjectDialog(val context: Context) {
|
|||
spinnerSubjects = dialog.getCustomView().findViewById(R.id.spinner_Lessons)
|
||||
|
||||
// fix not working accent color
|
||||
dialog.getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
|
||||
dialog.getActionButton(WhichButton.NEGATIVE).updateTextColor(Preferences.colorAccent)
|
||||
dialog.getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.cColorAccent)
|
||||
dialog.getActionButton(WhichButton.NEGATIVE).updateTextColor(Preferences.cColorAccent)
|
||||
|
||||
initSpinners()
|
||||
}
|
||||
|
@ -92,11 +92,6 @@ class AddSubjectDialog(val context: Context) {
|
|||
this.show()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun dismiss() {
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
private fun initSpinners() {
|
||||
setArrayAdapter(spinnerCourses, courseNamesList)
|
||||
val lessonsAdapter = setArrayAdapter(spinnerSubjects, subjectsList)
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package org.mosad.seil0.projectlaogai.uicomponents.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.callbacks.onDismiss
|
||||
import com.afollestad.materialdialogs.list.listItems
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
|
||||
class CourseSelectionDialog(val context: Context) {
|
||||
|
||||
private val dialog = MaterialDialog(context)
|
||||
|
||||
var list: List<String> = listOf()
|
||||
var selectedIndex = 0
|
||||
|
||||
init {
|
||||
dialog.title(R.string.select_course)
|
||||
}
|
||||
|
||||
fun show() {
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
fun show(func: CourseSelectionDialog.() -> Unit): CourseSelectionDialog = apply {
|
||||
func()
|
||||
this.show()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun dismiss() {
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
fun onDismiss(func: CourseSelectionDialog.() -> Unit): CourseSelectionDialog = apply {
|
||||
dialog.onDismiss {
|
||||
func()
|
||||
}
|
||||
}
|
||||
|
||||
fun listItems(func: CourseSelectionDialog.() -> Unit): CourseSelectionDialog = apply {
|
||||
dialog.listItems(items = list) { _, index, _ ->
|
||||
selectedIndex = index
|
||||
|
||||
func()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package org.mosad.seil0.projectlaogai.uicomponents.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.customview.customView
|
||||
import org.mosad.seil0.projectlaogai.R
|
||||
|
||||
class LoadingDialog(val context: Context) {
|
||||
|
||||
private val dialog = MaterialDialog(context)
|
||||
|
||||
init {
|
||||
dialog.cancelable(false)
|
||||
.cancelOnTouchOutside(false)
|
||||
.customView(R.layout.dialog_loading)
|
||||
}
|
||||
|
||||
fun show() {
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
fun show(func: LoadingDialog.() -> Unit): LoadingDialog = apply {
|
||||
func()
|
||||
this.show()
|
||||
}
|
||||
|
||||
fun dismiss() {
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
|
@ -56,8 +56,8 @@ class LoginDialog(val context: Context) {
|
|||
editTextPassword = dialog.getCustomView().findViewById(R.id.editText_password)
|
||||
|
||||
// fix not working accent color
|
||||
dialog.getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent)
|
||||
dialog.getActionButton(WhichButton.NEGATIVE).updateTextColor(Preferences.colorAccent)
|
||||
dialog.getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.cColorAccent)
|
||||
dialog.getActionButton(WhichButton.NEGATIVE).updateTextColor(Preferences.cColorAccent)
|
||||
}
|
||||
|
||||
fun positiveButton(func: LoginDialog.() -> Unit): LoginDialog = apply {
|
||||
|
@ -75,22 +75,13 @@ class LoginDialog(val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
fun show() {
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
fun show(func: LoginDialog.() -> Unit): LoginDialog = apply {
|
||||
func()
|
||||
|
||||
editTextEmail.setText(email)
|
||||
editTextPassword.setText(password)
|
||||
|
||||
show()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun dismiss() {
|
||||
dialog.dismiss()
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package org.mosad.seil0.projectlaogai.util
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
|
||||
class NotificationUtils(val context: Context) {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID_GRADES = "channel_grades"
|
||||
|
||||
val id = AtomicInteger(0)
|
||||
|
||||
fun getId() = id.incrementAndGet()
|
||||
}
|
||||
|
||||
init {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createNotificationChannel(CHANNEL_ID_GRADES, "Grades Channel", "A Channel")
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(26)
|
||||
private fun createNotificationChannel(channelId: String, name: String, desc: String) {
|
||||
val mChannel = NotificationChannel(channelId, name, NotificationManager.IMPORTANCE_DEFAULT)
|
||||
mChannel.description = desc
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(mChannel)
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,6 @@
|
|||
tools:openDrawer="start">
|
||||
|
||||
<include
|
||||
android:id="@+id/app_bar"
|
||||
layout="@layout/app_bar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
@ -23,6 +22,7 @@
|
|||
android:fitsSystemWindows="true"
|
||||
android:background="?themeSecondary"
|
||||
app:headerLayout="@layout/nav_header_main"
|
||||
app:itemTextColor="?colorAccent"
|
||||
app:menu="@menu/activity_main_drawer"/>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
|
|
@ -3,25 +3,19 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="?themeSecondary"
|
||||
app:cardUseCompatPadding="true"
|
||||
app:cardElevation="5dp"
|
||||
app:cardUseCompatPadding="true">
|
||||
app:cardBackgroundColor="?themeSecondary"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linear_day"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
android:layout_height="match_parent" android:id="@+id/linLayout_Day">
|
||||
<TextView
|
||||
android:id="@+id/text_day_heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sample_date"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?colorAccent"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" android:id="@+id/txtView_DayHeading" android:textSize="18sp"
|
||||
android:textAlignment="center" android:textStyle="bold" android:textColor="?colorAccent"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/linLayout_grade"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="7dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingRight="7dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linLayout_subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtView_subject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="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="@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_grade"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:background="?dividerColor" />
|
||||
</LinearLayout>
|
|
@ -15,30 +15,30 @@
|
|||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_lesson_subject"
|
||||
android:id="@+id/txtView_lessonSubject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_lesson_time"
|
||||
android:id="@+id/txtView_lessonTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end"
|
||||
android:text="@string/a_time"
|
||||
android:textColor="?textSecondary" />
|
||||
android:textColor="@color/textSecondaryLight" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_lesson_teacher"
|
||||
android:id="@+id/txtView_lessonTeacher"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_lesson_room"
|
||||
android:id="@+id/txtView_lessonRoom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/lienar_meal"
|
||||
android:id="@+id/linLayout_Meal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
|
@ -10,7 +10,7 @@
|
|||
android:paddingBottom="2dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_meal_heading"
|
||||
android:id="@+id/txtView_MealHeading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
|
@ -20,7 +20,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_meal"
|
||||
android:id="@+id/txtView_Meal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
android:shortcutLongLabel="@string/shortcut_timetable_long"
|
||||
android:shortcutDisabledMessage="@string/shortcut_timetable_disabled">
|
||||
<intent
|
||||
android:action="org.mosad.seil0.projectlaogai.fragments.TimetableFragment"
|
||||
android:action="org.mosad.seil0.projectlaogai.fragments.TimeTableFragment"
|
||||
android:targetPackage="org.mosad.seil0.projectlaogai"
|
||||
android:targetClass="org.mosad.seil0.projectlaogai.MainActivity" />
|
||||
<categories android:name="android.shortcut.conversation" />
|
||||
|
@ -40,18 +40,4 @@
|
|||
android:targetClass="org.mosad.seil0.projectlaogai.MainActivity" />
|
||||
<categories android:name="android.shortcut.conversation" />
|
||||
</shortcut>
|
||||
|
||||
<shortcut
|
||||
android:shortcutId="grades"
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_grading_black_24dp"
|
||||
android:shortcutShortLabel="@string/shortcut_grades_short"
|
||||
android:shortcutLongLabel="@string/shortcut_grades_long"
|
||||
android:shortcutDisabledMessage="@string/shortcut_grades_disabled">
|
||||
<intent
|
||||
android:action="org.mosad.seil0.projectlaogai.fragments.GradesFragment"
|
||||
android:targetPackage="org.mosad.seil0.projectlaogai"
|
||||
android:targetClass="org.mosad.seil0.projectlaogai.MainActivity" />
|
||||
<categories android:name="android.shortcut.conversation" />
|
||||
</shortcut>
|
||||
</shortcuts>
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".fragments.GradesFragment">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/refreshLayout_Grades"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?themePrimary">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView_Grades"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linLayout_Grades"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtView_Loading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="100dp"
|
||||
android:padding="7dp"
|
||||
android:text="@string/loading_from_hs"
|
||||
android:textAlignment="center"
|
||||
android:textSize="15sp" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -18,8 +18,7 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="11dp">
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardView_Info"
|
||||
|
@ -36,7 +35,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_info"
|
||||
android:id="@+id/txtView_Info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="7dp"
|
||||
|
@ -51,12 +50,11 @@
|
|||
android:id="@+id/linLayout_User"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="7dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_user"
|
||||
android:id="@+id/txtView_User"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sample_user"
|
||||
|
@ -64,7 +62,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_user_desc"
|
||||
android:id="@+id/txtView_UserDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/user_desc" />
|
||||
|
@ -80,12 +78,11 @@
|
|||
android:id="@+id/linLayout_Course"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="7dp">
|
||||
android:layout_margin="7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_course"
|
||||
android:id="@+id/txtView_Course"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sample_course"
|
||||
|
@ -93,7 +90,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_course_desc"
|
||||
android:id="@+id/txtView_CourseDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/course_desc" />
|
||||
|
@ -109,12 +106,11 @@
|
|||
android:id="@+id/linLayout_ManageLessons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="7dp">
|
||||
android:layout_margin="7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_manage_lessons"
|
||||
android:id="@+id/txtView_ManageLessons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/manage_lessons"
|
||||
|
@ -138,12 +134,11 @@
|
|||
android:id="@+id/linLayout_About"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="7dp">
|
||||
android:layout_margin="7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_about"
|
||||
android:id="@+id/txtView_About"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/about_txtView"
|
||||
|
@ -151,7 +146,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_about_desc"
|
||||
android:id="@+id/txtView_AboutDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/about_version" />
|
||||
|
@ -167,9 +162,8 @@
|
|||
android:id="@+id/linLayout_Licence"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="7dp">
|
||||
android:layout_margin="7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView3"
|
||||
|
@ -197,7 +191,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_settings"
|
||||
android:id="@+id/txtView_Settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="7dp"
|
||||
|
@ -212,12 +206,11 @@
|
|||
android:id="@+id/linLayout_Theme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="7dp">
|
||||
android:layout_margin="7dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_theme"
|
||||
android:id="@+id/txtView_Theme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/theme"
|
||||
|
@ -225,7 +218,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_theme_selected"
|
||||
android:id="@+id/txtView_SelectedTheme"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/themeLight" />
|
||||
|
@ -241,12 +234,11 @@
|
|||
android:id="@+id/linLayout_PrimaryColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:layout_margin="7dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center_vertical|end"
|
||||
android:orientation="horizontal"
|
||||
android:padding="7dp">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -254,7 +246,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_primary_color"
|
||||
android:id="@+id/txtView_PrimaryColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/primary_color"
|
||||
|
@ -262,7 +254,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_primary_color_desc"
|
||||
android:id="@+id/txtView_PrimaryColorDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/primary_color_desc" />
|
||||
|
@ -276,7 +268,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/view_primary_color"
|
||||
android:id="@+id/view_PrimaryColor"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="?colorPrimary" />
|
||||
|
@ -293,12 +285,11 @@
|
|||
android:id="@+id/linLayout_AccentColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:layout_margin="7dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center_vertical|end"
|
||||
android:orientation="horizontal"
|
||||
android:padding="7dp">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -306,7 +297,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_accent_color"
|
||||
android:id="@+id/txtView_AccentColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/accent_color"
|
||||
|
@ -314,7 +305,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_accent_color_desc"
|
||||
android:id="@+id/txtView_AccentColorDesc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/accent_color_desc" />
|
||||
|
@ -328,7 +319,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/view_accent_color"
|
||||
android:id="@+id/view_AccentColor"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="?colorAccent" />
|
||||
|
@ -345,11 +336,10 @@
|
|||
android:id="@+id/switch_buffet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="7dp"
|
||||
android:layout_margin="7dp"
|
||||
android:text="@string/show_buffet"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".fragments.TimetableFragment"
|
||||
tools:context=".fragments.TimeTableFragment"
|
||||
android:background="?themePrimary">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
android:id="@+id/nav_moodle"
|
||||
android:icon="@drawable/ic_school_black_24dp"
|
||||
android:title="@string/moodle"/>
|
||||
<item
|
||||
android:id="@+id/nav_grades"
|
||||
android:icon="@drawable/ic_grading_black_24dp"
|
||||
android:title="@string/grades" />
|
||||
<item
|
||||
android:id="@+id/nav_settings"
|
||||
android:icon="@drawable/ic_settings_black_24dp"
|
||||
|
|
|
@ -66,9 +66,6 @@
|
|||
<string name="primary_color_desc">Zum Ändern tippen, Standard ist Blaugrün.</string>
|
||||
<string name="accent_color">Akzentfarbe</string>
|
||||
<string name="accent_color_desc">Zum Ändern tippen, Standard ist Hellblau.</string>
|
||||
<string name="grades_sync">Aktualisierungsintervall Noten</string>
|
||||
<string name="grades_sync_desc">%1$d Stunden</string>
|
||||
<string name="grades_sync_desc_never">nie</string>
|
||||
<string name="show_buffet">Buffet immer anzeigen</string>
|
||||
|
||||
<!-- dialogs -->
|
||||
|
@ -83,12 +80,6 @@
|
|||
<string name="mensa_current">aktuell: %1$s\n</string>
|
||||
<string name="mensa_last">letzte Abbuchung: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<string name="notification_grades">Noten</string>
|
||||
<string name="notification_grades_single_desc">%1$s wurden hinzugefügt oder aktualisiert</string>
|
||||
<string name="notification_grades_multiple_desc">%1$s und %2$d weiter Vorlesungen wurden hinzugefügt oder aktualisiert</string>
|
||||
<string name="notification_grades_updating_desc">Suche nach neuen Noten …</string>
|
||||
|
||||
<!-- errors -->
|
||||
<string name="error">Fehler</string>
|
||||
<string name="timetable_error">Der Stundenplan konnte nicht geladen werden.</string>
|
||||
|
@ -106,16 +97,4 @@
|
|||
<string name="shortcut_moodle_long">Moodle</string>
|
||||
<string name="shortcut_moodle_disabled">Moodle deaktiviert</string>
|
||||
|
||||
<string name="shortcut_grades_short">Noten</string>
|
||||
<string name="shortcut_grades_long">Noten</string>
|
||||
<string name="shortcut_grades_disabled">Noten deaktiviert</string>
|
||||
|
||||
<string-array name="syncInterval">
|
||||
<item>Manuell</item>
|
||||
<item>1 Stunde</item>
|
||||
<item>3 Stunden</item>
|
||||
<item>6 Stunden</item>
|
||||
<item>12 Stunden</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,28 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- base theme colors -->
|
||||
<color name="colorPrimary">#009688</color>
|
||||
<color name="colorPrimaryDark">#009688</color>
|
||||
<color name="colorAccent">#0096ff</color>
|
||||
<color name="ic_laogai_icon_background">#ffffff</color>
|
||||
|
||||
<!-- light theme colors -->
|
||||
<!--theme color section, not the working colors-->
|
||||
<color name="themePrimaryDark">#000000</color>
|
||||
<color name="themeSecondaryDark">#303030</color>
|
||||
<color name="textPrimaryDark">#ffffff</color>
|
||||
<color name="textSecondaryDark">#c0c0c0</color>
|
||||
<color name="dividerDark">#232323</color>
|
||||
|
||||
<color name="themePrimaryLight">#f5f5f5</color>
|
||||
<color name="themeSecondaryLight">#ffffff</color>
|
||||
<color name="textPrimaryLight">#de000000</color>
|
||||
<color name="textSecondaryLight">#99000000</color>
|
||||
<color name="dividerLight">#22000000</color>
|
||||
<color name="textPrimaryLight">#000000</color>
|
||||
<color name="textSecondaryLight">#818181</color>
|
||||
<color name="dividerLight">#e0e0e0</color>
|
||||
|
||||
<!-- dark theme colors -->
|
||||
<color name="themePrimaryDark">#121212</color>
|
||||
<color name="themeSecondaryDark">#202020</color>
|
||||
<color name="textPrimaryDark">#deffffff</color>
|
||||
<color name="textSecondaryDark">#99ffffff</color>
|
||||
<color name="dividerDark">#22ffffff</color>
|
||||
<color name="controlHighlightDark">#11ffffff</color>
|
||||
|
||||
<!-- black theme colors -->
|
||||
<color name="themePrimaryBlack">#000000</color>
|
||||
<color name="themeSecondaryBlack">#303030</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -71,9 +71,6 @@
|
|||
<string name="primary_color_desc">Tap to change, default is teal blue.</string>
|
||||
<string name="accent_color">Accent color</string>
|
||||
<string name="accent_color_desc">Tap to change, default is light blue.</string>
|
||||
<string name="grades_sync">Update interval grades</string>
|
||||
<string name="grades_sync_desc">%1$d hours</string>
|
||||
<string name="grades_sync_desc_never">never</string>
|
||||
<string name="show_buffet">Always show buffet</string>
|
||||
|
||||
<!-- dialogs -->
|
||||
|
@ -88,12 +85,6 @@
|
|||
<string name="mensa_current">current: %1$s\n</string>
|
||||
<string name="mensa_last">last: %1$s</string>
|
||||
|
||||
<!-- notifications -->
|
||||
<string name="notification_grades">Grades</string>
|
||||
<string name="notification_grades_single_desc">%1$s was added or updated</string>
|
||||
<string name="notification_grades_multiple_desc">%1$s and %2$d other subjects have been added or updated</string>
|
||||
<string name="notification_grades_updating_desc">Checking for new grades …</string>
|
||||
|
||||
<!-- sample strings -->
|
||||
<string name="sample_user" translatable="false">spinefield@stud.hs-offenburg.de</string>
|
||||
<string name="sample_course" translatable="false">Everything</string>
|
||||
|
@ -121,10 +112,6 @@
|
|||
<string name="shortcut_moodle_long">Moodle</string>
|
||||
<string name="shortcut_moodle_disabled">Moodle disabled</string>
|
||||
|
||||
<string name="shortcut_grades_short">Grades</string>
|
||||
<string name="shortcut_grades_long">Grades</string>
|
||||
<string name="shortcut_grades_disabled">Grades disabled</string>
|
||||
|
||||
<!-- save keys -->
|
||||
<string name="preference_file_key" translatable="false">org.mosad.seil0.projectlaogai_preferences</string>
|
||||
<string name="encrypted_preference_file_key" translatable="false">org.mosad.seil0.projectlaogai_encrypted_preferences</string>
|
||||
|
@ -132,28 +119,13 @@
|
|||
<string name="save_key_courseTTLink" translatable="false">org.mosad.seil0.projectlaogai.courseTTLink</string>
|
||||
<string name="save_key_colorPrimary" translatable="false">org.mosad.seil0.projectlaogai.colorPrimary</string>
|
||||
<string name="save_key_colorAccent" translatable="false">org.mosad.seil0.projectlaogai.colorAccent</string>
|
||||
<string name="save_key_gradesSyncInterval" translatable="false">org.mosad.seil0.projectlaogai.gradesSyncInterval</string>
|
||||
<string name="save_key_showBuffet" translatable="false">org.mosad.seil0.projectlaogai.showBuffet</string>
|
||||
<string name="save_key_coursesCacheTime" translatable="false">org.mosad.seil0.projectlaogai.coursesCacheTime</string>
|
||||
<string name="save_key_mensaCacheTime" translatable="false">org.mosad.seil0.projectlaogai.mensaCacheTime</string>
|
||||
<string name="save_key_timetableCacheTime" translatable="false">org.mosad.seil0.projectlaogai.timetableCacheTime</string>
|
||||
<string name="save_key_gradesCacheTime" translatable="false">org.mosad.seil0.projectlaogai.gradesCacheTime</string>
|
||||
<string name="save_key_user_email" translatable="false">org.mosad.seil0.projectlaogai.user_email</string>
|
||||
<string name="save_key_user_password" translatable="false">org.mosad.seil0.projectlaogai.user_password</string>
|
||||
|
||||
<!-- intent actions -->
|
||||
<string name="intent_action_mensaFragment" translatable="false">org.mosad.seil0.projectlaogai.fragments.MensaFragment</string>
|
||||
<string name="intent_action_timetableFragment" translatable="false">org.mosad.seil0.projectlaogai.fragments.TimetableFragment</string>
|
||||
<string name="intent_action_moodleFragment" translatable="false">org.mosad.seil0.projectlaogai.fragments.MoodleFragment</string>
|
||||
<string name="intent_action_gradesFragment" translatable="false">org.mosad.seil0.projectlaogai.fragments.GradesFragment</string>
|
||||
|
||||
<string-array name="syncInterval">
|
||||
<item>Manually</item>
|
||||
<item>1 Hour</item>
|
||||
<item>3 Hours</item>
|
||||
<item>6 Hours</item>
|
||||
<item>12 Hours</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="courses">
|
||||
<item>AI-1</item>
|
||||
|
|
|
@ -12,13 +12,14 @@
|
|||
<item name="themeName">light</item>
|
||||
<item name="themePrimary">@color/themePrimaryLight</item>
|
||||
<item name="themeSecondary">@color/themeSecondaryLight</item>
|
||||
<item name="textPrimary">@color/textPrimaryLight</item>
|
||||
<item name="textSecondary">@color/textSecondaryLight</item>
|
||||
<item name="android:textColor">@color/textPrimaryLight</item>
|
||||
<item name="android:textColorPrimary">@color/textPrimaryLight</item>
|
||||
<item name="android:textColorHint">@color/textSecondaryLight</item>
|
||||
<item name="textPrimary">@color/textPrimaryLight</item>
|
||||
<item name="textSecondary">@color/textSecondaryLight</item>
|
||||
<item name="dividerColor">@color/dividerLight</item>
|
||||
<item name="md_background_color">@color/themeSecondaryLight</item>
|
||||
<item name="md_color_title">@color/textPrimaryLight</item>
|
||||
<item name="md_color_content">@color/textPrimaryLight</item>
|
||||
</style>
|
||||
|
||||
|
@ -26,23 +27,30 @@
|
|||
<item name="themeName">dark</item>
|
||||
<item name="themePrimary">@color/themePrimaryDark</item>
|
||||
<item name="themeSecondary">@color/themeSecondaryDark</item>
|
||||
<item name="textPrimary">@color/textPrimaryDark</item>
|
||||
<item name="textSecondary">@color/textSecondaryDark</item>
|
||||
<item name="android:textColor">@color/textPrimaryDark</item>
|
||||
<item name="android:textColorPrimary">@color/textPrimaryDark</item>
|
||||
<item name="android:textColorHint">@color/textSecondaryDark</item>
|
||||
<item name="textPrimary">@color/textPrimaryDark</item>
|
||||
<item name="textSecondary">@color/textSecondaryDark</item>
|
||||
<item name="dividerColor">@color/dividerDark</item>
|
||||
<item name="md_background_color">@color/themeSecondaryDark</item>
|
||||
<item name="md_color_title">@color/textPrimaryDark</item>
|
||||
<item name="md_color_content">@color/textPrimaryDark</item>
|
||||
|
||||
<!-- change on click indicator color for manually set components -->
|
||||
<item name="colorControlHighlight">@color/controlHighlightDark</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Black" parent="AppTheme.Dark">
|
||||
<style name="AppTheme.Black" parent="AppTheme">
|
||||
<item name="themeName">black</item>
|
||||
<item name="themePrimary">@color/themePrimaryBlack</item>
|
||||
<item name="themeSecondary">@color/themePrimaryBlack</item>
|
||||
<item name="themePrimary">@color/themePrimaryDark</item>
|
||||
<item name="themeSecondary">@color/themePrimaryDark</item>
|
||||
<item name="android:textColor">@color/textPrimaryDark</item>
|
||||
<item name="android:textColorPrimary">@color/textPrimaryDark</item>
|
||||
<item name="android:textColorHint">@color/textSecondaryDark</item>
|
||||
<item name="textPrimary">@color/textPrimaryDark</item>
|
||||
<item name="textSecondary">@color/textSecondaryDark</item>
|
||||
<item name="dividerColor">@color/dividerDark</item>
|
||||
<item name="md_background_color">@color/themeSecondaryDark</item>
|
||||
<item name="md_color_title">@color/textPrimaryDark</item>
|
||||
<item name="md_color_content">@color/textPrimaryDark</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package org.mosad.seil0.projectlaogai
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"WiSe 17/18":[
|
||||
{"credits":"4,0","grade":"1,0","id":"AI-1020","name":"Grundlagen der Elektronik","semester":"WiSe 17/18"},
|
||||
{"credits":"2,0","grade":"2,3","id":"AI-1040","name":"Prozedurale Programmierung","semester":"WiSe 17/18"}
|
||||
],
|
||||
"SoSe 18":[
|
||||
{"credits":"4,0","grade":"1,7","id":"AI-2010","name":"Technische Informatik","semester":"SoSe 18"},
|
||||
{"credits":"1,0","grade":"bestanden","id":"AI-2015","name":"Praktikum Technische Informatik","semester":"SoSe 18"}
|
||||
],
|
||||
"WiSe 18/19":[
|
||||
{"credits":"2,0","grade":"2,7","id":"AI-3010","name":"Computernetze","semester":"WiSe 18/19"},
|
||||
{"credits":"3,0","grade":"bestanden","id":"AI-3015","name":"Praktikum Computernetze","semester":"WiSe 18/19"}
|
||||
],
|
||||
"SoSe 19":[
|
||||
{"credits":"4,0","grade":"1,7","id":"AI-2010","name":"Mathemaik 7","semester":"SoSe 19"},
|
||||
{"credits":"1,0","grade":"bestanden","id":"AI-2015","name":"Praktikum Mathemaik 7","semester":"SoSe 19"}
|
||||
]
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"WiSe 17/18":[
|
||||
{"credits":"4,0","grade":"1,0","id":"AI-1020","name":"Grundlagen der Elektronik","semester":"WiSe 17/18"},
|
||||
{"credits":"2,0","grade":"2,3","id":"AI-1040","name":"Prozedurale Programmierung","semester":"WiSe 17/18"}
|
||||
],
|
||||
"SoSe 18":[
|
||||
{"credits":"4,0","grade":"1,7","id":"AI-2010","name":"Technische Informatik","semester":"SoSe 18"},
|
||||
{"credits":"1,0","grade":"bestanden","id":"AI-2015","name":"Praktikum Technische Informatik","semester":"SoSe 18"}
|
||||
],
|
||||
"WiSe 18/19":[
|
||||
{"credits":"2,0","grade":"0,7","id":"AI-3010","name":"Computernetze","semester":"WiSe 18/19"},
|
||||
{"credits":"3,0","grade":"bestanden","id":"AI-3015","name":"Praktikum Computernetze","semester":"WiSe 18/19"},
|
||||
{"credits":"2,0","grade":"1,7","id":"AI-3020","name":"Datenbanksysteme 1","semester":"WiSe 18/19"},
|
||||
{"credits":"3,0","grade":"bestanden","id":"AI-3025","name":"Praktikum Datenbanksysteme","semester":"WiSe 18/19"}
|
||||
]
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"WiSe 17/18":[
|
||||
{"credits":"4,0","grade":"1,0","id":"AI-1020","name":"Grundlagen der Elektronik","semester":"WiSe 17/18"},
|
||||
{"credits":"2,0","grade":"2,3","id":"AI-1040","name":"Prozedurale Programmierung","semester":"WiSe 17/18"}
|
||||
],
|
||||
"SoSe 18":[
|
||||
{"credits":"4,0","grade":"1,7","id":"AI-2010","name":"Technische Informatik","semester":"SoSe 18"},
|
||||
{"credits":"1,0","grade":"bestanden","id":"AI-2015","name":"Praktikum Technische Informatik","semester":"SoSe 18"}
|
||||
],
|
||||
"WiSe 18/19":[
|
||||
{"credits":"2,0","grade":"2,7","id":"AI-3010","name":"Computernetze","semester":"WiSe 18/19"},
|
||||
{"credits":"3,0","grade":"bestanden","id":"AI-3015","name":"Praktikum Computernetze","semester":"WiSe 18/19"}
|
||||
]
|
||||
}
|
10
build.gradle
10
build.gradle
|
@ -1,13 +1,13 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.9.22'
|
||||
ext.kotlin_version = '1.4.0'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.2.2'
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
@ -18,10 +18,10 @@ buildscript {
|
|||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('clean', Delete) {
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
Version 0.6.1 "anthropomorphised Athena"
|
||||
|
||||
* Grades can be synced in the background
|
||||
* Grades will be cached for offline use or if qispos is not reachable
|
||||
* The message "Menu empty" is no longer displayed if there is a menu in the next week
|
|
@ -15,6 +15,3 @@ org.gradle.jvmargs=-Xmx1536m
|
|||
kotlin.code.style=official
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
|
|
Binary file not shown.
|
@ -1,7 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -17,98 +17,67 @@
|
|||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
@ -118,9 +87,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
@ -129,120 +98,88 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
|
@ -26,7 +26,6 @@ if "%OS%"=="Windows_NT" setlocal
|
|||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
@ -41,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
@ -55,7 +54,7 @@ goto fail
|
|||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
|
@ -65,6 +64,21 @@ echo location of your Java installation.
|
|||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
|
@ -72,19 +86,17 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
|
Loading…
Reference in New Issue