made 0.8 release, cosmetic fixes, added scrollviews into mark fragments for accessibility (people w/ small phones)

This commit is contained in:
Odweta
2024-02-16 18:06:06 +01:00
parent 6817dd29b6
commit d789665d4b
29 changed files with 288 additions and 273 deletions
+1 -4
View File
@@ -1,6 +1,3 @@
*.pyc
*.swp
TODO.md
mobile/app/release/
pc_linux/
+5 -43
View File
@@ -2,57 +2,19 @@
An enhanced version of the ŠkolaOnLine (ŠOL) online school system.
Named after the Greek philosophist.
It aims to provide more readable data than the web version and remove some of the annoyances of the mobile app. This project has two version, the main one is the Android app but secondly there is also a linux version written in Python, although it is kind of outdated. At the moment, development is mainly focused on the Android app.
Insiration was taken from [@JakubAndrysek](https://github.com/JakubAndrysek)'s [skola-online-stahovani-znamek](https://github.com/JakubAndrysek/skola-online-stahovani-znamek) project.
# Android app
The latest release is availible on [this](https://gitlab.com/Odweta/solon/-/raw/main/release/solon-v0.7.apk?ref_type=heads&inline=false) link. View all relases [here](https://gitlab.com/Odweta/solon/-/releases).
View your timetable and marks in a pleasing format. No extra bloat.
Everything is colorful, animated and pretty, so your eyes should be pleased.
It aims to provide more readable data than the web version and remove some of the annoyances of the mobile app.
# PC Linux Python version
Named after the Greek philosopher.
This version of the project is not very relevant anymore, so its development is suspended (I won't work on it in the forseeable future). **Check out the Android app instead!**
Insiration was taken from [@JakubAndrysek](https://github.com/JakubAndrysek)'s [skola-online-stahovani-znamek](https://github.com/JakubAndrysek/skola-online-stahovani-znamek) project.
## Features
+ Shows the schedule for the current week
+ Shows all grades and their weighted average
+ Works offline (if the internet has been accessed at least once before)
<hr>
## Installation
The latest release is availible on [this](https://gitlab.com/Odweta/solon/-/raw/main/release/solon.apk?ref_type=heads&inline=false) link. View all relases [here](https://gitlab.com/Odweta/solon/-/releases).
**Clone the repo**
`git clone https://gitlab.com/Odweta/solon`
**Navigate into the repo directory**
`cd solon/pc_linux`
**Install**
`sudo make install`
**Run the program**
`solon`
## Usage
Upon startup, the user is prompted to enter their ŠkolaOnLine credentials. If the login proccess is successful, the preconfigured functions in `/bin/solon` will execute. By default, the functions are: showing the schedule for this week, showing the schedule for today and tomorrow and showing the grades. You can edit that file if you want to change what is being displayed. Alternatively, you can edit the `src/main.py` and then do the install step (`sudo make install`). There are optional command-line arguments for filtering what should be displayed. Here they are:
| Optional argument | Description |
| ----------------------------------- | --------------------------------------------------------------------------------------- |
| -t, --today-tomorrow | show the schedule for today and tomorrow |
| -w, --week | show the schedule for this week |
| -g, --grades | show the grades |
| -u, --username | provide the username for login |
| -p, --password | provide the password for login |
| -l, --local | only show the local data without attempting to connect to the internet |
| -d, --delete-local-files | deletes all locally stored user data, including schedules, grades and login credentials |
| -b, --backup | backs up all local user data into a .tar.gz archive |
| -R, --backup-restore PATH | restores a backup previously made with SOLEn |
+14 -1
View File
@@ -3,7 +3,20 @@
<component name="deploymentTargetDropDown">
<value>
<entry key="Run">
<State />
<State>
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_3a_API_34_extension_level_7_x86_64.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-02-16T14:53:01.463073218Z" />
</State>
</entry>
</value>
</component>
+1 -7
View File
@@ -12,9 +12,7 @@ android {
minSdk = 28
targetSdk = 34
versionCode = 1
versionName = "0.7"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
versionName = "0.8"
}
buildTypes {
@@ -36,7 +34,6 @@ android {
}
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
@@ -51,7 +48,4 @@ dependencies {
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.google.android.material:material:1.11.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
testImplementation("junit:junit:4.13.2")
}
+20
View File
@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.odweta.solon",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "0.7",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}
+2 -2
View File
@@ -14,14 +14,14 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Solen"
android:theme="@style/Theme.Solon"
tools:targetApi="tiramisu"
android:usesCleartextTraffic="true"
android:enableOnBackInvokedCallback="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.Solen"
android:theme="@style/Theme.Solon"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -29,7 +29,7 @@ class AboutFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.Theme_Solen)
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
}
override fun onCreateView(
@@ -52,7 +52,7 @@ class AboutFragment : DialogFragment() {
underlinedText.setSpan(UnderlineSpan(), 1, link.text.length, 0)
link.text = underlinedText
makeTextViewClickable(link, "https://gitlab.com/Odweta", 1)
makeTextViewClickable(link, "https://gitlab.com/Odweta", 0)
val srcLink = view.findViewById<TextView>(R.id.sourceCode)
@@ -67,7 +67,7 @@ class AboutFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solen_DialogAnimation
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
@@ -7,7 +7,6 @@ import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -28,6 +27,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import java.time.LocalDate
import java.time.LocalTime
import kotlin.math.floor
class CalWeekFragment : Fragment() {
override fun onCreateView(
@@ -237,7 +237,7 @@ class DayFragment(private val i: Int) : Fragment() {
val customFont = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
val scrollView = ScrollView(requireContext())
scrollView.scrollBarStyle = R.style.Theme_Solen_Scrollbar
scrollView.scrollBarStyle = R.style.Theme_Solon_Scrollbar
val dayLayout = LinearLayout(requireContext())
dayLayout.orientation = LinearLayout.VERTICAL
@@ -391,7 +391,7 @@ class DayFragment(private val i: Int) : Fragment() {
val subjectPlaceTextView = TextView(requireContext())
subjectPlaceTextView.typeface = customFont
subjectPlaceTextView.text = subj.place
subjectPlaceTextView.text = subj.place.replace("-", "")
if (subj.free) {
// underline
subjectPlaceTextView.setTypeface(customFont, Typeface.ITALIC)
@@ -429,7 +429,7 @@ class DayFragment(private val i: Int) : Fragment() {
timeTeacherLayout.gravity = Gravity.CENTER_VERTICAL
val subjectTimeTextView = TextView(requireContext())
val subjectTimeString = subj.start + " - " + subj.end
val subjectTimeString = subj.start + "" + subj.end
subjectTimeTextView.typeface = customFont
subjectTimeTextView.text = subjectTimeString
subjectTimeTextView.textSize = 20f
@@ -446,7 +446,7 @@ class DayFragment(private val i: Int) : Fragment() {
subjectTeacherTextView.text = subj.teacher
subjectTeacherTextView.typeface = customFont
subjectTeacherTextView.textSize = 12f
subjectTeacherTextView.setPadding(10, 0, 20, 10)
subjectTeacherTextView.setPadding(0, 0, 20, 10)
subjectTeacherTextView.textAlignment = View.TEXT_ALIGNMENT_TEXT_END
subjectTeacherTextView.setTextColor(
ContextCompat.getColor(
@@ -457,7 +457,7 @@ class DayFragment(private val i: Int) : Fragment() {
timeTeacherLayout.addView(subjectTimeTextView)
if (subj.name != "Volno") {
subjectTimeTextView.setPadding(10, 10, 20, 0)
subjectTimeTextView.setPadding(0, 10, 20, 0)
timeTeacherLayout.addView(subjectTeacherTextView)
}
timeTeacherLayout.setPadding(0, 0, 10, 0)
@@ -518,7 +518,12 @@ class DayFragment(private val i: Int) : Fragment() {
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
subjectLayoutParams.setMargins(20, 0, 20, 0)
subjectLayoutParams.setMargins(
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
0,
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
0
)
subjectLayout.layoutParams = subjectLayoutParams
if (prevSubj.name != subj.name && i != 0) {
@@ -534,7 +539,7 @@ class DayFragment(private val i: Int) : Fragment() {
subjectSeparator.setImageResource(R.drawable.squiggly_line_100_yellow_transparent_one_color_edge)
subjectSeparator.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
Util.pixelsToDp(20, resources)
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)
)
dayLayout.addView(subjectSeparator)
@@ -602,7 +607,12 @@ class DayFragment(private val i: Int) : Fragment() {
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
endParams.setMargins(20, 0, 20, 0)
endParams.setMargins(
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
0,
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/4,
0
)
dayEndTextView.layoutParams = endParams
if (day.subjects[0].substitute != "2") {
@@ -15,6 +15,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.Space
import android.widget.TableLayout
import android.widget.TableRow
@@ -31,13 +32,15 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
private lateinit var gestureDetector: GestureDetector
private var initialTouchY: Float = 0f
private val swipeThreshold = 100
private val swipeVelocityThreshold = 100
private lateinit var rootLayout: LinearLayout
private lateinit var scrollView: ScrollView
private var isScrollingToDismissEnabled = false
private var isScrollingToTop = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// set the style so the dialog is fullscreen
setStyle(STYLE_NORMAL, R.style.Theme_Solen)
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
}
override fun onCreateView(
@@ -64,10 +67,25 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
return view
}
@SuppressLint("ClickableViewAccessibility")
private fun gestures(view: View) {
// Set up GestureDetector
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
scrollView = view.findViewById(R.id.mark_detail_scroll)
scrollView.scrollY = 0
scrollView.setOnTouchListener { _, event ->
scrollView.performClick()
gestureDetector.onTouchEvent(event)
// Return false to allow normal scrolling
false
}
scrollView.viewTreeObserver.addOnScrollChangedListener {
isScrollingToTop = !scrollView.canScrollVertically(-1)
}
// Attach the gesture detector to the root layout
view.setOnTouchListener { _, event ->
view.performClick()
@@ -75,7 +93,32 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
}
}
// TODO: MAKE CONSTRUCT()
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
// Reset the flag when the user touches the screen
isScrollingToDismissEnabled = false
return true
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val diffY = e1?.let { e2.y - it.y } ?: 0f
if (diffY > swipeThreshold) {
// Swiped down
if (isScrollingToTop) {
// Enable dismissing only if scrolled to top
isScrollingToDismissEnabled = true
dismiss()
}
}
return false
}
}
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
private fun construct() {
/* show all the marks in separate views with yet another onclick listener for even more
@@ -88,33 +131,6 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
// FL == FrameLayout
// SV == ScrollView
/*val bgColor = if (!marks.contains(Mark().none())) {
Util.getAvgBgColor(requireContext(), Util.avg(marks))
} else {
ContextCompat.getColor(
requireContext(),
R.color.pastel_orange
)
}
val bgStroke = if (!marks.contains(Mark().none())) {
Util.getAvgStrokeColor(requireContext(), Util.avg(marks))
} else {
ContextCompat.getColor(
requireContext(),
R.color.pastel_orange
)
}
val bg = GradientDrawable()
bg.setColor(bgColor)
bg.setStroke(10, bgStroke)
bg.cornerRadius = resources.getDimension(R.dimen.corner_radius)*/
/* subject: <subject>
* desc: <desc>
* date: <date>
* weight: <weight>
*/
val font = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
val gradeTV = TextView(requireContext())
gradeTV.text = marks[idx!!].grade
@@ -123,26 +139,25 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
gradeTV.background = Util.getAvgDrawable(requireContext(), marks[idx!!].grade)
gradeTV.gravity = Gravity.CENTER
val pr = LinearLayout.LayoutParams(
300,
300
Util.getDisplayWidth(requireContext())/3,
Util.getDisplayWidth(requireContext())/3
)
pr.setMargins(0, 50, 0, 50)
pr.setMargins(0, 100, 0, 100)
gradeTV.layoutParams = pr
gradeTV.setPadding(20, 20, 20, 20)
gradeTV.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
val subjectDesc = makeTV("Předmět: ", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val subjectTV = makeTV(Vars.subjectNameMap[marks[idx!!].subject] ?: marks[idx!!].subject, Typeface.ITALIC, 22f)
val subjectDesc = makeTV("Předmět:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val subjectTV = makeTV(Vars.subjectNameMap[marks[idx!!].subject] ?: marks[idx!!].subject, Typeface.NORMAL, 22f)
val descDesc = makeTV("Popis: ", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val descTV = makeTV(marks[idx!!].theme, Typeface.ITALIC, 22f)
val descDesc = makeTV("Popis:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val descTV = makeTV(marks[idx!!].theme, Typeface.NORMAL, 22f)
val dateDesc = makeTV("Datum: ", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val dateTV = makeTV(getDate(marks[idx!!].date), Typeface.ITALIC, 22f)
val weightDesc = makeTV("Váha: ", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val weightTV = makeTV(marks[idx!!].weight, Typeface.ITALIC, 22f)
val dateDesc = makeTV("Datum:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val dateTV = makeTV(getDate(marks[idx!!].date), Typeface.NORMAL, 22f)
val weightDesc = makeTV("Váha:", Typeface.BOLD, Util.getDisplayWidth(requireContext())/3)
val weightTV = makeTV(marks[idx!!].weight, Typeface.NORMAL, 22f)
val subjectRow = makeRow(subjectDesc, subjectTV)
val descRow = makeRow(descDesc, descTV)
@@ -169,6 +184,7 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
val tv = TextView(requireContext())
tv.text = text
tv.textSize = 25f
tv.textAlignment = View.TEXT_ALIGNMENT_CENTER
tv.setPadding(40, 20, 20, 20)
tv.setTypeface(font, typeface)
tv.setTextColor(
@@ -181,9 +197,7 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
width,
LinearLayout.LayoutParams.MATCH_PARENT
)
p.setMargins(20, 60, 20, 20)
tv.layoutParams = p
tv.background = ResourcesCompat.getDrawable(resources, R.drawable.button_background, null)!!
tv.gravity = Gravity.CENTER_VERTICAL
tv.ellipsize = null
tv.setHorizontallyScrolling(false)
@@ -196,13 +210,13 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
val tv = TextView(requireContext())
tv.text = text
tv.textSize = size
tv.textAlignment = View.TEXT_ALIGNMENT_CENTER
tv.setPadding(40, 20, 20, 20)
tv.background = ResourcesCompat.getDrawable(resources, R.drawable.pastel_yellow_no_stroke, null)!!
val p = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
p.setMargins(20, 0, 20, 0)
p.gravity = Gravity.CENTER
tv.layoutParams = p
tv.setTypeface(font, typeface)
tv.setTextColor(
@@ -221,42 +235,53 @@ class MarkDetailsFragment(private val marks: MutableList<Mark>, private var idx:
private fun makeRow(left: TextView, right: TextView): LinearLayout {
val ll = LinearLayout(requireContext())
ll.orientation = LinearLayout.VERTICAL
ll.gravity = Gravity.CENTER_HORIZONTAL
val p = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
p.setMargins(20, 0, 20, 0)
ll.layoutParams = p
ll.background = ResourcesCompat.getDrawable(resources, R.drawable.pastel_yellow_no_stroke, null)!!
ll.addView(left)
ll.addView(right)
return ll
val otherLL = LinearLayout(requireContext())
otherLL.orientation = LinearLayout.VERTICAL
otherLL.addView(createSpace())
val root = LinearLayout(requireContext())
root.orientation = LinearLayout.VERTICAL
root.layoutParams = LinearLayout.LayoutParams(
Util.getDisplayWidth(requireContext())-40,
LinearLayout.LayoutParams.MATCH_PARENT
)
root.addView(ll)
root.addView(otherLL)
return root
}
private fun createSpace(): Space {
val space = Space(requireContext())
space.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)
)
return space
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solen_DialogAnimation
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
return dialog
}
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val diffY = e1?.let { e2.y.minus(it.y) } ?: 0f
if (diffY > swipeThreshold && abs(velocityY) > swipeVelocityThreshold) {
// Swiped down
dismiss()
return true
}
return false
}
}
@Suppress("SameReturnValue")
private fun handleTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
@@ -66,6 +66,8 @@ class MarksFragment : Fragment() {
root.addView(Vars.marks[subject]?.let { createMarkView(it) })
if (i < Vars.marks.keys.size-1) {
root.addView(createSpace())
} else {
root.addView(createSpace2())
}
}
@@ -83,6 +85,16 @@ class MarksFragment : Fragment() {
return space
}
private fun createSpace2(): Space {
val space = Space(requireContext())
space.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
resources.getDimensionPixelSize(R.dimen.cal_week_separator_height)/2
)
return space
}
private fun makeDR(marks: MutableList<Mark>): GradientDrawable {
val avgDrawable = GradientDrawable()
avgDrawable.shape = GradientDrawable.RECTANGLE
@@ -97,17 +109,6 @@ class MarksFragment : Fragment() {
)
}
)
avgDrawable.setStroke(
10,
if (!marks.contains(Mark().none())) {
Util.getAvgStrokeColor(requireContext(), Util.avg(marks))
} else {
ContextCompat.getColor(
requireContext(),
R.color.pastel_orange
)
}
)
return avgDrawable
}
@@ -183,9 +184,9 @@ class MarksFragment : Fragment() {
}
avgTextView.text = text
avgTextView.textSize = 30f
avgTextView.setPadding(0, 20, 30, 20)
avgTextView.setPadding(20, 20, 20, 20)
avgTextView.gravity = Gravity.CENTER // Center text vertically
avgTextView.setTypeface(customFont, Typeface.ITALIC)
avgTextView.setTypeface(customFont, Typeface.NORMAL)
avgTextView.setTextColor(
ContextCompat.getColor(
requireContext(),
@@ -219,18 +220,9 @@ class MarksFragment : Fragment() {
val space = TextView(requireContext())
space.setPadding(0, 40, 0, 40)
space.gravity = Gravity.CENTER_VERTICAL
space.text = " "
space.text = " "
space.textSize = 22f
space.setTextColor(
if (!marks.contains(Mark().none())) {
Util.getAvgBgColor(requireContext(), Util.avg(marks))
} else {
ContextCompat.getColor(
requireContext(),
R.color.pastel_orange_transparent
)
}
)
space.background = ResourcesCompat.getDrawable(resources, R.color.black, null)
space.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT
@@ -260,7 +252,11 @@ class MarksFragment : Fragment() {
R.color.white
)
)
marksTextView.gravity = Gravity.CENTER_VERTICAL
marksTextView.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
marksTextView.gravity = Gravity.CENTER
marksTextView.ellipsize = null
marksTextView.setHorizontallyScrolling(false)
@@ -5,7 +5,6 @@ import android.app.Dialog
import android.graphics.Typeface
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.util.Log
import android.view.GestureDetector
import android.view.Gravity
import android.view.LayoutInflater
@@ -14,11 +13,11 @@ import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.DialogFragment
import kotlin.math.abs
// details for the marks of one subject
@@ -26,11 +25,16 @@ import kotlin.math.abs
class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFragment() {
private var initialTouchY: Float = 0f
private lateinit var rootLayout: LinearLayout
private lateinit var scrollView: ScrollView
private val swipeThreshold = 100
private var isScrollingToDismissEnabled = false
private var isScrollingToTop = true
private lateinit var gestureDetector: GestureDetector
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// set the style so the dialog is fullscreen
setStyle(STYLE_NORMAL, R.style.Theme_Solen)
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
}
override fun onCreateView(
@@ -53,7 +57,24 @@ class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFrag
return view
}
@SuppressLint("ClickableViewAccessibility")
private fun gestures(view: View) {
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
scrollView = view.findViewById(R.id.mark_details_scroll)
scrollView.scrollY = 0
scrollView.setOnTouchListener { _, event ->
scrollView.performClick()
gestureDetector.onTouchEvent(event)
// Return false to allow normal scrolling
false
}
scrollView.viewTreeObserver.addOnScrollChangedListener {
isScrollingToTop = !scrollView.canScrollVertically(-1)
}
// Attach the gesture detector to the root layout
view.setOnTouchListener { _, event ->
view.performClick()
@@ -162,7 +183,7 @@ class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFrag
val markTV = TextView(requireContext())
markTV.text = mark.grade
markTV.setPadding(20, 20, 20, 20)
markTV.setPadding(30, 30, 30, 30)
markTV.textSize = 30f
markTV.setTextColor(
ContextCompat.getColor(
@@ -172,7 +193,7 @@ class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFrag
)
val descTV = TextView(requireContext())
descTV.text = "${mark.theme} "
descTV.text = mark.theme
descTV.setPadding(20, 20, 20, 20)
descTV.textSize = 20f
descTV.setTextColor(
@@ -185,7 +206,7 @@ class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFrag
descTV.setOnTouchListener { _, event ->
handleTouchEvent(event, i)
}
descTV.setTypeface(customFont, Typeface.ITALIC)
descTV.setTypeface(customFont, Typeface.NORMAL)
descTV.ellipsize = null
descTV.setHorizontallyScrolling(false)
@@ -206,7 +227,7 @@ class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFrag
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solen_DialogAnimation
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
@@ -246,4 +267,30 @@ class MarksOneSubjectFragment(private val marks: MutableList<Mark>) : DialogFrag
}
return true
}
inner class SwipeGestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
// Reset the flag when the user touches the screen
isScrollingToDismissEnabled = false
return true
}
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val diffY = e1?.let { e2.y - it.y } ?: 0f
if (diffY > swipeThreshold) {
// Swiped down
if (isScrollingToTop) {
// Enable dismissing only if scrolled to top
isScrollingToDismissEnabled = true
dismiss()
}
}
return false
}
}
}
@@ -34,7 +34,7 @@ class MenuFragment : Fragment() {
}
signOut.setOnClickListener {
val builder: AlertDialog.Builder = AlertDialog.Builder(context, R.style.Theme_Solen_AlertDialog)
val builder: AlertDialog.Builder = AlertDialog.Builder(context, R.style.Theme_Solon_AlertDialog)
builder
.setView(LayoutInflater.from(context).inflate(R.layout.alert_dialog_sign_out, null))
.setPositiveButton("Ano") { dialog, _ ->
@@ -59,8 +59,6 @@ class Network {
Vars.studentId = getStudentId()
Vars.syid = getSYID()
//Log.d("SYID", Vars.syid)
Vars.marksUrl = "${Vars.apiBaseUrl}/v1/students/${Vars.studentId}/marks/list?SemesterId=${Vars.syid}"
Vars.isAPISetUp = true
@@ -78,7 +76,7 @@ class Network {
syidNum += 1
}
// TODO: REMOVE LATER, JUST FOR DEBUG
// TODO: REMOVE LATER, JUST FOR DEBUG (NO MARKS IN THE CURRENT SEMESTER)
syidNum -= 1
return syidStart.toString() + syidNum.toString()
@@ -27,7 +27,7 @@ class SettingsFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.Theme_Solen)
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
}
inner class SwipeGestureListener : SimpleOnGestureListener() {
@@ -88,7 +88,7 @@ class SettingsFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solen_DialogAnimation
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
return dialog
}
}
@@ -23,7 +23,7 @@ class SignInFragment : DialogFragment() {
super.onCreate(savedInstanceState)
// Set up GestureDetector
gestureDetector = GestureDetector(requireContext(), SwipeGestureListener())
setStyle(STYLE_NORMAL, R.style.Theme_Solen)
setStyle(STYLE_NORMAL, R.style.Theme_Solon)
}
override fun onCreateView(
@@ -43,7 +43,7 @@ class SignInFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solen_DialogAnimation
dialog.window?.attributes?.windowAnimations = R.style.Theme_Solon_DialogAnimation
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
dialog.setCancelable(true)
@@ -127,10 +127,6 @@ class Util {
return (pixels * resources.displayMetrics.density).toInt()
}
/*fun dpToPixels(dp: Int, resources: Resources): Int {
return (dp / resources.displayMetrics.density).toInt()
}*/
fun avg(marks: MutableList<Mark>): String {
var sum = 0f
var len = 0
@@ -5,5 +5,4 @@
<corners android:radius="@dimen/corner_radius" />
<solid android:color="@color/pastel_yellow_transparent" />
<stroke android:width="5dp" android:color="@color/pastel_yellow" />
</shape>
@@ -5,5 +5,4 @@
<corners android:radius="@dimen/corner_radius" />
<solid android:color="#90FFCC33" />
<stroke android:width="5dp" android:color="@color/pastel_yellow" />
</shape>
@@ -5,15 +5,25 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/one_mark_root"
<ScrollView
android:id="@+id/mark_detail_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_marginTop="0dp"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:id="@+id/one_mark_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:gravity="center_horizontal"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -4,14 +4,24 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/mark_details_root"
<ScrollView
android:id="@+id/mark_details_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:id="@+id/mark_details_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
@@ -15,7 +15,7 @@
android:text="@string/lang_cz"
android:textColor="@color/white"
android:layout_marginHorizontal="20dp"
android:theme="@style/Theme.Solen.RadioButton" />
android:theme="@style/Theme.Solon.RadioButton" />
<RadioButton
android:layout_width="match_parent"
@@ -23,6 +23,6 @@
android:text="@string/lang_en"
android:textColor="@color/white"
android:layout_marginHorizontal="20dp"
android:theme="@style/Theme.Solen.RadioButton" />
android:theme="@style/Theme.Solon.RadioButton" />
</RadioGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
+1 -61
View File
@@ -19,64 +19,4 @@
android:layout_height="wrap_content"
android:icon="@drawable/menu_240"
android:title="@string/menu" />
</menu>
<!--
options menu for future reference
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_settings"
android:title="@string/settings" />
<item
android:id="@+id/item_sign_out"
android:title="@string/sign_out" />
<item
android:id="@+id/item_sign_in"
android:title="@string/sign_in" />
<item
android:id="@+id/item_about"
android:title="@string/about_app" />
</menu>
item click callbacks
// Override onOptionsItemSelected to handle menu item clicks
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
// TODO: IMPLEMENT MARKS/GRADES
// TODO: NOTE -> IN A NAVBAR
/*R.id.item_marks -> {
showMarksScreen()
return true
}*/
R.id.item_sign_in -> {
SignInFragment().show(supportFragmentManager, "fragment_sign_in")
return true
}
R.id.item_settings -> {
showSettingsScreen()
return true
}
R.id.item_sign_out -> {
Dialogs.SignOut(this).show()
return true
}
R.id.item_about -> {
AboutFragment().show(supportFragmentManager, "fragment_about")
return true
}
}
return super.onOptionsItemSelected(item)
}
-->
</menu>
+1 -1
View File
@@ -1,4 +1,4 @@
<resources>
<dimen name="cal_week_separator_height">20dp</dimen>
<dimen name="cal_week_separator_height">16dp</dimen>
<dimen name="corner_radius">8dp</dimen>
</resources>
+1 -1
View File
@@ -14,7 +14,7 @@
<string name="slogan">Přehlednost je podstata.</string>
<string name="desc_about">Vylepšená verze mobilní aplikace ŠkolaOnLine</string>
<string name="odweta"> Odweta</string>
<string name="development_vyvoj">Vývoj:</string>
<string name="development_vyvoj">Vývoj: </string>
<string name="source_code">Zdrojový kód</string>
<string name="username">Uživatelské jméno</string>
<string name="password">Heslo</string>
+8 -8
View File
@@ -1,6 +1,6 @@
<resources>
<!-- Base application theme. -->
<style name="Theme.Solen" parent="Theme.AppCompat">
<style name="Theme.Solon" parent="Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="iconTint">@color/white</item>
@@ -21,7 +21,7 @@
<item name="android:colorBackground">@color/black</item>
</style>
<style name="LinkText" parent="Theme.Solen">
<style name="LinkText" parent="Theme.Solon">
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Body1</item>
<item name="android:textColor">@color/white</item>
<item name="android:textStyle">normal</item>
@@ -37,26 +37,26 @@
<item name="cornerRadius">@dimen/corner_radius</item>
</style>
<style name="Theme.Solen.RadioButton">
<style name="Theme.Solon.RadioButton">
<item name="colorControlActivated">@color/primary</item>
</style>
<style name="Theme.Solen.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<style name="Theme.Solon.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:windowBackground">@drawable/alert_dialog_background</item>
<item name="android:buttonBarButtonStyle">@style/Theme.Solen.DialogButton</item>
<item name="android:buttonBarButtonStyle">@style/Theme.Solon.DialogButton</item>
</style>
<style name="Theme.Solen.DialogButton" parent="Widget.AppCompat.Button">
<style name="Theme.Solon.DialogButton" parent="Widget.AppCompat.Button">
<item name="android:textColor">@color/white</item>
<item name="android:background">@color/transparent</item>
</style>
<style name="Theme.Solen.DialogAnimation">
<style name="Theme.Solon.DialogAnimation">
<item name="android:windowEnterAnimation">@anim/slide_up</item>
<item name="android:windowExitAnimation">@anim/slide_down</item>
</style>
<style name="Theme.Solen.Scrollbar">
<style name="Theme.Solon.Scrollbar">
<item name="color">@color/primary</item>
</style>
</resources>
@@ -5,7 +5,7 @@
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<!--
<include .../>
<exclude .../>
-->
+1 -1
View File
@@ -15,5 +15,5 @@ dependencyResolutionManagement {
}
}
rootProject.name = "Solen"
rootProject.name = "Solon"
include(":app")
Binary file not shown.