forked from github/wulkanowy-mirror
Compare commits
6 Commits
develop
...
bugfix/cla
Author | SHA1 | Date | |
---|---|---|---|
|
2bae532f6d | ||
|
157e04b239 | ||
|
2a0ac7f91e | ||
|
d7b1a08098 | ||
|
985be92a4d | ||
|
6616a313e2 |
@ -1,7 +1,7 @@
|
|||||||
[*]
|
[*]
|
||||||
charset=utf-8
|
charset=utf-8
|
||||||
end_of_line=lf
|
end_of_line=lf
|
||||||
insert_final_newline=Advanced
|
insert_final_newline=true
|
||||||
indent_style=space
|
indent_style=space
|
||||||
indent_size=4
|
indent_size=4
|
||||||
|
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
changelog:
|
|
||||||
exclude:
|
|
||||||
labels:
|
|
||||||
- "release ignore"
|
|
||||||
categories:
|
|
||||||
- title: breaking changes
|
|
||||||
labels:
|
|
||||||
- major
|
|
||||||
- title: new features
|
|
||||||
labels:
|
|
||||||
- minor
|
|
||||||
- fr:approved
|
|
||||||
- title: translation updates
|
|
||||||
labels:
|
|
||||||
- translation
|
|
||||||
- title: features
|
|
||||||
labels:
|
|
||||||
- "*"
|
|
@ -1,84 +0,0 @@
|
|||||||
name: Generate APK
|
|
||||||
|
|
||||||
env:
|
|
||||||
main_project_module: app
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types:
|
|
||||||
- closed
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
env:
|
|
||||||
RUNNER_TOOL_CACHE: /toolcache
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set current date as env variable
|
|
||||||
run: echo "date_today=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set repository name as env variable
|
|
||||||
run: echo "repository_name=$(echo '${{ gitea.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
distribution: 'zulu'
|
|
||||||
java-version: '17'
|
|
||||||
cache: 'gradle'
|
|
||||||
|
|
||||||
- name: Set up Go environment
|
|
||||||
uses: actions/setup-go@v3
|
|
||||||
with:
|
|
||||||
go-version: '1.22'
|
|
||||||
|
|
||||||
- name: Get hash of Gradle files
|
|
||||||
uses: https://gitea.com/actions/go-hashfiles@v0.0.1
|
|
||||||
id: get-hash
|
|
||||||
with:
|
|
||||||
patterns: |-
|
|
||||||
**/*.gradle*
|
|
||||||
|
|
||||||
- name: Cache Gradle
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.gradle/caches
|
|
||||||
~/.gradle/wrapper
|
|
||||||
key: gradle-${{ runner.os }}-${{ steps.get-hash.outputs.hash }}
|
|
||||||
|
|
||||||
- name: Get app version
|
|
||||||
id: get_version
|
|
||||||
run: echo "VERSION_NAME=$(grep -m1 "versionName" app/build.gradle | awk '{print $2}' | tr -d \'\'\"\')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Change wrapper permissions
|
|
||||||
run: chmod +x ./gradlew
|
|
||||||
|
|
||||||
- name: Setup Android SDK
|
|
||||||
uses: android-actions/setup-android@v3
|
|
||||||
|
|
||||||
- name: Build debug APK
|
|
||||||
run: ./gradlew assembleDebug
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v3 # not v4 because of GHES
|
|
||||||
with:
|
|
||||||
name: wulkanowy_mod_debug_builds
|
|
||||||
path: |
|
|
||||||
app/build/outputs/**/*-debug.apk
|
|
||||||
|
|
||||||
- name: Create release
|
|
||||||
uses: akkuman/gitea-release-action@v1
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: '--experimental-fetch'
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
app/build/outputs/**/*-debug.apk
|
|
||||||
|
|
||||||
name: Release ${{ env.VERSION_NAME }} (${{ env.date_today }})
|
|
||||||
tag_name: v${{ env.VERSION_NAME }}
|
|
79
.github/workflows/deploy-store.yml
vendored
Normal file
79
.github/workflows/deploy-store.yml
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
name: Deploy release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [ created ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
deploy-google-play:
|
||||||
|
name: Google Play
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
environment: google-play
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Decrypt keys
|
||||||
|
env:
|
||||||
|
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||||
|
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
|
||||||
|
run: |
|
||||||
|
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg
|
||||||
|
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
|
||||||
|
- name: Upload apk to google play
|
||||||
|
env:
|
||||||
|
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
|
||||||
|
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
|
||||||
|
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
|
||||||
|
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
|
||||||
|
ADMOB_PROJECT_ID: ${{ secrets.ADMOB_PROJECT_ID }}
|
||||||
|
SINGLE_SUPPORT_AD_ID: ${{ secrets.SINGLE_SUPPORT_AD_ID }}
|
||||||
|
DASHBOARD_TILE_AD_ID: ${{ secrets.DASHBOARD_TILE_AD_ID }}
|
||||||
|
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
|
||||||
|
run: ./gradlew publishPlayReleaseApps --stacktrace;
|
||||||
|
|
||||||
|
deploy-app-gallery:
|
||||||
|
name: AppGallery
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
environment: app-gallery
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Decrypt keys
|
||||||
|
env:
|
||||||
|
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
|
||||||
|
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
|
||||||
|
run: |
|
||||||
|
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/agconnect-services.json.gpg
|
||||||
|
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
|
||||||
|
- name: Prepare credentials
|
||||||
|
env:
|
||||||
|
AGC_CREDENTIALS: ${{ secrets.AGC_CREDENTIALS }}
|
||||||
|
run: echo $AGC_CREDENTIALS > ./app/src/release/agconnect-credentials.json
|
||||||
|
- name: Build and publish HMS version
|
||||||
|
env:
|
||||||
|
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
|
||||||
|
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
|
||||||
|
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
|
||||||
|
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
|
||||||
|
run: ./gradlew bundleHmsRelease --stacktrace && ./gradlew publishHuaweiAppGalleryHmsRelease --stacktrace
|
145
.github/workflows/deploy-test.yml
vendored
Normal file
145
.github/workflows/deploy-test.yml
vendored
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
name: Deploy DEV
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
# branches: [ develop ]
|
||||||
|
branches: [ '!*' ]
|
||||||
|
pull_request_target:
|
||||||
|
# branches: [ develop ]
|
||||||
|
branches: [ '!*' ]
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
deploy-appcenter:
|
||||||
|
name: App Center
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
environment: app-center
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Set run number with offset
|
||||||
|
env:
|
||||||
|
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
|
||||||
|
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
|
||||||
|
- name: Prepare build configuration
|
||||||
|
run: |
|
||||||
|
sed -i -e "s#applicationIdSuffix \".dev\"#applicationIdSuffix \".${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/build.gradle
|
||||||
|
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/google-services.json
|
||||||
|
sed -i -e '/versionNameSuffix/d' app/build.gradle
|
||||||
|
- name: Add signing config
|
||||||
|
run: |
|
||||||
|
cat >> app/build.gradle <<EOF
|
||||||
|
android.signingConfigs.debug {
|
||||||
|
storeFile file("bitrise.jks")
|
||||||
|
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
|
||||||
|
keyAlias System.getenv("BITRISE_KEY_ALIAS")
|
||||||
|
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- name: Decrypt keys
|
||||||
|
env:
|
||||||
|
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
|
||||||
|
run: |
|
||||||
|
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
|
||||||
|
- name: Bump version
|
||||||
|
uses: chkfung/android-version-actions@v1.1
|
||||||
|
with:
|
||||||
|
gradlePath: app/build.gradle
|
||||||
|
versionCode: ${{ env.RUN_NUMBER }}
|
||||||
|
versionName: ${{ env.RUN_NUMBER }}-${{ github.head_ref }}
|
||||||
|
- name: Build apk
|
||||||
|
env:
|
||||||
|
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
|
||||||
|
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
|
||||||
|
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||||
|
run: ./gradlew assembleFdroidDebug --stacktrace
|
||||||
|
- name: Upload apk to github artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
|
||||||
|
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
||||||
|
- name: Deploy to app center
|
||||||
|
uses: wzieba/AppCenter-Github-Action@v1
|
||||||
|
with:
|
||||||
|
appName: wulkanowy/wulkanowy
|
||||||
|
token: ${{ secrets.APP_CENTER_TOKEN }}
|
||||||
|
group: Testers
|
||||||
|
file: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
|
||||||
|
notifyTesters: true
|
||||||
|
debug: true
|
||||||
|
|
||||||
|
deploy-app-distribution:
|
||||||
|
name: App Distribution
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
environment: app-distribution
|
||||||
|
if: github.event_name != 'pull_request_target'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Set run number with offset
|
||||||
|
env:
|
||||||
|
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
|
||||||
|
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
|
||||||
|
- name: Add signing config
|
||||||
|
run: |
|
||||||
|
cat >> app/build.gradle <<EOF
|
||||||
|
android.signingConfigs.debug {
|
||||||
|
storeFile file("bitrise.jks")
|
||||||
|
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
|
||||||
|
keyAlias System.getenv("BITRISE_KEY_ALIAS")
|
||||||
|
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
- name: Decrypt keys
|
||||||
|
env:
|
||||||
|
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
|
||||||
|
BITRISE_SERVICES_ENCRYPT_KEY: ${{ secrets.BITRISE_SERVICES_ENCRYPT_KEY }}
|
||||||
|
run: |
|
||||||
|
gpg --yes --batch --passphrase=$BITRISE_SERVICES_ENCRYPT_KEY ./app/src/debug/google-services.json.gpg
|
||||||
|
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
|
||||||
|
- name: Bump version
|
||||||
|
uses: chkfung/android-version-actions@v1.1
|
||||||
|
with:
|
||||||
|
gradlePath: app/build.gradle
|
||||||
|
versionCode: ${{ env.RUN_NUMBER }}
|
||||||
|
versionName: ${{ env.RUN_NUMBER }}
|
||||||
|
- name: Build apk
|
||||||
|
env:
|
||||||
|
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
|
||||||
|
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
|
||||||
|
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
|
||||||
|
run: ./gradlew assemblePlayDebug --stacktrace
|
||||||
|
- name: Upload apk to github artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
|
||||||
|
path: app/build/outputs/apk/play/debug/app-play-debug.apk
|
||||||
|
- name: Deploy to app distribution
|
||||||
|
uses: wzieba/Firebase-Distribution-Github-Action@v1
|
||||||
|
with:
|
||||||
|
appId: ${{ secrets.FIREBASE_APP_ID }}
|
||||||
|
token: ${{ secrets.FIREBASE_TOKEN }}
|
||||||
|
groups: discord
|
||||||
|
file: app/build/outputs/apk/play/debug/app-play-debug.apk
|
90
.github/workflows/test.yml
vendored
Normal file
90
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
name: Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- 'hotfix/**'
|
||||||
|
tags: [ '*' ]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
tests-fdroid:
|
||||||
|
name: F-Droid
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testFdroidDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
||||||
|
|
||||||
|
tests-play:
|
||||||
|
name: Play
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testPlayDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
||||||
|
|
||||||
|
tests-hms:
|
||||||
|
name: HMS
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: fkirc/skip-duplicate-actions@master
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: gradle/wrapper-validation-action@v1
|
||||||
|
- uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
|
||||||
|
- name: Unit tests
|
||||||
|
run: |
|
||||||
|
./gradlew testHmsDebugUnitTest --stacktrace
|
||||||
|
./gradlew jacocoTestReport --stacktrace
|
||||||
|
- uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
flags: unit
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -127,4 +127,3 @@ google-services.json
|
|||||||
!app/google-services.json
|
!app/google-services.json
|
||||||
|
|
||||||
|
|
||||||
.idea/appInsightsSettings.xml
|
|
||||||
|
88
README.cs.md
88
README.cs.md
@ -1,33 +1,73 @@
|
|||||||
Česká verze / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
Česká verze / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
# Wulkanowy MOD
|
# Wulkanowy
|
||||||
|
|
||||||
## Funkce:
|
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
* skrýt známky
|
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
* Skrýt jednotlivé záznamy o docházce.
|
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
||||||
* Skrýt komentáře.
|
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
* falešná docházka %
|
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Chcete-li se dostat na skrytý panel:
|
Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
|
||||||
1. Přejděte na kartu „Další“.
|
|
||||||
2. Přejděte na panel „Nastavení“.
|
|
||||||
3. Přejděte na panel „O aplikaci“.
|
|
||||||
4. Klikněte 5x na logo aplikace
|
|
||||||
5. Přejděte na domovskou obrazovku
|
|
||||||
6. Přejděte do nastavení
|
|
||||||
7. Zadejte „tajná nastavení“
|
|
||||||
|
|
||||||
# Instalace
|
## Funkce
|
||||||
|
|
||||||
| Název souboru | Přizpůsobeno |
|
* přihlášení pomocí emailu a hesla
|
||||||
| ---------------- | ----------------- |
|
* funkce z webové stránky deníku:
|
||||||
| `*-fdroid-*.apk` | F-Droid |
|
* známky
|
||||||
| `*-hms-*.apk` | Huawei AppGallery |
|
* statistiky známek
|
||||||
| `*-play-*.apk` | Play Store |
|
* frekvence
|
||||||
|
* procento frekvence
|
||||||
|
* zkoušky
|
||||||
|
* plán lekce
|
||||||
|
* dokončené lekce
|
||||||
|
* zprávy
|
||||||
|
* domácí úkoly
|
||||||
|
* poznámky
|
||||||
|
* šťastné číslo
|
||||||
|
* další lekce
|
||||||
|
* školní setkání
|
||||||
|
* informace o žáku a škole
|
||||||
|
* výpočet průměru nezávisle na preferencích školy
|
||||||
|
* upozornění, např. o nových známkách
|
||||||
|
* podpora více účtů s možností přejmenování žáků
|
||||||
|
* tmavý a černý (AMOLED) motiv
|
||||||
|
* offline režim
|
||||||
|
* volitelné reklamy na podporu projektu
|
||||||
|
|
||||||
Stáhněte si vybranou verzi z [releases](https://git.sador.me/sadorowo/wulkanowy-mod/releases).
|
## Stáhnout
|
||||||
Doporučujeme stáhnout nejnovější dostupnou verzi.
|
|
||||||
|
|
||||||
# O projektu Wulkanowy
|
Aktuální verzi si můžete stáhnout z Google Play, F-Droid nebo Huawei AppGallery
|
||||||
|
|
||||||
Chcete si přečíst více o projektu Wulkanowy? [Klikněte sem](https://github.com/wulkanowy/wulkanowy)
|
[<img src="https://play.google.com/intl/cs-CZ/badges/images/generic/cs_badge_web_generic.png"
|
||||||
|
alt="Nyní na Google Play"
|
||||||
|
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Stáhnout s F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
[<img src="https://i.imgur.com/baTGiDP.png"
|
||||||
|
alt="Objevuj v AppGallery"
|
||||||
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
|
Můžete si také stáhnout [vývojovou verzi](https://wulkanowy.github.io/#download), která zahrnuje nové funkce připravované pro příští vydání
|
||||||
|
|
||||||
|
## Postaveno s pomocí
|
||||||
|
|
||||||
|
|
||||||
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
|
||||||
|
* [Hilt](https://dagger.dev/hilt/)
|
||||||
|
* [Room](https://developer.android.com/topic/libraries/architecture/room)
|
||||||
|
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
|
||||||
|
|
||||||
|
## Spolupráce
|
||||||
|
|
||||||
|
Přispějte do projektu vytvořením PR nebo odesláním issue na GitHub.
|
||||||
|
|
||||||
|
Pro zájemce o překlad aplikace do různých jazyků poskytujeme Crowdin:
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
Tento projekt je licencován pod licencí Apache License 2.0 - podrobnosti v souboru [LICENSE](LICENSE)
|
||||||
|
88
README.de.md
88
README.de.md
@ -1,33 +1,73 @@
|
|||||||
[Česká verze](README.cs.md) / Deutsche Version / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
[Česká verze](README.cs.md) / Deutsche Version / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
# Wulkanowy MOD
|
# Wulkanowy
|
||||||
|
|
||||||
## Funktionen:
|
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
* Noten ausblenden
|
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
* Individuelle Anwesenheitslisten ausblenden.
|
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
||||||
* Kommentare ausblenden.
|
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
* Anwesenheit fälschen %
|
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
So gelangen Sie zum ausgeblendeten Bereich:
|
Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern
|
||||||
1. Gehen Sie zur Registerkarte „Mehr“.
|
|
||||||
2. Gehen Sie zum Bereich „Einstellungen“.
|
|
||||||
3. Gehen Sie zum Bereich „Über die Anwendung“.
|
|
||||||
4. Klicken Sie fünfmal auf das Anwendungslogo
|
|
||||||
5. Gehen Sie zum Startbildschirm
|
|
||||||
6. Gehen Sie zu den Einstellungen
|
|
||||||
7. Geben Sie „Geheime Einstellungen“ ein
|
|
||||||
|
|
||||||
# Installation
|
## Merkmale
|
||||||
|
|
||||||
| Dateiname | Angepasst an |
|
* Einloggen mit E-Mail und Passwort
|
||||||
| ---------------- | ----------------- |
|
* Funktionen von der Registerwebsite:
|
||||||
| `*-fdroid-*.apk` | F-Droid |
|
* Noten
|
||||||
| `*-hms-*.apk` | Huawei AppGallery |
|
* Notenstatistik
|
||||||
| `*-play-*.apk` | Play Store |
|
* Anwesenheit
|
||||||
|
* Prozentsatz der Anwesenheit
|
||||||
|
* Prüfungen
|
||||||
|
* Stundenplan
|
||||||
|
* abgeschlossene Unterrichtsstunden
|
||||||
|
* Nachrichten
|
||||||
|
* Hausaufgaben
|
||||||
|
* Anmerkungen
|
||||||
|
* Glückszahl
|
||||||
|
* Zusätzliche Lektionen
|
||||||
|
* Schulkonferenzen
|
||||||
|
* Schüler- und Schulinformationen
|
||||||
|
* Berechnung des Durchschnitts unabhängig von den Präferenzen der Schule
|
||||||
|
* Benachrichtigungen, z. B. über eine neue Note
|
||||||
|
* Unterstützung für mehrere Konten mit der Möglichkeit, den Namen des Schülers zu ändern
|
||||||
|
* dunkles und schwarzes (AMOLED) Thema
|
||||||
|
* Offline-Modus
|
||||||
|
* optionale Werbungen, die es uns ermöglichen das Projekt zu unterstützen
|
||||||
|
|
||||||
Laden Sie die ausgewählte Version von [hier](https://git.sador.me/sadorowo/wulkanowy-mod/releases) herunter.
|
## Herunterladen
|
||||||
Wir empfehlen, die neueste verfügbare Version herunterzuladen.
|
|
||||||
|
|
||||||
# Über das Wulkanowy-Projekt
|
Die aktuelle Version können Sie von der Google Play, F-Droid oder Huawei AppGallery store herunterladen
|
||||||
|
|
||||||
Möchten Sie mehr über das Wulkanowy-Projekt lesen? [Hier klicken](https://github.com/wulkanowy/wulkanowy)
|
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||||
|
alt="Get it on Google Play"
|
||||||
|
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Get it on F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
[<img src="appgallery_badge.png"
|
||||||
|
alt="Explore it on AppGallery"
|
||||||
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
|
Sie können auch eine [Entwicklungsversion herunterladen](https://wulkanowy.github.io/#download) die beinhaltet neue Funktionen, die für die nächste Version vorbereitet werden
|
||||||
|
|
||||||
|
## Gebaut mit
|
||||||
|
|
||||||
|
|
||||||
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
|
||||||
|
* [Hilt](https://dagger.dev/hilt/)
|
||||||
|
* [Room](https://developer.android.com/topic/libraries/architecture/room)
|
||||||
|
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
|
||||||
|
|
||||||
|
## Beitragen
|
||||||
|
|
||||||
|
Bitte tragen Sie zum Projekt bei, indem Sie entweder eine PR erstellen oder ein Issue auf GitHub einreichen.
|
||||||
|
|
||||||
|
Für Personen, die daran interessiert sind, die Anwendung in verschiedene Sprachen zu übersetzen, bieten wir Crowdin
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
|
## Lizenz
|
||||||
|
|
||||||
|
Dieses Projekt ist unter der Apache License 2.0 lizenziert - siehe die [LIZENZ](LICENSE) Datei für Details
|
||||||
|
88
README.en.md
88
README.en.md
@ -1,33 +1,73 @@
|
|||||||
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / English version / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / English version / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
# Wulkanowy MOD
|
# Wulkanowy
|
||||||
|
|
||||||
## Functions:
|
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
* hide grades
|
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
* hide individual attendance entries
|
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
||||||
* hide comments
|
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
* fake attendance %.
|
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
To get to the hidden panel:
|
Unofficial android VULCAN UONET+ register client for both students and their parents
|
||||||
1. Go to the "More" tab
|
|
||||||
2. Go to the "Settings" panel
|
|
||||||
3. Go to the "About application" panel
|
|
||||||
4. Click on the application logo 5 times
|
|
||||||
5. Go to the home screen
|
|
||||||
6. Go to settings
|
|
||||||
7. Enter "secret settings"
|
|
||||||
|
|
||||||
# Installation
|
## Features
|
||||||
|
|
||||||
| File name | Adapted to |
|
* logging in using the email and password
|
||||||
| ---------------- | ----------------- |
|
* functions from the register website:
|
||||||
| `*-fdroid-*.apk` | F-Droid |
|
* grades
|
||||||
| `*-hms-*.apk` | Huawei AppGallery |
|
* grade statistics
|
||||||
| `*-play-*.apk` | Play Store |
|
* attendance
|
||||||
|
* percentage of attendance
|
||||||
|
* exams
|
||||||
|
* timetable
|
||||||
|
* completed lessons
|
||||||
|
* messages
|
||||||
|
* homework
|
||||||
|
* notes
|
||||||
|
* lucky number
|
||||||
|
* additional lessons
|
||||||
|
* school conferences
|
||||||
|
* student and school information
|
||||||
|
* calculation of the average independently of school's preferences
|
||||||
|
* notifications, e.g. about a new grade
|
||||||
|
* support for multiple accounts with the ability to rename students
|
||||||
|
* dark and black (AMOLED) theme
|
||||||
|
* offline mode
|
||||||
|
* optional ads which allow to support the project
|
||||||
|
|
||||||
Download application from [releases](https://git.sador.me/sadorowo/wulkanowy-mod/releases).
|
## Download
|
||||||
We recommend downloading the latest available version.
|
|
||||||
|
|
||||||
# About the Wulkanowy project
|
You can download the current version from the Google Play, F-Droid or Huawei AppGallery store
|
||||||
|
|
||||||
Want to read more about the Wulkanowy project? [Click here](https://github.com/wulkanowy/wulkanowy)
|
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||||
|
alt="Get it on Google Play"
|
||||||
|
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Get it on F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
[<img src="appgallery_badge.png"
|
||||||
|
alt="Explore it on AppGallery"
|
||||||
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
|
You can also download a [development version](https://wulkanowy.github.io/#download) that includes new features being prepared for the next release
|
||||||
|
|
||||||
|
## Built With
|
||||||
|
|
||||||
|
|
||||||
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
|
||||||
|
* [Hilt](https://dagger.dev/hilt/)
|
||||||
|
* [Room](https://developer.android.com/topic/libraries/architecture/room)
|
||||||
|
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please contribute to the project either by creating a PR or submitting an issue on GitHub.
|
||||||
|
|
||||||
|
For people interested in translating the application into different languages, we provide Crowdin
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details
|
||||||
|
89
README.md
89
README.md
@ -1,33 +1,74 @@
|
|||||||
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / Polska wersja / [Slovenská verzia](README.sk.md)
|
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / Polska wersja / [Slovenská verzia](README.sk.md)
|
||||||
|
|
||||||
# Wulkanowy MOD
|
# Wulkanowy
|
||||||
|
|
||||||
## Funkcje:
|
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
* ukryj oceny
|
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
* ukryj poszczególne wpisy frekwencji
|
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
||||||
* ukryj uwagi
|
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
* sfałszuj % frekwencji
|
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Aby dostać się do ukrytego panelu:
|
Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
|
||||||
1. Przejdź do karty "Więcej"
|
|
||||||
2. Przejdź do panelu "Ustawienia"
|
|
||||||
3. Przejdź do panelu "O aplikacji"
|
|
||||||
4. Kliknij 5 razy w logo aplikacji
|
|
||||||
5. Przejdź na ekran główny
|
|
||||||
6. Wejdź w ustawienia
|
|
||||||
7. Wejdź w "sekretne ustawienia"
|
|
||||||
|
|
||||||
# Instalacja
|
## Funkcje
|
||||||
|
|
||||||
| Nazwa pliku | Przystosowana do |
|
* logowanie za pomocą e-maila i hasła
|
||||||
| ---------------- | ----------------- |
|
* funkcje ze strony internetowej dziennika:
|
||||||
| `*-fdroid-*.apk` | F-Droid |
|
* oceny
|
||||||
| `*-hms-*.apk` | Huawei AppGallery |
|
* statystyki ocen
|
||||||
| `*-play-*.apk` | Sklep Play |
|
* frekwencja
|
||||||
|
* procent frekwencji
|
||||||
|
* sprawdziany
|
||||||
|
* plan lekcji
|
||||||
|
* lekcje zrealizowane
|
||||||
|
* wiadomości
|
||||||
|
* zadania domowe
|
||||||
|
* uwagi
|
||||||
|
* szczęśliwy numerek
|
||||||
|
* dodatkowe lekcje
|
||||||
|
* zebrania w szkole
|
||||||
|
* informacje o uczniu i szkole
|
||||||
|
* obliczanie średniej niezależnie od preferencji szkoły
|
||||||
|
* powiadomienia np. o nowej ocenie
|
||||||
|
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
|
||||||
|
* ciemny i czarny (AMOLED) motyw
|
||||||
|
* tryb offline
|
||||||
|
* opcjonalne reklamy umożliwiające wsparcie projektu
|
||||||
|
|
||||||
Pobierz wybraną wersję z [wydań](https://git.sador.me/sadorowo/wulkanowy-mod/releases).
|
## Pobierz
|
||||||
Zalecamy pobranie najnowszej dostępnej wersji.
|
|
||||||
|
|
||||||
# O projekcie Wulkanowy
|
Aktualną wersję możesz pobrać ze sklepu Google Play, F-Droid lub Huawei AppGallery
|
||||||
|
|
||||||
Chcesz poczytać więcej o projekcie Wulkanowy? [Kliknij tutaj](https://github.com/wulkanowy/wulkanowy)
|
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||||
|
alt="Pobierz z Google Play"
|
||||||
|
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Pobierz z F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
[<img src="appgallery_badge.png"
|
||||||
|
alt="Odkrywaj w AppGallery"
|
||||||
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
|
|
||||||
|
Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#download), która zawiera nowe funkcje przygotowywane do następnego wydania
|
||||||
|
|
||||||
|
|
||||||
|
## Zbudowana za pomocą
|
||||||
|
|
||||||
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
|
||||||
|
* [Hilt](https://dagger.dev/hilt/)
|
||||||
|
* [Room](https://developer.android.com/topic/libraries/architecture/room)
|
||||||
|
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
|
||||||
|
|
||||||
|
## Współpraca
|
||||||
|
|
||||||
|
Wnieś swój wkład w projekt, tworząc PR lub wysyłając issue na GitHub.
|
||||||
|
|
||||||
|
Dla osób zainteresowanych tłumaczeniem aplikacji na różne języki udostępniamy Crowdina
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
|
## Licencja
|
||||||
|
|
||||||
|
Ten projekt udostępniany jest na licencji Apache License 2.0 - szczegóły w pliku [LICENSE](LICENSE)
|
||||||
|
88
README.sk.md
88
README.sk.md
@ -1,33 +1,73 @@
|
|||||||
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / Slovenská verzia
|
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / Slovenská verzia
|
||||||
|
|
||||||
# Wulkanowy MOD
|
# Wulkanowy
|
||||||
|
|
||||||
## Funkcie:
|
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=develop&style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
|
||||||
* skryť známky
|
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
|
||||||
* Skryť individuálne záznamy o dochádzke.
|
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
|
||||||
* Skryť komentáre.
|
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
* falošná dochádzka %
|
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
|
||||||
|
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
|
||||||
|
|
||||||
Ak chcete prejsť na skrytý panel:
|
Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
|
||||||
1. Prejdite na kartu „Viac“.
|
|
||||||
2. Prejdite na panel „Nastavenia“.
|
|
||||||
3. Prejdite na panel „O aplikácii“.
|
|
||||||
4. Kliknite 5-krát na logo aplikácie
|
|
||||||
5. Prejdite na domovskú obrazovku
|
|
||||||
6. Prejdite do nastavení
|
|
||||||
7. Zadajte „tajné nastavenia“
|
|
||||||
|
|
||||||
# Inštalácia
|
## Funkcie
|
||||||
|
|
||||||
| Názov súboru | Prispôsobené |
|
* prihlásenie pomocou emailu a hesla
|
||||||
| ---------------- | ----------------- |
|
* funkcie z webovej stránky denníka:
|
||||||
| `*-fdroid-*.apk` | F-Droid |
|
* známky
|
||||||
| `*-hms-*.apk` | Huawei AppGallery |
|
* štatistiky známok
|
||||||
| `*-play-*.apk` | Play Store |
|
* frekvencia
|
||||||
|
* percento frekvencie
|
||||||
|
* skúšky
|
||||||
|
* plán lekcie
|
||||||
|
* dokončené lekcie
|
||||||
|
* správy
|
||||||
|
* domáce úlohy
|
||||||
|
* poznámky
|
||||||
|
* šťastné číslo
|
||||||
|
* ďalšie lekcie
|
||||||
|
* školské stretnutie
|
||||||
|
* informácie o žiakovi a škole
|
||||||
|
* výpočet priemeru nezávisle od preferencií školy
|
||||||
|
* upozornenia, napr. o nových známkach
|
||||||
|
* podpora viacerých účtov s možnosťou premenovania žiakov
|
||||||
|
* tmavý a čierny (AMOLED) motív
|
||||||
|
* offline režim
|
||||||
|
* voliteľné reklamy na podporu projektu
|
||||||
|
|
||||||
Stiahnite si vybranú verziu z [releases](https://git.sador.me/sadorowo/wulkanowy-mod/releases).
|
## Stiahnuť
|
||||||
Odporúčame stiahnuť najnovšiu dostupnú verziu.
|
|
||||||
|
|
||||||
# O projekte Wulkanowy
|
Aktuálnu verziu si môžete stiahnuť z Google Play, F-Droid alebo Huawei AppGallery
|
||||||
|
|
||||||
Chcete si prečítať viac o projekte Wulkanowy? [Kliknite sem](https://github.com/wulkanowy/wulkanowy)
|
[<img src="https://play.google.com/intl/sk/badges/images/generic/sk_badge_web_generic.png"
|
||||||
|
alt="Nyní na Google Play"
|
||||||
|
height="80">](https://play.google.com/store/apps/details?id=io.github.wulkanowy)
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Stiahnuť s F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/io.github.wulkanowy/)
|
||||||
|
[<img src="https://i.imgur.com/sX8UyAw.png"
|
||||||
|
alt="Objavíte v AppGallery"
|
||||||
|
height="80">](https://appgallery.cloud.huawei.com/ag/n/app/C101440411?channelId=Badge&id=1b3f7fbb700849a9be0dba6b520b2282&s=EB1D3BF9ED9D1564D869B7B94B18016D3CABFCA5AEFB8E29F675FA04E0DC131D&detailType=0&v=)
|
||||||
|
|
||||||
|
Môžete si tiež stiahnuť [vývojovú verziu](https://wulkanowy.github.io/#download), ktorá zahrňuje nové funkcie pripravované pre budúce vydanie
|
||||||
|
|
||||||
|
## Postavené s pomocou
|
||||||
|
|
||||||
|
|
||||||
|
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
|
||||||
|
* [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html)
|
||||||
|
* [Hilt](https://dagger.dev/hilt/)
|
||||||
|
* [Room](https://developer.android.com/topic/libraries/architecture/room)
|
||||||
|
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)
|
||||||
|
|
||||||
|
## Spolupráca
|
||||||
|
|
||||||
|
Prispejte do projektu vytvorením PR alebo odoslaním issue na GitHub.
|
||||||
|
|
||||||
|
Pre záujemcov o preklad aplikácie do rôznych jazykov poskytujeme Crowdin:
|
||||||
|
https://crowdin.com/project/wulkanowy2
|
||||||
|
|
||||||
|
## Licencia
|
||||||
|
|
||||||
|
Tento projekt je licencovaný pod licenciou Apache License 2.0 - podrobnosti v súbore [LICENSE](LICENSE)
|
||||||
|
@ -27,8 +27,8 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 34
|
targetSdkVersion 34
|
||||||
versionCode 173
|
versionCode 161
|
||||||
versionName "2.6.13"
|
versionName "2.6.1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
resValue "string", "app_name", "Wulkanowy"
|
resValue "string", "app_name", "Wulkanowy"
|
||||||
@ -62,8 +62,8 @@ android {
|
|||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
// signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
||||||
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
|
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
|
||||||
}
|
}
|
||||||
@ -160,8 +160,8 @@ play {
|
|||||||
defaultToAppBundles = false
|
defaultToAppBundles = false
|
||||||
track = 'production'
|
track = 'production'
|
||||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||||
userFraction = 0.1d
|
userFraction = 0.25d
|
||||||
updatePriority = 2
|
updatePriority = 1
|
||||||
enabled.set(false)
|
enabled.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,17 +187,16 @@ ext {
|
|||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
chucker = "4.0.0"
|
chucker = "4.0.0"
|
||||||
mockk = "1.13.10"
|
mockk = "1.13.10"
|
||||||
coroutines = "1.8.1"
|
coroutines = "1.8.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'io.github.wulkanowy:sdk:2.6.11'
|
implementation 'io.github.wulkanowy:sdk:2.6.0'
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:$coroutines"
|
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.13.1'
|
implementation 'androidx.core:core-ktx:1.13.1'
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||||
@ -205,7 +204,6 @@ dependencies {
|
|||||||
implementation "androidx.appcompat:appcompat:1.6.1"
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||||
implementation "androidx.fragment:fragment-ktx:1.7.0"
|
implementation "androidx.fragment:fragment-ktx:1.7.0"
|
||||||
implementation "androidx.annotation:annotation:1.7.1"
|
implementation "androidx.annotation:annotation:1.7.1"
|
||||||
implementation "androidx.javascriptengine:javascriptengine:1.0.0-beta01"
|
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.2.1"
|
implementation "androidx.preference:preference-ktx:1.2.1"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.3.2"
|
implementation "androidx.recyclerview:recyclerview:1.3.2"
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:installLocation="internalOnly">
|
android:installLocation="internalOnly">
|
||||||
|
|
||||||
<uses-sdk tools:overrideLibrary="androidx.javascriptengine" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
@ -44,9 +42,9 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:resizeableActivity="true"
|
|
||||||
android:supportsRtl="false"
|
android:supportsRtl="false"
|
||||||
android:theme="@style/WulkanowyTheme"
|
android:theme="@style/WulkanowyTheme"
|
||||||
|
android:resizeableActivity="true"
|
||||||
tools:ignore="DataExtractionRules,UnusedAttribute">
|
tools:ignore="DataExtractionRules,UnusedAttribute">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.splash.SplashActivity"
|
android:name=".ui.modules.splash.SplashActivity"
|
||||||
|
@ -13,8 +13,8 @@ import dagger.Provides
|
|||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import io.github.wulkanowy.data.api.services.SchoolsService
|
import io.github.wulkanowy.data.api.AdminMessageService
|
||||||
import io.github.wulkanowy.data.api.services.WulkanowyService
|
import io.github.wulkanowy.data.api.SchoolsService
|
||||||
import io.github.wulkanowy.data.db.AppDatabase
|
import io.github.wulkanowy.data.db.AppDatabase
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
@ -71,7 +71,7 @@ internal class DataModule {
|
|||||||
okHttpClient: OkHttpClient,
|
okHttpClient: OkHttpClient,
|
||||||
json: Json,
|
json: Json,
|
||||||
appInfo: AppInfo
|
appInfo: AppInfo
|
||||||
): WulkanowyService = Retrofit.Builder()
|
): AdminMessageService = Retrofit.Builder()
|
||||||
.baseUrl(appInfo.messagesBaseUrl)
|
.baseUrl(appInfo.messagesBaseUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||||
|
@ -1,21 +1,13 @@
|
|||||||
package io.github.wulkanowy.data
|
package io.github.wulkanowy.data
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.javascriptengine.JavaScriptSandbox
|
|
||||||
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
import com.chuckerteam.chucker.api.ChuckerInterceptor
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import io.github.wulkanowy.data.db.dao.StudentDao
|
import io.github.wulkanowy.data.db.dao.StudentDao
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
|
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
|
||||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.scrapper.EvaluateHandler
|
|
||||||
import io.github.wulkanowy.utils.RemoteConfigHelper
|
import io.github.wulkanowy.utils.RemoteConfigHelper
|
||||||
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
||||||
import kotlinx.coroutines.guava.await
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -24,24 +16,18 @@ import javax.inject.Singleton
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class WulkanowySdkFactory @Inject constructor(
|
class WulkanowySdkFactory @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
private val chuckerInterceptor: ChuckerInterceptor,
|
private val chuckerInterceptor: ChuckerInterceptor,
|
||||||
private val remoteConfig: RemoteConfigHelper,
|
private val remoteConfig: RemoteConfigHelper,
|
||||||
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
|
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
|
||||||
private val studentDb: StudentDao,
|
private val studentDb: StudentDao,
|
||||||
private val wulkanowyRepository: WulkanowyRepository,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val eduOneMutex = Mutex()
|
private val eduOneMutex = Mutex()
|
||||||
private val migrationFailedStudentIds = mutableSetOf<Long>()
|
private val migrationFailedStudentIds = mutableSetOf<Long>()
|
||||||
private val sandbox: ListenableFuture<JavaScriptSandbox>? =
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && JavaScriptSandbox.isSupported())
|
|
||||||
JavaScriptSandbox.createConnectedInstanceAsync(context)
|
|
||||||
else null
|
|
||||||
|
|
||||||
private val sdk = Sdk().apply {
|
private val sdk = Sdk().apply {
|
||||||
androidVersion = Build.VERSION.RELEASE
|
androidVersion = android.os.Build.VERSION.RELEASE
|
||||||
buildTag = Build.MODEL
|
buildTag = android.os.Build.MODEL
|
||||||
userAgentTemplate = remoteConfig.userAgentTemplate
|
userAgentTemplate = remoteConfig.userAgentTemplate
|
||||||
setSimpleHttpLogger { Timber.d(it) }
|
setSimpleHttpLogger { Timber.d(it) }
|
||||||
setAdditionalCookieManager(webkitCookieManagerProxy)
|
setAdditionalCookieManager(webkitCookieManagerProxy)
|
||||||
@ -50,46 +36,14 @@ class WulkanowySdkFactory @Inject constructor(
|
|||||||
addInterceptor(chuckerInterceptor, network = true)
|
addInterceptor(chuckerInterceptor, network = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createBase() = sdk
|
fun create() = sdk
|
||||||
|
|
||||||
suspend fun create(): Sdk {
|
|
||||||
val mapping = wulkanowyRepository.getMapping()
|
|
||||||
|
|
||||||
return createBase().apply {
|
|
||||||
if (mapping != null) {
|
|
||||||
endpointsMapping = mapping.endpoints
|
|
||||||
vTokenMapping = mapping.vTokens
|
|
||||||
vHeaders = mapping.vHeaders
|
|
||||||
vParamsEvaluation = createIsolate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun createIsolate(): suspend () -> EvaluateHandler {
|
|
||||||
return {
|
|
||||||
val isolate = sandbox?.await()?.createIsolate()
|
|
||||||
object : EvaluateHandler {
|
|
||||||
override suspend fun evaluate(code: String): String? {
|
|
||||||
return isolate?.evaluateJavaScriptAsync(code)?.await()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
isolate?.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun create(student: Student, semester: Semester? = null): Sdk {
|
suspend fun create(student: Student, semester: Semester? = null): Sdk {
|
||||||
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
|
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
|
||||||
return buildSdk(student, semester, overrideIsEduOne)
|
return buildSdk(student, semester, overrideIsEduOne)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun buildSdk(
|
private fun buildSdk(student: Student, semester: Semester?, isStudentEduOne: Boolean): Sdk {
|
||||||
student: Student,
|
|
||||||
semester: Semester?,
|
|
||||||
isStudentEduOne: Boolean
|
|
||||||
): Sdk {
|
|
||||||
return create().apply {
|
return create().apply {
|
||||||
email = student.email
|
email = student.email
|
||||||
password = student.password
|
password = student.password
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
package io.github.wulkanowy.data.api.services
|
package io.github.wulkanowy.data.api
|
||||||
|
|
||||||
import io.github.wulkanowy.data.api.models.Mapping
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
interface WulkanowyService {
|
interface AdminMessageService {
|
||||||
|
|
||||||
@GET("/v1.json")
|
@GET("/v1.json")
|
||||||
suspend fun getAdminMessages(): List<AdminMessage>
|
suspend fun getAdminMessages(): List<AdminMessage>
|
||||||
|
|
||||||
@GET("/mapping2.json")
|
|
||||||
suspend fun getMapping(): Mapping
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.wulkanowy.data.api.services
|
package io.github.wulkanowy.data.api
|
||||||
|
|
||||||
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
||||||
import io.github.wulkanowy.data.pojos.LoginEvent
|
import io.github.wulkanowy.data.pojos.LoginEvent
|
@ -1,20 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.api.models
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Mapping(
|
|
||||||
|
|
||||||
@SerialName("endpoints")
|
|
||||||
val endpoints: Map<String, Map<String, Map<String, String>>>,
|
|
||||||
|
|
||||||
@SerialName("vTokens")
|
|
||||||
val vTokens: Map<String, Map<String, Map<String, String>>>,
|
|
||||||
|
|
||||||
@SerialName("vTokenScheme")
|
|
||||||
val vTokenScheme: Map<String, Map<String, String>> = emptyMap(),
|
|
||||||
|
|
||||||
@SerialName("vHeaders")
|
|
||||||
val vHeaders: Map<String, Map<String, Map<String, String>>> = emptyMap(),
|
|
||||||
)
|
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import io.github.wulkanowy.data.db.entities.Attendance
|
import io.github.wulkanowy.data.db.entities.Attendance
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
@ -12,8 +12,4 @@ interface GradeDao : BaseDao<Grade> {
|
|||||||
|
|
||||||
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
|
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
|
||||||
fun loadAll(semesterId: Int, studentId: Int): Flow<List<Grade>>
|
fun loadAll(semesterId: Int, studentId: Int): Flow<List<Grade>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId " +
|
|
||||||
"AND entry NOT IN(:censoredEntries)")
|
|
||||||
fun loadAllCensored(semesterId: Int, studentId: Int, censoredEntries: Array<String>): Flow<List<Grade>>
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Dao
|
@Dao
|
||||||
interface NoteDao : BaseDao<Note> {
|
interface NoteDao : BaseDao<Note> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Notes WHERE student_id = :studentId")
|
@Query("SELECT * FROM Notes WHERE student_id = :studentId")
|
||||||
fun loadAll(studentId: Int): Flow<List<Note>>
|
fun loadAll(studentId: Int): Flow<List<Note>>
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import io.github.wulkanowy.data.db.entities.School
|
import io.github.wulkanowy.data.db.entities.School
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -11,5 +12,16 @@ import javax.inject.Singleton
|
|||||||
interface SchoolDao : BaseDao<School> {
|
interface SchoolDao : BaseDao<School> {
|
||||||
|
|
||||||
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
|
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
|
||||||
fun load(studentId: Int, classId: Int): Flow<School?>
|
fun loadWithClassId(studentId: Int, classId: Int): Flow<School?>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM School WHERE student_id = :studentId")
|
||||||
|
fun loadNoClassId(studentId: Int): Flow<School?>
|
||||||
|
|
||||||
|
fun load(student: Student): Flow<School?> {
|
||||||
|
return if (student.isEduOne == true) {
|
||||||
|
loadNoClassId(student.studentId)
|
||||||
|
} else {
|
||||||
|
loadWithClassId(student.studentId, student.classId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import androidx.room.Insert
|
|||||||
import androidx.room.OnConflictStrategy
|
import androidx.room.OnConflictStrategy
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@ -14,6 +15,17 @@ interface SemesterDao : BaseDao<Semester> {
|
|||||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
suspend fun insertSemesters(items: List<Semester>): List<Long>
|
suspend fun insertSemesters(items: List<Semester>): List<Long>
|
||||||
|
|
||||||
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId) OR (student_id = :studentId AND class_id = 0)")
|
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId)")
|
||||||
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
|
suspend fun loadAllWithClassId(studentId: Int, classId: Int): List<Semester>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||||
|
suspend fun loadAllNoClassId(studentId: Int): List<Semester>
|
||||||
|
|
||||||
|
suspend fun loadAll(student: Student): List<Semester> {
|
||||||
|
return if (student.isEduOne == true) {
|
||||||
|
loadAllNoClassId(student.studentId)
|
||||||
|
} else {
|
||||||
|
loadAllWithClassId(student.studentId, student.classId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,13 +47,9 @@ abstract class StudentDao {
|
|||||||
abstract suspend fun loadAll(): List<Student>
|
abstract suspend fun loadAll(): List<Student>
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0)")
|
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id)")
|
||||||
abstract suspend fun loadStudentsWithSemesters(): Map<Student, List<Semester>>
|
abstract suspend fun loadStudentsWithSemesters(): Map<Student, List<Semester>>
|
||||||
|
|
||||||
@Transaction
|
|
||||||
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0) WHERE Students.id = :id")
|
|
||||||
abstract suspend fun loadStudentWithSemestersById(id: Long): Map<Student, List<Semester>>
|
|
||||||
|
|
||||||
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||||
abstract suspend fun updateCurrent(id: Long)
|
abstract suspend fun updateCurrent(id: Long)
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.data.db.dao
|
|||||||
|
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.Teacher
|
import io.github.wulkanowy.data.db.entities.Teacher
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -11,5 +12,16 @@ import javax.inject.Singleton
|
|||||||
interface TeacherDao : BaseDao<Teacher> {
|
interface TeacherDao : BaseDao<Teacher> {
|
||||||
|
|
||||||
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
|
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
|
||||||
fun loadAll(studentId: Int, classId: Int): Flow<List<Teacher>>
|
fun loadAllWithClassId(studentId: Int, classId: Int): Flow<List<Teacher>>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM Teachers WHERE student_id = :studentId")
|
||||||
|
fun loadAllNoClassId(studentId: Int): Flow<List<Teacher>>
|
||||||
|
|
||||||
|
fun loadAll(student: Student): Flow<List<Teacher>> {
|
||||||
|
return if (student.isEduOne == true) {
|
||||||
|
loadAllNoClassId(student.studentId)
|
||||||
|
} else {
|
||||||
|
loadAllWithClassId(student.studentId, student.classId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,15 @@ import androidx.sqlite.db.SupportSQLiteDatabase
|
|||||||
class Migration63 : AutoMigrationSpec {
|
class Migration63 : AutoMigrationSpec {
|
||||||
|
|
||||||
override fun onPostMigrate(db: SupportSQLiteDatabase) {
|
override fun onPostMigrate(db: SupportSQLiteDatabase) {
|
||||||
db.execSQL("UPDATE Students SET is_edu_one = NULL WHERE is_edu_one = 0")
|
db.execSQL("DROP TABLE IF EXISTS `Semesters`")
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS `School`")
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS `Teachers`")
|
||||||
|
|
||||||
|
db.execSQL("CREATE TABLE IF NOT EXISTS `Semesters` (`student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `kindergarten_diary_id` INTEGER NOT NULL DEFAULT 0, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL)")
|
||||||
|
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_kindergarten_diary_id_semester_id` ON `Semesters` (`student_id`, `diary_id`, `kindergarten_diary_id`, `semester_id`)")
|
||||||
|
db.execSQL("CREATE TABLE IF NOT EXISTS `School` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)")
|
||||||
|
db.execSQL("CREATE TABLE IF NOT EXISTS `Teachers` (`student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)")
|
||||||
|
|
||||||
|
db.execSQL("UPDATE Students SET is_edu_one = NULL")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ enum class AppTheme(val value: String) {
|
|||||||
BLACK("black");
|
BLACK("black");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = entries.find { it.value == value } ?: LIGHT
|
fun getByValue(value: String) = values().find { it.value == value } ?: LIGHT
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,6 @@ enum class GradeColorTheme(val value: String) : Serializable {
|
|||||||
GRADE_COLOR("grade_color");
|
GRADE_COLOR("grade_color");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = entries.find { it.value == value } ?: VULCAN
|
fun getByValue(value: String) = values().find { it.value == value } ?: VULCAN
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,6 @@ enum class GradeExpandMode(val value: String) {
|
|||||||
ALWAYS_EXPANDED("always");
|
ALWAYS_EXPANDED("always");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = entries.find { it.value == value } ?: ONE
|
fun getByValue(value: String) = values().find { it.value == value } ?: ONE
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,6 @@ enum class GradeSortingMode(val value: String) {
|
|||||||
AVERAGE("average");
|
AVERAGE("average");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = entries.find { it.value == value } ?: ALPHABETIC
|
fun getByValue(value: String) = values().find { it.value == value } ?: ALPHABETIC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,6 @@ enum class TimetableMode(val value: String) {
|
|||||||
SMALL_OTHER_GROUP("small");
|
SMALL_OTHER_GROUP("small");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = entries.find { it.value == value } ?: ONLY_CURRENT_GROUP
|
fun getByValue(value: String) = values().find { it.value == value } ?: ONLY_CURRENT_GROUP
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package io.github.wulkanowy.data.exceptions
|
||||||
|
|
||||||
|
class NoSuchStudentException(id: Long) :
|
||||||
|
Exception("There is no student with id $id in database")
|
@ -0,0 +1,34 @@
|
|||||||
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.Resource
|
||||||
|
import io.github.wulkanowy.data.api.AdminMessageService
|
||||||
|
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
||||||
|
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||||
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.filterNot
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class AdminMessageRepository @Inject constructor(
|
||||||
|
private val adminMessageService: AdminMessageService,
|
||||||
|
private val adminMessageDao: AdminMessageDao,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
|
fun getAdminMessages(): Flow<Resource<List<AdminMessage>>> =
|
||||||
|
networkBoundResource(
|
||||||
|
mutex = saveFetchResultMutex,
|
||||||
|
isResultEmpty = { false },
|
||||||
|
query = { adminMessageDao.loadAll() },
|
||||||
|
fetch = { adminMessageService.getAdminMessages() },
|
||||||
|
shouldFetch = { true },
|
||||||
|
saveFetchResult = { oldItems, newItems ->
|
||||||
|
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.filterNot { it is Resource.Intermediate }
|
||||||
|
}
|
@ -9,15 +9,12 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
import io.github.wulkanowy.data.networkBoundResource
|
||||||
import io.github.wulkanowy.sdk.pojo.Absent
|
import io.github.wulkanowy.sdk.pojo.Absent
|
||||||
import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance
|
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
import io.github.wulkanowy.utils.AutoRefreshHelper
|
||||||
import io.github.wulkanowy.utils.getRefreshKey
|
import io.github.wulkanowy.utils.getRefreshKey
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
import io.github.wulkanowy.utils.sunday
|
import io.github.wulkanowy.utils.sunday
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
@ -31,71 +28,12 @@ class AttendanceRepository @Inject constructor(
|
|||||||
private val timetableDb: TimetableDao,
|
private val timetableDb: TimetableDao,
|
||||||
private val wulkanowySdkFactory: WulkanowySdkFactory,
|
private val wulkanowySdkFactory: WulkanowySdkFactory,
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private val cacheKey = "attendance"
|
private val cacheKey = "attendance"
|
||||||
|
|
||||||
private fun filterAttendance(
|
|
||||||
hiddenAttendanceTiles: List<DashboardItem.HiddenAttendanceTile>,
|
|
||||||
attendanceItem: Attendance
|
|
||||||
): Boolean {
|
|
||||||
return when {
|
|
||||||
attendanceItem.absence && attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.EXCUSED_ABSENCE
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.absence && !attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.UNEXCUSED_ABSENCE
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.lateness && attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.EXCUSED_LATENESS
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.lateness && !attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.UNEXCUSED_LATENESS
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.exemption && hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.EXEMPTION) -> false
|
|
||||||
attendanceItem.deleted && hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.DELETED) -> false
|
|
||||||
attendanceItem.presence && hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.PRESENT) -> false
|
|
||||||
|
|
||||||
else -> !hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.UNKNOWN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun filterAttendance(
|
|
||||||
hiddenAttendanceTiles: List<DashboardItem.HiddenAttendanceTile>,
|
|
||||||
attendanceItem: SdkAttendance
|
|
||||||
): Boolean {
|
|
||||||
return when {
|
|
||||||
attendanceItem.absence && attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.EXCUSED_ABSENCE
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.absence && !attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.UNEXCUSED_ABSENCE
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.lateness && attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.EXCUSED_LATENESS
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.lateness && !attendanceItem.excused && hiddenAttendanceTiles.contains(
|
|
||||||
DashboardItem.HiddenAttendanceTile.UNEXCUSED_LATENESS
|
|
||||||
) -> false
|
|
||||||
|
|
||||||
attendanceItem.exemption && hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.EXEMPTION) -> false
|
|
||||||
attendanceItem.deleted && hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.DELETED) -> false
|
|
||||||
attendanceItem.presence && hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.PRESENT) -> false
|
|
||||||
|
|
||||||
else -> !hiddenAttendanceTiles.contains(DashboardItem.HiddenAttendanceTile.UNKNOWN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAttendance(
|
fun getAttendance(
|
||||||
student: Student,
|
student: Student,
|
||||||
semester: Semester,
|
semester: Semester,
|
||||||
@ -113,24 +51,14 @@ class AttendanceRepository @Inject constructor(
|
|||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = {
|
query = {
|
||||||
val hiddenAttendanceItems = preferencesRepository.hiddenAttendanceItems
|
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
||||||
|
|
||||||
attendanceDb
|
|
||||||
.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
|
||||||
.map {
|
|
||||||
it.filter { item -> filterAttendance(hiddenAttendanceItems, item) }
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
val hiddenAttendanceItems = preferencesRepository.hiddenAttendanceItems
|
|
||||||
|
|
||||||
val lessons = timetableDb.load(
|
val lessons = timetableDb.load(
|
||||||
semester.diaryId, semester.studentId, start.monday, end.sunday
|
semester.diaryId, semester.studentId, start.monday, end.sunday
|
||||||
)
|
)
|
||||||
|
|
||||||
wulkanowySdkFactory.create(student, semester)
|
wulkanowySdkFactory.create(student, semester)
|
||||||
.getAttendance(start.monday, end.sunday)
|
.getAttendance(start.monday, end.sunday)
|
||||||
.filter { item -> filterAttendance(hiddenAttendanceItems, item) }
|
|
||||||
.mapToEntities(semester, lessons)
|
.mapToEntities(semester, lessons)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
@ -151,13 +79,7 @@ class AttendanceRepository @Inject constructor(
|
|||||||
start: LocalDate,
|
start: LocalDate,
|
||||||
end: LocalDate
|
end: LocalDate
|
||||||
): Flow<List<Attendance>> {
|
): Flow<List<Attendance>> {
|
||||||
val hiddenAttendanceItems = preferencesRepository.hiddenAttendanceItems
|
return attendanceDb.loadAll(semester.diaryId, semester.studentId, start, end)
|
||||||
|
|
||||||
return attendanceDb
|
|
||||||
.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
|
|
||||||
.map {
|
|
||||||
it.filter { item -> filterAttendance(hiddenAttendanceItems, item) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateTimetable(timetable: List<Attendance>) {
|
suspend fun updateTimetable(timetable: List<Attendance>) {
|
||||||
|
@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import timber.log.Timber
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -31,18 +30,10 @@ class GradeRepository @Inject constructor(
|
|||||||
private val gradeDescriptiveDb: GradeDescriptiveDao,
|
private val gradeDescriptiveDb: GradeDescriptiveDao,
|
||||||
private val wulkanowySdkFactory: WulkanowySdkFactory,
|
private val wulkanowySdkFactory: WulkanowySdkFactory,
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
|
|
||||||
private fun loadGrades(semesterId: Int, studentId: Int): Flow<List<Grade>> {
|
|
||||||
val hiddenGrades = preferencesRepository.hiddenGrades
|
|
||||||
|
|
||||||
Timber.i("Load grades for semester $semesterId student $studentId")
|
|
||||||
return gradeDb.loadAllCensored(semesterId, studentId, hiddenGrades.toTypedArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getGrades(
|
fun getGrades(
|
||||||
student: Student,
|
student: Student,
|
||||||
semester: Semester,
|
semester: Semester,
|
||||||
@ -70,15 +61,11 @@ class GradeRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetch = {
|
fetch = {
|
||||||
val hiddenGrades = preferencesRepository.hiddenGrades
|
|
||||||
|
|
||||||
val (details, summary, descriptive) = wulkanowySdkFactory.create(student, semester)
|
val (details, summary, descriptive) = wulkanowySdkFactory.create(student, semester)
|
||||||
.getGrades(semester.semesterId)
|
.getGrades(semester.semesterId)
|
||||||
|
|
||||||
val censoredDetails = details.filterNot { it.entry in hiddenGrades }
|
|
||||||
|
|
||||||
Triple(
|
Triple(
|
||||||
censoredDetails.mapToEntities(semester),
|
details.mapToEntities(semester),
|
||||||
summary.mapToEntities(semester),
|
summary.mapToEntities(semester),
|
||||||
descriptive.mapToEntities(semester)
|
descriptive.mapToEntities(semester)
|
||||||
)
|
)
|
||||||
@ -170,13 +157,13 @@ class GradeRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
|
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
|
||||||
return loadGrades(semester.semesterId, semester.studentId).map {
|
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
|
||||||
it.filter { grade -> !grade.isRead }
|
it.filter { grade -> !grade.isRead }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesFromDatabase(semester: Semester): Flow<List<Grade>> {
|
fun getGradesFromDatabase(semester: Semester): Flow<List<Grade>> {
|
||||||
return loadGrades(semester.semesterId, semester.studentId)
|
return gradeDb.loadAll(semester.semesterId, semester.studentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesPredictedFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
|
fun getGradesPredictedFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
|
||||||
|
@ -21,7 +21,6 @@ class NoteRepository @Inject constructor(
|
|||||||
private val noteDb: NoteDao,
|
private val noteDb: NoteDao,
|
||||||
private val wulkanowySdkFactory: WulkanowySdkFactory,
|
private val wulkanowySdkFactory: WulkanowySdkFactory,
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
private val refreshHelper: AutoRefreshHelper,
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
private val saveFetchResultMutex = Mutex()
|
||||||
@ -40,16 +39,12 @@ class NoteRepository @Inject constructor(
|
|||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
val isExpired = refreshHelper.shouldBeRefreshed(
|
||||||
getRefreshKey(cacheKey, semester)
|
getRefreshKey(cacheKey, semester)
|
||||||
)
|
)
|
||||||
|
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { noteDb.loadAll(student.studentId) },
|
query = { noteDb.loadAll(student.studentId) },
|
||||||
fetch = {
|
fetch = {
|
||||||
val showNotes = preferencesRepository.showNotes
|
|
||||||
|
|
||||||
wulkanowySdkFactory.create(student, semester)
|
wulkanowySdkFactory.create(student, semester)
|
||||||
.getNotes()
|
.getNotes()
|
||||||
.filter { showNotes }
|
|
||||||
.mapToEntities(semester)
|
.mapToEntities(semester)
|
||||||
},
|
},
|
||||||
saveFetchResult = { old, new ->
|
saveFetchResult = { old, new ->
|
||||||
|
@ -7,10 +7,8 @@ import androidx.core.content.edit
|
|||||||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
|
||||||
import com.fredporciuncula.flow.preferences.Preference
|
import com.fredporciuncula.flow.preferences.Preference
|
||||||
import com.fredporciuncula.flow.preferences.Serializer
|
import com.fredporciuncula.flow.preferences.Serializer
|
||||||
import com.fredporciuncula.flow.preferences.map
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.api.models.Mapping
|
|
||||||
import io.github.wulkanowy.data.enums.AppTheme
|
import io.github.wulkanowy.data.enums.AppTheme
|
||||||
import io.github.wulkanowy.data.enums.AttendanceCalculatorSortingMode
|
import io.github.wulkanowy.data.enums.AttendanceCalculatorSortingMode
|
||||||
import io.github.wulkanowy.data.enums.GradeColorTheme
|
import io.github.wulkanowy.data.enums.GradeColorTheme
|
||||||
@ -26,7 +24,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import timber.log.Timber
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -39,7 +36,6 @@ class PreferencesRepository @Inject constructor(
|
|||||||
private val flowSharedPref: FlowSharedPreferences,
|
private val flowSharedPref: FlowSharedPreferences,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
) {
|
) {
|
||||||
private val NO_ATTENDANCE_VALUE = -1.0
|
|
||||||
|
|
||||||
val isShowPresent: Boolean
|
val isShowPresent: Boolean
|
||||||
get() = getBoolean(
|
get() = getBoolean(
|
||||||
@ -305,60 +301,6 @@ class PreferencesRepository @Inject constructor(
|
|||||||
selectedDashboardTilesPreference.set(filteredValue)
|
selectedDashboardTilesPreference.set(filteredValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
var attendancePercentage: Double?
|
|
||||||
get() = attendancePercentagePreference.get().takeIf { it != NO_ATTENDANCE_VALUE }
|
|
||||||
set(value) = attendancePercentagePreference.set(value ?: NO_ATTENDANCE_VALUE)
|
|
||||||
|
|
||||||
var hiddenAttendanceItems: List<DashboardItem.HiddenAttendanceTile>
|
|
||||||
get() = hiddenAttendanceItemsPreference.get().toList()
|
|
||||||
set(value) = hiddenAttendanceItemsPreference.set(value.toSet())
|
|
||||||
|
|
||||||
var hiddenGrades: List<String>
|
|
||||||
get() = hiddenGradesPreference.get().toList()
|
|
||||||
set(value) = hiddenGradesPreference.set(value.toSet())
|
|
||||||
|
|
||||||
var showNotes: Boolean
|
|
||||||
get() = showNotesPreference.get()
|
|
||||||
set(value) = showNotesPreference.set(value)
|
|
||||||
|
|
||||||
var developerMode: Boolean
|
|
||||||
get() = developerModePreference.get()
|
|
||||||
set(value) = developerModePreference.set(value)
|
|
||||||
|
|
||||||
private val developerModePreference: Preference<Boolean>
|
|
||||||
get() = flowSharedPref.getBoolean(
|
|
||||||
context.getString(R.string.pref_key_developer_mode),
|
|
||||||
context.resources.getBoolean(R.bool.pref_default_developer_mode)
|
|
||||||
)
|
|
||||||
|
|
||||||
private val hiddenGradesPreference: Preference<Set<String>>
|
|
||||||
get() {
|
|
||||||
val defaultSet = context.resources.getStringArray(R.array.pref_default_hidden_grades).toSet()
|
|
||||||
val prefKey = "hidden_grades"
|
|
||||||
|
|
||||||
return flowSharedPref.getStringSet(prefKey, defaultSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val showNotesPreference: Preference<Boolean>
|
|
||||||
get() = flowSharedPref.getBoolean(
|
|
||||||
context.getString(R.string.pref_key_show_notes),
|
|
||||||
context.resources.getBoolean(R.bool.pref_default_show_notes)
|
|
||||||
)
|
|
||||||
|
|
||||||
private val hiddenAttendanceItemsPreference: Preference<Set<DashboardItem.HiddenAttendanceTile>>
|
|
||||||
get() {
|
|
||||||
val defaultSet =
|
|
||||||
context.resources.getStringArray(R.array.pref_default_hidden_attendance_items).toSet()
|
|
||||||
val prefKey = "attendance_items"
|
|
||||||
|
|
||||||
return flowSharedPref
|
|
||||||
.getStringSet(prefKey, defaultSet)
|
|
||||||
.map(
|
|
||||||
mapper = { it -> it.map { DashboardItem.HiddenAttendanceTile.valueOf(it) }.toSet() },
|
|
||||||
reverse = { it -> it.map { it.name }.toSet() }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val selectedDashboardTilesPreference: Preference<Set<String>>
|
private val selectedDashboardTilesPreference: Preference<Set<String>>
|
||||||
get() {
|
get() {
|
||||||
val defaultSet =
|
val defaultSet =
|
||||||
@ -368,19 +310,6 @@ class PreferencesRepository @Inject constructor(
|
|||||||
return flowSharedPref.getStringSet(prefKey, defaultSet)
|
return flowSharedPref.getStringSet(prefKey, defaultSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val attendancePercentagePreference: Preference<Double>
|
|
||||||
get() {
|
|
||||||
val prefKey = context.getString(R.string.pref_key_attendance_percentage)
|
|
||||||
val defaultValue = context.resources.getString(R.string.pref_default_attendance_percentage)
|
|
||||||
|
|
||||||
return flowSharedPref
|
|
||||||
.getString(prefKey, defaultValue)
|
|
||||||
.map(
|
|
||||||
mapper = { it.toDoubleOrNull() ?: NO_ATTENDANCE_VALUE },
|
|
||||||
reverse = { it.toString() }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
var dismissedAdminMessageIds: List<Int>
|
var dismissedAdminMessageIds: List<Int>
|
||||||
get() = sharedPref.getStringSet(PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS, emptySet())
|
get() = sharedPref.getStringSet(PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS, emptySet())
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
@ -446,15 +375,6 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
|
||||||
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
|
||||||
|
|
||||||
var mapping: Mapping?
|
|
||||||
get() {
|
|
||||||
val value = sharedPref.getString("mapping", null)
|
|
||||||
return value?.let { json.decodeFromString(it) }
|
|
||||||
}
|
|
||||||
set(value) = sharedPref.edit(commit = true) {
|
|
||||||
putString("mapping", value?.let { json.encodeToString(it) })
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (installationId.isEmpty()) {
|
if (installationId.isEmpty()) {
|
||||||
installationId = UUID.randomUUID().toString()
|
installationId = UUID.randomUUID().toString()
|
||||||
|
@ -36,7 +36,7 @@ class SchoolRepository @Inject constructor(
|
|||||||
)
|
)
|
||||||
it == null || forceRefresh || isExpired
|
it == null || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { schoolDb.load(semester.studentId, semester.classId) },
|
query = { schoolDb.load(student) },
|
||||||
fetch = {
|
fetch = {
|
||||||
wulkanowySdkFactory.create(student, semester)
|
wulkanowySdkFactory.create(student, semester)
|
||||||
.getSchool()
|
.getSchool()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
package io.github.wulkanowy.data.repositories
|
||||||
|
|
||||||
import io.github.wulkanowy.data.WulkanowySdkFactory
|
import io.github.wulkanowy.data.WulkanowySdkFactory
|
||||||
import io.github.wulkanowy.data.api.services.SchoolsService
|
import io.github.wulkanowy.data.api.SchoolsService
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
@ -27,11 +27,11 @@ class SemesterRepository @Inject constructor(
|
|||||||
forceRefresh: Boolean = false,
|
forceRefresh: Boolean = false,
|
||||||
refreshOnNoCurrent: Boolean = false
|
refreshOnNoCurrent: Boolean = false
|
||||||
) = withContext(dispatchers.io) {
|
) = withContext(dispatchers.io) {
|
||||||
val semesters = semesterDb.loadAll(student.studentId, student.classId)
|
val semesters = semesterDb.loadAll(student)
|
||||||
|
|
||||||
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
|
||||||
refreshSemesters(student)
|
refreshSemesters(student)
|
||||||
semesterDb.loadAll(student.studentId, student.classId)
|
semesterDb.loadAll(student)
|
||||||
} else semesters
|
} else semesters
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ class SemesterRepository @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val old = semesterDb.loadAll(student.studentId, student.classId)
|
val old = semesterDb.loadAll(student)
|
||||||
semesterDb.removeOldAndSaveNew(
|
semesterDb.removeOldAndSaveNew(
|
||||||
oldItems = old uniqueSubtract new,
|
oldItems = old uniqueSubtract new,
|
||||||
newItems = new uniqueSubtract old,
|
newItems = new uniqueSubtract old,
|
||||||
|
@ -12,6 +12,7 @@ import io.github.wulkanowy.data.db.entities.StudentName
|
|||||||
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
|
import io.github.wulkanowy.data.exceptions.NoSuchStudentException
|
||||||
import io.github.wulkanowy.data.mappers.mapToEntities
|
import io.github.wulkanowy.data.mappers.mapToEntities
|
||||||
import io.github.wulkanowy.data.mappers.mapToPojo
|
import io.github.wulkanowy.data.mappers.mapToPojo
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||||
@ -65,7 +66,8 @@ class StudentRepository @Inject constructor(
|
|||||||
.mapToPojo(password)
|
.mapToPojo(password)
|
||||||
.also { it.logErrors() }
|
.also { it.logErrors() }
|
||||||
|
|
||||||
suspend fun getSavedStudents(decryptPass: Boolean = true): List<StudentWithSemesters> {
|
@Deprecated("Semesters are not synced within this method and students with empty semesters are not returned")
|
||||||
|
suspend fun getSavedStudentsWithSemesters(decryptPass: Boolean = true): List<StudentWithSemesters> {
|
||||||
return studentDb.loadStudentsWithSemesters().map { (student, semesters) ->
|
return studentDb.loadStudentsWithSemesters().map { (student, semesters) ->
|
||||||
StudentWithSemesters(
|
StudentWithSemesters(
|
||||||
student = student.apply {
|
student = student.apply {
|
||||||
@ -80,22 +82,25 @@ class StudentRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true): StudentWithSemesters? =
|
suspend fun getSavedStudents(decryptPass: Boolean = true): List<Student> {
|
||||||
studentDb.loadStudentWithSemestersById(id).let { res ->
|
val students = studentDb.loadAll()
|
||||||
StudentWithSemesters(
|
if (!decryptPass) return students
|
||||||
student = res.keys.firstOrNull() ?: return null,
|
|
||||||
semesters = res.values.first(),
|
return students.map { student ->
|
||||||
)
|
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
|
||||||
}.apply {
|
return@map student
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
}
|
||||||
student.password = withContext(dispatchers.io) {
|
|
||||||
|
student.apply {
|
||||||
|
password = withContext(dispatchers.io) {
|
||||||
scrambler.decrypt(student.password)
|
scrambler.decrypt(student.password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
|
||||||
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
|
val student = studentDb.loadById(id) ?: throw NoSuchStudentException(id)
|
||||||
|
|
||||||
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
|
||||||
student.password = withContext(dispatchers.io) {
|
student.password = withContext(dispatchers.io) {
|
||||||
@ -123,7 +128,7 @@ class StudentRepository @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentStudentSemesters = semesterDb.loadAll(student.studentId, student.classId)
|
val currentStudentSemesters = semesterDb.loadAll(student)
|
||||||
if (currentStudentSemesters.isEmpty()) {
|
if (currentStudentSemesters.isEmpty()) {
|
||||||
Timber.d("Check isAuthorized: apply empty semesters workaround")
|
Timber.d("Check isAuthorized: apply empty semesters workaround")
|
||||||
semesterDb.insertSemesters(
|
semesterDb.insertSemesters(
|
||||||
@ -181,8 +186,8 @@ class StudentRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun switchStudent(studentWithSemesters: StudentWithSemesters) {
|
suspend fun switchStudent(student: Student) {
|
||||||
studentDb.switchCurrent(studentWithSemesters.student.id)
|
studentDb.switchCurrent(student.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun logoutStudent(student: Student) = studentDb.delete(student)
|
suspend fun logoutStudent(student: Student) = studentDb.delete(student)
|
||||||
@ -190,8 +195,8 @@ class StudentRepository @Inject constructor(
|
|||||||
suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) =
|
suspend fun updateStudentNickAndAvatar(studentNickAndAvatar: StudentNickAndAvatar) =
|
||||||
studentDb.update(studentNickAndAvatar)
|
studentDb.update(studentNickAndAvatar)
|
||||||
|
|
||||||
suspend fun isOneUniqueStudent() = getSavedStudents(false)
|
suspend fun isOneUniqueStudent() = studentDb.loadAll()
|
||||||
.distinctBy { it.student.studentName }.size == 1
|
.distinctBy { it.studentName }.size == 1
|
||||||
|
|
||||||
suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) =
|
suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) =
|
||||||
wulkanowySdkFactory.create(student, semester)
|
wulkanowySdkFactory.create(student, semester)
|
||||||
@ -199,7 +204,7 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun refreshStudentAfterAuthorize(student: Student, semester: Semester) {
|
suspend fun refreshStudentAfterAuthorize(student: Student, semester: Semester) {
|
||||||
val wulkanowySdk = wulkanowySdkFactory.create(student, semester)
|
val wulkanowySdk = wulkanowySdkFactory.create(student, semester)
|
||||||
val newCurrentApiStudent = runCatching { wulkanowySdk.getCurrentStudent() }
|
val newCurrentApiStudent = runCatching { wulkanowySdk.getCurrentStudent() }
|
||||||
.onFailure { Timber.e(it, "Can't find student with id ${student.studentId}") }
|
.onFailure { Timber.e(it, "Can't find student with id ${student.studentId}") }
|
||||||
.getOrNull() ?: return
|
.getOrNull() ?: return
|
||||||
|
|
||||||
@ -209,7 +214,7 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
studentDb.update(studentName)
|
studentDb.update(studentName)
|
||||||
semesterDb.removeOldAndSaveNew(
|
semesterDb.removeOldAndSaveNew(
|
||||||
oldItems = semesterDb.loadAll(student.studentId, semester.classId),
|
oldItems = semesterDb.loadAll(student),
|
||||||
newItems = newCurrentApiStudent.semesters.mapToEntities(newCurrentApiStudent.studentId)
|
newItems = newCurrentApiStudent.semesters.mapToEntities(newCurrentApiStudent.studentId)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class TeacherRepository @Inject constructor(
|
|||||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
|
||||||
it.isEmpty() || forceRefresh || isExpired
|
it.isEmpty() || forceRefresh || isExpired
|
||||||
},
|
},
|
||||||
query = { teacherDb.loadAll(semester.studentId, semester.classId) },
|
query = { teacherDb.loadAll(student) },
|
||||||
fetch = {
|
fetch = {
|
||||||
wulkanowySdkFactory.create(student, semester)
|
wulkanowySdkFactory.create(student, semester)
|
||||||
.getTeachers()
|
.getTeachers()
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
package io.github.wulkanowy.data.repositories
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.Resource
|
|
||||||
import io.github.wulkanowy.data.api.models.Mapping
|
|
||||||
import io.github.wulkanowy.data.api.services.WulkanowyService
|
|
||||||
import io.github.wulkanowy.data.db.dao.AdminMessageDao
|
|
||||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
|
||||||
import io.github.wulkanowy.data.networkBoundResource
|
|
||||||
import io.github.wulkanowy.utils.AutoRefreshHelper
|
|
||||||
import io.github.wulkanowy.utils.getRefreshKey
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.filterNot
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class WulkanowyRepository @Inject constructor(
|
|
||||||
private val wulkanowyService: WulkanowyService,
|
|
||||||
private val adminMessageDao: AdminMessageDao,
|
|
||||||
private val preferencesRepository: PreferencesRepository,
|
|
||||||
private val refreshHelper: AutoRefreshHelper,
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val saveFetchResultMutex = Mutex()
|
|
||||||
|
|
||||||
private val cacheKey = "mapping_refresh_key"
|
|
||||||
|
|
||||||
fun getAdminMessages(): Flow<Resource<List<AdminMessage>>> =
|
|
||||||
networkBoundResource(
|
|
||||||
mutex = saveFetchResultMutex,
|
|
||||||
isResultEmpty = { false },
|
|
||||||
query = { adminMessageDao.loadAll() },
|
|
||||||
fetch = { wulkanowyService.getAdminMessages() },
|
|
||||||
shouldFetch = { true },
|
|
||||||
saveFetchResult = { oldItems, newItems ->
|
|
||||||
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.filterNot { it is Resource.Intermediate }
|
|
||||||
|
|
||||||
suspend fun getMapping(): Mapping? {
|
|
||||||
var savedMapping = preferencesRepository.mapping
|
|
||||||
|
|
||||||
val isExpired = refreshHelper.shouldBeRefreshed(
|
|
||||||
key = getRefreshKey(cacheKey)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (savedMapping == null || isExpired) {
|
|
||||||
fetchMapping()
|
|
||||||
savedMapping = preferencesRepository.mapping
|
|
||||||
}
|
|
||||||
|
|
||||||
return savedMapping
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun fetchMapping() {
|
|
||||||
runCatching { wulkanowyService.getMapping() }
|
|
||||||
.onFailure { Timber.e(it) }
|
|
||||||
.onSuccess {
|
|
||||||
preferencesRepository.mapping = it
|
|
||||||
refreshHelper.updateLastRefreshTimestamp(cacheKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,14 +5,14 @@ import io.github.wulkanowy.data.db.entities.AdminMessage
|
|||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.enums.MessageType
|
import io.github.wulkanowy.data.enums.MessageType
|
||||||
import io.github.wulkanowy.data.mapResourceData
|
import io.github.wulkanowy.data.mapResourceData
|
||||||
|
import io.github.wulkanowy.data.repositories.AdminMessageRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
import io.github.wulkanowy.utils.AppInfo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class GetAppropriateAdminMessageUseCase @Inject constructor(
|
class GetAppropriateAdminMessageUseCase @Inject constructor(
|
||||||
private val wulkanowyRepository: WulkanowyRepository,
|
private val adminMessageRepository: AdminMessageRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val appInfo: AppInfo
|
private val appInfo: AppInfo
|
||||||
) {
|
) {
|
||||||
@ -22,7 +22,7 @@ class GetAppropriateAdminMessageUseCase @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
|
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
|
||||||
return wulkanowyRepository.getAdminMessages().mapResourceData { adminMessages ->
|
return adminMessageRepository.getAdminMessages().mapResourceData { adminMessages ->
|
||||||
adminMessages
|
adminMessages
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.isNotDismissed() }
|
.filter { it.isNotDismissed() }
|
||||||
|
@ -59,7 +59,7 @@ class GetMailboxByStudentUseCase @Inject constructor(
|
|||||||
private fun String.getUnauthorizedVersion(): String {
|
private fun String.getUnauthorizedVersion(): String {
|
||||||
return normalizeStudentName().split(" ")
|
return normalizeStudentName().split(" ")
|
||||||
.joinToString(" ") {
|
.joinToString(" ") {
|
||||||
it.firstOrNull()?.toString().orEmpty() + "*".repeat((it.length - 1).coerceAtLeast(0))
|
it.first() + "*".repeat(it.length - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,18 +19,16 @@ class NewGradeNotification @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun notifyDetails(items: List<Grade>, student: Student) {
|
suspend fun notifyDetails(items: List<Grade>, student: Student) {
|
||||||
val notificationDataList = items
|
val notificationDataList = items.map {
|
||||||
.filter { !it.isNotified }
|
NotificationData(
|
||||||
.map {
|
title = context.getPlural(R.plurals.grade_new_items, 1),
|
||||||
NotificationData(
|
content = buildString {
|
||||||
title = context.getPlural(R.plurals.grade_new_items, 1),
|
append("${it.subject}: ${it.entry}")
|
||||||
content = buildString {
|
if (it.comment.isNotBlank()) append(" (${it.comment})")
|
||||||
append("${it.subject}: ${it.entry}")
|
},
|
||||||
if (it.comment.isNotBlank()) append(" (${it.comment})")
|
destination = Destination.Grade,
|
||||||
},
|
)
|
||||||
destination = Destination.Grade,
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val groupNotificationData = GroupNotificationData(
|
val groupNotificationData = GroupNotificationData(
|
||||||
notificationDataList = notificationDataList,
|
notificationDataList = notificationDataList,
|
||||||
|
@ -3,19 +3,14 @@ package io.github.wulkanowy.ui.modules.about
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.databinding.ItemAboutBinding
|
import io.github.wulkanowy.databinding.ItemAboutBinding
|
||||||
import io.github.wulkanowy.databinding.ScrollableHeaderAboutBinding
|
import io.github.wulkanowy.databinding.ScrollableHeaderAboutBinding
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AboutAdapter @Inject constructor(
|
class AboutAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
||||||
|
|
||||||
private var developerModeClicks = 0
|
|
||||||
private enum class ViewType(val id: Int) {
|
private enum class ViewType(val id: Int) {
|
||||||
ITEM_HEADER(1),
|
ITEM_HEADER(1),
|
||||||
ITEM_ELEMENT(2)
|
ITEM_ELEMENT(2)
|
||||||
@ -51,19 +46,6 @@ class AboutAdapter @Inject constructor(
|
|||||||
|
|
||||||
private fun bindHeaderViewHolder(binding: ScrollableHeaderAboutBinding) {
|
private fun bindHeaderViewHolder(binding: ScrollableHeaderAboutBinding) {
|
||||||
with(binding.aboutScrollableHeaderIcon) {
|
with(binding.aboutScrollableHeaderIcon) {
|
||||||
setOnClickListener {
|
|
||||||
if (++developerModeClicks == 5 && !preferencesRepository.developerMode) {
|
|
||||||
preferencesRepository.developerMode = true
|
|
||||||
developerModeClicks = 0
|
|
||||||
|
|
||||||
Toast.makeText(
|
|
||||||
context,
|
|
||||||
"done!",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setImageDrawable(ResourcesCompat.getDrawableForDensity(
|
setImageDrawable(ResourcesCompat.getDrawableForDensity(
|
||||||
context.resources, context.applicationInfo.icon, 640, null)
|
context.resources, context.applicationInfo.icon, 640, null)
|
||||||
)
|
)
|
||||||
|
@ -33,7 +33,7 @@ class AccountPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
resourceFlow { studentRepository.getSavedStudents(false) }
|
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
|
||||||
.logResourceStatus("load account data")
|
.logResourceStatus("load account data")
|
||||||
.onResourceSuccess { view?.updateData(createAccountItems(it)) }
|
.onResourceSuccess { view?.updateData(createAccountItems(it)) }
|
||||||
.onResourceError(errorHandler::dispatch)
|
.onResourceError(errorHandler::dispatch)
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account.accountdetails
|
package io.github.wulkanowy.ui.modules.account.accountdetails
|
||||||
|
|
||||||
import io.github.wulkanowy.data.*
|
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.logResourceStatus
|
||||||
|
import io.github.wulkanowy.data.onResourceError
|
||||||
|
import io.github.wulkanowy.data.onResourceLoading
|
||||||
|
import io.github.wulkanowy.data.onResourceNotLoading
|
||||||
|
import io.github.wulkanowy.data.onResourceSuccess
|
||||||
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
@ -14,6 +20,7 @@ import javax.inject.Inject
|
|||||||
class AccountDetailsPresenter @Inject constructor(
|
class AccountDetailsPresenter @Inject constructor(
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
|
private val semeRepository: SemesterRepository,
|
||||||
private val syncManager: SyncManager
|
private val syncManager: SyncManager
|
||||||
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
|
) : BasePresenter<AccountDetailsView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -46,7 +53,12 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
resourceFlow { studentRepository.getSavedStudentById(studentId ?: -1) }
|
resourceFlow {
|
||||||
|
val student = studentRepository.getStudentById(studentId ?: -1)
|
||||||
|
val semesters = semeRepository.getSemesters(student)
|
||||||
|
|
||||||
|
StudentWithSemesters(student, semesters)
|
||||||
|
}
|
||||||
.logResourceStatus("loading account details view")
|
.logResourceStatus("loading account details view")
|
||||||
.onResourceLoading {
|
.onResourceLoading {
|
||||||
view?.run {
|
view?.run {
|
||||||
@ -85,7 +97,7 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
|
|
||||||
Timber.i("Select student ${studentWithSemesters!!.student.id}")
|
Timber.i("Select student ${studentWithSemesters!!.student.id}")
|
||||||
|
|
||||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!) }
|
resourceFlow { studentRepository.switchStudent(studentWithSemesters!!.student) }
|
||||||
.logResourceStatus("change student")
|
.logResourceStatus("change student")
|
||||||
.onResourceSuccess { view?.recreateMainView() }
|
.onResourceSuccess { view?.recreateMainView() }
|
||||||
.onResourceNotLoading { view?.popViewToMain() }
|
.onResourceNotLoading { view?.popViewToMain() }
|
||||||
@ -122,10 +134,12 @@ class AccountDetailsPresenter @Inject constructor(
|
|||||||
syncManager.stopSyncWorker()
|
syncManager.stopSyncWorker()
|
||||||
openClearLoginView()
|
openClearLoginView()
|
||||||
}
|
}
|
||||||
|
|
||||||
studentWithSemesters?.student?.isCurrent == true -> {
|
studentWithSemesters?.student?.isCurrent == true -> {
|
||||||
Timber.i("Logout result: Logout student and switch to another")
|
Timber.i("Logout result: Logout student and switch to another")
|
||||||
recreateMainView()
|
recreateMainView()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Timber.i("Logout result: Logout student")
|
Timber.i("Logout result: Logout student")
|
||||||
recreateMainView()
|
recreateMainView()
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account.accountquick
|
package io.github.wulkanowy.ui.modules.account.accountquick
|
||||||
|
|
||||||
import io.github.wulkanowy.data.*
|
|
||||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||||
|
import io.github.wulkanowy.data.logResourceStatus
|
||||||
|
import io.github.wulkanowy.data.onResourceError
|
||||||
|
import io.github.wulkanowy.data.onResourceNotLoading
|
||||||
|
import io.github.wulkanowy.data.onResourceSuccess
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.ui.modules.account.AccountItem
|
import io.github.wulkanowy.ui.modules.account.AccountItem
|
||||||
@ -40,7 +44,7 @@ class AccountQuickPresenter @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceFlow { studentRepository.switchStudent(studentWithSemesters) }
|
resourceFlow { studentRepository.switchStudent(studentWithSemesters.student) }
|
||||||
.logResourceStatus("change student")
|
.logResourceStatus("change student")
|
||||||
.onResourceSuccess { view?.recreateMainView() }
|
.onResourceSuccess { view?.recreateMainView() }
|
||||||
.onResourceNotLoading { view?.popView() }
|
.onResourceNotLoading { view?.popView() }
|
||||||
|
@ -5,7 +5,6 @@ import android.view.ViewGroup
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.databinding.ItemAttendanceSummaryBinding
|
import io.github.wulkanowy.databinding.ItemAttendanceSummaryBinding
|
||||||
import io.github.wulkanowy.databinding.ScrollableHeaderAttendanceSummaryBinding
|
import io.github.wulkanowy.databinding.ScrollableHeaderAttendanceSummaryBinding
|
||||||
import io.github.wulkanowy.utils.calculatePercentage
|
import io.github.wulkanowy.utils.calculatePercentage
|
||||||
@ -14,13 +13,9 @@ import java.time.Month
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AttendanceSummaryAdapter @Inject constructor(
|
class AttendanceSummaryAdapter @Inject constructor() :
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) :
|
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private val attendancePercentage = preferencesRepository.attendancePercentage
|
|
||||||
|
|
||||||
private enum class ViewType(val id: Int) {
|
private enum class ViewType(val id: Int) {
|
||||||
HEADER(1),
|
HEADER(1),
|
||||||
ITEM(2)
|
ITEM(2)
|
||||||
@ -53,10 +48,7 @@ class AttendanceSummaryAdapter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindHeaderViewHolder(binding: ScrollableHeaderAttendanceSummaryBinding) {
|
private fun bindHeaderViewHolder(binding: ScrollableHeaderAttendanceSummaryBinding) {
|
||||||
binding.attendanceSummaryScrollableHeaderPercentage.text = formatPercentage(
|
binding.attendanceSummaryScrollableHeaderPercentage.text = formatPercentage(items.calculatePercentage())
|
||||||
attendancePercentage ?:
|
|
||||||
items.calculatePercentage()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindItemViewHolder(binding: ItemAttendanceSummaryBinding, position: Int) {
|
private fun bindItemViewHolder(binding: ItemAttendanceSummaryBinding, position: Int) {
|
||||||
@ -68,8 +60,8 @@ class AttendanceSummaryAdapter @Inject constructor(
|
|||||||
else -> item.month.getFormattedName()
|
else -> item.month.getFormattedName()
|
||||||
}
|
}
|
||||||
attendanceSummaryPercentage.text = when (position) {
|
attendanceSummaryPercentage.text = when (position) {
|
||||||
-1 -> formatPercentage(attendancePercentage ?: item.calculatePercentage())
|
-1 -> formatPercentage(items.calculatePercentage())
|
||||||
else -> formatPercentage(attendancePercentage ?: item.calculatePercentage())
|
else -> formatPercentage(item.calculatePercentage())
|
||||||
}
|
}
|
||||||
|
|
||||||
attendanceSummaryPresent.text = item.presence.toString()
|
attendanceSummaryPresent.text = item.presence.toString()
|
||||||
|
@ -59,7 +59,7 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
|||||||
webView = this
|
webView = this
|
||||||
with(settings) {
|
with(settings) {
|
||||||
javaScriptEnabled = true
|
javaScriptEnabled = true
|
||||||
userAgentString = wulkanowySdkFactory.createBase().userAgent
|
userAgentString = wulkanowySdkFactory.create().userAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
webViewClient = object : WebViewClient() {
|
webViewClient = object : WebViewClient() {
|
||||||
|
@ -30,7 +30,6 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
|
|||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.notificationscenter.NotificationsCenterFragment
|
import io.github.wulkanowy.ui.modules.notificationscenter.NotificationsCenterFragment
|
||||||
import io.github.wulkanowy.ui.modules.panicmode.PanicModeFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
|
||||||
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
|
||||||
import io.github.wulkanowy.utils.capitalise
|
import io.github.wulkanowy.utils.capitalise
|
||||||
@ -126,7 +125,6 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
mainActivity.pushView(ConferenceFragment.newInstance())
|
mainActivity.pushView(ConferenceFragment.newInstance())
|
||||||
}
|
}
|
||||||
onAdminMessageClickListener = presenter::onAdminMessageSelected
|
onAdminMessageClickListener = presenter::onAdminMessageSelected
|
||||||
onPanicButtonClickListener = presenter::onPanicButtonClicked
|
|
||||||
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed
|
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed
|
||||||
|
|
||||||
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||||
@ -210,11 +208,7 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
binding = binding.dashboardErrorAdminMessage,
|
binding = binding.dashboardErrorAdminMessage,
|
||||||
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
||||||
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
||||||
onPanicButtonClickListener = presenter::onPanicButtonClicked,
|
).bind(adminMessageItem.adminMessage)
|
||||||
).bind(
|
|
||||||
item = adminMessageItem.adminMessage,
|
|
||||||
showPanicButton = true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,10 +236,6 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
|||||||
requireContext().openInternetBrowser(url)
|
requireContext().openInternetBrowser(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openPanicWebView(url: String) {
|
|
||||||
(requireActivity() as MainActivity).pushView(PanicModeFragment.newInstance(url))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
dashboardAdapter.clearTimers()
|
dashboardAdapter.clearTimers()
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
|
@ -147,17 +147,6 @@ sealed class DashboardItem(val type: Type) {
|
|||||||
EXAMS,
|
EXAMS,
|
||||||
CONFERENCES,
|
CONFERENCES,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class HiddenAttendanceTile {
|
|
||||||
UNEXCUSED_ABSENCE,
|
|
||||||
EXEMPTION,
|
|
||||||
EXCUSED_LATENESS,
|
|
||||||
UNEXCUSED_LATENESS,
|
|
||||||
PRESENT,
|
|
||||||
DELETED,
|
|
||||||
EXCUSED_ABSENCE,
|
|
||||||
UNKNOWN,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DashboardItem.Tile.toDashboardItemType() = when (this) {
|
fun DashboardItem.Tile.toDashboardItemType() = when (this) {
|
||||||
|
@ -11,7 +11,6 @@ import io.github.wulkanowy.data.errorOrNull
|
|||||||
import io.github.wulkanowy.data.flatResourceFlow
|
import io.github.wulkanowy.data.flatResourceFlow
|
||||||
import io.github.wulkanowy.data.mapResourceData
|
import io.github.wulkanowy.data.mapResourceData
|
||||||
import io.github.wulkanowy.data.onResourceError
|
import io.github.wulkanowy.data.onResourceError
|
||||||
import io.github.wulkanowy.data.onResourceSuccess
|
|
||||||
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
import io.github.wulkanowy.data.repositories.AttendanceSummaryRepository
|
||||||
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
import io.github.wulkanowy.data.repositories.ConferenceRepository
|
||||||
import io.github.wulkanowy.data.repositories.ExamRepository
|
import io.github.wulkanowy.data.repositories.ExamRepository
|
||||||
@ -24,7 +23,6 @@ import io.github.wulkanowy.data.repositories.SchoolAnnouncementRepository
|
|||||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.TimetableRepository
|
import io.github.wulkanowy.data.repositories.TimetableRepository
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
|
||||||
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
import io.github.wulkanowy.domain.adminmessage.GetAppropriateAdminMessageUseCase
|
||||||
import io.github.wulkanowy.domain.timetable.IsStudentHasLessonsOnWeekendUseCase
|
import io.github.wulkanowy.domain.timetable.IsStudentHasLessonsOnWeekendUseCase
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -46,7 +44,6 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -285,26 +282,8 @@ class DashboardPresenter @Inject constructor(
|
|||||||
url?.let { view?.openInternetBrowser(it) }
|
url?.let { view?.openInternetBrowser(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPanicButtonClicked() {
|
|
||||||
resourceFlow { studentRepository.getCurrentStudent() }
|
|
||||||
.onResourceError { errorHandler.dispatch(it) }
|
|
||||||
.onResourceSuccess {
|
|
||||||
val baseUrl = it.scrapperBaseUrl.toHttpUrl()
|
|
||||||
val urlToOpen = baseUrl.newBuilder()
|
|
||||||
.host("uonetplus${it.scrapperDomainSuffix}.${baseUrl.host}")
|
|
||||||
.addPathSegment(it.symbol)
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
view?.openPanicWebView(urlToOpen)
|
|
||||||
}
|
|
||||||
.launch("panic_button")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
|
||||||
flow {
|
flow {
|
||||||
val attendancePercentage = preferencesRepository.attendancePercentage
|
|
||||||
|
|
||||||
val selectedTiles = selectedDashboardTiles
|
val selectedTiles = selectedDashboardTiles
|
||||||
val flowSuccess = flowOf(Resource.Success(null))
|
val flowSuccess = flowOf(Resource.Success(null))
|
||||||
|
|
||||||
@ -357,7 +336,7 @@ class DashboardPresenter @Inject constructor(
|
|||||||
} else null
|
} else null
|
||||||
},
|
},
|
||||||
attendancePercentage = DashboardItem.HorizontalGroup.Cell(
|
attendancePercentage = DashboardItem.HorizontalGroup.Cell(
|
||||||
data = attendancePercentage ?: attendanceResource.dataOrNull?.calculatePercentage(),
|
data = attendanceResource.dataOrNull?.calculatePercentage(),
|
||||||
error = attendanceResource.errorOrNull != null,
|
error = attendanceResource.errorOrNull != null,
|
||||||
isLoading = attendanceResource is Resource.Loading,
|
isLoading = attendanceResource is Resource.Loading,
|
||||||
),
|
),
|
||||||
|
@ -31,6 +31,4 @@ interface DashboardView : BaseView {
|
|||||||
fun openNotificationsCenterView()
|
fun openNotificationsCenterView()
|
||||||
|
|
||||||
fun openInternetBrowser(url: String)
|
fun openInternetBrowser(url: String)
|
||||||
|
|
||||||
fun openPanicWebView(url: String)
|
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,6 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
|
|
||||||
var onAdminMessageClickListener: (String?) -> Unit = {}
|
var onAdminMessageClickListener: (String?) -> Unit = {}
|
||||||
|
|
||||||
var onPanicButtonClickListener: () -> Unit = {}
|
|
||||||
|
|
||||||
var onAdminMessageDismissClickListener: (AdminMessage) -> Unit = {}
|
var onAdminMessageDismissClickListener: (AdminMessage) -> Unit = {}
|
||||||
|
|
||||||
val items = mutableListOf<DashboardItem>()
|
val items = mutableListOf<DashboardItem>()
|
||||||
@ -88,46 +86,35 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
DashboardItem.Type.ACCOUNT.ordinal -> AccountViewHolder(
|
DashboardItem.Type.ACCOUNT.ordinal -> AccountViewHolder(
|
||||||
ItemDashboardAccountBinding.inflate(inflater, parent, false)
|
ItemDashboardAccountBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.HORIZONTAL_GROUP.ordinal -> HorizontalGroupViewHolder(
|
DashboardItem.Type.HORIZONTAL_GROUP.ordinal -> HorizontalGroupViewHolder(
|
||||||
ItemDashboardHorizontalGroupBinding.inflate(inflater, parent, false)
|
ItemDashboardHorizontalGroupBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.GRADES.ordinal -> GradesViewHolder(
|
DashboardItem.Type.GRADES.ordinal -> GradesViewHolder(
|
||||||
ItemDashboardGradesBinding.inflate(inflater, parent, false)
|
ItemDashboardGradesBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.LESSONS.ordinal -> LessonsViewHolder(
|
DashboardItem.Type.LESSONS.ordinal -> LessonsViewHolder(
|
||||||
ItemDashboardLessonsBinding.inflate(inflater, parent, false)
|
ItemDashboardLessonsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.HOMEWORK.ordinal -> HomeworkViewHolder(
|
DashboardItem.Type.HOMEWORK.ordinal -> HomeworkViewHolder(
|
||||||
ItemDashboardHomeworkBinding.inflate(inflater, parent, false)
|
ItemDashboardHomeworkBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.ANNOUNCEMENTS.ordinal -> AnnouncementsViewHolder(
|
DashboardItem.Type.ANNOUNCEMENTS.ordinal -> AnnouncementsViewHolder(
|
||||||
ItemDashboardAnnouncementsBinding.inflate(inflater, parent, false)
|
ItemDashboardAnnouncementsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.EXAMS.ordinal -> ExamsViewHolder(
|
DashboardItem.Type.EXAMS.ordinal -> ExamsViewHolder(
|
||||||
ItemDashboardExamsBinding.inflate(inflater, parent, false)
|
ItemDashboardExamsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.CONFERENCES.ordinal -> ConferencesViewHolder(
|
DashboardItem.Type.CONFERENCES.ordinal -> ConferencesViewHolder(
|
||||||
ItemDashboardConferencesBinding.inflate(inflater, parent, false)
|
ItemDashboardConferencesBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
DashboardItem.Type.ADMIN_MESSAGE.ordinal -> AdminMessageViewHolder(
|
||||||
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false),
|
ItemDashboardAdminMessageBinding.inflate(inflater, parent, false),
|
||||||
onAdminMessageDismissClickListener = onAdminMessageDismissClickListener,
|
onAdminMessageDismissClickListener = onAdminMessageDismissClickListener,
|
||||||
onAdminMessageClickListener = onAdminMessageClickListener,
|
onAdminMessageClickListener = onAdminMessageClickListener,
|
||||||
onPanicButtonClickListener = onPanicButtonClickListener,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
|
DashboardItem.Type.ADS.ordinal -> AdsViewHolder(
|
||||||
ItemDashboardAdsBinding.inflate(inflater, parent, false)
|
ItemDashboardAdsBinding.inflate(inflater, parent, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> throw IllegalArgumentException()
|
else -> throw IllegalArgumentException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,11 +129,7 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
is AnnouncementsViewHolder -> bindAnnouncementsViewHolder(holder, position)
|
is AnnouncementsViewHolder -> bindAnnouncementsViewHolder(holder, position)
|
||||||
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
is ExamsViewHolder -> bindExamsViewHolder(holder, position)
|
||||||
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
is ConferencesViewHolder -> bindConferencesViewHolder(holder, position)
|
||||||
is AdminMessageViewHolder -> holder.bind(
|
is AdminMessageViewHolder -> holder.bind((items[position] as DashboardItem.AdminMessages).adminMessage)
|
||||||
(items[position] as DashboardItem.AdminMessages).adminMessage,
|
|
||||||
showPanicButton = true
|
|
||||||
)
|
|
||||||
|
|
||||||
is AdsViewHolder -> bindAdsViewHolder(holder, position)
|
is AdsViewHolder -> bindAdsViewHolder(holder, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,15 +240,12 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
attendancePercentage == null || attendancePercentage == .0 -> {
|
attendancePercentage == null || attendancePercentage == .0 -> {
|
||||||
root.context.getThemeAttrColor(R.attr.colorOnSurface)
|
root.context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||||
}
|
}
|
||||||
|
|
||||||
attendancePercentage <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> {
|
attendancePercentage <= ATTENDANCE_SECOND_WARNING_THRESHOLD -> {
|
||||||
root.context.getThemeAttrColor(R.attr.colorPrimary)
|
root.context.getThemeAttrColor(R.attr.colorPrimary)
|
||||||
}
|
}
|
||||||
|
|
||||||
attendancePercentage <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
attendancePercentage <= ATTENDANCE_FIRST_WARNING_THRESHOLD -> {
|
||||||
root.context.getThemeAttrColor(R.attr.colorTimetableChange)
|
root.context.getThemeAttrColor(R.attr.colorTimetableChange)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> root.context.getThemeAttrColor(R.attr.colorOnSurface)
|
else -> root.context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||||
}
|
}
|
||||||
val attendanceString = if (attendancePercentage == null || attendancePercentage == .0) {
|
val attendanceString = if (attendancePercentage == null || attendancePercentage == .0) {
|
||||||
@ -356,28 +336,24 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||||
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
tomorrowTimetable.isNotEmpty() -> {
|
tomorrowTimetable.isNotEmpty() -> {
|
||||||
dateToNavigate = tomorrowDate
|
dateToNavigate = tomorrowDate
|
||||||
updateLessonView(item, tomorrowTimetable, binding)
|
updateLessonView(item, tomorrowTimetable, binding)
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||||
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
currentDayHeader != null && currentDayHeader.content.isNotBlank() -> {
|
||||||
dateToNavigate = currentDate
|
dateToNavigate = currentDate
|
||||||
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
updateLessonView(item, emptyList(), binding, currentDayHeader)
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = false
|
||||||
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
tomorrowDayHeader != null && tomorrowDayHeader.content.isNotBlank() -> {
|
tomorrowDayHeader != null && tomorrowDayHeader.content.isNotBlank() -> {
|
||||||
dateToNavigate = tomorrowDate
|
dateToNavigate = tomorrowDate
|
||||||
updateLessonView(item, emptyList(), binding, tomorrowDayHeader)
|
updateLessonView(item, emptyList(), binding, tomorrowDayHeader)
|
||||||
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
binding.dashboardLessonsItemTitleTomorrow.isVisible = true
|
||||||
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
binding.dashboardLessonsItemTitleTodayAndTomorrow.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
dateToNavigate = currentDate
|
dateToNavigate = currentDate
|
||||||
updateLessonView(item, emptyList(), binding)
|
updateLessonView(item, emptyList(), binding)
|
||||||
@ -485,7 +461,6 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
firstTitleText =
|
firstTitleText =
|
||||||
context.getString(R.string.dashboard_timetable_first_lesson_title_moment)
|
context.getString(R.string.dashboard_timetable_first_lesson_title_moment)
|
||||||
}
|
}
|
||||||
|
|
||||||
minutesToStartLesson < 240 -> {
|
minutesToStartLesson < 240 -> {
|
||||||
firstTitleAndValueTextColor =
|
firstTitleAndValueTextColor =
|
||||||
context.getThemeAttrColor(R.attr.colorOnSurface)
|
context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||||
@ -493,7 +468,6 @@ class DashboardAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView
|
|||||||
firstTitleText =
|
firstTitleText =
|
||||||
context.getString(R.string.dashboard_timetable_first_lesson_title_soon)
|
context.getString(R.string.dashboard_timetable_first_lesson_title_soon)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
firstTitleAndValueTextColor =
|
firstTitleAndValueTextColor =
|
||||||
context.getThemeAttrColor(R.attr.colorOnSurface)
|
context.getThemeAttrColor(R.attr.colorOnSurface)
|
||||||
|
@ -13,10 +13,9 @@ class AdminMessageViewHolder(
|
|||||||
private val binding: ItemDashboardAdminMessageBinding,
|
private val binding: ItemDashboardAdminMessageBinding,
|
||||||
private val onAdminMessageDismissClickListener: (AdminMessage) -> Unit,
|
private val onAdminMessageDismissClickListener: (AdminMessage) -> Unit,
|
||||||
private val onAdminMessageClickListener: (String?) -> Unit,
|
private val onAdminMessageClickListener: (String?) -> Unit,
|
||||||
private val onPanicButtonClickListener: () -> Unit,
|
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(item: AdminMessage?, showPanicButton: Boolean = false) {
|
fun bind(item: AdminMessage?) {
|
||||||
item ?: return
|
item ?: return
|
||||||
|
|
||||||
val context = binding.root.context
|
val context = binding.root.context
|
||||||
@ -49,14 +48,10 @@ class AdminMessageViewHolder(
|
|||||||
dashboardAdminMessageItemClose.setOnClickListener {
|
dashboardAdminMessageItemClose.setOnClickListener {
|
||||||
onAdminMessageDismissClickListener(item)
|
onAdminMessageDismissClickListener(item)
|
||||||
}
|
}
|
||||||
dashboardPanicSection.root.isVisible = showPanicButton
|
|
||||||
dashboardPanicSection.dashboardPanicButton.setOnClickListener {
|
|
||||||
onPanicButtonClickListener()
|
|
||||||
}
|
|
||||||
|
|
||||||
dashboardAdminMessage.setCardBackgroundColor(backgroundColor?.let { ColorStateList.valueOf(it) })
|
root.setCardBackgroundColor(backgroundColor?.let { ColorStateList.valueOf(it) })
|
||||||
item.destinationUrl?.let { url ->
|
item.destinationUrl?.let { url ->
|
||||||
dashboardAdminMessage.setOnClickListener { onAdminMessageClickListener(url) }
|
root.setOnClickListener { onAdminMessageClickListener(url) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,6 @@ enum class GradeAverageMode(val value: String) {
|
|||||||
BOTH_SEMESTERS("both_semesters");
|
BOTH_SEMESTERS("both_semesters");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByValue(value: String) = entries.firstOrNull { it.value == value } ?: ONE_SEMESTER
|
fun getByValue(value: String) = values().firstOrNull { it.value == value } ?: ONE_SEMESTER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,5 @@ class LoginActivity : BaseActivity<LoginPresenter, ActivityLoginBinding>(), Logi
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
inAppUpdateHelper.onResume()
|
inAppUpdateHelper.onResume()
|
||||||
presenter.updateSdkMappings()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login
|
package io.github.wulkanowy.ui.modules.login
|
||||||
|
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LoginPresenter @Inject constructor(
|
class LoginPresenter @Inject constructor(
|
||||||
private val wulkanowyRepository: WulkanowyRepository,
|
|
||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository
|
studentRepository: StudentRepository
|
||||||
) : BasePresenter<LoginView>(errorHandler, studentRepository) {
|
) : BasePresenter<LoginView>(errorHandler, studentRepository) {
|
||||||
@ -19,11 +16,4 @@ class LoginPresenter @Inject constructor(
|
|||||||
view.initView()
|
view.initView()
|
||||||
Timber.i("Login view was initialized")
|
Timber.i("Login view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSdkMappings() {
|
|
||||||
presenterScope.launch {
|
|
||||||
runCatching { wulkanowyRepository.fetchMapping() }
|
|
||||||
.onFailure { Timber.e(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,6 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
|||||||
binding = binding.loginFormMessage,
|
binding = binding.loginFormMessage,
|
||||||
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
||||||
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
||||||
onPanicButtonClickListener = {},
|
|
||||||
).bind(message)
|
).bind(message)
|
||||||
binding.loginFormMessage.root.isVisible = message != null
|
binding.loginFormMessage.root.isVisible = message != null
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,6 @@ class LoginStudentSelectFragment :
|
|||||||
binding = binding.loginStudentSelectAdminMessage,
|
binding = binding.loginStudentSelectAdminMessage,
|
||||||
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
||||||
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
||||||
onPanicButtonClickListener = {},
|
|
||||||
).bind(adminMessage)
|
).bind(adminMessage)
|
||||||
binding.loginStudentSelectAdminMessage.root.isVisible = adminMessage != null
|
binding.loginStudentSelectAdminMessage.root.isVisible = adminMessage != null
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
resetSelectedState()
|
resetSelectedState()
|
||||||
|
|
||||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach {
|
||||||
students = it.dataOrNull.orEmpty()
|
students = it.dataOrNull.orEmpty()
|
||||||
when (it) {
|
when (it) {
|
||||||
is Resource.Loading -> Timber.d("Login student select students load started")
|
is Resource.Loading -> Timber.d("Login student select students load started")
|
||||||
|
@ -188,7 +188,6 @@ class LoginSymbolFragment :
|
|||||||
binding = binding.loginSymbolAdminMessage,
|
binding = binding.loginSymbolAdminMessage,
|
||||||
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
onAdminMessageDismissClickListener = presenter::onAdminMessageDismissed,
|
||||||
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
onAdminMessageClickListener = presenter::onAdminMessageSelected,
|
||||||
onPanicButtonClickListener = {},
|
|
||||||
).bind(adminMessage)
|
).bind(adminMessage)
|
||||||
binding.loginSymbolAdminMessage.root.isVisible = adminMessage != null
|
binding.loginSymbolAdminMessage.root.isVisible = adminMessage != null
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class LuckyNumberWidgetConfigurePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }.onEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Resource.Loading -> Timber.d("Lucky number widget configure students data load")
|
is Resource.Loading -> Timber.d("Lucky number widget configure students data load")
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
|
@ -132,7 +132,7 @@ class LuckyNumberWidgetProvider : AppWidgetProvider() {
|
|||||||
private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking {
|
private fun getLuckyNumber(studentId: Long, appWidgetId: Int) = runBlocking {
|
||||||
try {
|
try {
|
||||||
val students = studentRepository.getSavedStudents()
|
val students = studentRepository.getSavedStudents()
|
||||||
val student = students.singleOrNull { it.student.id == studentId }?.student
|
val student = students.singleOrNull { it.id == studentId }
|
||||||
val currentStudent = when {
|
val currentStudent = when {
|
||||||
student != null -> student
|
student != null -> student
|
||||||
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
|
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
|
||||||
|
@ -138,7 +138,6 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
inAppUpdateHelper.onResume()
|
inAppUpdateHelper.onResume()
|
||||||
presenter.updateSdkMappings()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
@ -6,7 +6,6 @@ import io.github.wulkanowy.data.onResourceError
|
|||||||
import io.github.wulkanowy.data.onResourceSuccess
|
import io.github.wulkanowy.data.onResourceSuccess
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.WulkanowyRepository
|
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.services.sync.SyncManager
|
import io.github.wulkanowy.services.sync.SyncManager
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -30,7 +29,6 @@ class MainPresenter @Inject constructor(
|
|||||||
errorHandler: ErrorHandler,
|
errorHandler: ErrorHandler,
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
private val wulkanowyRepository: WulkanowyRepository,
|
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
@ -87,7 +85,7 @@ class MainPresenter @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceFlow { studentRepository.getSavedStudents(false) }
|
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
|
||||||
.logResourceStatus("load student avatar")
|
.logResourceStatus("load student avatar")
|
||||||
.onResourceSuccess {
|
.onResourceSuccess {
|
||||||
studentsWitSemesters = it
|
studentsWitSemesters = it
|
||||||
@ -201,11 +199,4 @@ class MainPresenter @Inject constructor(
|
|||||||
.onFailure { errorHandler.dispatch(it) }
|
.onFailure { errorHandler.dispatch(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSdkMappings() {
|
|
||||||
presenterScope.launch {
|
|
||||||
runCatching { wulkanowyRepository.fetchMapping() }
|
|
||||||
.onFailure { Timber.e(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
|
|||||||
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
import io.github.wulkanowy.ui.modules.message.MessageFragment
|
||||||
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
|
import io.github.wulkanowy.ui.modules.message.mailboxchooser.MailboxChooserDialog
|
||||||
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
import io.github.wulkanowy.ui.modules.message.preview.MessagePreviewFragment
|
||||||
import io.github.wulkanowy.ui.modules.panicmode.PanicModeFragment
|
|
||||||
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
import io.github.wulkanowy.ui.widgets.DividerItemDecoration
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
@ -133,7 +132,6 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
)
|
)
|
||||||
messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
|
messageTabErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
messageTabErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
messageTabPanicSection.dashboardPanicButton.setOnClickListener { presenter.onPanicButtonClicked() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFragmentResultListener(requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!) { _, bundle ->
|
setFragmentResultListener(requireArguments().getString(MESSAGE_TAB_FOLDER_ID)!!) { _, bundle ->
|
||||||
@ -285,10 +283,6 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openPanicWebView(url: String) {
|
|
||||||
(requireActivity() as MainActivity).pushView(PanicModeFragment.newInstance(url))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hideKeyboard() {
|
override fun hideKeyboard() {
|
||||||
activity?.hideSoftInput()
|
activity?.hideSoftInput()
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import kotlinx.coroutines.flow.debounce
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.xdrop.fuzzywuzzy.FuzzySearch
|
import me.xdrop.fuzzywuzzy.FuzzySearch
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -430,20 +429,4 @@ class MessageTabPresenter @Inject constructor(
|
|||||||
+ dateRatio.toDouble().pow(2) * 2
|
+ dateRatio.toDouble().pow(2) * 2
|
||||||
).toInt()
|
).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onPanicButtonClicked() {
|
|
||||||
resourceFlow { studentRepository.getCurrentStudent() }
|
|
||||||
.onResourceError { errorHandler.dispatch(it) }
|
|
||||||
.onResourceSuccess {
|
|
||||||
val baseUrl = it.scrapperBaseUrl.toHttpUrl()
|
|
||||||
val urlToOpen = baseUrl.newBuilder()
|
|
||||||
.host("uonetplus${it.scrapperDomainSuffix}-wiadomosciplus.${baseUrl.host}")
|
|
||||||
.addPathSegment(it.symbol)
|
|
||||||
.build()
|
|
||||||
.toString()
|
|
||||||
|
|
||||||
view?.openPanicWebView(urlToOpen)
|
|
||||||
}
|
|
||||||
.launch("panic_button")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,4 @@ interface MessageTabView : BaseView {
|
|||||||
fun showRecyclerBottomPadding(show: Boolean)
|
fun showRecyclerBottomPadding(show: Boolean)
|
||||||
|
|
||||||
fun showMailboxChooser(mailboxes: List<Mailbox>)
|
fun showMailboxChooser(mailboxes: List<Mailbox>)
|
||||||
|
|
||||||
fun openPanicWebView(url: String)
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,6 @@ class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemV
|
|||||||
|
|
||||||
var onClickListener: (moreItem: MoreItem) -> Unit = {}
|
var onClickListener: (moreItem: MoreItem) -> Unit = {}
|
||||||
|
|
||||||
var onLongClickListener: (moreItem: MoreItem) -> Unit = {}
|
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
|
||||||
@ -29,10 +27,6 @@ class MoreAdapter @Inject constructor() : RecyclerView.Adapter<MoreAdapter.ItemV
|
|||||||
moreItemImage.setImageResource(item.icon)
|
moreItemImage.setImageResource(item.icon)
|
||||||
|
|
||||||
root.setOnClickListener { onClickListener(item) }
|
root.setOnClickListener { onClickListener(item) }
|
||||||
root.setOnLongClickListener {
|
|
||||||
onLongClickListener(item)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import android.view.View
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
import io.github.wulkanowy.databinding.FragmentMoreBinding
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
@ -24,9 +23,6 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var moreAdapter: MoreAdapter
|
lateinit var moreAdapter: MoreAdapter
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var preferencesRepository: PreferencesRepository
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = MoreFragment()
|
fun newInstance() = MoreFragment()
|
||||||
}
|
}
|
||||||
@ -77,9 +73,4 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
|
|||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun restartApp() {
|
|
||||||
startActivity(MainActivity.getStartIntent(requireContext()))
|
|
||||||
requireActivity().finishAffinity()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,4 @@ interface MoreView : BaseView {
|
|||||||
fun popView(depth: Int)
|
fun popView(depth: Int)
|
||||||
|
|
||||||
fun openView(destination: Destination)
|
fun openView(destination: Destination)
|
||||||
|
|
||||||
fun restartApp()
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.modules.note
|
|||||||
import io.github.wulkanowy.data.*
|
import io.github.wulkanowy.data.*
|
||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.repositories.NoteRepository
|
import io.github.wulkanowy.data.repositories.NoteRepository
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.SemesterRepository
|
import io.github.wulkanowy.data.repositories.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
import io.github.wulkanowy.ui.base.BasePresenter
|
||||||
@ -18,7 +17,6 @@ class NotePresenter @Inject constructor(
|
|||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
private val noteRepository: NoteRepository,
|
private val noteRepository: NoteRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
|
||||||
private val analytics: AnalyticsHelper
|
private val analytics: AnalyticsHelper
|
||||||
) : BasePresenter<NoteView>(errorHandler, studentRepository) {
|
) : BasePresenter<NoteView>(errorHandler, studentRepository) {
|
||||||
|
|
||||||
@ -50,19 +48,6 @@ class NotePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData(forceRefresh: Boolean = false) {
|
private fun loadData(forceRefresh: Boolean = false) {
|
||||||
if (!preferencesRepository.showNotes) {
|
|
||||||
view?.run {
|
|
||||||
enableSwipe(false)
|
|
||||||
showEmpty(false)
|
|
||||||
showContent(false)
|
|
||||||
showErrorView(false)
|
|
||||||
showProgress(false)
|
|
||||||
showEmpty(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
flatResourceFlow {
|
flatResourceFlow {
|
||||||
val student = studentRepository.getCurrentStudent()
|
val student = studentRepository.getCurrentStudent()
|
||||||
val semester = semesterRepository.getCurrentSemester(student)
|
val semester = semesterRepository.getCurrentSemester(student)
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
package io.github.wulkanowy.ui.modules.panicmode
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import androidx.activity.addCallback
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import io.github.wulkanowy.R
|
|
||||||
import io.github.wulkanowy.data.WulkanowySdkFactory
|
|
||||||
import io.github.wulkanowy.databinding.FragmentPanicModeBinding
|
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
|
||||||
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
|
|
||||||
import io.github.wulkanowy.utils.openInternetBrowser
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class PanicModeFragment : BaseFragment<FragmentPanicModeBinding>(R.layout.fragment_panic_mode),
|
|
||||||
MainView.TitledView {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var wulkanowySdkFactory: WulkanowySdkFactory
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var webkitCookieManagerProxy: WebkitCookieManagerProxy
|
|
||||||
|
|
||||||
private var webView: WebView? = null
|
|
||||||
|
|
||||||
override val titleStringId: Int get() = R.string.panic_mode_title
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private const val PANIC_URL = "panic_mode_url"
|
|
||||||
fun newInstance(url: String?): PanicModeFragment {
|
|
||||||
return PanicModeFragment().apply {
|
|
||||||
arguments = bundleOf(PANIC_URL to url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
binding = FragmentPanicModeBinding.bind(view)
|
|
||||||
|
|
||||||
binding.panicModeRefresh.setOnClickListener {
|
|
||||||
binding.panicModeWebview.loadUrl(
|
|
||||||
binding.panicModeWebview.url ?: arguments?.getString(PANIC_URL).orEmpty()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
binding.panicModeBack.setOnClickListener { binding.panicModeWebview.goBack() }
|
|
||||||
binding.panicModeHome.setOnClickListener {
|
|
||||||
binding.panicModeWebview.loadUrl(
|
|
||||||
arguments?.getString(PANIC_URL).orEmpty()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
binding.panicModeForward.setOnClickListener { binding.panicModeWebview.goForward() }
|
|
||||||
binding.panicModeShare.setOnClickListener {
|
|
||||||
requireContext().openInternetBrowser(
|
|
||||||
binding.panicModeWebview.url.toString(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val onBackPressedCallback = requireActivity().onBackPressedDispatcher
|
|
||||||
.addCallback(viewLifecycleOwner) {
|
|
||||||
binding.panicModeWebview.goBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
with(binding.panicModeWebview) {
|
|
||||||
webView = this
|
|
||||||
with(settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
userAgentString = wulkanowySdkFactory.createBase().userAgent
|
|
||||||
}
|
|
||||||
|
|
||||||
webViewClient = object : WebViewClient() {
|
|
||||||
override fun doUpdateVisitedHistory(
|
|
||||||
view: WebView?,
|
|
||||||
url: String?,
|
|
||||||
isReload: Boolean
|
|
||||||
) {
|
|
||||||
binding.panicModeBack.isEnabled = binding.panicModeWebview.canGoBack()
|
|
||||||
binding.panicModeForward.isEnabled = binding.panicModeWebview.canGoForward()
|
|
||||||
onBackPressedCallback.isEnabled = binding.panicModeWebview.canGoBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadUrl(arguments?.getString(PANIC_URL).orEmpty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
webkitCookieManagerProxy.webkitCookieManager?.flush()
|
|
||||||
webView?.destroy()
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +1,13 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings
|
package io.github.wulkanowy.ui.modules.settings
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.ui.base.BaseActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
class SettingsFragment : PreferenceFragmentCompat(), MainView.TitledView, SettingsView {
|
||||||
class SettingsFragment : PreferenceFragmentCompat(),
|
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
|
||||||
MainView.TitledView, SettingsView {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -25,26 +16,11 @@ class SettingsFragment : PreferenceFragmentCompat(),
|
|||||||
|
|
||||||
override val titleStringId get() = R.string.settings_title
|
override val titleStringId get() = R.string.settings_title
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var preferencesRepository: PreferencesRepository
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.scheme_preferences, rootKey)
|
setPreferencesFromResource(R.xml.scheme_preferences, rootKey)
|
||||||
|
|
||||||
val prefScreen: PreferenceScreen? = findPreference("settings_preferences")
|
|
||||||
val prefDeveloper: Preference? = findPreference("mod_settings")
|
|
||||||
|
|
||||||
if (!preferencesRepository.developerMode && prefScreen != null && prefDeveloper != null) {
|
|
||||||
prefScreen.removePreference(prefDeveloper)
|
|
||||||
}
|
|
||||||
|
|
||||||
Timber.i("Settings view was initialized")
|
Timber.i("Settings view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.scheme_preferences, rootKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {}
|
override fun showError(text: String, error: Throwable) {}
|
||||||
|
|
||||||
override fun showMessage(text: String) {}
|
override fun showMessage(text: String) {}
|
||||||
|
@ -1,147 +0,0 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings.mod_settings
|
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.preference.EditTextPreference
|
|
||||||
import androidx.preference.MultiSelectListPreference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import io.github.wulkanowy.R
|
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.ui.base.BaseActivity
|
|
||||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
|
||||||
import io.github.wulkanowy.utils.AppInfo
|
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class ModSettingsFragment : PreferenceFragmentCompat(),
|
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
|
||||||
MainView.TitledView, ModSettingsView {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var presenter: ModSettingsPresenter
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var appInfo: AppInfo
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var preferencesRepository: PreferencesRepository
|
|
||||||
|
|
||||||
override val titleStringId get() = R.string.pref_mod_settings_title
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
presenter.onAttachView(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
|
||||||
setPreferencesFromResource(R.xml.scheme_preferences_mod_settings, rootKey)
|
|
||||||
|
|
||||||
val attendancePercentagePreference: EditTextPreference? = findPreference("attendance_percentage")
|
|
||||||
attendancePercentagePreference?.setOnBindEditTextListener { editText ->
|
|
||||||
editText.inputType = android.text.InputType.TYPE_CLASS_NUMBER or android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
|
|
||||||
editText.filters = arrayOf(
|
|
||||||
android.text.InputFilter { source, _, _, dest, _, _ ->
|
|
||||||
if (source == "." && dest.isEmpty()) {
|
|
||||||
return@InputFilter "0."
|
|
||||||
}
|
|
||||||
|
|
||||||
val input = dest.toString() + source.toString()
|
|
||||||
if (input == "100.00") {
|
|
||||||
return@InputFilter null
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputVal = input.toFloatOrNull()
|
|
||||||
if (inputVal != null && inputVal >= 0 && inputVal <= 100) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
|
||||||
presenter.onSharedPreferenceChanged(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showError(text, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showMessage(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showExpiredCredentialsDialog() {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showExpiredCredentialsDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCaptchaVerificationRequired(url: String?) {
|
|
||||||
(activity as? BaseActivity<*, *>)?.onCaptchaVerificationRequired(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showDecryptionFailedDialog() {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showDecryptionFailedDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showChangePasswordSnackbar(redirectUrl: String) {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showChangePasswordSnackbar(redirectUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openClearLoginView() {
|
|
||||||
(activity as? BaseActivity<*, *>)?.openClearLoginView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showErrorDetailsDialog(error: Throwable) {
|
|
||||||
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showAuthDialog() {
|
|
||||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
preferenceScreen.sharedPreferences?.registerOnSharedPreferenceChangeListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
preferenceScreen.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showAttendanceSettings(items: List<DashboardItem.HiddenAttendanceTile>) {
|
|
||||||
val entries = requireContext().resources.getStringArray(R.array.mod_settings_attendance_entries)
|
|
||||||
val values = requireContext().resources.getStringArray(R.array.mod_settings_attendance_values)
|
|
||||||
val selectedItemsState = values.map { value -> items.any { it.name == value } }
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder(requireContext())
|
|
||||||
.setTitle(R.string.attendance_title)
|
|
||||||
.setMultiChoiceItems(entries, selectedItemsState.toBooleanArray()) { _, _, _ -> }
|
|
||||||
.setPositiveButton(android.R.string.ok) { dialog, _ ->
|
|
||||||
val selectedState = (dialog as AlertDialog).listView.checkedItemPositions
|
|
||||||
val selectedValues = values
|
|
||||||
.filterIndexed { index, _ -> selectedState[index] }
|
|
||||||
.map { DashboardItem.HiddenAttendanceTile.valueOf(it) }
|
|
||||||
|
|
||||||
Timber.i("Selected attendance to hide: $selectedValues")
|
|
||||||
presenter.onAttendanceSettingsSelected(selectedValues)
|
|
||||||
}
|
|
||||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun restartApp() {
|
|
||||||
startActivity(MainActivity.getStartIntent(requireContext()))
|
|
||||||
requireActivity().finishAffinity()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings.mod_settings
|
|
||||||
|
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
|
||||||
import io.github.wulkanowy.ui.base.BasePresenter
|
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
|
||||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class ModSettingsPresenter @Inject constructor(
|
|
||||||
errorHandler: ErrorHandler,
|
|
||||||
studentRepository: StudentRepository,
|
|
||||||
private val analytics: AnalyticsHelper,
|
|
||||||
private val preferencesRepository: PreferencesRepository
|
|
||||||
) : BasePresenter<ModSettingsView>(errorHandler, studentRepository) {
|
|
||||||
|
|
||||||
override fun onAttachView(view: ModSettingsView) {
|
|
||||||
super.onAttachView(view)
|
|
||||||
|
|
||||||
Timber.i("Mod settings view was initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onSharedPreferenceChanged(key: String?) {
|
|
||||||
key ?: return
|
|
||||||
Timber.i("Change mod settings $key")
|
|
||||||
analytics.logEvent("setting_changed", "name" to key)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onHiddenGradesSelected(selectedItems: List<String>) {
|
|
||||||
preferencesRepository.hiddenGrades = selectedItems
|
|
||||||
view?.restartApp()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onAttendanceSettingsSelected(selectedValues: List<DashboardItem.HiddenAttendanceTile>) {
|
|
||||||
preferencesRepository.hiddenAttendanceItems = selectedValues
|
|
||||||
view?.restartApp()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
package io.github.wulkanowy.ui.modules.settings.mod_settings
|
|
||||||
|
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
|
||||||
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
|
|
||||||
|
|
||||||
interface ModSettingsView : BaseView {
|
|
||||||
fun restartApp()
|
|
||||||
fun showAttendanceSettings(items: List<DashboardItem.HiddenAttendanceTile>)
|
|
||||||
}
|
|
@ -42,22 +42,24 @@ class TimetableWidgetConfigurePresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() {
|
private fun loadData() {
|
||||||
resourceFlow { studentRepository.getSavedStudents(false) }.onEach {
|
resourceFlow { studentRepository.getSavedStudentsWithSemesters(false) }
|
||||||
when (it) {
|
.onEach {
|
||||||
is Resource.Loading -> Timber.d("Timetable widget configure students data load")
|
when (it) {
|
||||||
is Resource.Success -> {
|
is Resource.Loading -> Timber.d("Timetable widget configure students data load")
|
||||||
val selectedStudentId = appWidgetId?.let { id ->
|
is Resource.Success -> {
|
||||||
sharedPref.getLong(getStudentWidgetKey(id), 0)
|
val selectedStudentId = appWidgetId?.let { id ->
|
||||||
} ?: -1
|
sharedPref.getLong(getStudentWidgetKey(id), 0)
|
||||||
when {
|
} ?: -1
|
||||||
it.data.isEmpty() -> view?.openLoginView()
|
when {
|
||||||
it.data.size == 1 && !isFromProvider -> onItemSelect(it.data.single().student)
|
it.data.isEmpty() -> view?.openLoginView()
|
||||||
else -> view?.updateData(it.data, selectedStudentId)
|
it.data.size == 1 && !isFromProvider -> onItemSelect(it.data.single().student)
|
||||||
|
else -> view?.updateData(it.data, selectedStudentId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is Resource.Error -> errorHandler.dispatch(it.error)
|
||||||
}
|
}
|
||||||
is Resource.Error -> errorHandler.dispatch(it.error)
|
}.launch()
|
||||||
}
|
|
||||||
}.launch()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerStudent(student: Student?) {
|
private fun registerStudent(student: Student?) {
|
||||||
|
@ -95,7 +95,7 @@ class TimetableWidgetFactory(
|
|||||||
|
|
||||||
private suspend fun getStudent(studentId: Long): Student? {
|
private suspend fun getStudent(studentId: Long): Student? {
|
||||||
val students = studentRepository.getSavedStudents()
|
val students = studentRepository.getSavedStudents()
|
||||||
return students.singleOrNull { it.student.id == studentId }?.student
|
return students.singleOrNull { it.id == studentId }
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getLessons(
|
private suspend fun getLessons(
|
||||||
|
@ -2,7 +2,11 @@ package io.github.wulkanowy.ui.modules.timetablewidget
|
|||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetManager.*
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_DELETED
|
||||||
|
import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
|
||||||
|
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS
|
||||||
|
import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@ -22,7 +26,14 @@ import io.github.wulkanowy.data.repositories.StudentRepository
|
|||||||
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
||||||
import io.github.wulkanowy.ui.modules.Destination
|
import io.github.wulkanowy.ui.modules.Destination
|
||||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||||
import io.github.wulkanowy.utils.*
|
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||||
|
import io.github.wulkanowy.utils.PendingIntentCompat
|
||||||
|
import io.github.wulkanowy.utils.capitalise
|
||||||
|
import io.github.wulkanowy.utils.nextOrSameSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.nextSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.nickOrName
|
||||||
|
import io.github.wulkanowy.utils.previousSchoolDay
|
||||||
|
import io.github.wulkanowy.utils.toFormattedString
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -244,7 +255,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
|
|
||||||
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
|
private suspend fun getStudent(studentId: Long, appWidgetId: Int) = try {
|
||||||
val students = studentRepository.getSavedStudents(false)
|
val students = studentRepository.getSavedStudents(false)
|
||||||
val student = students.singleOrNull { it.student.id == studentId }?.student
|
val student = students.singleOrNull { it.id == studentId }
|
||||||
when {
|
when {
|
||||||
student != null -> student
|
student != null -> student
|
||||||
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
|
studentId != 0L && studentRepository.isCurrentStudentSet() -> {
|
||||||
@ -263,7 +274,10 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupAccountView(
|
private fun setupAccountView(
|
||||||
context: Context, student: Student, remoteViews: RemoteViews, widgetId: Int
|
context: Context,
|
||||||
|
student: Student,
|
||||||
|
remoteViews: RemoteViews,
|
||||||
|
widgetId: Int
|
||||||
) {
|
) {
|
||||||
val accountInitials = getAccountInitials(student.nickOrName)
|
val accountInitials = getAccountInitials(student.nickOrName)
|
||||||
val accountPickerPendingIntent = createAccountPickerPendingIntent(context, widgetId)
|
val accountPickerPendingIntent = createAccountPickerPendingIntent(context, widgetId)
|
||||||
|
@ -30,10 +30,6 @@ fun getRefreshKey(name: String, mailbox: Mailbox?, folder: MessageFolder): Strin
|
|||||||
return "${name}_${mailbox?.globalKey ?: "all"}_${folder.id}"
|
return "${name}_${mailbox?.globalKey ?: "all"}_${folder.id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getRefreshKey(name: String): String {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
class AutoRefreshHelper @Inject constructor(
|
class AutoRefreshHelper @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val sharedPref: SharedPrefProvider
|
private val sharedPref: SharedPrefProvider
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
Wersja 2.6.13
|
Wersja 2.6.1
|
||||||
|
|
||||||
— dodaliśmy tryb awaryjny (no w sensie taka przeglądarka z dziennikiem w apce, ale nie trzeba się ręcznie logować)
|
— dodaliśmy kalkulator frekwencji
|
||||||
— naprawiliśmy ładowania ucznia na tle klasy i lekcji zrealizowanych
|
— dodaliśmy wyświetlanie lekcji dodatkowych w planie lekcji
|
||||||
|
— ulepszyliśmy wyjaśnienie na ekranie z miejscem na wpisanie numeru PESEL
|
||||||
|
— naprawiliśmy rzadkie sytuacje, gdy plan lekcji nakładał się na informację o jego braku
|
||||||
|
|
||||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||||
|
@ -60,16 +60,6 @@
|
|||||||
tools:ignore="UseCompoundDrawables"
|
tools:ignore="UseCompoundDrawables"
|
||||||
tools:visibility="invisible">
|
tools:visibility="invisible">
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/message_tab_panic_section"
|
|
||||||
layout="@layout/item_dashboard_panic_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginVertical="16dp"
|
|
||||||
android:visibility="visible"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/dashboard_error_admin_message" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="100dp"
|
android:layout_width="100dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
<LinearLayout 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:orientation="vertical"
|
|
||||||
tools:context=".ui.modules.panicmode.PanicModeFragment">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?colorControlHighlight">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/panic_mode_share"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
app:icon="@drawable/ic_share"
|
|
||||||
app:iconTint="?colorOnSurface" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/panic_mode_home"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
app:icon="@drawable/ic_all_home"
|
|
||||||
app:iconTint="?colorOnSurface" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/panic_mode_refresh"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:contentDescription="@string/logviewer_refresh"
|
|
||||||
app:icon="@drawable/ic_refresh"
|
|
||||||
app:iconTint="?colorOnSurface" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/panic_mode_back"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
app:icon="@drawable/ic_chevron_left"
|
|
||||||
app:iconTint="?colorOnSurface" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/panic_mode_forward"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
app:icon="@drawable/ic_chevron_right"
|
|
||||||
app:iconTint="?colorOnSurface" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<WebView
|
|
||||||
android:id="@+id/panic_mode_webview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -1,105 +1,87 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginVertical="6dp">
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/dashboard_admin_message"
|
android:id="@+id/dashboard_admin_message_item_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent">
|
||||||
android:layout_marginHorizontal="12dp"
|
|
||||||
android:layout_marginVertical="6dp">
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/dashboard_admin_message_item_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:src="@drawable/ic_error"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/dashboard_admin_message_item_title"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/dashboard_admin_message_item_title"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
|
tools:tint="@android:color/black" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<TextView
|
||||||
android:id="@+id/dashboard_admin_message_item_content"
|
android:id="@+id/dashboard_admin_message_item_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/dashboard_admin_message_item_close"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/dashboard_admin_message_item_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="@tools:sample/lorem" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/dashboard_admin_message_item_icon"
|
android:id="@+id/dashboard_admin_message_item_close"
|
||||||
android:layout_width="24dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="48dp"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:src="@drawable/ic_error"
|
android:padding="12dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/dashboard_admin_message_item_title"
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:src="@drawable/ic_close"
|
||||||
app:layout_constraintTop_toTopOf="@id/dashboard_admin_message_item_title"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:ignore="ContentDescription"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:tint="@android:color/black" />
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/dashboard_admin_message_item_title"
|
android:id="@+id/dashboard_admin_message_item_description"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:textSize="18sp"
|
android:layout_marginBottom="16dp"
|
||||||
android:textStyle="bold"
|
android:textSize="14sp"
|
||||||
app:layout_constraintEnd_toStartOf="@id/dashboard_admin_message_item_close"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/dashboard_admin_message_item_icon"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
tools:text="@tools:sample/lorem" />
|
app:layout_constraintTop_toBottomOf="@id/dashboard_admin_message_item_title"
|
||||||
|
app:layout_constraintVertical_bias="0"
|
||||||
|
app:lineHeight="20dp"
|
||||||
|
tools:maxLines="5"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/dashboard_admin_message_item_close"
|
android:id="@+id/dashboard_admin_message_item_dismiss"
|
||||||
android:layout_width="48dp"
|
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
||||||
android:layout_height="48dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginTop="8dp"
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
android:layout_marginEnd="16dp"
|
||||||
android:padding="12dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:src="@drawable/ic_close"
|
android:text="@android:string/ok"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:ignore="ContentDescription" />
|
app:layout_constraintTop_toBottomOf="@id/dashboard_admin_message_item_description"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
<TextView
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
android:id="@+id/dashboard_admin_message_item_description"
|
</com.google.android.material.card.MaterialCardView>
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/dashboard_admin_message_item_title"
|
|
||||||
app:layout_constraintVertical_bias="0"
|
|
||||||
app:lineHeight="20dp"
|
|
||||||
tools:maxLines="5"
|
|
||||||
tools:text="@tools:sample/lorem/random" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/dashboard_admin_message_item_dismiss"
|
|
||||||
style="@style/Widget.Material3.Button.TextButton.Dialog"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:text="@android:string/ok"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/dashboard_admin_message_item_description"
|
|
||||||
app:layout_constraintVertical_bias="0" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/dashboard_panic_section"
|
|
||||||
layout="@layout/item_dashboard_panic_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="16dp"
|
|
||||||
android:layout_marginVertical="16dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/dashboard_error_admin_message" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="12dp"
|
|
||||||
android:layout_marginVertical="6dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Aplikacja nie działa?"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/dashboard_panic_button"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:text="Otwórz stronę dziennika" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="pref_mod_settings_title">Skrytá nastavení</string>
|
|
||||||
<string name="pref_hidden_settings_attendance_percentage">Procento docházky</string>
|
|
||||||
<string name="pref_hidden_settings_hidden_grades">Skrýt známky</string>
|
|
||||||
<string name="pref_mod_settings_hidden_attendance_items">Skryté položky docházky</string>
|
|
||||||
<string name="pref_mod_settings_show_notes">Poznámky k pořadu</string>
|
|
||||||
|
|
||||||
<string-array name="mod_settings_attendance_entries">
|
|
||||||
<item>Neomluvená absence</item>
|
|
||||||
<item>Výjimka</item>
|
|
||||||
<item>Ospravedlněné zpoždění</item>
|
|
||||||
<item>Neomluvené zpoždění</item>
|
|
||||||
<item>Přítomnost</item>
|
|
||||||
<item>Smazáno</item>
|
|
||||||
<item>Ospravedlněná absence</item>
|
|
||||||
<item>Neznámá</item>
|
|
||||||
</string-array>
|
|
||||||
<string name="pref_mod_settings_developer_mode">Režim pro vývojáře (přístup na tuto stránku)</string>
|
|
||||||
<string name="pref_mod_settings_developer_mode_summary">Po deaktivaci tohoto nastavení již nebudete mít přístup na tuto stránku, ale nastavení se bude nadále používat.</string>
|
|
||||||
</resources>
|
|
@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources></resources>
|
|
@ -893,5 +893,4 @@
|
|||||||
<string name="message_unmute">Zrušit ztlumení</string>
|
<string name="message_unmute">Zrušit ztlumení</string>
|
||||||
<string name="message_mute_success">Ztlumili jste tohoto uživatele</string>
|
<string name="message_mute_success">Ztlumili jste tohoto uživatele</string>
|
||||||
<string name="message_unmute_success">Zrušili jste ztlumení tohoto uživatele</string>
|
<string name="message_unmute_success">Zrušili jste ztlumení tohoto uživatele</string>
|
||||||
<string name="pref_mod_settings_other_title">Jiné</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="pref_mod_settings_title">Hidden settings</string>
|
|
||||||
<string name="pref_hidden_settings_attendance_percentage">Attendance percentage</string>
|
|
||||||
<string name="pref_hidden_settings_hidden_grades">Hide grades</string>
|
|
||||||
<string name="pref_mod_settings_hidden_attendance_items">Hidden attendance items</string>
|
|
||||||
<string name="pref_mod_settings_show_notes">Show notes</string>
|
|
||||||
|
|
||||||
<string-array name="mod_settings_attendance_entries">
|
|
||||||
<item>Unexcused absence</item>
|
|
||||||
<item>Exemption</item>
|
|
||||||
<item>Excused lateness</item>
|
|
||||||
<item>Unexcused lateness</item>
|
|
||||||
<item>Present</item>
|
|
||||||
<item>Deleted</item>
|
|
||||||
<item>Excused absence</item>
|
|
||||||
<item>Unknown</item>
|
|
||||||
</string-array>
|
|
||||||
<string name="pref_mod_settings_developer_mode">Developer mode (access to this page)</string>
|
|
||||||
<string name="pref_mod_settings_developer_mode_summary">After disabling this setting, you will not be able to access this page anymore, but the settings will still be applied.</string>
|
|
||||||
</resources>
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user