Compare commits

...

93 Commits

Author SHA1 Message Date
Kuba Szczodrzyński
2d6d823a87
Merge branch 'develop-v4' into develop 2025-02-02 17:40:10 +01:00
Kuba Szczodrzyński
02a9724587
[4.14] Update build.gradle, signing and changelog 2025-02-02 17:04:56 +01:00
Kuba Szczodrzyński
c17237015e
Merge branch 'develop-v4' into develop 2025-02-02 17:03:32 +01:00
Kuba Szczodrzyński
2681794676
[Actions] Fix release workflow trigger tag name pattern 2025-02-02 16:59:23 +01:00
Kuba Szczodrzyński
42e59ac0db
[Actions] Update actions/upload-artifact to v4 2025-02-02 16:25:52 +01:00
Kuba Szczodrzyński
cac98ee3d4
[App] Force full sync on update 2025-02-02 15:48:11 +01:00
Kuba Szczodrzyński
aeecc48639
[App] Disable profile archiver permanently, force app sync on first login 2025-02-01 23:40:00 +01:00
Kuba Szczodrzyński
db444d89f0
[UI/Grades] Add config options for university grades 2025-02-01 23:00:21 +01:00
Kuba Szczodrzyński
29971777a7
[UI/Grades] Add "no grade" entity in USOS, count ECTS points by term 2025-02-01 22:24:27 +01:00
Kuba Szczodrzyński
88cd18b8c6
[UI/Grades] Allow filtering by semester for university grades 2025-02-01 21:40:46 +01:00
Kuba Szczodrzyński
30a77f1a99
[UI/Grades] Update views for university grades 2025-01-31 23:10:07 +01:00
Kuba Szczodrzyński
6de7ee9cee
[API/Usos] Store term names, add term ID to grades 2025-01-31 21:31:02 +01:00
Kuba Szczodrzyński
d44b85073a
[API/Usos] Implement basic grades support 2025-01-31 21:03:00 +01:00
Kuba Szczodrzyński
514fbafd00
[API/Usos] Change team codes to include unique ID or current year 2025-01-31 19:16:03 +01:00
Kuba Szczodrzyński
c35222cdfd
[API/Usos] Fix year end date on new school year 2025-01-31 19:03:31 +01:00
Kuba Szczodrzyński
37a94595c0
[UI] Enable colored app bars on scroll (#211)
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 25s
* Extract fragment scroll listener to separate file

* Replace canRefresh with isScrolled

* Add empty helper class to animate app bar color

* Implement AppBarColorAnimator

* Rename getRefreshScrollingView() to getScrollingView()

* Set isScrolled on drag start

* Clear isScrolled on fling to top

* Add getSyncParams() to fragments

* Convert getAppBars() to property

* Tint TabLayout background drawable
2024-07-09 18:15:03 +02:00
Kuba Szczodrzyński
58d9dec33c
[App] Enable nightly app updates, check every 12 hours
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 26s
2024-07-08 20:49:01 +02:00
Kuba Szczodrzyński
095403cc76
Merge branch 'master' into develop 2024-07-08 15:49:43 +02:00
Kuba Szczodrzyński
7f3a607246
[App] Fix RecyclerTabLayout ProGuard rules 2024-07-08 15:39:44 +02:00
Kuba Szczodrzyński
ffee78d4f7
[UI] Fix closing bottom sheet on scrim view click 2024-07-08 15:39:07 +02:00
Kuba Szczodrzyński
f2a20c3aae
Merge branch 'hotfix/nologin'
Some checks failed
Push (master) / Build for Google Play (AAB) (push) Failing after 1s
2024-07-08 14:39:02 +02:00
Kuba Szczodrzyński
1e7dbba995
[4.13.7] Update build.gradle, signing and changelog 2024-07-08 14:10:29 +02:00
Kuba Szczodrzyński
0b8f3fe94b
[Actions] Add build fixes from develop 2024-07-08 14:10:23 +02:00
Kuba Szczodrzyński
0e8b0673ca
[App] Add Demo login method 2024-07-08 13:28:54 +02:00
Kuba Szczodrzyński
8450f6953e
[UI] Enable swipe-to-refresh on home, grades, behaviour fragments
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 28s
2024-07-07 23:22:37 +02:00
Kuba Szczodrzyński
ddefda08f1
[App] Simplify enabling Dev Mode on nightly builds 2024-07-07 22:55:20 +02:00
Mateusz T
c5b173b40a
[API/Usos] Remove non-digit characters from student number (#189)
* Save only USOS ID number without indexes

* Checking student number is or is not empty

* Apply suggestions from code review

---------

Co-authored-by: Kuba Szczodrzyński <kuba@szczodrzynski.pl>
2024-07-07 22:24:50 +02:00
Kuba Szczodrzyński
f10bc42c7b
[UI] Implement RecyclerTabLayout, enable swipe-to-refresh in timetable (#209)
* Enable swipe-to-refresh in timetable

* Add basic RecyclerTabLayout view

* Implement tab scrolling in RecyclerTabLayout

* Implement tab clicking in RecyclerTabLayout

* Add selected tab indicator to RecyclerTabLayout

* Add ProGuard rules for RecyclerTabLayout

* Set RecyclerTabLayout background
2024-07-07 22:18:00 +02:00
Kuba Szczodrzyński
6371d71b7a
[UI] Add SimpleDialog class, migrate app dialogs (#208)
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 21s
* Make onShow() abstract and onDismiss() suspend

* Add dialog suspend show method

* Add SimpleDialog, support text field and choice items in BaseDialog

* Migrate MaterialAlertDialogBuilder to SimpleDialog

* Remove dialog onShow and onDismiss listeners
2024-07-06 19:36:59 +02:00
Kuba Szczodrzyński
09f0c986e0
[UI] Reformat layout XMLs, cleanup NavLib code (#207)
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 19s
* Remove Themes and getColorFromAttr() usage

* Reformat all layout XML files

* Remove <layout> from non-data binding XMLs

* Cleanup unused NavLib code

* Migrate NavBottomSheet to view binding, remove unused components

* Add IIcon.toDrawable() extension

* Make BottomSheet scrim opacity linear

* Support touch events on BottomSheet scrim
2024-07-05 18:46:37 +02:00
Kuba Szczodrzyński
10043cc62c
[UI] Migrate to base fragment classes, restructure base modules (#206)
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 20s
* Replace android:visibility with android:isVisible

* Move base dialogs and views to .ui.base

* Move uncategorized classes to ui.main

* Fix view classes in XML

* Add BaseFragment, use for LazyFragment

* Migrate fragments to BaseFragment

* Move activity setup from BaseFragment, recreate Job on attach

* Move BaseFragment initialization to onResume

* Add base PagerFragment, add TemplateFragment to drawer

* Support swipe-to-refresh in base fragments

* Remove SwipeRefreshLayout split implementation

* Rename onViewCreated to onViewReady

* Remove LazyFragment

* Save page selection in PagerFragment, migrate AttendanceFragment

* Migrate fragments to PagerFragment

* Migrate contributors to a fragment

* Migrate TimetableFragment to PagerFragment

* Fix disabling SwipeToRefresh on page scroll

* Fix crash in CrashActivity
2024-07-04 22:14:52 +02:00
Kuba Szczodrzyński
f795412551
[Actions] Use Europe/Warsaw timezone for build dates
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 23s
2024-07-02 14:01:05 +02:00
Kuba Szczodrzyński
6a7020a516
[Gradle] Fix copying signed release APK 2024-07-02 13:44:59 +02:00
Adam Rurański
137ea65e0f
[UI] Make snowfall condition consistent (#195)
Some checks failed
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
Schedule/dispatch / Check new changes (push) Failing after 17s
2024-07-01 22:39:47 +02:00
koliwbr
50ef7f8617
[Git] Fix build status badges in README (#193)
* Popraw statusy budowania w README

* Update README.md

---------

Co-authored-by: Kuba Szczodrzyński <kuba@szczodrzynski.pl>
2024-07-01 22:38:43 +02:00
Kuba Szczodrzyński
e1dbc2f050
[App] Refactor app core modules, use Timber for logging (#205)
* [App] Fix config migration issues

* Move .sync to .core

* Move .firebase, .network, .managers, .receivers, .sync to .core

* Replace HyperLog with Timber

* Cleanup logs every 7 days

* Rename NotificationChannelManager, reformat App

* Create FirebaseManager, ShortcutManager
2024-07-01 22:35:11 +02:00
Kuba Szczodrzyński
77e1acbb1e
[App] Disable R8 full mode, support devModePassword, fix build timestamp 2024-07-01 11:53:14 +02:00
Kuba Szczodrzyński
6e19f37d79
[Actions] Refactor build workflows, fix Gradle rename task
Some checks failed
Schedule/dispatch / Check new changes (push) Failing after 1m11s
Schedule/dispatch / Build nightly release (APK) (push) Has been skipped
2024-06-30 19:51:21 +02:00
0823e72328
[UI] Upgrade to Material 3 design, refactor some core elements (#201)
* Material 3 theme and color support, filled cards

* Change drawer header, dark bottombar color

* Replace MaterialComponents with Material3

* wielki powrót pr m3 do szkolnego (nie czytajcie tego kodu)

* fix M3 UI code & upgrade kotlin

* update dependencies

* fix missing Intent receiver flags for Tiramisu+

* fix kapt errors related to SelectiveDAO + migrate BuildConfig

* adapt code to updated dependencies + align lessons (based by szkolny-eu/szkolny-android#196)

* fix: no query filtering

* fix: duplicated items in about card

* fix: "Back button opens drawer" (redundant super call)

* fix: too small heading in agenda dialog

* adapt notes fragment to MD3

* add lock layout function (szkolny-eu/szkolny-android#199)

* hide classroom heading when no classroom is specified

* add support for grade column codes

* grades: join code and category together

* add cosmetic ui changes + fix build issues

* fix proguard rules (attempt 1)

* add new Retrofit2 rules

* add new ProGuard rules + fix QR scanning

* fix agenda view crash when building release variant

* improve LessonDetailsDialog

* remove duplicated string extension

* set separate app ID & icon for debug version

* remove unneeded import statement

* fix collapsing toolbar title when doing back gesture

* remove useless dependencies

* fix UI issues on old Android versions

* fix missing color resources + cleanup dependencies

* fix release building issue

* fix release building issue & remove ripple from NavView

* move version badge to the top bar

* Revert changes introduced by rebase

* Update NavLib from sadorowo/NavLib

* Revert "add lock layout function (szkolny-eu/szkolny-android#199)"

This reverts commit 2fd7038d0c0b43f2d39333d2e556bde066cd28b6.

* Revert "add support for grade column codes"

* Revert unnecessary code changes, part 1

* Lower minSdk to 19

* Revert unnecessary code changes, part 2

* Add new application logo

* Restore bottom bar support in NavLib, revert unnecessary changes

* Use new IconicsMaterialButton in MessageFragment

* Migrate NavView to view binding

* Support IconButton in IconicsMaterialButton

* Cleanup NavLib w600dp styles

* Remove NavLib text styles

* Refactor all application themes, update styles in layouts

* Move enums and config entry to .data, fix app crashing

* Rename non-theme styles to AppStyle

* Restructure app config classes, move config to .data

* Add Theme enum and UiManager, support basic theme changing

* Actually support basic theme changing

* Serialize enum as string, fix config migration, bring back DebugDb

* Fix changing themes, apply night mode in App

* Fix resolving ColorStateList attributes, add LabPlaygroundFragment

* add Iconics methods into ProGuard rules

* Replace home card icon buttons, remove unused icons

* Update gradle properties

* Update build.gradle

* Remove unnecessary dependencies

* Remove playstore icon

* Apply fixes after review

---------

Co-authored-by: Adam Kasprzycki <66315787+santoni0@users.noreply.github.com>
Co-authored-by: Kuba Szczodrzyński <kuba@szczodrzynski.pl>
2024-06-30 16:12:07 +02:00
Kuba Szczodrzyński
fadf1d7754
[Gradle] Add NavLib 0.8.0 as local module
Some checks failed
Nightly build / Prepare build environment (push) Has been cancelled
Nightly build / Build APK (push) Has been cancelled
Nightly build / Sign APK (push) Has been cancelled
Nightly build / Publish APK (push) Has been cancelled
2024-06-18 17:45:26 +02:00
Kuba Szczodrzyński
1071a0848a
Merge branch 'develop' 2023-03-25 10:10:42 +01:00
Kuba Szczodrzyński
cefb0deba8
[Actions] Rename changelog output name. 2023-03-25 10:09:36 +01:00
Kuba Szczodrzyński
53c813f014
Merge branch 'develop' 2023-03-24 22:35:54 +01:00
Kuba Szczodrzyński
90a151c129
[4.13.6] Update build.gradle, signing and changelog. 2023-03-24 22:27:27 +01:00
Kuba Szczodrzyński
9fd9721ae7
[UI] Hide Debugging menu without dev mode. 2023-03-24 22:24:33 +01:00
Kuba Szczodrzyński
ceca75ef4b
[UI/Timetable] Add option to sync current week. 2023-03-24 22:16:34 +01:00
Kuba Szczodrzyński
21c00bbe53
[API] Fix detecting session cookies. Remove expired cookies. 2023-03-24 22:09:31 +01:00
Kuba Szczodrzyński
db00566ebf
[UI/Login] Fallback reCAPTCHA to WebView activity. 2023-03-24 22:09:31 +01:00
B.O.S.S
07ab1b984f
[API/Librus] Fix login. (#176) 2023-03-24 22:09:03 +01:00
Kuba Szczodrzyński
8177d4aa2d
[Widgets] Fix pending intents mutability. Hide timetable sync button. 2023-03-24 11:13:00 +01:00
Kuba Szczodrzyński
beff1b6460
[App] Fix cookie persistence. 2023-03-24 10:56:35 +01:00
Kuba Szczodrzyński
31b569b02e
[4.13.5] Update build.gradle, signing and changelog. 2023-03-22 23:16:28 +01:00
Kuba Szczodrzyński
8bf77817d2
[UI] Fix writing files on Android 13 and newer. 2023-03-22 23:15:45 +01:00
Kuba Szczodrzyński
87b7bd9b30
Merge branch 'develop' 2022-12-27 12:30:23 +01:00
Kuba Szczodrzyński
27b61adf1d
[Actions] Fix Play release publishing workflow. 2022-12-27 12:30:03 +01:00
Kuba Szczodrzyński
8d7dc511ea
Merge branch 'develop' 2022-12-27 12:09:04 +01:00
Kuba Szczodrzyński
a0244841ad
[4.13.4] Update build.gradle, signing and changelog. 2022-12-26 14:45:29 +01:00
Kuba Szczodrzyński
12c0c6f2ec
[UI] Always show event subject dropdown for university school. 2022-12-26 14:43:42 +01:00
Kuba Szczodrzyński
aaa3b8626e
[UI] Update event types for university school. 2022-12-26 14:01:25 +01:00
Kuba Szczodrzyński
48c9e2dfe3
[4.13.3] Update build.gradle, signing and changelog. 2022-12-06 10:35:23 +01:00
Kuba Szczodrzyński
81d4801d27
[UI] Add snowfall to CounterActivity. Enable in February as well. 2022-12-06 10:34:12 +01:00
Kuba Szczodrzyński
5f8016061d
[API/Vulcan] Fix wrong serializing of null in JSON causing API error. 2022-12-06 10:22:47 +01:00
Kuba Szczodrzyński
5007587192
[UI/Agenda] Allow prioritizing event subject over event type. 2022-11-30 11:29:43 +01:00
Kuba Szczodrzyński
dfd1083e41
[UI/Timetable] Show lesson replacing notes in all places. 2022-11-30 10:41:43 +01:00
Kuba Szczodrzyński
a322986df5
Merge branch 'develop' 2022-11-28 20:39:51 +01:00
kuba2k2
726c22b70a
Merge branch 'develop' 2022-10-26 22:21:13 +02:00
Kuba Szczodrzyński
ef0996c80e
Merge branch 'develop' 2022-09-23 12:05:03 +02:00
Kuba Szczodrzyński
14952307b3
Merge branch 'develop' 2022-09-17 23:06:32 +02:00
Kuba Szczodrzyński
86c41d9191
Merge branch 'develop' 2022-04-19 23:13:15 +02:00
Kuba Szczodrzyński
c1ef0e9d11
Merge branch 'develop' 2022-03-14 18:46:37 +01:00
Kuba Szczodrzyński
2e97467c57
Merge branch 'develop' 2022-02-21 22:12:46 +01:00
Kuba Szczodrzyński
46de915965
Merge branch 'develop' 2022-02-05 21:11:40 +01:00
Kuba Szczodrzyński
9a6d56ec77
Merge branch 'develop' 2021-11-01 14:00:30 +01:00
Kuba Szczodrzyński
41217190bb
Merge branch 'develop' 2021-09-23 22:09:20 +02:00
Kuba Szczodrzyński
d60e622626
Merge branch 'develop' 2021-09-11 00:31:21 +02:00
Kuba Szczodrzyński
c011f550bb
Merge branch 'develop' 2021-05-26 22:32:14 +02:00
Kuba Szczodrzyński
61b7410bd0
Merge branch 'develop' 2021-04-07 18:43:05 +02:00
Kuba Szczodrzyński
d5c10fbd2b
Merge branch 'develop' 2021-04-07 18:31:03 +02:00
Kuba Szczodrzyński
fd31cafd8f Merge branch 'develop' 2021-02-26 23:45:28 +01:00
Kuba Szczodrzyński
df7044cc64 Merge branch 'develop' 2021-02-22 00:18:20 +01:00
Kuba Szczodrzyński
0a127ac6ee Merge branch 'develop' 2020-10-17 00:22:35 +02:00
Kuba Szczodrzyński
6b75715e87 Merge branch 'develop' 2020-09-05 19:39:17 +02:00
Kuba Szczodrzyński
b9e0d91220 Merge branch 'develop' 2020-09-04 15:44:55 +02:00
Kuba Szczodrzyński
0d5bb331f3 Merge branch 'develop' 2020-09-03 14:09:55 +02:00
Kuba Szczodrzyński
0e52fb7386 Merge branch 'develop' 2020-08-29 00:01:16 +02:00
Kuba Szczodrzyński
339bb9c8f6 Merge branch 'develop' 2020-08-28 15:32:36 +02:00
Kuba Szczodrzyński
b44fa6b2e4 Merge branch 'develop' 2020-05-22 14:49:24 +02:00
Kuba Szczodrzyński
9cc98fcf08 Merge branch 'develop' 2020-05-17 17:52:28 +02:00
Kuba Szczodrzyński
67b794ce2b Merge branch 'develop' 2020-04-20 19:13:49 +02:00
Kuba Szczodrzyński
31b502bb6c Merge branch 'develop' 2019-10-31 17:58:02 +01:00
Kuba Szczodrzyński
7686c451e6 Merge branch 'develop' 2019-10-09 19:16:15 +02:00
Kuba Szczodrzyński
04f3ce4d64 Merge branch 'develop' 2019-10-02 20:44:19 +02:00
Kuba Szczodrzyński
3a6087e421 Merge branch 'hotfix-3.0.3' 2019-09-26 22:36:28 +02:00
884 changed files with 22112 additions and 14352 deletions

View File

@ -23,8 +23,6 @@ def get_password(
auth_plugin="mysql_native_password",
)
print(f"Generating passwords for version {version_name} ({version_code})")
password = base64.b64encode(secrets.token_bytes(16)).decode()
iv = secrets.token_bytes(16)

View File

@ -102,7 +102,9 @@ def get_commit_log(project_dir: str, format: str, max_lines: int = None) -> str:
)
log = subprocess.run(
args=f"git log {last_tag}..HEAD --format=%an%x00%at%x00%h%x00%s%x00%D".split(" "),
args=f"git log {last_tag}..HEAD --format=%an%x00%at%x00%h%x00%s%x00%D".split(
" "
),
cwd=project_dir,
stdout=subprocess.PIPE,
)

View File

@ -1,10 +1,7 @@
import json
import os
import re
import sys
from datetime import datetime, timedelta
import requests
from zoneinfo import ZoneInfo
from _utils import (
get_commit_log,
@ -18,38 +15,20 @@ if __name__ == "__main__":
print("usage: bump_nightly.py <project dir>")
exit(-1)
repo = os.getenv("GITHUB_REPOSITORY")
sha = os.getenv("GITHUB_SHA")
if not repo or not sha:
print("Missing GitHub environment variables.")
exit(-1)
with requests.get(
f"https://api.github.com/repos/{repo}/actions/runs?per_page=5&status=success"
) as r:
data = json.loads(r.text)
runs = [run for run in data["workflow_runs"] if run["head_sha"] == sha]
if runs:
print("::set-output name=hasNewChanges::false")
exit(0)
print("::set-output name=hasNewChanges::true")
project_dir = get_project_dir()
(version_code, version_name) = read_gradle_version(project_dir)
version_name = version_name.split("+")[0]
date = datetime.now()
date = datetime.now(tz=ZoneInfo("Europe/Warsaw"))
if date.hour > 6:
version_name += "+daily." + date.strftime("%Y%m%d-%H%M")
else:
date -= timedelta(days=1)
version_name += "+nightly." + date.strftime("%Y%m%d")
print("::set-output name=appVersionName::" + version_name)
print("::set-output name=appVersionCode::" + str(version_code))
print("appVersionName=" + version_name)
print("appVersionCode=" + str(version_code))
write_gradle_version(project_dir, version_code, version_name)

23
.github/utils/check_nightly.py vendored Normal file
View File

@ -0,0 +1,23 @@
import json
import os
import requests
if __name__ == "__main__":
repo = os.getenv("GITHUB_REPOSITORY")
sha = os.getenv("GITHUB_SHA")
if not repo or not sha:
print("Missing GitHub environment variables.")
exit(-1)
with requests.get(
f"https://api.github.com/repos/{repo}/actions/runs?per_page=5&status=success"
) as r:
data = json.loads(r.text)
runs = [run for run in data["workflow_runs"] if run["head_sha"] == sha]
if runs:
print("hasNewChanges=false")
exit(0)
print("hasNewChanges=true")

View File

@ -12,24 +12,24 @@ if __name__ == "__main__":
(version_code, version_name) = read_gradle_version(project_dir)
print("::set-output name=appVersionName::" + version_name)
print("::set-output name=appVersionCode::" + str(version_code))
print("appVersionName=" + version_name)
print("appVersionCode=" + str(version_code))
dir = f"{project_dir}/app/release/whatsnew-{version_name}/"
os.makedirs(dir, exist_ok=True)
print("::set-output name=changelogDir::" + dir)
print("changelogDir=" + dir)
(title, changelog) = get_changelog(project_dir, format="plain")
# plain text changelog - Firebase App Distribution
with open(dir + "whatsnew-titled.txt", "w", encoding="utf-8") as f:
with open(dir + "whatsnew_titled.txt", "w", encoding="utf-8") as f:
f.write(title)
f.write("\n")
f.write(changelog)
print("::set-output name=changelogPlainTitledFile::" + dir + "whatsnew-titled.txt")
print("changelogPlainTitledFile=" + dir + "whatsnew_titled.txt")
print("::set-output name=changelogTitle::" + title)
print("changelogTitle=" + title)
# plain text changelog, max 500 chars - Google Play
with open(dir + "whatsnew-pl-PL", "w", encoding="utf-8") as f:
@ -41,32 +41,31 @@ if __name__ == "__main__":
changelog = changelog.strip()
f.write(changelog)
print("::set-output name=changelogPlainFile::" + dir + "whatsnew-pl-PL")
print("changelogPlainFile=" + dir + "whatsnew-pl-PL")
# markdown changelog - Discord webhook
(_, changelog) = get_changelog(project_dir, format="markdown")
with open(dir + "whatsnew.md", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogMarkdownFile::" + dir + "whatsnew.md")
print("changelogMarkdownFile=" + dir + "whatsnew.md")
# html changelog - version info in DB
(_, changelog) = get_changelog(project_dir, format="html")
with open(dir + "whatsnew.html", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogHtmlFile::" + dir + "whatsnew.html")
print("changelogHtmlFile=" + dir + "whatsnew.html")
changelog = get_commit_log(project_dir, format="plain", max_lines=10)
with open(dir + "commit_log.txt", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=commitLogPlainFile::" + dir + "commit_log.txt")
print("commitLogPlainFile=" + dir + "commit_log.txt")
changelog = get_commit_log(project_dir, format="markdown", max_lines=10)
with open(dir + "commit_log.md", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=commitLogMarkdownFile::" + dir + "commit_log.md")
print("commitLogMarkdownFile=" + dir + "commit_log.md")
changelog = get_commit_log(project_dir, format="html", max_lines=10)
with open(dir + "commit_log.html", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=commitLogHtmlFile::" + dir + "commit_log.html")
print("commitLogHtmlFile=" + dir + "commit_log.html")

View File

@ -13,7 +13,7 @@ if __name__ == "__main__":
files = glob.glob(f"{project_dir}/app/release/*.*")
for file in files:
file_relative = file.replace(os.getenv("GITHUB_WORKSPACE") + "/", "")
file_relative = file.replace(project_dir + "/", "")
if "-aligned.apk" in file:
os.unlink(file)
elif "-signed.apk" in file:
@ -22,5 +22,5 @@ if __name__ == "__main__":
os.unlink(new_file)
os.rename(file, new_file)
elif ".apk" in file or ".aab" in file:
print("::set-output name=signedReleaseFile::" + file)
print("::set-output name=signedReleaseFileRelative::" + file_relative)
print("signedReleaseFile=" + file)
print("signedReleaseFileRelative=" + file_relative)

View File

@ -3,6 +3,7 @@ import os
import sys
from datetime import datetime
from time import time
from zoneinfo import ZoneInfo
import mysql.connector as mysql
from dotenv import load_dotenv
@ -59,12 +60,22 @@ def save_version(
build_date = int(os.stat(file).st_mtime)
bundle_name_play = output_aab_play
build_date = datetime.fromtimestamp(build_date).strftime("%Y-%m-%d %H:%M:%S")
build_date = datetime.fromtimestamp(
build_date,
tz=ZoneInfo("Europe/Warsaw"),
).strftime("%Y-%m-%d %H:%M:%S")
if build_type in ["nightly", "daily"]:
download_url = apk_server_nightly + apk_name if apk_name else None
else:
download_url = apk_server_release + apk_name if apk_name else None
# download_url = apk_server_release + apk_name if apk_name else None
download_url = (
f"https://github.com/szkolny-eu/szkolny-android/releases/download/v{version_name}/{apk_name}"
if apk_name
else None
)
if download_url:
print("downloadUrl=" + download_url)
cols = [
"versionCode",
@ -119,4 +130,12 @@ if __name__ == "__main__":
APK_SERVER_RELEASE = os.getenv("APK_SERVER_RELEASE")
APK_SERVER_NIGHTLY = os.getenv("APK_SERVER_NIGHTLY")
save_version(project_dir, DB_HOST, DB_USER, DB_PASS, DB_NAME, APK_SERVER_RELEASE, APK_SERVER_NIGHTLY)
save_version(
project_dir,
DB_HOST,
DB_USER,
DB_PASS,
DB_NAME,
APK_SERVER_RELEASE,
APK_SERVER_NIGHTLY,
)

View File

@ -31,8 +31,6 @@ def sign(
SIGNING_FORMAT = "$param1.{}.$param2"
CPP_FORMAT = "/*{}*/\nstatic toys AES_IV[16] = {{\n\t{} }};"
print(f"Writing passwords for version {version_name} ({version_code})")
iv_hex = " ".join(["{:02x}".format(x) for x in iv])
iv_cpp = ", ".join(["0x{:02x}".format(x) for x in iv])
@ -71,8 +69,8 @@ if __name__ == "__main__":
version_name, version_code, DB_HOST, DB_USER, DB_PASS, DB_NAME
)
print("::set-output name=appVersionName::" + version_name)
print("::set-output name=appVersionCode::" + str(version_code))
print("appVersionName=" + version_name)
print("appVersionCode=" + str(version_code))
sign(
project_dir,

View File

@ -1,6 +1,7 @@
import os
import sys
from datetime import datetime
from zoneinfo import ZoneInfo
import requests
from dotenv import load_dotenv
@ -11,8 +12,7 @@ from _utils import get_changelog, get_commit_log, get_project_dir, read_gradle_v
def post_webhook(
project_dir: str,
apk_file: str,
apk_server_release: str,
apk_server_nightly: str,
download_url: str,
webhook_release: str,
webhook_testing: str,
):
@ -25,16 +25,13 @@ def post_webhook(
testing = ["dev", "beta", "nightly", "daily"]
testing = build_type in testing
apk_name = os.path.basename(apk_file)
if build_type in ["nightly", "daily"]:
download_url = apk_server_nightly + apk_name
else:
download_url = apk_server_release + apk_name
if testing:
build_date = int(os.stat(apk_file).st_mtime)
if build_date:
build_date = datetime.fromtimestamp(build_date).strftime("%Y-%m-%d %H:%M")
build_date = datetime.fromtimestamp(
build_date,
tz=ZoneInfo("Europe/Warsaw"),
).strftime("%Y-%m-%d %H:%M")
# untagged release, get commit log
if build_type in ["nightly", "daily"]:
@ -48,13 +45,17 @@ def post_webhook(
requests.post(url=webhook_testing, json=webhook)
else:
changelog = get_changelog(project_dir, format="markdown")
webhook = get_webhook_release(changelog, download_url)
webhook = get_webhook_release(version_name, changelog, download_url)
requests.post(url=webhook_release, json=webhook)
def get_webhook_release(changelog: str, download_url: str):
def get_webhook_release(version_name: str, changelog: str, download_url: str):
(title, content) = changelog
return {"content": f"__**{title}**__\n{content}\n{download_url}"}
return {
"content": (
f"__**{title}**__\n{content}\n[Szkolny.eu {version_name}]({download_url})"
),
}
def get_webhook_testing(
@ -73,9 +74,11 @@ def get_webhook_testing(
"fields": [
{
"name": f"Wersja `{version_name}`",
"value": f"[Pobierz .APK]({download_url})"
if download_url
else "*Pobieranie niedostępne*",
"value": (
f"[Pobierz .APK]({download_url})"
if download_url
else "*Pobieranie niedostępne*"
),
"inline": False,
},
{
@ -103,16 +106,14 @@ if __name__ == "__main__":
load_dotenv()
APK_FILE = os.getenv("APK_FILE")
APK_SERVER_RELEASE = os.getenv("APK_SERVER_RELEASE")
APK_SERVER_NIGHTLY = os.getenv("APK_SERVER_NIGHTLY")
DOWNLOAD_URL = os.getenv("DOWNLOAD_URL")
WEBHOOK_RELEASE = os.getenv("WEBHOOK_RELEASE")
WEBHOOK_TESTING = os.getenv("WEBHOOK_TESTING")
post_webhook(
project_dir,
APK_FILE,
APK_SERVER_RELEASE,
APK_SERVER_NIGHTLY,
DOWNLOAD_URL,
WEBHOOK_RELEASE,
WEBHOOK_TESTING,
)

195
.github/workflows/_build.yml vendored Normal file
View File

@ -0,0 +1,195 @@
name: "[reusable] Szkolny.eu Build"
on:
workflow_call:
inputs:
nightly:
type: boolean
default: false
build-apk:
type: boolean
default: false
build-aab:
type: boolean
default: false
release-ssh:
type: boolean
default: false
release-github:
type: boolean
default: false
release-firebase:
type: boolean
default: false
release-google-play:
type: boolean
default: false
release-discord:
type: boolean
default: false
secrets:
APK_SERVER_NIGHTLY:
APK_SERVER_RELEASE:
DB_HOST:
DB_NAME:
DB_PASS:
DB_USER:
FIREBASE_APP_ID:
FIREBASE_GROUPS_NIGHTLY:
FIREBASE_GROUPS_RELEASE:
FIREBASE_SERVICE_ACCOUNT_JSON:
KEY_ALIAS_PASSWORD:
KEY_ALIAS:
KEY_STORE_PASSWORD:
KEY_STORE:
PLAY_RELEASE_TRACK:
PLAY_SERVICE_ACCOUNT_JSON:
SSH_IP:
SSH_KEY:
SSH_PATH_NIGHTLY:
SSH_PATH_RELEASE:
SSH_USERNAME:
WEBHOOK_RELEASE:
WEBHOOK_TESTING:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
clean: false
- name: Setup JDK 17
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Setup Python
uses: actions/setup-python@v4
- name: Install Python packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Bump nightly version
if: ${{ inputs.nightly }}
run: python $GITHUB_WORKSPACE/.github/utils/bump_nightly.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Write signing passwords and keystore
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
KEY_STORE: ${{ secrets.KEY_STORE }}
run: |
python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit >> $GITHUB_OUTPUT
echo $KEY_STORE | base64 --decode > keystore.jks
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Build app with Gradle
if: ${{ inputs.build-apk || inputs.build-aab }}
run: |
chmod +x ./gradlew
./gradlew \
${{ inputs.build-apk && 'assembleOfficialRelease' || '' }} \
${{ inputs.build-aab && 'bundlePlayRelease' || '' }} \
-P android.injected.signing.store.file=${{ github.workspace }}/keystore.jks \
-P android.injected.signing.store.password=${{ secrets.KEY_STORE_PASSWORD }} \
-P android.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \
-P android.injected.signing.key.password=${{ secrets.KEY_ALIAS_PASSWORD }}
- name: Upload release to server
if: ${{ inputs.release-ssh }}
uses: easingthemes/ssh-deploy@v2.1.6
env:
REMOTE_HOST: ${{ secrets.SSH_IP }}
REMOTE_USER: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: app/release/
TARGET: ${{ inputs.nightly && secrets.SSH_PATH_NIGHTLY || secrets.SSH_PATH_RELEASE }}
- name: Find signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/find_artifacts.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Extract release changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Save version to database
id: save
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Release on GitHub
if: ${{ inputs.release-github }}
uses: softprops/action-gh-release@v1
with:
name: ${{ steps.changelog.outputs.changelogTitle }}
body_path: ${{ steps.changelog.outputs.changelogMarkdownFile }}
files: ${{ steps.artifacts.outputs.signedReleaseFile }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Distribute to App Distribution
if: ${{ inputs.release-firebase }}
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON }}
file: ${{ steps.artifacts.outputs.signedReleaseFile }}
groups: ${{ inputs.nightly && secrets.FIREBASE_GROUPS_NIGHTLY || secrets.FIREBASE_GROUPS_RELEASE }}
releaseNotesFile: ${{ inputs.nightly && steps.changelog.outputs.commitLogPlainFile || steps.changelog.outputs.changelogPlainTitledFile }}
- name: Publish AAB to Google Play
if: ${{ inputs.release-google-play }}
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
packageName: pl.szczodrzynski.edziennik
releaseFiles: ${{ steps.artifacts.outputs.signedReleaseFile }}
releaseName: ${{ steps.changelog.outputs.appVersionName }}
track: ${{ secrets.PLAY_RELEASE_TRACK }}
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
status: completed
- name: Post Discord webhook
if: ${{ inputs.release-discord }}
env:
APK_FILE: ${{ steps.artifacts.outputs.signedReleaseFile }}
DOWNLOAD_URL: ${{ steps.save.outputs.downloadUrl }}
WEBHOOK_RELEASE: ${{ secrets.WEBHOOK_RELEASE }}
WEBHOOK_TESTING: ${{ secrets.WEBHOOK_TESTING }}
run: python $GITHUB_WORKSPACE/.github/utils/webhook_discord.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

View File

@ -1,154 +0,0 @@
name: Nightly build
on:
schedule:
# 23:30 UTC, 0:30 or 1:30 CET/CEST
- cron: "30 23 * * *"
workflow_dispatch:
jobs:
prepare:
name: Prepare build environment
runs-on: self-hosted
outputs:
hasNewChanges: ${{ steps.nightly.outputs.hasNewChanges }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
clean: false
- name: Set executable permissions to gradlew
run: chmod +x ./gradlew
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Bump nightly version
id: nightly
run: python $GITHUB_WORKSPACE/.github/utils/bump_nightly.py $GITHUB_WORKSPACE
- name: Write signing passwords
if: steps.nightly.outputs.hasNewChanges
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
run: python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit
build:
name: Build APK
runs-on: self-hosted
needs:
- prepare
if: ${{ needs.prepare.outputs.hasNewChanges == 'true' }}
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Assemble official release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: assembleOfficialRelease
sign:
name: Sign APK
runs-on: self-hosted
needs:
- build
outputs:
signedReleaseFile: ${{ steps.artifacts.outputs.signedReleaseFile }}
signedReleaseFileRelative: ${{ steps.artifacts.outputs.signedReleaseFileRelative }}
steps:
- name: Sign build artifacts
id: sign_app
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/release
signingKeyBase64: ${{ secrets.KEY_STORE }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_ALIAS_PASSWORD }}
env:
ANDROID_HOME: ${{ needs.build.outputs.androidHome }}
ANDROID_SDK_ROOT: ${{ needs.build.outputs.androidSdkRoot }}
BUILD_TOOLS_VERSION: "30.0.2"
- name: Rename signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/rename_artifacts.py $GITHUB_WORKSPACE
publish:
name: Publish APK
runs-on: self-hosted
needs:
- sign
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Extract changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE
- name: Upload APK to SFTP
uses: easingthemes/ssh-deploy@v2.1.6
env:
REMOTE_HOST: ${{ secrets.SSH_IP }}
REMOTE_USER: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: ${{ needs.sign.outputs.signedReleaseFileRelative }}
TARGET: ${{ secrets.SSH_PATH_NIGHTLY }}
- name: Save version metadata
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE
- name: Distribute to App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: ${{ secrets.FIREBASE_GROUPS_NIGHTLY }}
file: ${{ needs.sign.outputs.signedReleaseFile }}
releaseNotesFile: ${{ steps.changelog.outputs.commitLogPlainFile }}
- name: Post Discord webhook
env:
APK_FILE: ${{ needs.sign.outputs.signedReleaseFile }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
WEBHOOK_RELEASE: ${{ secrets.WEBHOOK_RELEASE }}
WEBHOOK_TESTING: ${{ secrets.WEBHOOK_TESTING }}
run: python $GITHUB_WORKSPACE/.github/utils/webhook_discord.py $GITHUB_WORKSPACE
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: true
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

View File

@ -1,131 +0,0 @@
name: Release build - Google Play [AAB]
on:
push:
branches:
- "master"
jobs:
prepare:
name: Prepare build environment
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
clean: false
- name: Set executable permissions to gradlew
run: chmod +x ./gradlew
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Write signing passwords
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
run: python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit
build:
name: Build App Bundle
runs-on: self-hosted
needs:
- prepare
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Bundle play release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: bundlePlayRelease
sign:
name: Sign App Bundle
runs-on: self-hosted
needs:
- build
outputs:
signedReleaseFile: ${{ steps.artifacts.outputs.signedReleaseFile }}
signedReleaseFileRelative: ${{ steps.artifacts.outputs.signedReleaseFileRelative }}
steps:
- name: Sign build artifacts
id: sign_app
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/release
signingKeyBase64: ${{ secrets.KEY_STORE }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_ALIAS_PASSWORD }}
env:
ANDROID_HOME: ${{ needs.build.outputs.androidHome }}
ANDROID_SDK_ROOT: ${{ needs.build.outputs.androidSdkRoot }}
BUILD_TOOLS_VERSION: "30.0.2"
- name: Rename signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/rename_artifacts.py $GITHUB_WORKSPACE
publish:
name: Publish App Bundle
runs-on: self-hosted
needs:
- sign
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Extract changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE
- name: Save version metadata
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE
- name: Publish AAB to Google Play
uses: r0adkll/upload-google-play@v1
if: ${{ endsWith(needs.sign.outputs.signedReleaseFile, '.aab') }}
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
packageName: pl.szczodrzynski.edziennik
releaseFile: ${{ needs.sign.outputs.signedReleaseFile }}
releaseName: ${{ steps.changelog.outputs.appVersionName }}
track: ${{ secrets.PLAY_RELEASE_TRACK }}
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: always()
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

View File

@ -1,154 +0,0 @@
name: Release build - official
on:
push:
tags:
- "*"
jobs:
prepare:
name: Prepare build environment
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
clean: false
- name: Set executable permissions to gradlew
run: chmod +x ./gradlew
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Write signing passwords
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
run: python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit
build:
name: Build APK
runs-on: self-hosted
needs:
- prepare
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Assemble official release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: assembleOfficialRelease
sign:
name: Sign APK
runs-on: self-hosted
needs:
- build
outputs:
signedReleaseFile: ${{ steps.artifacts.outputs.signedReleaseFile }}
signedReleaseFileRelative: ${{ steps.artifacts.outputs.signedReleaseFileRelative }}
steps:
- name: Sign build artifacts
id: sign_app
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/release
signingKeyBase64: ${{ secrets.KEY_STORE }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_ALIAS_PASSWORD }}
env:
ANDROID_HOME: ${{ needs.build.outputs.androidHome }}
ANDROID_SDK_ROOT: ${{ needs.build.outputs.androidSdkRoot }}
BUILD_TOOLS_VERSION: "30.0.2"
- name: Rename signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/rename_artifacts.py $GITHUB_WORKSPACE
publish:
name: Publish APK
runs-on: self-hosted
needs:
- sign
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Extract changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE
- name: Upload APK to SFTP
uses: easingthemes/ssh-deploy@v2.1.6
env:
REMOTE_HOST: ${{ secrets.SSH_IP }}
REMOTE_USER: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: ${{ needs.sign.outputs.signedReleaseFileRelative }}
TARGET: ${{ secrets.SSH_PATH_RELEASE }}
- name: Save version metadata
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE
- name: Distribute to App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: ${{ secrets.FIREBASE_GROUPS_RELEASE }}
file: ${{ needs.sign.outputs.signedReleaseFile }}
releaseNotesFile: ${{ steps.changelog.outputs.changelogPlainTitledFile }}
- name: Release on GitHub
uses: softprops/action-gh-release@v1
with:
name: ${{ steps.changelog.outputs.changelogTitle }}
body_path: ${{ steps.changelog.outputs.changelogMarkdownFile }}
files: ${{ needs.sign.outputs.signedReleaseFile }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Post Discord webhook
env:
APK_FILE: ${{ needs.sign.outputs.signedReleaseFile }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
WEBHOOK_RELEASE: ${{ secrets.WEBHOOK_RELEASE }}
WEBHOOK_TESTING: ${{ secrets.WEBHOOK_TESTING }}
run: python $GITHUB_WORKSPACE/.github/utils/webhook_discord.py $GITHUB_WORKSPACE
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: true
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

13
.github/workflows/push-master.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Push (master)
on:
push:
branches: ["master"]
jobs:
build:
name: Build for Google Play (AAB)
uses: szkolny-eu/szkolny-android/.github/workflows/_build.yml@develop
with:
build-aab: true
release-ssh: true
release-google-play: true
secrets: inherit

15
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Release
on:
push:
tags: ["v*.*.*"]
jobs:
build:
name: Build release (APK)
uses: szkolny-eu/szkolny-android/.github/workflows/_build.yml@develop
with:
build-apk: true
release-ssh: true
release-github: true
release-firebase: true
release-discord: true
secrets: inherit

42
.github/workflows/schedule-dispatch.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: Schedule/dispatch
on:
schedule:
# 23:30 UTC, 0:30 or 1:30 CET/CEST
- cron: "30 23 * * *"
workflow_dispatch:
jobs:
check:
name: Check new changes
runs-on: ubuntu-latest
outputs:
hasNewChanges: ${{ steps.nightly.outputs.hasNewChanges }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
clean: false
- name: Setup Python
uses: actions/setup-python@v4
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
requests
- name: Check new changes
id: nightly
run: python $GITHUB_WORKSPACE/.github/utils/check_nightly.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
build:
name: Build nightly release (APK)
needs:
- check
if: ${{ needs.check.outputs.hasNewChanges == 'true' }}
uses: szkolny-eu/szkolny-android/.github/workflows/_build.yml@develop
with:
nightly: true
build-apk: true
release-ssh: true
release-firebase: true
release-discord: true
secrets: inherit

View File

@ -1,7 +1,23 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<AndroidXmlCodeStyleSettings>
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
<option name="MANIFEST_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
<option name="OTHER_SETTINGS">
<value>
<option name="INSERT_LINE_BREAK_BEFORE_NAMESPACE_DECLARATION" value="true" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="ALLOW_TRAILING_COMMA" value="true" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
@ -127,6 +143,9 @@
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="PARAMETER_ANNOTATION_WRAP" value="2" />
<option name="ENUM_CONSTANTS_WRAP" value="2" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -4,6 +4,7 @@
<w>autoryzacji</w>
<w>ciasteczko</w>
<w>csrf</w>
<w>daynight</w>
<w>edziennik</w>
<w>eggfall</w>
<w>elearning</w>

View File

@ -6,13 +6,13 @@
[![Oficjalna strona](https://img.shields.io/badge/-website-orange?style=for-the-badge&logo=internet-explorer&logoColor=white)](https://szkolny.eu/)
[![Facebook Fanpage](https://img.shields.io/badge/-facebook-blue?style=for-the-badge&logo=facebook&logoColor=white)](https://szkolny.eu/facebook)
![Wersja Androida](https://img.shields.io/badge/android-4.1%2B-orange?style=for-the-badge&logo=android)
![Wersja Androida](https://img.shields.io/badge/android-4.4%2B-orange?style=for-the-badge&logo=android)
[![Najnowsza wersja](https://img.shields.io/github/v/release/szkolny-eu/szkolny-android?color=%2344CC11&include_prereleases&logo=github&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/releases/latest)
![Licencja](https://img.shields.io/github/license/szkolny-eu/szkolny-android?color=blue&logo=github&logoColor=white&style=for-the-badge)
[![Release build](https://img.shields.io/github/workflow/status/szkolny-eu/szkolny-android/Release%20build%20-%20official?label=Release&logo=github-actions&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/actions/workflows/build-release-apk.yml)
[![Play build](https://img.shields.io/github/workflow/status/szkolny-eu/szkolny-android/Release%20build%20-%20Google%20Play%20%5BAAB%5D?label=Play&logo=google-play&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/actions/workflows/build-release-aab-play.yml)
[![Nightly build](https://img.shields.io/github/workflow/status/szkolny-eu/szkolny-android/Nightly%20build?label=Nightly&logo=github-actions&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/actions/workflows/build-nightly-apk.yml)
[![Release build](https://img.shields.io/github/actions/workflow/status/szkolny-eu/szkolny-android/release.yml?label=Release&logo=github-actions&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/actions/workflows/release.yml)
[![Play build](https://img.shields.io/github/actions/workflow/status/szkolny-eu/szkolny-android/push-master.yml?label=Play&logo=google-play&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/actions/workflows/push-master.yml)
[![Nightly build](https://img.shields.io/github/actions/workflow/status/szkolny-eu/szkolny-android/schedule-dispatch.yml?label=Nightly&logo=github-actions&logoColor=white&style=for-the-badge)](https://github.com/szkolny-eu/szkolny-android/actions/workflows/schedule-dispatch.yml)
</div>

View File

@ -10,8 +10,10 @@ apply from: 'git-info.gradle'
android {
compileSdkVersion setup.compileSdk
namespace "pl.szczodrzynski.edziennik"
defaultConfig {
applicationId 'pl.szczodrzynski.edziennik'
applicationId "pl.szczodrzynski.edziennik"
minSdkVersion setup.minSdk
targetSdkVersion setup.targetSdk
@ -20,8 +22,9 @@ android {
buildConfigField "java.util.Map<String, String>", "GIT_INFO", gitInfoMap
buildConfigField "String", "VERSION_BASE", "\"${release.versionName}\""
manifestPlaceholders = [
buildTimestamp: String.valueOf(System.currentTimeMillis())
buildTimestamp: String.valueOf(System.currentTimeMillis())
]
multiDexEnabled = true
@ -36,6 +39,8 @@ android {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
correctErrorTypes = true
}
}
@ -43,10 +48,12 @@ android {
debug {
getIsDefault().set(true)
minifyEnabled = false
applicationIdSuffix = ".debug"
manifestPlaceholders = [
buildTimestamp: 0
buildTimestamp: "0"
]
}
release {
minifyEnabled = true
shrinkResources = true
@ -54,28 +61,35 @@ android {
proguardFiles fileTree('proguard').asList().toArray()
}
}
flavorDimensions "platform"
flavorDimensions += "platform"
productFlavors {
unofficial {
getIsDefault().set(true)
versionName "${release.versionName}-${gitInfo.versionSuffix}"
}
official {}
play {}
}
variantFilter { variant ->
def flavors = variant.flavors*.name
setIgnore(variant.buildType.name == "debug" && !flavors.contains("unofficial") || flavors.contains("main"))
}
sourceSets {
unofficial {
java.srcDirs = ["src/main/java", "src/play-not/java"]
manifest.srcFile("src/play-not/AndroidManifest.xml")
}
official {
java.srcDirs = ["src/main/java", "src/play-not/java"]
manifest.srcFile("src/play-not/AndroidManifest.xml")
}
play {
java.srcDirs = ["src/main/java", "src/play/java"]
}
@ -84,37 +98,45 @@ android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
buildFeatures {
dataBinding = true
viewBinding = true
buildConfig = true
}
compileOptions {
coreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xcontext-receivers"
}
packagingOptions {
resources {
excludes += ['META-INF/library-core_release.kotlin_module']
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
lint {
checkReleaseBuilds false
}
}
tasks.whenTaskAdded { task ->
if (!task.name.endsWith("Release") && !task.name.endsWith("ReleaseWithR8"))
if (!(task.name == "assembleUnofficialRelease" || task.name == "assembleOfficialRelease" || task.name == "signPlayReleaseBundle"))
return
def renameTaskName = "rename${task.name.capitalize()}"
def flavor = ""
@ -124,17 +146,22 @@ tasks.whenTaskAdded { task ->
flavor = task.name.substring("assemble".length(), task.name.indexOf("Release")).uncapitalize()
if (task.name.startsWith("minify"))
flavor = task.name.substring("minify".length(), task.name.indexOf("Release")).uncapitalize()
if (task.name.startsWith("sign"))
flavor = task.name.substring("sign".length(), task.name.indexOf("Release")).uncapitalize()
if (flavor != "") {
tasks.create(renameTaskName, Copy) {
tasks.register(renameTaskName, Copy) {
dependsOn(task.name)
duplicatesStrategy DuplicatesStrategy.FAIL
from file("${projectDir}/${flavor}/release/"),
file("${buildDir}/outputs/mapping/${flavor}Release/"),
file("${buildDir}/outputs/apk/${flavor}/release/"),
file("${buildDir}/outputs/bundle/${flavor}Release/")
include "*.aab", "*.apk", "mapping.txt", "output-metadata.json"
file("${projectDir}/build/outputs/apk/${flavor}/release/"),
file("${projectDir}/build/outputs/mapping/${flavor}Release/"),
file("${projectDir}/build/outputs/bundle/${flavor}Release/")
include "*-release.aab", "*-release.apk", "mapping.txt", "output-metadata.json"
destinationDir file("${projectDir}/release/")
rename ".+?\\.(.+)", "Edziennik_${android.defaultConfig.versionName}_${flavor}." + '$1'
}
task.finalizedBy(renameTaskName)
}
}
@ -145,28 +172,29 @@ dependencies {
// Language cores
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.multidex:multidex:2.0.1"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
// Android Jetpack
implementation "androidx.appcompat:appcompat:1.5.1"
implementation "androidx.appcompat:appcompat:1.7.0"
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.core:core-ktx:1.9.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.room:room-runtime:2.4.3"
implementation "androidx.work:work-runtime-ktx:2.7.1"
kapt "androidx.room:room-compiler:2.4.3"
implementation "androidx.core:core-ktx:1.13.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.2"
implementation "androidx.navigation:navigation-fragment-ktx:2.7.7"
implementation "androidx.recyclerview:recyclerview:1.3.2"
implementation "androidx.room:room-runtime:2.6.1"
implementation "androidx.room:room-ktx:2.6.1"
implementation "androidx.work:work-runtime-ktx:2.9.0"
kapt "androidx.room:room-compiler:2.6.1"
// Google design libs
implementation "com.google.android.material:material:1.6.1"
implementation "com.google.android.material:material:1.12.0"
implementation "com.google.android.flexbox:flexbox:3.0.0"
// Play Services/Firebase
implementation "com.google.android.gms:play-services-wearable:17.1.0"
implementation "com.google.android.gms:play-services-wearable:18.2.0"
implementation("com.google.firebase:firebase-core") { version { strictly "19.0.2" } }
implementation "com.google.firebase:firebase-crashlytics:18.2.13"
implementation "com.google.firebase:firebase-crashlytics:19.0.1"
implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
// OkHttp, Retrofit, Gson, Jsoup
@ -174,12 +202,13 @@ dependencies {
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
implementation "com.squareup.retrofit2:converter-scalars:2.9.0"
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'org.jsoup:jsoup:1.14.3'
implementation "pl.droidsonroids:jspoon:1.3.2"
implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
// Szkolny.eu libraries/forks
implementation project(":navlib")
implementation "eu.szkolny:android-snowfall:1ca9ea2da3"
implementation "eu.szkolny:agendacalendarview:1.0.4"
implementation "eu.szkolny:cafebar:5bf0c618de"
@ -187,20 +216,22 @@ dependencies {
implementation "eu.szkolny:material-about-library:1d5ebaf47c"
implementation "eu.szkolny:mhttp:af4b62e6e9"
implementation "eu.szkolny:nachos:0e5dfcaceb"
implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
implementation "eu.szkolny.selective-dao:annotation:6a337f9"
officialImplementation "eu.szkolny:ssl-provider:1.0.0"
unofficialImplementation "eu.szkolny:ssl-provider:1.0.0"
implementation "pl.szczodrzynski:navlib:0.8.0"
implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
implementation "pl.szczodrzynski:recyclertablayout:700f980584"
implementation "pl.szczodrzynski:tachyon:551943a6b5"
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
kapt "eu.szkolny.selective-dao:codegen:6a337f9"
// Iconics & related
implementation "com.mikepenz:iconics-core:5.3.2"
implementation "com.mikepenz:iconics-views:5.3.2"
implementation "com.mikepenz:materialdrawer:9.0.1"
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
implementation "eu.szkolny:szkolny-font:77e33acc2a"
implementation 'com.mikepenz:google-material-typeface:4.0.0.2-kotlin@aar'
implementation "eu.szkolny:szkolny-font:95eabe7"
// Other dependencies
implementation "cat.ereza:customactivityoncrash:2.3.0"
@ -211,11 +242,11 @@ dependencies {
implementation "com.github.ChuckerTeam.Chucker:library:3.5.2" // https://github.com/ChuckerTeam/chucker
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" // https://github.com/antonKozyriatskyi/CircularProgressIndicator
implementation "com.github.bassaer:chatmessageview:2.0.1" // https://github.com/bassaer/ChatMessageView
implementation "com.github.hypertrack:hyperlog-android:0.0.10" // https://github.com/hypertrack/hyperlog-android
implementation "com.github.smuyyh:JsonViewer:V1.0.6" // https://github.com/smuyyh/JsonViewer
implementation "com.github.underwindfall.PowerPermission:powerpermission-coroutines:1.4.0" // https://github.com/underwindfall/PowerPermission
implementation "com.github.underwindfall.PowerPermission:powerpermission:1.4.0" // https://github.com/underwindfall/PowerPermission
implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31" // https://github.com/wulkanowy/uonet-request-signer
implementation 'com.jakewharton.timber:timber:5.0.1'
implementation "com.jaredrummler:colorpicker:1.1.0"
implementation "io.coil-kt:coil:1.1.1"
implementation "me.dm7.barcodescanner:zxing:1.9.8"

View File

@ -5,7 +5,7 @@
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath "org.eclipse.jgit:org.eclipse.jgit:5.5.+"

View File

@ -36,6 +36,37 @@
"status": 2
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:640759989760:android:4aa71407b25cdc8d",
"android_client_info": {
"package_name": "pl.szczodrzynski.edziennik.debug"
}
},
"oauth_client": [
{
"client_id": "640759989760-6f8q00u864lnuh3gh36e8g4cer9lv8pv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAvq9HMPxulz9ntdAHZ0eZuPf2YQs4nDSU"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"

View File

@ -19,10 +19,13 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keepattributes Signature
-keep class android.support.v7.widget.** { *; }
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
-keep class pl.szczodrzynski.edziennik.data.db.enums.* { *; }
-keep class pl.szczodrzynski.edziennik.data.enums.* { *; }
-keep class pl.szczodrzynski.edziennik.data.db.entity.Event { *; }
-keep class pl.szczodrzynski.edziennik.data.db.full.EventFull { *; }
-keep class pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage { *; }
@ -32,9 +35,9 @@
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.timetable.WidgetTimetableProvider
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.notifications.WidgetNotificationsProvider
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
-keep class pl.szczodrzynski.edziennik.config.AppData { *; }
-keep class pl.szczodrzynski.edziennik.config.AppData$** { *; }
-keep class pl.szczodrzynski.edziennik.utils.managers.TextStylingManager$HtmlMode { *; }
-keep class pl.szczodrzynski.edziennik.data.config.AppData { *; }
-keep class pl.szczodrzynski.edziennik.data.config.AppData$** { *; }
-keep class pl.szczodrzynski.edziennik.core.manager.TextStylingManager$HtmlMode { *; }
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
@ -42,6 +45,20 @@
-keepclassmembernames class androidx.appcompat.view.menu.MenuItemImpl { private *; }
-keepclassmembernames class com.mikepenz.materialdrawer.widget.MiniDrawerSliderView { private *; }
-keepclassmembernames class com.mikepenz.iconics.internal.IconicsViewsAttrsApplier {
<fields>;
readIconicsTextView(android.content.Context, android.util.AttributeSet, com.mikepenz.iconics.internal.CompoundIconsBundle);
getIconicsImageViewDrawable(android.content.Context, android.util.AttributeSet);
}
-keepclassmembernames class com.mikepenz.iconics.internal.CompoundIconsBundle {
setIcons(android.widget.TextView);
}
# for RecyclerTabView
-keepclassmembernames class com.google.android.material.tabs.TabLayout { *; }
-keepclassmembernames class com.google.android.material.tabs.TabLayout$TabView { *; }
-keepclassmembernames class com.google.android.material.tabs.TabIndicatorInterpolator { *; }
-keep class .R
-keep class **.R$* {
@ -55,8 +72,19 @@
-keep class com.google.android.material.tabs.** {*;}
# Exclude AgendaCalendarView
# Preserve generic type information for EventRenderer and its subclasses
-keepclassmembers class * extends com.github.tibolte.agendacalendarview.render.EventRenderer {
<fields>;
<methods>;
}
# Keep the EventRenderer class itself and all its subclasses
-keep class com.github.tibolte.agendacalendarview.render.EventRenderer
-keep class * extends com.github.tibolte.agendacalendarview.render.EventRenderer
# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
# Most of volatile fields are updated with AFU and should not be mangled
@ -70,6 +98,7 @@
-keep class pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing { public final byte[] pleaseStopRightNow(java.lang.String, long); }
-keepclassmembers class pl.szczodrzynski.edziennik.ui.login.qr.* { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.login.LoginInfo$Platform { *; }

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="pl.szczodrzynski.edziennik">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
@ -12,19 +11,21 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
<uses-sdk
tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core, com.mikepenz:materialdrawer, com.mikepenz.iconics.typeface.library.navlibfont, androidx.appcompat.resources, androidx.appcompat, com.google.android.gms.wearable, com.google.android.gms.base, com.google.firebase.crashlytics, com.google.firebase.sessions, com.google.firebase.ktx, com.google.firebase, com.google.android.gms.tasks, com.google.android.gms.common, com.google.firebase.components" />
<application
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_descriptor"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/ic_launcher_v5"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:theme="@style/AppTheme.Dark"
android:theme="@style/AppTheme.M3.Blue"
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute">
@ -40,7 +41,6 @@
|___/ -->
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:exported="true"
android:theme="@style/SplashTheme">
@ -67,7 +67,7 @@
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true"
android:theme="@style/AppTheme.Dark.NoDisplay">
android:theme="@style/AppTheme.M3.NoDisplay">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
@ -84,14 +84,14 @@
android:resource="@xml/widget_timetable_info" />
</receiver>
<service android:name=".ui.widgets.timetable.WidgetTimetableService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
android:permission="android.permission.BIND_REMOTEVIEWS" android:foregroundServiceType="dataSync"/>
<activity android:name=".ui.widgets.LessonDialogActivity"
android:label=""
android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true"
android:noHistory="true"
android:exported="true"
android:theme="@style/AppTheme.Dark.NoDisplay" />
android:theme="@style/AppTheme.M3.NoDisplay" />
<!-- NOTIFICATIONS -->
<receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
android:label="@string/widget_notifications_title"
@ -105,7 +105,7 @@
android:resource="@xml/widget_notifications_info" />
</receiver>
<service android:name=".ui.widgets.notifications.WidgetNotificationsService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
android:permission="android.permission.BIND_REMOTEVIEWS" android:foregroundServiceType="dataSync"/>
<!-- LUCKY NUMBER -->
<receiver android:name=".ui.widgets.luckynumber.WidgetLuckyNumberProvider"
android:label="@string/widget_lucky_number_title"
@ -126,33 +126,31 @@
/ ____ \ (__| |_| |\ V /| | |_| | __/\__ \
/_/ \_\___|\__|_| \_/ |_|\__|_|\___||___/
-->
<activity android:name=".ui.base.CrashActivity"
<activity android:name=".ui.main.CrashActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:process=":error_activity"
android:exported="false"
android:theme="@style/DeadTheme" />
<activity android:name=".ui.intro.ChangelogIntroActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:exported="false"
android:theme="@style/Theme.Intro" />
<activity android:name=".ui.login.LoginActivity"
android:configChanges="orientation|screenSize"
android:launchMode="singleTop"
android:exported="false"
android:theme="@style/AppTheme.Light" />
android:theme="@style/AppTheme.M3" />
<activity android:name=".ui.home.CounterActivity"
android:exported="false"
android:theme="@style/AppTheme.Black" />
android:theme="@style/AppTheme.M3" />
<activity android:name=".ui.feedback.FeedbackActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name"
android:exported="false"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme.M3" />
<activity android:name=".ui.settings.SettingsLicenseActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@style/AppTheme" />
android:theme="@style/AppTheme.M3" />
<activity android:name="com.canhub.cropper.CropImageActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
@ -160,9 +158,12 @@
<activity android:name=".ui.login.oauth.OAuthLoginActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@style/AppTheme.Light" />
<activity android:name=".ui.base.BuildInvalidActivity" android:exported="false" />
<activity android:name=".ui.settings.contributors.ContributorsActivity" android:exported="false" />
android:theme="@style/Theme.MaterialComponents.Light.DarkActionBar" />
<activity android:name=".ui.login.recaptcha.RecaptchaActivity"
android:configChanges="orientation|keyboardHidden"
android:exported="false"
android:theme="@style/Theme.MaterialComponents.Light.DarkActionBar" />
<activity android:name=".ui.main.BuildInvalidActivity" android:exported="false" />
<!-- _____ _
| __ \ (_)
@ -171,7 +172,7 @@
| | \ \ __/ (_| __/ |\ V / __/ | \__ \
|_| \_\___|\___\___|_| \_/ \___|_| |___/
-->
<receiver android:name=".receivers.UserPresentReceiver"
<receiver android:name=".core.receiver.UserPresentReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
@ -184,7 +185,7 @@
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
<receiver android:name=".receivers.SzkolnyReceiver"
<receiver android:name=".core.receiver.SzkolnyReceiver"
android:exported="true">
<intent-filter>
<action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" />
@ -198,15 +199,15 @@
____) | __/ | \ V /| | (_| __/\__ \
|_____/ \___|_| \_/ |_|\___\___||___/
-->
<service android:name=".data.api.ApiService" />
<service android:name=".data.firebase.MyFirebaseService"
android:exported="false">
<service android:name=".data.api.ApiService" android:foregroundServiceType="dataSync"/>
<service android:name=".core.firebase.MyFirebaseService"
android:exported="false" android:foregroundServiceType="dataSync">
<intent-filter android:priority="10000000">
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name=".sync.UpdateDownloaderService" />
<service android:name=".sync.UpdateDownloaderService" android:foregroundServiceType="dataSync"/>
<!--
_____ _ _

View File

@ -1,9 +1,11 @@
<h3>Wersja 4.13.2, 2022-11-28</h3>
<h3>Wersja 4.14, 2025-02-02</h3>
<ul>
<li>Poprawiono synchronizację w Mobidzienniku bez ustawionego adresu e-mail.</li>
<li>Poprawiono błąd synchronizacji w Vulcanie.</li>
<li>USOS: <b>dodano obsługę ocen</b>.</li>
<li>USOS: obliczanie średniej za studia oraz punktów ECTS.</li>
<li>USOS: poprawiono brak planu zajęć po rozpoczęciu roku.</li>
<li>Wyłączono archiwizator profili.</li>
</ul>
<br>
<br>
Dzięki za korzystanie ze Szkolnego!<br>
<i>&copy; [Kuba Szczodrzyński](@kuba2k2) 2022</i>
<i>&copy; [Kuba Szczodrzyński](@kuba2k2) 2025</i>

View File

@ -5,6 +5,8 @@
cmake_minimum_required(VERSION 3.4.1)
project(szkolny-signing)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
@ -41,4 +43,4 @@ target_link_libraries( # Specifies the target library.
# Links the target library to the log library
# included in the NDK.
${log-lib} )
${log-lib} )

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/
static toys AES_IV[16] = {
0x8c, 0xad, 0x9c, 0x3e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0xee, 0x23, 0xf1, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -4,12 +4,6 @@
package pl.szczodrzynski.edziennik
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon
import android.os.Build
import android.provider.Settings
import android.util.Log
import android.widget.Toast
@ -20,12 +14,7 @@ import cat.ereza.customactivityoncrash.config.CaocConfig
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.chuckerteam.chucker.api.RetentionManager
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.iid.FirebaseInstanceId
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.Gson
import com.hypertrack.hyperlog.HyperLog
import com.mikepenz.iconics.Iconics
import im.wangchao.mhttp.MHttp
import kotlinx.coroutines.CoroutineScope
@ -36,42 +25,39 @@ import kotlinx.coroutines.withContext
import me.leolin.shortcutbadger.ShortcutBadger
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.config.Config
import pl.szczodrzynski.edziennik.core.manager.AttendanceManager
import pl.szczodrzynski.edziennik.core.manager.AvailabilityManager
import pl.szczodrzynski.edziennik.core.manager.BuildManager
import pl.szczodrzynski.edziennik.core.manager.EventManager
import pl.szczodrzynski.edziennik.core.manager.FirebaseManager
import pl.szczodrzynski.edziennik.core.manager.GradesManager
import pl.szczodrzynski.edziennik.core.manager.LoggingManager
import pl.szczodrzynski.edziennik.core.manager.MessageManager
import pl.szczodrzynski.edziennik.core.manager.NoteManager
import pl.szczodrzynski.edziennik.core.manager.NotificationManager
import pl.szczodrzynski.edziennik.core.manager.PermissionManager
import pl.szczodrzynski.edziennik.core.manager.ShortcutManager
import pl.szczodrzynski.edziennik.core.manager.TextStylingManager
import pl.szczodrzynski.edziennik.core.manager.TimetableManager
import pl.szczodrzynski.edziennik.core.manager.UiManager
import pl.szczodrzynski.edziennik.core.manager.UpdateManager
import pl.szczodrzynski.edziennik.core.manager.UserActionManager
import pl.szczodrzynski.edziennik.core.network.DumbCookieJar
import pl.szczodrzynski.edziennik.core.work.SyncWorker
import pl.szczodrzynski.edziennik.core.work.UpdateWorker
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
import pl.szczodrzynski.edziennik.data.config.AppData
import pl.szczodrzynski.edziennik.data.config.Config
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.DAY
import pl.szczodrzynski.edziennik.ext.MS
import pl.szczodrzynski.edziennik.ext.putExtras
import pl.szczodrzynski.edziennik.ext.setLanguage
import pl.szczodrzynski.edziennik.data.enums.LoginType
import pl.szczodrzynski.edziennik.network.SSLProviderInstaller
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.sync.UpdateWorker
import pl.szczodrzynski.edziennik.ui.base.CrashActivity
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
import pl.szczodrzynski.edziennik.utils.DebugLogFormat
import pl.szczodrzynski.edziennik.ui.main.CrashActivity
import pl.szczodrzynski.edziennik.utils.PermissionChecker
import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.managers.AttendanceManager
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager
import pl.szczodrzynski.edziennik.utils.managers.BuildManager
import pl.szczodrzynski.edziennik.utils.managers.EventManager
import pl.szczodrzynski.edziennik.utils.managers.GradesManager
import pl.szczodrzynski.edziennik.utils.managers.MessageManager
import pl.szczodrzynski.edziennik.utils.managers.NoteManager
import pl.szczodrzynski.edziennik.utils.managers.NotificationChannelsManager
import pl.szczodrzynski.edziennik.utils.managers.PermissionManager
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager
import pl.szczodrzynski.edziennik.utils.managers.TimetableManager
import pl.szczodrzynski.edziennik.utils.managers.UpdateManager
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import timber.log.Timber
import java.util.concurrent.TimeUnit
import kotlin.coroutines.CoroutineContext
import kotlin.system.exitProcess
@ -82,7 +68,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
lateinit var db: AppDb
private set
lateinit var config: Config
// private set // for LabFragment
// private set // for LabFragment
lateinit var profile: Profile
private set
lateinit var data: AppData
@ -91,7 +78,6 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
get() = profile.id
var enableChucker = false
var debugMode = false
var devMode = false
}
@ -100,13 +86,17 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
val availabilityManager by lazy { AvailabilityManager(this) }
val buildManager by lazy { BuildManager(this) }
val eventManager by lazy { EventManager(this) }
val firebaseManager by lazy { FirebaseManager(this) }
val gradesManager by lazy { GradesManager(this) }
val loggingManager by lazy { LoggingManager(this) }
val messageManager by lazy { MessageManager(this) }
val noteManager by lazy { NoteManager(this) }
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
val notificationManager by lazy { NotificationManager(this) }
val permissionManager by lazy { PermissionManager(this) }
val shortcutManager by lazy { ShortcutManager(this) }
val textStylingManager by lazy { TextStylingManager(this) }
val timetableManager by lazy { TimetableManager(this) }
val uiManager by lazy { UiManager(this) }
val updateManager by lazy { UpdateManager(this) }
val userActionManager by lazy { UserActionManager(this) }
@ -124,9 +114,10 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setMinimumLoggingLevel(Log.VERBOSE)
.build()
override val workManagerConfiguration: Configuration = Configuration.Builder()
.setMinimumLoggingLevel(Log.VERBOSE)
.build()
val permissionChecker by lazy { PermissionChecker(this) }
val gson by lazy { Gson() }
@ -155,7 +146,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
if (devMode) {
if (enableChucker) {
val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
val chuckerCollector =
ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
builder.addInterceptor(chuckerInterceptor)
}
@ -170,6 +162,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
MHttp.instance().customOkHttpClient(http)
}
val cookieJar by lazy { DumbCookieJar(this) }
/* _____ _ _
@ -180,7 +173,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|_____/|_|\__, |_| |_|\__,_|\__|\__,_|_| \___|
__/ |
|__*/
val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }
val deviceId: String by lazy {
Settings.Secure.getString(
contentResolver,
Settings.Secure.ANDROID_ID
) ?: ""
}
private var unreadBadgesAvailable = true
/* _____ _
@ -191,35 +189,46 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
\___/|_| |_|\_____|_| \___|\__,_|\__\__*/
override fun onCreate() {
super.onCreate()
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM)
.enabled(true)
.showErrorDetails(true)
.showRestartButton(true)
.logErrorOnRestart(true)
.trackActivities(true)
.minTimeBetweenCrashesMs(60*1000)
.errorDrawable(R.drawable.ic_rip)
.restartActivity(MainActivity::class.java)
.errorActivity(CrashActivity::class.java)
.apply()
Iconics.init(applicationContext)
Iconics.respectFontBoundsDefault = true
// initialize companion object values
// initialize Timber to enable basic logging
Timber.plant(loggingManager.logcatTree)
Timber.i("Initializing Szkolny.eu app v${BuildConfig.VERSION_NAME}")
// initialize core objects
AppData.read(this)
App.db = AppDb(this)
App.config = Config(App.db)
debugMode = BuildConfig.DEBUG
devMode = config.devMode ?: debugMode
// read and migrate global config
App.config = Config(this)
App.config.migrate()
// add database logging to Timber
Timber.plant(loggingManager.databaseTree)
Timber.i("Initialized Szkolny.eu app v${BuildConfig.VERSION_NAME}")
devMode = config.devMode ?: BuildConfig.DEBUG
if (config.devModePassword != null)
checkDevModePassword()
enableChucker = config.enableChucker ?: devMode
if (devMode) {
HyperLog.initialize(this)
HyperLog.setLogLevel(Log.VERBOSE)
HyperLog.setLogFormat(DebugLogFormat(this))
}
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM)
.enabled(true)
.showErrorDetails(true)
.showRestartButton(true)
.logErrorOnRestart(true)
.trackActivities(true)
.minTimeBetweenCrashesMs(60 * 1000)
.errorDrawable(R.drawable.ic_rip)
.restartActivity(MainActivity::class.java)
.errorActivity(CrashActivity::class.java)
.apply()
Iconics.init(applicationContext)
Iconics.respectFontBoundsDefault = true
Signing.getCert(this)
Utils.initializeStorageDir(this)
buildHttp()
uiManager.applyNightMode()
uiManager.applyLanguage(this)
if (!profileLoadById(config.lastProfileId)) {
val success = db.profileDao().firstId?.let { profileLoadById(it) }
@ -227,192 +236,38 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
profileLoad(Profile(0, 0, LoginType.TEMPLATE, ""))
}
buildHttp()
launch(Dispatchers.Default) {
buildManager.fetchInstalledTime()
firebaseManager.initializeApps()
loggingManager.cleanupIfNeeded()
loggingManager.cleanupHyperLogDatabase()
notificationManager.registerAllChannels()
shortcutManager.createShortcuts()
if (config.appVersionCore < BuildConfig.VERSION_CODE) {
// force syncing all endpoints on update
db.endpointTimerDao().clear()
config.sync.lastAppSync = 0L
config.hash = "invalid"
config.appVersionCore = BuildConfig.VERSION_CODE
}
Themes.themeInt = config.ui.theme
config.ui.language?.let {
setLanguage(it)
SSLProviderInstaller.install(applicationContext, this@App::buildHttp)
if (config.sync.enabled)
SyncWorker.scheduleNext(this@App, false)
else
SyncWorker.cancelNext(this@App)
if (config.sync.notifyAboutUpdates)
UpdateWorker.scheduleNext(this@App, false)
else
UpdateWorker.cancelNext(this@App)
}
Signing.getCert(this)
launch {
withContext(Dispatchers.Default) {
config.migrate(this@App)
SSLProviderInstaller.install(applicationContext, this@App::buildHttp)
if (config.devModePassword != null)
checkDevModePassword()
if (config.sync.enabled)
SyncWorker.scheduleNext(this@App, false)
else
SyncWorker.cancelNext(this@App)
if (config.sync.notifyAboutUpdates)
UpdateWorker.scheduleNext(this@App, false)
else
UpdateWorker.cancelNext(this@App)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
val shortcutManager = getSystemService(ShortcutManager::class.java)
val shortcutTimetable = ShortcutInfo.Builder(this@App, "item_timetable")
.setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtras("fragmentId" to NavTarget.TIMETABLE))
.build()
val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda")
.setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtras("fragmentId" to NavTarget.AGENDA))
.build()
val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades")
.setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtras("fragmentId" to NavTarget.GRADES))
.build()
val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks")
.setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtras("fragmentId" to NavTarget.HOMEWORK))
.build()
val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages")
.setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages))
.setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages))
.setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java)
.putExtras("fragmentId" to NavTarget.MESSAGES))
.build()
shortcutManager.dynamicShortcuts = listOf(
shortcutTimetable,
shortcutAgenda,
shortcutGrades,
shortcutHomework,
shortcutMessages
)
} // shortcuts - end
notificationChannelsManager.registerAllChannels()
if (config.appInstalledTime == 0L)
try {
config.appInstalledTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
config.appRateSnackbarTime = config.appInstalledTime + 7 * DAY * MS
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
val pushMobidziennikApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setProjectId("mobidziennik")
.setStorageBucket("mobidziennik.appspot.com")
.setDatabaseUrl("https://mobidziennik.firebaseio.com")
.setGcmSenderId("747285019373")
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
.build(),
"Mobidziennik2"
)
val pushLibrusApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setProjectId("synergiadru")
.setStorageBucket("synergiadru.appspot.com")
.setDatabaseUrl("https://synergiadru.firebaseio.com")
.setGcmSenderId("513056078587")
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
.setApplicationId("1:513056078587:android:1e29083b760af544")
.build(),
"Librus"
)
val pushVulcanApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setProjectId("dzienniczekplus")
.setStorageBucket("dzienniczekplus.appspot.com")
.setDatabaseUrl("https://dzienniczekplus.firebaseio.com")
.setGcmSenderId("987828170337")
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
.build(),
"Vulcan"
)
val pushVulcanHebeApp = FirebaseApp.initializeApp(
this@App,
FirebaseOptions.Builder()
.setProjectId("dzienniczekplus")
.setStorageBucket("dzienniczekplus.appspot.com")
.setDatabaseUrl("https://dzienniczekplus.firebaseio.com")
.setGcmSenderId("987828170337")
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
.setApplicationId("1:987828170337:android:7e16404b9e5deaaa")
.build(),
"VulcanHebe"
)
try {
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
d("Firebase", "Got App token: $token")
config.sync.tokenApp = token
}
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
d("Firebase", "Got Mobidziennik2 token: $token")
if (token != config.sync.tokenMobidziennik) {
config.sync.tokenMobidziennik = token
config.sync.tokenMobidziennikList = listOf()
}
}
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
d("Firebase", "Got Librus token: $token")
if (token != config.sync.tokenLibrus) {
config.sync.tokenLibrus = token
config.sync.tokenLibrusList = listOf()
}
}
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
d("Firebase", "Got Vulcan token: $token")
if (token != config.sync.tokenVulcan) {
config.sync.tokenVulcan = token
config.sync.tokenVulcanList = listOf()
}
}
FirebaseInstanceId.getInstance(pushVulcanHebeApp).instanceId.addOnSuccessListener { instanceIdResult ->
val token = instanceIdResult.token
d("Firebase", "Got VulcanHebe token: $token")
if (token != config.sync.tokenVulcanHebe) {
config.sync.tokenVulcanHebe = token
config.sync.tokenVulcanHebeList = listOf()
}
}
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
} catch (e: IllegalStateException) {
e.printStackTrace()
}
}
db.metadataDao().countUnseen().observeForever { count: Int ->
if (unreadBadgesAvailable)
unreadBadgesAvailable = ShortcutBadger.applyCount(this@App, count)
}
db.metadataDao().countUnseen().observeForever { count: Int ->
if (unreadBadgesAvailable)
unreadBadgesAvailable = ShortcutBadger.applyCount(this@App, count)
}
}
@ -421,9 +276,15 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
App.config.lastProfileId = profile.id
try {
App.data = AppData.get(profile.loginStoreType)
d("App", "Loaded AppData: ${App.data}")
Timber.d("Loaded AppData: ${App.data}")
// apply newly-added config overrides, if not changed by the user yet
for ((key, value) in App.data.configOverrides) {
val config = App.profile.config
if (key !in config)
config[key] = value
}
} catch (e: Exception) {
Log.e("App", "Cannot load AppData", e)
Timber.e(e, "Cannot load AppData")
Toast.makeText(this, R.string.app_cannot_load_data, Toast.LENGTH_LONG).show()
exitProcess(0)
}
@ -436,6 +297,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
}
return false
}
fun profileLoad(profileId: Int, onSuccess: (profile: Profile) -> Unit) {
launch {
val success = withContext(Dispatchers.Default) {
@ -447,6 +309,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
profileLoadLast(onSuccess)
}
}
fun profileLoadLast(onSuccess: (profile: Profile) -> Unit) {
launch {
val success = withContext(Dispatchers.Default) {
@ -454,12 +317,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
}
if (!success) {
EventBus.getDefault().post(ProfileListEmptyEvent())
}
else {
} else {
onSuccess(profile)
}
}
}
fun profileSave() = profileSave(profile)
fun profileSave(profile: Profile) {
if (profile.id == profileId)
@ -470,10 +333,13 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
}
fun checkDevModePassword() {
devMode = try {
Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", config.devModePassword) == "ok here you go it's enabled now" || BuildConfig.DEBUG
devMode = devMode || try {
Utils.AESCrypt.decrypt(
"nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=",
config.devModePassword
) == "ok here you go it's enabled now"
} catch (e: Exception) {
e.printStackTrace()
Timber.e(e)
false
}
}

View File

@ -15,70 +15,99 @@ import android.view.Gravity
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
import androidx.navigation.NavOptions
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.danimahardhika.cafebar.CafeBar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.danimahardhika.cafebar.CafeBarTheme
import com.jetradarmobile.snowfall.SnowfallView
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp
import com.mikepenz.materialdrawer.model.*
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.model.DividerDrawerItem
import com.mikepenz.materialdrawer.model.ExpandableDrawerItem
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.descriptionRes
import com.mikepenz.materialdrawer.model.interfaces.nameRes
import com.mikepenz.materialdrawer.model.utils.hiddenInMiniDrawer
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.droidsonroids.gif.GifDrawable
import pl.szczodrzynski.edziennik.core.manager.AvailabilityManager.Error.Type
import pl.szczodrzynski.edziennik.core.manager.UserActionManager
import pl.szczodrzynski.edziennik.core.work.AppManagerDetectedEvent
import pl.szczodrzynski.edziennik.core.work.SyncWorker
import pl.szczodrzynski.edziennik.core.work.UpdateStateEvent
import pl.szczodrzynski.edziennik.core.work.UpdateWorker
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.*
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskProgressEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskStartedEvent
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.FeatureType
import pl.szczodrzynski.edziennik.data.enums.NavTarget
import pl.szczodrzynski.edziennik.data.enums.NavTargetLocation
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
import pl.szczodrzynski.edziennik.sync.SyncWorker
import pl.szczodrzynski.edziennik.sync.UpdateStateEvent
import pl.szczodrzynski.edziennik.sync.UpdateWorker
import pl.szczodrzynski.edziennik.ui.base.MainSnackbar
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
import pl.szczodrzynski.edziennik.ui.base.enums.NavTargetLocation
import pl.szczodrzynski.edziennik.ext.JsonObject
import pl.szczodrzynski.edziennik.ext.getAppData
import pl.szczodrzynski.edziennik.ext.getEnum
import pl.szczodrzynski.edziennik.ext.getIntOrNull
import pl.szczodrzynski.edziennik.ext.hasUIFeature
import pl.szczodrzynski.edziennik.ext.isBeforeYear
import pl.szczodrzynski.edziennik.ext.keys
import pl.szczodrzynski.edziennik.ext.putExtras
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.resolveString
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ext.shouldArchive
import pl.szczodrzynski.edziennik.ext.takePositive
import pl.szczodrzynski.edziennik.ext.toDrawable
import pl.szczodrzynski.edziennik.ext.toImageHolder
import pl.szczodrzynski.edziennik.ui.base.dialog.SimpleDialog
import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog
import pl.szczodrzynski.edziennik.ui.dialogs.ErrorDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.ServerMessageDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateAvailableDialog
import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateProgressDialog
import pl.szczodrzynski.edziennik.ui.error.ErrorDetailsDialog
import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
import pl.szczodrzynski.edziennik.ui.main.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.main.MainSnackbar
import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
import pl.szczodrzynski.edziennik.utils.*
import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
import pl.szczodrzynski.edziennik.utils.BigNightUtil
import pl.szczodrzynski.edziennik.utils.PausedNavigationData
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.appManagerIntentList
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.*
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
import pl.szczodrzynski.navlib.NavView
import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
import pl.szczodrzynski.navlib.drawer.NavDrawer
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
import java.io.IOException
import java.util.*
import timber.log.Timber
import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt
@ -99,7 +128,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
val requestHandler by lazy { MainActivityRequestHandler(this) }
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
val swipeRefreshLayout: SwipeRefreshLayout by lazy { b.swipeRefreshLayout }
var onBeforeNavigate: (() -> Boolean)? = null
private var pausedNavigationData: PausedNavigationData? = null
@ -125,22 +154,19 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
d(TAG, "Activity created")
setTheme(Themes.appTheme)
app.config.ui.language?.let {
setLanguage(it)
}
Timber.i("Activity created")
app.uiManager.applyTheme(this)
app.uiManager.applyLanguage(this)
app.buildManager.validateBuild(this)
if (App.profileId == 0) {
Timber.i("Profile is not loaded")
onProfileListEmptyEvent(ProfileListEmptyEvent())
return
}
d(TAG, "Profile is valid, inflating views")
Timber.i("Profile is valid, inflating views")
setContentView(b.root)
@ -148,10 +174,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
val versionBadge = app.buildManager.versionBadge
b.nightlyText.isVisible = versionBadge != null
b.nightlyText.text = versionBadge
navView.nightlyText.isVisible = versionBadge != null
navView.nightlyText.text = versionBadge
if (versionBadge != null) {
b.nightlyText.background.setTintColor(0xa0ff0000.toInt())
navView.nightlyText.background.setTintColor(0xa0ff0000.toInt())
}
navLoading = true
@ -159,57 +185,34 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
b.navView.apply {
drawer.init(this@MainActivity)
SystemBarsUtil(this@MainActivity).run {
//paddingByKeyboard = b.navView
appFullscreen = false
statusBarColor = getColorFromAttr(context, android.R.attr.colorBackground)
statusBarDarker = false
statusBarFallbackLight = COLOR_HALF_TRANSPARENT
statusBarFallbackGradient = COLOR_HALF_TRANSPARENT
navigationBarTransparent = false
b.navView.configSystemBarsUtil(this)
// fix for setting status bar color to window color, outside of navlib
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = statusBarColor
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ColorUtils.calculateLuminance(statusBarColor) > 0.6
) {
@Suppress("deprecation")
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
// TODO fix navlib navbar detection, orientation change issues, status bar color setting if not fullscreen
commit()
val statusBarColor = android.R.attr.colorBackground.resolveAttr(context)
// fix for setting status bar color to window color, outside of navlib
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = statusBarColor
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ColorUtils.calculateLuminance(statusBarColor) > 0.6
) {
@Suppress("deprecation")
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
enable = true
enableMenuControls = true
}
bottomBar.apply {
enable = false
enableMenuControls = false
fabEnable = false
fabExtendable = true
fabExtended = false
fabGravity = Gravity.CENTER
if (Themes.isDark) {
setBackgroundColor(blendColors(
getColorFromAttr(context, R.attr.colorSurface),
getColorFromRes(R.color.colorSurface_4dp)
))
elevation = dpToPx(4).toFloat()
}
fabGravity = Gravity.END
}
bottomSheet.apply {
removeAllItems()
toggleGroupEnabled = false
textInputEnabled = false
onCloseListener = {
if (!app.config.ui.bottomSheetOpened)
app.config.ui.bottomSheetOpened = true
@ -226,7 +229,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (item is ExpandableDrawerItem)
false
else
navigate(navTarget = id.asNavTargetOrNull())
navigate(navTarget = NavTarget.getById(id))
}
drawerProfileSelectedListener = { id, _, _, _ ->
// why is this negated -_-
@ -289,9 +292,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
drawer.setUnreadCounterList(unreadCounters)
}
b.swipeRefreshLayout.isEnabled = true
b.swipeRefreshLayout.setOnRefreshListener { launch { syncCurrentFeature() } }
b.swipeRefreshLayout.setColorSchemeResources(
swipeRefreshLayout.setOnRefreshListener { launch { syncCurrentFeature() } }
swipeRefreshLayout.setColorSchemeResources(
R.color.md_blue_500,
R.color.md_amber_500,
R.color.md_green_500
@ -322,7 +324,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// IT'S WINTER MY DUDES
val today = Date.getToday()
if ((today.month % 11 == 1) && app.config.ui.snowfall) {
if ((today.month / 3 % 4 == 0) && app.config.ui.snowfall) {
b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false))
} else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) {
val eggfall = layoutInflater.inflate(
@ -358,12 +360,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (app.config.appRateSnackbarTime != 0L && app.config.appRateSnackbarTime <= System.currentTimeMillis()) {
navView.coordinator.postDelayed({
CafeBar.builder(this)
.theme(CafeBarTheme.Custom(R.attr.colorSurfaceInverse.resolveAttr(this)))
.content(R.string.rate_snackbar_text)
.icon(IconicsDrawable(this).apply {
icon = CommunityMaterial.Icon3.cmd_star_outline
sizeDp = 24
colorInt = Themes.getPrimaryTextColor(this@MainActivity)
})
.icon(CommunityMaterial.Icon3.cmd_star_outline.toDrawable())
.positiveText(R.string.rate_snackbar_positive)
.positiveColor(-0xb350b0)
.negativeText(R.string.rate_snackbar_negative)
@ -417,7 +416,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
private var profileSettingClickListener = { itemId: Int, _: View? ->
when (val item = itemId.asNavTarget()) {
when (val item = NavTarget.getById(itemId)) {
NavTarget.PROFILE_ADD -> {
requestHandler.requestLogin()
}
@ -457,37 +456,37 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|__*/
private suspend fun syncCurrentFeature() {
if (app.profile.archived) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile_archived_title)
.setMessage(
SimpleDialog<Unit>(this) {
title(R.string.profile_archived_title)
message(
R.string.profile_archived_text,
app.profile.studentSchoolYearStart,
app.profile.studentSchoolYearStart + 1
)
.setPositiveButton(R.string.ok, null)
.show()
positive(R.string.ok)
}.show()
swipeRefreshLayout.isRefreshing = false
return
}
if (app.profile.shouldArchive()) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile_archiving_title)
.setMessage(
SimpleDialog<Unit>(this) {
title(R.string.profile_archiving_title)
message(
R.string.profile_archiving_format,
app.profile.dateYearEnd.formattedString
)
.setPositiveButton(R.string.ok, null)
.show()
positive(R.string.ok)
}.show()
}
if (app.profile.isBeforeYear()) {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.profile_year_not_started_title)
.setMessage(
SimpleDialog<Unit>(this) {
title(R.string.profile_year_not_started_title)
message(
R.string.profile_year_not_started_format,
app.profile.dateSemester1Start.formattedString
)
.setPositiveButton(R.string.ok, null)
.show()
positive(R.string.ok)
}.show()
swipeRefreshLayout.isRefreshing = false
return
}
@ -560,8 +559,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
swipeRefreshLayout.isRefreshing = true
if (event.profileId == App.profileId) {
navView.toolbar.apply {
subtitleFormat = null
subtitleFormatWithUnread = null
subtitle = getString(R.string.toolbar_subtitle_syncing)
}
}
@ -569,7 +566,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onProfileListEmptyEvent(event: ProfileListEmptyEvent) {
d(TAG, "Profile list is empty. Launch LoginActivity.")
app.config.loginFinished = false
startActivity(Intent(this, LoginActivity::class.java))
finish()
@ -579,8 +575,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
if (event.profileId == App.profileId) {
navView.toolbar.apply {
subtitleFormat = null
subtitleFormatWithUnread = null
subtitle = if (event.progress < 0f)
event.progressText ?: ""
else
@ -599,8 +593,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
EventBus.getDefault().removeStickyEvent(event)
if (event.profileId == App.profileId) {
navView.toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
subtitle = "Gotowe"
}
}
@ -621,8 +613,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
ErrorDetailsDialog(this, listOf(event.error)).show()
}
navView.toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
subtitle = "Gotowe"
}
mainSnackbar.dismiss()
@ -634,10 +624,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
EventBus.getDefault().removeStickyEvent(event)
if (app.config.sync.dontShowAppManagerDialog)
return
MaterialAlertDialogBuilder(this)
.setTitle(R.string.app_manager_dialog_title)
.setMessage(R.string.app_manager_dialog_text)
.setPositiveButton(R.string.ok) { _, _ ->
SimpleDialog<Unit>(this) {
title(R.string.app_manager_dialog_title)
message(R.string.app_manager_dialog_text)
positive(R.string.ok) {
try {
for (intent in appManagerIntentList) {
if (packageManager.resolveActivity(intent,
@ -650,17 +640,17 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
try {
startActivity(Intent(Settings.ACTION_SETTINGS))
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT)
Timber.e(e)
Toast.makeText(this@MainActivity, R.string.app_manager_open_failed, Toast.LENGTH_SHORT)
.show()
}
}
}
.setNeutralButton(R.string.dont_ask_again) { _, _ ->
neutral(R.string.dont_ask_again) {
app.config.sync.dontShowAppManagerDialog = true
}
.setCancelable(false)
.show()
cancelable(false)
}.show()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -698,14 +688,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
fun handleIntent(extras: Bundle?) {
d(TAG, "handleIntent() {")
extras?.keySet()?.forEach { key ->
d(TAG, " \"$key\": " + extras.get(key))
}
d(TAG, "}")
Timber.d("handleIntent() ${extras?.keySet()}")
val intentProfileId = extras.getIntOrNull("profileId").takePositive()
var intentNavTarget = extras.getIntOrNull("fragmentId").asNavTargetOrNull()
var intentNavTarget = extras.getEnum<NavTarget>("fragmentId")
if (extras?.containsKey("action") == true) {
val handled = when (extras.getString("action")) {
@ -808,7 +794,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
if (arguments != null)
intent.putExtras(arguments)
if (navTarget != null) {
intent.putExtra("fragmentId", navTarget.id)
intent.putExtras("fragmentId" to navTarget)
}
finish()
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
@ -816,33 +802,38 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
override fun onStart() {
d(TAG, "Activity started")
Timber.i("Activity started")
super.onStart()
}
override fun onStop() {
d(TAG, "Activity stopped")
Timber.i("Activity stopped")
super.onStop()
}
override fun onResume() {
d(TAG, "Activity resumed")
Timber.i("Activity resumed")
val filter = IntentFilter()
filter.addAction(Intent.ACTION_MAIN)
registerReceiver(intentReceiver, filter)
ContextCompat.registerReceiver(
this,
intentReceiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
EventBus.getDefault().register(this)
super.onResume()
}
override fun onPause() {
d(TAG, "Activity paused")
Timber.i("Activity paused")
unregisterReceiver(intentReceiver)
EventBus.getDefault().unregister(this)
super.onPause()
}
override fun onDestroy() {
d(TAG, "Activity destroyed")
Timber.i("Activity destroyed")
super.onDestroy()
}
@ -896,7 +887,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
args: Bundle? = null,
skipBeforeNavigate: Boolean = false,
): Boolean {
d(TAG, "navigate(profileId = ${profile?.id ?: profileId}, target = ${navTarget?.name}, args = $args)")
Timber.d("navigate(profileId = ${profile?.id ?: profileId}, target = ${navTarget?.name}, args = $args)")
if (!(skipBeforeNavigate || navTarget == this.navTarget) && !canNavigate()) {
bottomSheet.close()
drawer.close()
@ -929,7 +920,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
args: Bundle?,
profileChanged: Boolean,
) {
d(TAG, "navigateImpl(profileId = ${profile.id}, target = ${navTarget.name}, args = $args)")
Timber.d("navigateImpl(profileId = ${profile.id}, target = ${navTarget.name}, args = $args)")
if (navTarget.featureType != null && !profile.hasUIFeature(navTarget.featureType)) {
navigateImpl(profile, NavTarget.HOME, args, profileChanged)
@ -971,9 +962,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
val arguments = args
?: navBackStack.firstOrNull { it.first == navTarget }?.second
?: Bundle()
swipeRefreshLayout.isEnabled = false
bottomSheet.close()
bottomSheet.removeAllContextual()
bottomSheet.toggleGroupEnabled = false
drawer.close()
if (drawer.getSelection() != navTarget.id)
drawer.setSelection(navTarget.id, fireOnClick = false)
@ -982,9 +973,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
navView.bottomBar.fabExtended = false
navView.bottomBar.setFabOnClickListener(null)
d("NavDebug", "Navigating from ${this.navTarget.name} to ${navTarget.name}")
Timber.d("Navigating from ${this.navTarget.name} to ${navTarget.name}")
val fragment = navTarget.fragmentClass?.newInstance() ?: return
val fragment = navTarget.fragmentClass?.getDeclaredConstructor()?.newInstance() ?: return
fragment.arguments = arguments
val transaction = fragmentManager.beginTransaction()
@ -1042,9 +1033,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
}
d("NavDebug", "Current fragment ${navTarget.name}, back stack:")
Timber.d("Current fragment ${navTarget.name}, back stack:")
navBackStack.forEachIndexed { index, item ->
d("NavDebug", " - $index: ${item.first.name}")
Timber.d(" - $index: ${item.first.name}")
}
transaction.replace(R.id.fragment, fragment)
@ -1052,7 +1043,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
// TASK DESCRIPTION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val bm = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
val bm = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher_v5)
@Suppress("deprecation")
val taskDesc = ActivityManager.TaskDescription(
@ -1061,7 +1052,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
else
getString(R.string.app_task_format, getString(navTarget.nameRes)),
bm,
getColorFromAttr(this, R.attr.colorSurface)
R.attr.colorPrimary.resolveAttr(this)
)
setTaskDescription(taskDesc)
}
@ -1105,9 +1096,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
fun gainAttention() {
if (app.config.ui.bottomSheetOpened)
return
b.navView.postDelayed({
navView.gainAttentionOnBottomBar()
}, 2000)
}
fun gainAttentionFAB() {
@ -1130,8 +1118,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
else
BitmapDrawable.createFromPath(it)
}
} catch (e: IOException) {
e.printStackTrace()
} catch (e: Exception) {
Timber.e(e)
}
}
@ -1172,7 +1160,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
}
fun setDrawerItems() {
d("NavDebug", "setDrawerItems() app.profile = ${app.profile}")
Timber.d("setDrawerItems() app.profile = ${app.profile}")
val drawerItems = arrayListOf<IDrawerItem<*>>()
val drawerItemsMore = arrayListOf<IDrawerItem<*>>()
val drawerItemsBottom = arrayListOf<IDrawerItem<*>>()

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
import pl.szczodrzynski.edziennik.data.db.AppDb
import pl.szczodrzynski.edziennik.ext.takePositive
import kotlin.coroutines.CoroutineContext
abstract class BaseConfig(
@Transient
val db: AppDb,
val profileId: Int? = null,
protected var entries: List<ConfigEntry>? = null,
) : CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Default
val values = hashMapOf<String, String?>()
init {
if (entries == null)
entries = db.configDao().getAllNow()
values.clear()
for ((profileId, key, value) in entries!!) {
if (profileId.takePositive() != this.profileId)
continue
values[key] = value
}
}
fun set(key: String, value: String?) {
values[key] = value
launch(Dispatchers.IO) {
db.configDao().add(ConfigEntry(profileId ?: -1, key, value))
}
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.config.utils.*
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
import pl.szczodrzynski.edziennik.data.db.AppDb
@Suppress("RemoveExplicitTypeArguments")
class Config(db: AppDb) : BaseConfig(db) {
companion object {
const val DATA_VERSION = 12
}
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
val ui by lazy { ConfigUI(this) }
val sync by lazy { ConfigSync(this) }
val timetable by lazy { ConfigTimetable(this) }
val grades by lazy { ConfigGrades(this) }
var dataVersion by config<Int>(DATA_VERSION)
var hash by config<String>("")
var lastProfileId by config<Int>(0)
var loginFinished by config<Boolean>(false)
var privacyPolicyAccepted by config<Boolean>(false)
var update by config<Update?>(null)
var updatesChannel by config<String>("release")
var devMode by config<Boolean?>("debugMode", null)
var devModePassword by config<String?>(null)
var enableChucker by config<Boolean?>(null)
var apiAvailabilityCheck by config<Boolean>(true)
var apiInvalidCert by config<String?>(null)
var apiKeyCustom by config<String?>(null)
var appInstalledTime by config<Long>(0L)
var appRateSnackbarTime by config<Long>(0L)
var appVersion by config<Int>(BuildConfig.VERSION_CODE)
var validation by config<String?>(null, "buildValidation")
var archiverEnabled by config<Boolean>(true)
var runSync by config<Boolean>(false)
var widgetConfigs by config<JsonObject> { JsonObject() }
fun migrate(app: App) {
if (dataVersion < DATA_VERSION || hash == "")
// migrate old data version OR freshly installed app (or updated from 3.x)
ConfigMigration(app, this)
}
operator fun get(profileId: Int): ProfileConfig {
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also {
profileConfigs[profileId] = it
}
}
}

View File

@ -1,13 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
@Suppress("RemoveExplicitTypeArguments")
class ConfigGrades(base: Config) {
var orderBy by base.config<Int>("gradesOrderBy", ORDER_BY_DATE_DESC)
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
import pl.szczodrzynski.edziennik.ext.HOUR
import pl.szczodrzynski.edziennik.utils.models.Time
@Suppress("RemoveExplicitTypeArguments")
class ConfigSync(base: Config) {
var enabled by base.config<Boolean>("syncEnabled", true)
var interval by base.config<Int>("syncInterval", 1 * HOUR.toInt())
var onlyWifi by base.config<Boolean>("syncOnlyWifi", false)
var dontShowAppManagerDialog by base.config<Boolean>(false)
var lastAppSync by base.config<Long>(0L)
var notifyAboutUpdates by base.config<Boolean>(true)
var webPushEnabled by base.config<Boolean>(true)
// Quiet Hours
var quietHoursEnabled by base.config<Boolean>(false)
var quietHoursStart by base.config<Time?>(null)
var quietHoursEnd by base.config<Time?>(null)
var quietDuringLessons by base.config<Boolean>(false)
// FCM Tokens
var tokenApp by base.config<String?>(null)
var tokenMobidziennik by base.config<String?>(null)
var tokenLibrus by base.config<String?>(null)
var tokenVulcan by base.config<String?>(null)
var tokenVulcanHebe by base.config<String?>(null)
var tokenMobidziennikList by base.config<List<Int>> { listOf() }
var tokenLibrusList by base.config<List<Int>> { listOf() }
var tokenVulcanList by base.config<List<Int>> { listOf() }
var tokenVulcanHebeList by base.config<List<Int>> { listOf() }
// Register Availability
private var registerAvailabilityMap by base.config<Map<String, RegisterAvailabilityStatus>>("registerAvailability") { mapOf() }
private var registerAvailabilityFlavor by base.config<String?>(null)
var registerAvailability: Map<String, RegisterAvailabilityStatus>
get() {
if (BuildConfig.FLAVOR != registerAvailabilityFlavor)
return mapOf()
return registerAvailabilityMap
}
set(value) {
registerAvailabilityMap = value
registerAvailabilityFlavor = BuildConfig.FLAVOR
}
}

View File

@ -1,15 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.utils.models.Time
@Suppress("RemoveExplicitTypeArguments")
class ConfigTimetable(base: Config) {
var bellSyncMultiplier by base.config<Int>(0)
var bellSyncDiff by base.config<Time?>(null)
var countInSeconds by base.config<Boolean>(false)
}

Some files were not shown because too many files have changed in this diff Show More