mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-20 00:58:02 +02:00
Compare commits
176 Commits
Author | SHA1 | Date | |
---|---|---|---|
98a89b1ca1 | |||
6d1e18cce2 | |||
8fe0f88be4 | |||
aeed735521 | |||
e314fafaff | |||
2ab0dd7546 | |||
aa06868a4e | |||
2b104e6463 | |||
afb1863827 | |||
d8228748e4 | |||
b0608c47c4 | |||
dda0d88f19 | |||
a1b5560977 | |||
86f5811bda | |||
3f11e75985 | |||
c39b5442c9 | |||
3b80adf355 | |||
cae41d17b6 | |||
519d75d9d9 | |||
cb953ea8a8 | |||
52968cafad | |||
b7755dae96 | |||
113ecc0ef1 | |||
23bd9b8e05 | |||
decfd2068a | |||
a88cfb8ae3 | |||
50cb0acc7d | |||
27413a9745 | |||
49a093201b | |||
7c925cb88a | |||
8745d7d526 | |||
e02246f97d | |||
e629e03b33 | |||
e2ad3758e0 | |||
f3e2d21b89 | |||
fd62653d79 | |||
ca3e6f7fc9 | |||
d8abac1917 | |||
2807659da3 | |||
7884bf4077 | |||
59f80c049c | |||
f1e58db151 | |||
74b766f18a | |||
7e0f69d95d | |||
fa318d4509 | |||
63b74a9fda | |||
1a543814f4 | |||
50ae767fcd | |||
44263ac95f | |||
a6aca42c8c | |||
83daae46b8 | |||
6611fc5843 | |||
fe82c86c93 | |||
692555732d | |||
d59286bb05 | |||
91cfa7e945 | |||
2d277e80cc | |||
3cdca5eb33 | |||
591abb4bb8 | |||
0b4421c7a7 | |||
325efd8b14 | |||
959168771b | |||
18c306b9ea | |||
c6be1a7954 | |||
e8e9f04050 | |||
3700a71c39 | |||
60f0628f5e | |||
80dcd9aa69 | |||
91b685576b | |||
2e3e3dcf3c | |||
118f5e1794 | |||
e902352a4b | |||
2f7fcb6dc3 | |||
21ddb9d706 | |||
efa63452e7 | |||
83f84de019 | |||
b9aca981e5 | |||
5913707519 | |||
dd6a2c0979 | |||
9fdee6e0c7 | |||
b31bf5c1ab | |||
cf4906f2f4 | |||
680a5dfea3 | |||
c1062cd7ed | |||
8edc581f0b | |||
ea9d801d08 | |||
8f72e11d0c | |||
452271e8c0 | |||
7b4effe889 | |||
e2bf48d1b6 | |||
c88056ddb9 | |||
96dbb0a057 | |||
288c80ea26 | |||
5a217aca01 | |||
4bed62aa6f | |||
a4d604e146 | |||
ae4405ef78 | |||
71ca51e813 | |||
1bf07d736f | |||
909899612e | |||
4184fbb2cd | |||
75010c0771 | |||
5562498e84 | |||
c2d0940a80 | |||
baa98f25c5 | |||
26645ee83c | |||
85d74bec1c | |||
fd0fc652a3 | |||
c85dac2e4d | |||
c855f08f9c | |||
a31c68e87a | |||
99021f6b3a | |||
e2b47db3fd | |||
8609956ae7 | |||
e25ca930e0 | |||
47ec1899a1 | |||
1e8fb6a9ae | |||
02eb5b7ee4 | |||
776806caef | |||
755b846b50 | |||
73f3ba17de | |||
07fb1e0e12 | |||
297867cbf3 | |||
db598af28a | |||
ec765c9070 | |||
5eaa754401 | |||
b48b5589f4 | |||
634ef16bc5 | |||
ccf0bdaf05 | |||
4647da7803 | |||
613f271c4e | |||
8b1529f240 | |||
3eb09033bf | |||
12619f6bde | |||
f5ceaa9afe | |||
777ae945e0 | |||
3eae8fb58b | |||
b14ef5cd78 | |||
98bf4f3bdc | |||
2d6cf50ca7 | |||
95baf9fb9c | |||
dd0972b528 | |||
d17f6297d3 | |||
3ae785a45c | |||
dd254d4bec | |||
e04bd75f1f | |||
929ccb53db | |||
72319a4613 | |||
e389e6c073 | |||
cd6951dcbb | |||
02d60754b6 | |||
6884251646 | |||
582e2059d8 | |||
ea2974bfae | |||
b8ff649c96 | |||
8661ecdafb | |||
fe8cbc061d | |||
b4459e1fd4 | |||
fd6553871f | |||
a4ca44e1ce | |||
e124c429d1 | |||
e9a2dae1e4 | |||
8b0f3490e3 | |||
131606a6cf | |||
cacafa205e | |||
9c620de1e7 | |||
3e98fb967b | |||
8db81478f3 | |||
8f9861bac6 | |||
5b35e3500e | |||
fc4c297bef | |||
e7cb699bcf | |||
5301b4efad | |||
bf595dd09c | |||
cb4b168b2a | |||
b2fcbb8289 |
BIN
.github/readme-banner.png
vendored
Normal file
BIN
.github/readme-banner.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
2
.github/utils/.gitignore
vendored
Normal file
2
.github/utils/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.env
|
||||
__pycache__/
|
57
.github/utils/_get_password.py
vendored
Normal file
57
.github/utils/_get_password.py
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
import base64
|
||||
import secrets
|
||||
from hashlib import sha256
|
||||
from typing import Tuple
|
||||
|
||||
import mysql.connector as mysql
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
|
||||
def get_password(
|
||||
version_name: str,
|
||||
version_code: int,
|
||||
db_host: str,
|
||||
db_user: str,
|
||||
db_pass: str,
|
||||
db_name: str,
|
||||
) -> Tuple[str, bytes]:
|
||||
db = mysql.connect(
|
||||
host=db_host,
|
||||
user=db_user,
|
||||
password=db_pass,
|
||||
database=db_name,
|
||||
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)
|
||||
|
||||
key = f"{version_name}.{password}.{version_code}"
|
||||
key = sha256(key.encode()).digest()
|
||||
data = "ThisIsOurHardWorkPleaseDoNotCopyOrSteal(c)2019.KubaSz"
|
||||
data = sha256(data.encode()).digest()
|
||||
data = data + (chr(16) * 16).encode()
|
||||
|
||||
aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)
|
||||
|
||||
app_password = base64.b64encode(aes.encrypt(data)).decode()
|
||||
|
||||
c = db.cursor()
|
||||
c.execute(
|
||||
"INSERT IGNORE INTO _appPasswords (versionCode, appPassword, password, iv) VALUES (%s, %s, %s, %s);",
|
||||
(version_code, app_password, password, iv),
|
||||
)
|
||||
db.commit()
|
||||
|
||||
c = db.cursor()
|
||||
c.execute(
|
||||
"SELECT password, iv FROM _appPasswords WHERE versionCode = %s;",
|
||||
(version_code,),
|
||||
)
|
||||
row = c.fetchone()
|
||||
|
||||
db.close()
|
||||
|
||||
return (row[0], row[1])
|
142
.github/utils/_utils.py
vendored
Normal file
142
.github/utils/_utils.py
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import Tuple
|
||||
|
||||
VERSION_NAME_REGEX = r'versionName: "(.+?)"'
|
||||
VERSION_CODE_REGEX = r"versionCode: ([0-9]+)"
|
||||
VERSION_NAME_FORMAT = 'versionName: "{}"'
|
||||
VERSION_CODE_FORMAT = "versionCode: {}"
|
||||
|
||||
|
||||
def get_project_dir() -> str:
|
||||
project_dir = sys.argv[1]
|
||||
if project_dir[-1:] == "/" or project_dir[-1:] == "\\":
|
||||
project_dir = project_dir[:-1]
|
||||
return project_dir
|
||||
|
||||
|
||||
def read_gradle_version(project_dir: str) -> Tuple[int, str]:
|
||||
GRADLE_PATH = f"{project_dir}/build.gradle"
|
||||
|
||||
with open(GRADLE_PATH, "r") as f:
|
||||
gradle = f.read()
|
||||
|
||||
version_name = re.search(VERSION_NAME_REGEX, gradle).group(1)
|
||||
version_code = int(re.search(VERSION_CODE_REGEX, gradle).group(1))
|
||||
|
||||
return (version_code, version_name)
|
||||
|
||||
|
||||
def write_gradle_version(project_dir: str, version_code: int, version_name: str):
|
||||
GRADLE_PATH = f"{project_dir}/build.gradle"
|
||||
|
||||
with open(GRADLE_PATH, "r") as f:
|
||||
gradle = f.read()
|
||||
|
||||
gradle = re.sub(
|
||||
VERSION_NAME_REGEX, VERSION_NAME_FORMAT.format(version_name), gradle
|
||||
)
|
||||
gradle = re.sub(
|
||||
VERSION_CODE_REGEX, VERSION_CODE_FORMAT.format(version_code), gradle
|
||||
)
|
||||
|
||||
with open(GRADLE_PATH, "w") as f:
|
||||
f.write(gradle)
|
||||
|
||||
|
||||
def build_version_code(version_name: str) -> int:
|
||||
version = version_name.split("+")[0].split("-")
|
||||
version_base = version[0]
|
||||
version_suffix = version[1] if len(version) == 2 else ""
|
||||
|
||||
base_parts = version_base.split(".")
|
||||
major = int(base_parts[0]) or 0
|
||||
minor = int(base_parts[1]) if len(base_parts) > 1 else 0
|
||||
patch = int(base_parts[2]) if len(base_parts) > 2 else 0
|
||||
|
||||
beta = 9
|
||||
rc = 9
|
||||
if "dev" in version_suffix:
|
||||
beta = 0
|
||||
rc = 0
|
||||
elif "beta." in version_suffix:
|
||||
beta = int(version_suffix.split(".")[1])
|
||||
rc = 0
|
||||
elif "rc." in version_suffix:
|
||||
beta = 0
|
||||
rc = int(version_suffix.split(".")[1])
|
||||
|
||||
version_code = beta + rc * 10 + patch * 100 + minor * 10000 + major * 1000000
|
||||
return version_code
|
||||
|
||||
|
||||
def get_changelog(project_dir: str, format: str) -> Tuple[str, str]:
|
||||
with open(
|
||||
f"{project_dir}/app/src/main/assets/pl-changelog.html", "r", encoding="utf-8"
|
||||
) as f:
|
||||
changelog = f.read()
|
||||
|
||||
title = re.search(r"<h3>(.+?)</h3>", changelog).group(1)
|
||||
content = re.search(r"(?s)<ul>(.+)</ul>", changelog).group(1).strip()
|
||||
content = "\n".join(line.strip() for line in content.split("\n"))
|
||||
|
||||
if format != "html":
|
||||
content = content.replace("<li>", "- ")
|
||||
content = content.replace("<br>", "\n")
|
||||
if format == "markdown":
|
||||
content = re.sub(r"<u>(.+?)</u>", "__\\1__", content)
|
||||
content = re.sub(r"<i>(.+?)</i>", "*\\1*", content)
|
||||
content = re.sub(r"<b>(.+?)</b>", "**\\1**", content)
|
||||
content = re.sub(r"</?.+?>", "", content)
|
||||
|
||||
return (title, content)
|
||||
|
||||
|
||||
def get_commit_log(project_dir: str, format: str, max_lines: int = None) -> str:
|
||||
last_tag = (
|
||||
subprocess.check_output("git describe --tags --abbrev=0".split(" "))
|
||||
.decode()
|
||||
.strip()
|
||||
)
|
||||
|
||||
log = subprocess.run(
|
||||
args=f"git log {last_tag}..HEAD --format=%an%x00%at%x00%h%x00%s%x00%D".split(" "),
|
||||
cwd=project_dir,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
log = log.stdout.strip().decode()
|
||||
|
||||
commits = [line.split("\x00") for line in log.split("\n")]
|
||||
if max_lines:
|
||||
commits = commits[:max_lines]
|
||||
|
||||
output = []
|
||||
valid = False
|
||||
|
||||
for commit in commits:
|
||||
if not commit[0]:
|
||||
continue
|
||||
if "origin/" in commit[4]:
|
||||
valid = True
|
||||
if not valid:
|
||||
continue
|
||||
date = datetime.fromtimestamp(float(commit[1]))
|
||||
date = date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
if format == "html":
|
||||
output.append(f"<li>{commit[3]} <i> - {commit[0]}</i></li>")
|
||||
elif format == "markdown":
|
||||
output.append(f"[{date}] {commit[0]}\n {commit[3]}")
|
||||
elif format == "markdown_full":
|
||||
output.append(
|
||||
f"_[{date}] {commit[0]}_\n` `__`{commit[2]}`__ **{commit[3]}**"
|
||||
)
|
||||
elif format == "plain":
|
||||
output.append(f"- {commit[3]}")
|
||||
|
||||
if format == "markdown":
|
||||
output.insert(0, "```")
|
||||
output.append("```")
|
||||
|
||||
return "\n".join(output)
|
69
.github/utils/bump_nightly.py
vendored
Normal file
69
.github/utils/bump_nightly.py
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import requests
|
||||
|
||||
from _utils import (
|
||||
get_commit_log,
|
||||
get_project_dir,
|
||||
read_gradle_version,
|
||||
write_gradle_version,
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
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()
|
||||
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))
|
||||
|
||||
write_gradle_version(project_dir, version_code, version_name)
|
||||
|
||||
commit_log = get_commit_log(project_dir, format="html", max_lines=10)
|
||||
|
||||
with open(
|
||||
f"{project_dir}/app/src/main/assets/pl-changelog.html", "r", encoding="utf-8"
|
||||
) as f:
|
||||
changelog = f.read()
|
||||
|
||||
changelog = re.sub(r"<h3>(.+?)</h3>", f"<h3>{version_name}</h3>", changelog)
|
||||
changelog = re.sub(r"(?s)<ul>(.+)</ul>", f"<ul>\n{commit_log}\n</ul>", changelog)
|
||||
|
||||
with open(
|
||||
f"{project_dir}/app/src/main/assets/pl-changelog.html", "w", encoding="utf-8"
|
||||
) as f:
|
||||
f.write(changelog)
|
41
.github/utils/bump_version.py
vendored
Normal file
41
.github/utils/bump_version.py
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from _get_password import get_password
|
||||
from _utils import build_version_code, write_gradle_version
|
||||
from sign import sign
|
||||
|
||||
if __name__ == "__main__":
|
||||
version_name = input("Enter version name: ")
|
||||
version_code = build_version_code(version_name)
|
||||
|
||||
print(f"Bumping version to {version_name} ({version_code})")
|
||||
|
||||
project_dir = "../.."
|
||||
|
||||
load_dotenv()
|
||||
DB_HOST = os.getenv("DB_HOST")
|
||||
DB_USER = os.getenv("DB_USER")
|
||||
DB_PASS = os.getenv("DB_PASS")
|
||||
DB_NAME = os.getenv("DB_NAME")
|
||||
|
||||
write_gradle_version(project_dir, version_code, version_name)
|
||||
(password, iv) = get_password(
|
||||
version_name, version_code, DB_HOST, DB_USER, DB_PASS, DB_NAME
|
||||
)
|
||||
|
||||
sign(project_dir, version_name, version_code, password, iv, commit=False)
|
||||
|
||||
print("Writing mock passwords")
|
||||
os.chdir(project_dir)
|
||||
os.system(
|
||||
"sed -i -E 's/\/\*([0-9a-f]{2} ?){16}\*\//\/*secret password - removed for source code publication*\//g' app/src/main/cpp/szkolny-signing.cpp"
|
||||
)
|
||||
os.system(
|
||||
"sed -i -E 's/\\t0x.., 0x(.)., 0x.(.), 0x.(.), 0x.., 0x.., 0x.., 0x.(.), 0x.., 0x.(.), 0x(.)., 0x(.)., 0x.., 0x.., 0x.., 0x.(.)/\\t0x\\3\\6, 0x\\7\\4, 0x\\1\\8, 0x\\2\\5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /g' app/src/main/cpp/szkolny-signing.cpp"
|
||||
)
|
||||
os.system(
|
||||
"sed -i -E 's/param1\..(.).(.).(.).(.)..(.)..(.)..(.)..(.).../param1.MTIzNDU2Nzg5MD\\5\\2\\7\\6\\1\\3\\4\8==/g' app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt"
|
||||
)
|
||||
input("Press any key to finish")
|
72
.github/utils/extract_changelogs.py
vendored
Normal file
72
.github/utils/extract_changelogs.py
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
from _utils import get_changelog, get_commit_log, get_project_dir, read_gradle_version
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: extract_changelogs.py <project dir>")
|
||||
exit(-1)
|
||||
|
||||
project_dir = get_project_dir()
|
||||
|
||||
(version_code, version_name) = read_gradle_version(project_dir)
|
||||
|
||||
print("::set-output name=appVersionName::" + version_name)
|
||||
print("::set-output name=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)
|
||||
|
||||
(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:
|
||||
f.write(title)
|
||||
f.write("\n")
|
||||
f.write(changelog)
|
||||
print("::set-output name=changelogPlainTitledFile::" + dir + "whatsnew-titled.txt")
|
||||
|
||||
print("::set-output name=changelogTitle::" + title)
|
||||
|
||||
# plain text changelog, max 500 chars - Google Play
|
||||
with open(dir + "whatsnew-pl-PL", "w", encoding="utf-8") as f:
|
||||
changelog_lines = changelog.split("\n")
|
||||
changelog = ""
|
||||
for line in changelog_lines:
|
||||
if len(changelog) + len(line) < 500:
|
||||
changelog += "\n" + line
|
||||
changelog = changelog.strip()
|
||||
f.write(changelog)
|
||||
|
||||
print("::set-output name=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")
|
||||
|
||||
# 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")
|
||||
|
||||
|
||||
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")
|
||||
|
||||
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")
|
||||
|
||||
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")
|
26
.github/utils/rename_artifacts.py
vendored
Normal file
26
.github/utils/rename_artifacts.py
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
|
||||
from _utils import get_project_dir
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: rename_artifacts.py <project dir>")
|
||||
exit(-1)
|
||||
|
||||
project_dir = get_project_dir()
|
||||
|
||||
files = glob.glob(f"{project_dir}/app/release/*.*")
|
||||
for file in files:
|
||||
file_relative = file.replace(os.getenv("GITHUB_WORKSPACE") + "/", "")
|
||||
if "-aligned.apk" in file:
|
||||
os.unlink(file)
|
||||
elif "-signed.apk" in file:
|
||||
new_file = file.replace("-signed.apk", ".apk")
|
||||
if os.path.isfile(new_file):
|
||||
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)
|
122
.github/utils/save_version.py
vendored
Normal file
122
.github/utils/save_version.py
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
|
||||
import mysql.connector as mysql
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from _utils import get_changelog, get_commit_log, get_project_dir, read_gradle_version
|
||||
|
||||
|
||||
def save_version(
|
||||
project_dir: str,
|
||||
db_host: str,
|
||||
db_user: str,
|
||||
db_pass: str,
|
||||
db_name: str,
|
||||
apk_server_release: str,
|
||||
apk_server_nightly: str,
|
||||
):
|
||||
db = mysql.connect(
|
||||
host=db_host,
|
||||
user=db_user,
|
||||
password=db_pass,
|
||||
database=db_name,
|
||||
auth_plugin="mysql_native_password",
|
||||
)
|
||||
|
||||
(version_code, version_name) = read_gradle_version(project_dir)
|
||||
(_, changelog) = get_changelog(project_dir, format="html")
|
||||
|
||||
types = ["dev", "beta", "nightly", "daily", "rc", "release"]
|
||||
build_type = [x for x in types if x in version_name]
|
||||
build_type = build_type[0] if build_type else "release"
|
||||
|
||||
if "+nightly." in version_name or "+daily." in version_name:
|
||||
changelog = get_commit_log(project_dir, format="html")
|
||||
build_type = "nightly"
|
||||
elif "-dev" in version_name:
|
||||
build_type = "dev"
|
||||
elif "-beta." in version_name:
|
||||
build_type = "beta"
|
||||
elif "-rc." in version_name:
|
||||
build_type = "rc"
|
||||
|
||||
build_date = int(time())
|
||||
apk_name = None
|
||||
bundle_name_play = None
|
||||
|
||||
files = glob.glob(f"{project_dir}/app/release/*.*")
|
||||
output_apk = f"Edziennik_{version_name}_official.apk"
|
||||
output_aab_play = f"Edziennik_{version_name}_play.aab"
|
||||
for file in files:
|
||||
if output_apk in file:
|
||||
build_date = int(os.stat(file).st_mtime)
|
||||
apk_name = output_apk
|
||||
if output_aab_play in file:
|
||||
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")
|
||||
|
||||
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
|
||||
|
||||
cols = [
|
||||
"versionCode",
|
||||
"versionName",
|
||||
"releaseDate",
|
||||
"releaseNotes",
|
||||
"releaseType",
|
||||
"downloadUrl",
|
||||
"apkName",
|
||||
"bundleNamePlay",
|
||||
]
|
||||
updated = {
|
||||
"versionCode": version_code,
|
||||
"downloadUrl": download_url,
|
||||
"apkName": apk_name,
|
||||
"bundleNamePlay": bundle_name_play,
|
||||
}
|
||||
|
||||
values = [
|
||||
version_code,
|
||||
version_name,
|
||||
build_date,
|
||||
changelog,
|
||||
build_type,
|
||||
download_url,
|
||||
apk_name,
|
||||
bundle_name_play,
|
||||
]
|
||||
values.extend(val for val in updated.values() if val)
|
||||
|
||||
updated = ", ".join(f"{col} = %s" for (col, val) in updated.items() if val)
|
||||
|
||||
sql = f"INSERT INTO updates ({', '.join(cols)}) VALUES ({'%s, ' * (len(cols) - 1)}%s) ON DUPLICATE KEY UPDATE {updated};"
|
||||
|
||||
c = db.cursor()
|
||||
c.execute(sql, tuple(values))
|
||||
db.commit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: save_version.py <project dir>")
|
||||
exit(-1)
|
||||
|
||||
project_dir = get_project_dir()
|
||||
|
||||
load_dotenv()
|
||||
DB_HOST = os.getenv("DB_HOST")
|
||||
DB_USER = os.getenv("DB_USER")
|
||||
DB_PASS = os.getenv("DB_PASS")
|
||||
DB_NAME = os.getenv("DB_NAME")
|
||||
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)
|
84
.github/utils/sign.py
vendored
Normal file
84
.github/utils/sign.py
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from _get_password import get_password
|
||||
from _utils import get_project_dir, read_gradle_version
|
||||
|
||||
|
||||
def sign(
|
||||
project_dir: str,
|
||||
version_name: str,
|
||||
version_code: int,
|
||||
password: str,
|
||||
iv: bytes,
|
||||
commit: bool = False,
|
||||
):
|
||||
SIGNING_PATH = f"{project_dir}/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt"
|
||||
CPP_PATH = f"{project_dir}/app/src/main/cpp/szkolny-signing.cpp"
|
||||
|
||||
with open(SIGNING_PATH, "r") as f:
|
||||
signing = f.read()
|
||||
|
||||
with open(CPP_PATH, "r") as f:
|
||||
cpp = f.read()
|
||||
|
||||
SIGNING_REGEX = r"\$param1\..*\.\$param2"
|
||||
CPP_REGEX = r"(?s)/\*.+?toys AES_IV\[16\] = {.+?};"
|
||||
|
||||
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])
|
||||
|
||||
signing = re.sub(SIGNING_REGEX, SIGNING_FORMAT.format(password), signing)
|
||||
cpp = re.sub(CPP_REGEX, CPP_FORMAT.format(iv_hex, iv_cpp), cpp)
|
||||
|
||||
with open(SIGNING_PATH, "w") as f:
|
||||
f.write(signing)
|
||||
|
||||
with open(CPP_PATH, "w") as f:
|
||||
f.write(cpp)
|
||||
|
||||
if commit:
|
||||
os.chdir(project_dir)
|
||||
os.system("git add .")
|
||||
os.system(
|
||||
f'git commit -m "[{version_name}] Update build.gradle, signing and changelog."'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: sign.py <project dir> [commit]")
|
||||
exit(-1)
|
||||
|
||||
project_dir = get_project_dir()
|
||||
|
||||
load_dotenv()
|
||||
DB_HOST = os.getenv("DB_HOST")
|
||||
DB_USER = os.getenv("DB_USER")
|
||||
DB_PASS = os.getenv("DB_PASS")
|
||||
DB_NAME = os.getenv("DB_NAME")
|
||||
|
||||
(version_code, version_name) = read_gradle_version(project_dir)
|
||||
(password, iv) = get_password(
|
||||
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))
|
||||
|
||||
sign(
|
||||
project_dir,
|
||||
version_name,
|
||||
version_code,
|
||||
password,
|
||||
iv,
|
||||
commit="commit" in sys.argv,
|
||||
)
|
118
.github/utils/webhook_discord.py
vendored
Normal file
118
.github/utils/webhook_discord.py
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from _utils import get_changelog, get_commit_log, get_project_dir, read_gradle_version
|
||||
|
||||
|
||||
def post_webhook(
|
||||
project_dir: str,
|
||||
apk_file: str,
|
||||
apk_server_release: str,
|
||||
apk_server_nightly: str,
|
||||
webhook_release: str,
|
||||
webhook_testing: str,
|
||||
):
|
||||
(_, version_name) = read_gradle_version(project_dir)
|
||||
|
||||
types = ["dev", "beta", "nightly", "daily", "rc", "release"]
|
||||
build_type = [x for x in types if x in version_name]
|
||||
build_type = build_type[0] if build_type else None
|
||||
|
||||
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")
|
||||
|
||||
# untagged release, get commit log
|
||||
if build_type in ["nightly", "daily"]:
|
||||
changelog = get_commit_log(project_dir, format="markdown", max_lines=5)
|
||||
else:
|
||||
changelog = get_changelog(project_dir, format="markdown")
|
||||
|
||||
webhook = get_webhook_testing(
|
||||
version_name, build_type, changelog, download_url, build_date
|
||||
)
|
||||
requests.post(url=webhook_testing, json=webhook)
|
||||
else:
|
||||
changelog = get_changelog(project_dir, format="markdown")
|
||||
webhook = get_webhook_release(changelog, download_url)
|
||||
requests.post(url=webhook_release, json=webhook)
|
||||
|
||||
|
||||
def get_webhook_release(changelog: str, download_url: str):
|
||||
(title, content) = changelog
|
||||
return {"content": f"__**{title}**__\n{content}\n{download_url}"}
|
||||
|
||||
|
||||
def get_webhook_testing(
|
||||
version_name: str,
|
||||
build_type: str,
|
||||
changelog: str,
|
||||
download_url: str,
|
||||
build_date: str,
|
||||
):
|
||||
return {
|
||||
"embeds": [
|
||||
{
|
||||
"title": f"Nowa wersja {build_type} aplikacji Szkolny.eu",
|
||||
"description": f"Dostępna jest nowa wersja testowa **{build_type}**.",
|
||||
"color": 2201331,
|
||||
"fields": [
|
||||
{
|
||||
"name": f"Wersja `{version_name}`",
|
||||
"value": f"[Pobierz .APK]({download_url})"
|
||||
if download_url
|
||||
else "*Pobieranie niedostępne*",
|
||||
"inline": False,
|
||||
},
|
||||
{
|
||||
"name": "Data kompilacji",
|
||||
"value": build_date or "-",
|
||||
"inline": False,
|
||||
},
|
||||
{
|
||||
"name": "Ostatnie zmiany",
|
||||
"value": changelog or "-",
|
||||
"inline": False,
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("usage: webhook_discord.py <project dir>")
|
||||
exit(-1)
|
||||
|
||||
project_dir = get_project_dir()
|
||||
|
||||
load_dotenv()
|
||||
APK_FILE = os.getenv("APK_FILE")
|
||||
APK_SERVER_RELEASE = os.getenv("APK_SERVER_RELEASE")
|
||||
APK_SERVER_NIGHTLY = os.getenv("APK_SERVER_NIGHTLY")
|
||||
WEBHOOK_RELEASE = os.getenv("WEBHOOK_RELEASE")
|
||||
WEBHOOK_TESTING = os.getenv("WEBHOOK_TESTING")
|
||||
|
||||
post_webhook(
|
||||
project_dir,
|
||||
APK_FILE,
|
||||
APK_SERVER_RELEASE,
|
||||
APK_SERVER_NIGHTLY,
|
||||
WEBHOOK_RELEASE,
|
||||
WEBHOOK_TESTING,
|
||||
)
|
154
.github/workflows/build-nightly-apk.yml
vendored
Normal file
154
.github/workflows/build-nightly-apk.yml
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
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
|
131
.github/workflows/build-release-aab-play.yml
vendored
Normal file
131
.github/workflows/build-release-aab-play.yml
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
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
|
154
.github/workflows/build-release-apk.yml
vendored
Normal file
154
.github/workflows/build-release-apk.yml
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
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
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -265,3 +265,4 @@ fabric.properties
|
||||
# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,gradle,java,kotlin
|
||||
|
||||
signatures/
|
||||
.idea/*.xml
|
||||
|
10
.idea/codeStyles/Project.xml
generated
10
.idea/codeStyles/Project.xml
generated
@ -1,6 +1,7 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
@ -15,6 +16,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -25,6 +27,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -36,6 +39,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -46,6 +50,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -56,6 +61,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -66,6 +72,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -76,6 +83,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -87,6 +95,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
@ -98,6 +107,7 @@
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
|
6
.idea/copyright/Antoni.xml
generated
Normal file
6
.idea/copyright/Antoni.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="Copyright (c) Antoni Czaplicki &#36;{today.year}-&#36;{today.month}-&#36;{today.day}. " />
|
||||
<option name="myName" value="Antoni" />
|
||||
</copyright>
|
||||
</component>
|
1
.idea/dictionaries/Kuba.xml
generated
1
.idea/dictionaries/Kuba.xml
generated
@ -5,6 +5,7 @@
|
||||
<w>ciasteczko</w>
|
||||
<w>csrf</w>
|
||||
<w>edziennik</w>
|
||||
<w>elearning</w>
|
||||
<w>gson</w>
|
||||
<w>hebe</w>
|
||||
<w>idziennik</w>
|
||||
|
9
.idea/discord.xml
generated
9
.idea/discord.xml
generated
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
</component>
|
||||
<component name="ProjectNotificationSettings">
|
||||
<option name="askShowProject" value="false" />
|
||||
</component>
|
||||
</project>
|
6
.idea/kotlinc.xml
generated
6
.idea/kotlinc.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="1.8" />
|
||||
</component>
|
||||
</project>
|
13
.idea/runConfigurations.xml
generated
13
.idea/runConfigurations.xml
generated
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
34
README.md
34
README.md
@ -1,9 +1,7 @@
|
||||
# Szkolny.eu
|
||||
|
||||
Nieoficjalna aplikacja do obsługi najpopularniejszych dzienników elektronicznych w Polsce.
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
[](https://szkolny.eu/discord)
|
||||
[](https://szkolny.eu/)
|
||||
[](https://szkolny.eu/facebook)
|
||||
@ -12,6 +10,10 @@ Nieoficjalna aplikacja do obsługi najpopularniejszych dzienników elektroniczny
|
||||
[](https://github.com/szkolny-eu/szkolny-android/releases/latest)
|
||||

|
||||
|
||||
[](https://github.com/szkolny-eu/szkolny-android/actions/workflows/build-release-apk.yml)
|
||||
[](https://github.com/szkolny-eu/szkolny-android/actions/workflows/build-release-aab-play.yml)
|
||||
[](https://github.com/szkolny-eu/szkolny-android/actions/workflows/build-nightly-apk.yml)
|
||||
|
||||
</div>
|
||||
|
||||
## Ważna informacja
|
||||
@ -30,17 +32,17 @@ Szkolny.eu jest nieoficjalną aplikacją, umożliwiającą rodzicom i uczniom do
|
||||
|
||||
- plan lekcji, terminarz, oceny, wiadomości, zadania domowe, uwagi, frekwencja
|
||||
- wygodne **widgety** na ekran główny
|
||||
- łatwa komunikacja z nauczycielami - **odbieranie, wyszukiwanie i wysyłanie wiadomości**
|
||||
- łatwa komunikacja z nauczycielami — **odbieranie, wyszukiwanie i wysyłanie wiadomości**
|
||||
- pobieranie **załączników wiadomości i zadań domowych**
|
||||
- **powiadomienia** o nowych informacjach na telefonie lub na komputerze
|
||||
- organizacja zadań domowych i sprawdzianów - łatwe oznaczanie jako wykonane
|
||||
- organizacja zadań domowych i sprawdzianów — łatwe oznaczanie jako wykonane
|
||||
- obliczanie **średniej ocen** ze wszystkich przedmiotów, oceny proponowane i końcowe
|
||||
- Symulator edycji ocen - obliczanie średniej z przedmiotu po zmianie dowolnych jego ocen
|
||||
- Symulator edycji ocen — obliczanie średniej z przedmiotu po zmianie dowolnych jego ocen
|
||||
- **dodawanie własnych wydarzeń** i zadań do terminarza
|
||||
- nowoczesny i intuicyjny interfejs użytkownika
|
||||
- **obsługa wielu profili** uczniów - jeżeli jesteś Rodzicem, możesz skonfigurować wszystkie swoje konta uczniowskie i łatwo między nimi przełączać
|
||||
- **obsługa wielu profili** uczniów — jeżeli jesteś Rodzicem, możesz skonfigurować wszystkie swoje konta uczniowskie i łatwo między nimi przełączać
|
||||
- opcja **automatycznej synchronizacji** z E-dziennikiem
|
||||
- opcja Ciszy nocnej - nigdy więcej budzących Cię dźwięków z telefonu
|
||||
- opcja Ciszy nocnej — nigdy więcej budzących Cię dźwięków z telefonu
|
||||
|
||||
[Zobacz porównanie funkcji z innymi aplikacjami](https://szkolny.eu/funkcje)
|
||||
|
||||
@ -53,7 +55,7 @@ Najnowsze wersje możesz pobrać z Google Play lub bezpośrednio z naszej strony
|
||||
|
||||
### Kompilacja
|
||||
|
||||
Aby uruchomić aplikację "ze źródeł" należy użyć Android Studio w wersji co najmniej 4.2 Beta 6. Wersja `debug` może wtedy zostać zainstalowana np. na emulatorze Androida.
|
||||
Aby uruchomić aplikację „ze źródeł” należy użyć Android Studio w wersji co najmniej 4.2 Beta 6. Wersja `debug` może wtedy zostać zainstalowana np. na emulatorze Androida.
|
||||
|
||||
Aby zbudować wersję produkcyjną, tzn. `release` należy użyć wariantu `mainRelease` oraz podpisać wyjściowy plik .APK sygnaturą w wersji V1 i V2.
|
||||
|
||||
@ -68,15 +70,15 @@ __Jeśli masz jakieś pytania, zapraszamy na [nasz serwer Discord](https://szkol
|
||||
## Licencja
|
||||
|
||||
Szkolny.eu publikowany jest na licencji [GNU GPLv3](LICENSE). W szczególności, deweloper:
|
||||
- może modyfikować oraz usprawniać kod aplikacji
|
||||
- może dystrybuować wersje produkcyjne
|
||||
- musi opublikować wszelkie wprowadzone zmiany, tzn. publiczny fork tego repozytorium
|
||||
- nie może zmieniać licencji ani copyrightu aplikacji
|
||||
- Może modyfikować oraz usprawniać kod aplikacji
|
||||
- Może dystrybuować wersje produkcyjne
|
||||
- Musi opublikować wszelkie wprowadzone zmiany, tzn. publiczny fork tego repozytorium
|
||||
- Nie może zmieniać licencji ani copyrightu aplikacji
|
||||
|
||||
Dodatkowo:
|
||||
- zabronione jest modyfikowanie lub usuwanie kodu odpowiedzialnego za zgodność wersji produkcyjnych z licencją
|
||||
- Zabronione jest modyfikowanie lub usuwanie kodu odpowiedzialnego za zgodność wersji produkcyjnych z licencją.
|
||||
|
||||
- **wersje skompilowane nie mogą być dystrybuowane za pomocą Google Play oraz żadnej platformy, na której istnieje oficjalna wersja aplikacji**
|
||||
- **Wersje skompilowane nie mogą być dystrybuowane za pomocą Google Play oraz żadnej platformy, na której istnieje oficjalna wersja aplikacji**.
|
||||
|
||||
**Autorzy aplikacji nie biorą odpowiedzialności za używanie aplikacji, modyfikowanie oraz dystrybuowanie.**
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
@ -18,8 +19,10 @@ android {
|
||||
versionName release.versionName
|
||||
|
||||
buildConfigField "java.util.Map<String, String>", "GIT_INFO", gitInfoMap
|
||||
buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis())
|
||||
buildConfigField "String", "VERSION_BASE", "\"${release.versionName}\""
|
||||
manifestPlaceholders = [
|
||||
buildTimestamp: String.valueOf(System.currentTimeMillis())
|
||||
]
|
||||
|
||||
multiDexEnabled = true
|
||||
|
||||
@ -28,11 +31,20 @@ android {
|
||||
cppFlags "-std=c++11"
|
||||
}
|
||||
}
|
||||
|
||||
kapt {
|
||||
arguments {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled = false
|
||||
manifestPlaceholders = [
|
||||
buildTimestamp: 0
|
||||
]
|
||||
}
|
||||
release {
|
||||
minifyEnabled = true
|
||||
@ -44,7 +56,7 @@ android {
|
||||
flavorDimensions "platform"
|
||||
productFlavors {
|
||||
main {
|
||||
versionName gitInfo.versionHuman
|
||||
versionName "${release.versionName}-${gitInfo.versionSuffix}"
|
||||
}
|
||||
official {}
|
||||
play {}
|
||||
@ -98,7 +110,10 @@ tasks.whenTaskAdded { task ->
|
||||
|
||||
if (flavor != "") {
|
||||
tasks.create(renameTaskName, Copy) {
|
||||
from file("${projectDir}/${flavor}/release/"), file("${buildDir}/outputs/mapping/${flavor}Release/")
|
||||
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"
|
||||
destinationDir file("${projectDir}/release/")
|
||||
rename ".+?\\.(.+)", "Edziennik_${android.defaultConfig.versionName}_${flavor}." + '$1'
|
||||
@ -115,25 +130,25 @@ dependencies {
|
||||
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
|
||||
|
||||
// Android Jetpack
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.appcompat:appcompat:1.3.1"
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:2.3.4"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||
implementation "androidx.room:room-runtime:2.2.6"
|
||||
implementation "androidx.work:work-runtime-ktx:2.5.0"
|
||||
kapt "androidx.room:room-compiler:2.2.6"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:2.3.5"
|
||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||
implementation "androidx.room:room-runtime:2.3.0"
|
||||
implementation "androidx.work:work-runtime-ktx:2.6.0"
|
||||
kapt "androidx.room:room-compiler:2.3.0"
|
||||
|
||||
// Google design libs
|
||||
implementation "com.google.android.material:material:1.3.0"
|
||||
implementation "com.google.android:flexbox:2.0.1"
|
||||
implementation "com.google.android.material:material:1.4.0"
|
||||
implementation "com.google.android.flexbox:flexbox:3.0.0"
|
||||
|
||||
// Play Services/Firebase
|
||||
implementation "com.google.android.gms:play-services-wearable:17.0.0"
|
||||
implementation "com.google.firebase:firebase-core:18.0.2"
|
||||
implementation "com.google.firebase:firebase-crashlytics:17.4.0"
|
||||
implementation "com.google.android.gms:play-services-wearable:17.1.0"
|
||||
implementation "com.google.firebase:firebase-core:19.0.2"
|
||||
implementation "com.google.firebase:firebase-crashlytics:18.2.3"
|
||||
implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
|
||||
|
||||
// OkHttp, Retrofit, Gson, Jsoup
|
||||
@ -141,13 +156,14 @@ 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.6'
|
||||
implementation "org.jsoup:jsoup:1.13.1"
|
||||
implementation 'com.google.code.gson:gson:2.8.8'
|
||||
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 "eu.szkolny:agendacalendarview:1799f8ef47"
|
||||
implementation "eu.szkolny:android-snowfall:1ca9ea2da3"
|
||||
implementation "eu.szkolny:agendacalendarview:1.0.4"
|
||||
implementation "eu.szkolny:cafebar:5bf0c618de"
|
||||
implementation "eu.szkolny.fslogin:lib:2.0.0"
|
||||
implementation "eu.szkolny:material-about-library:1d5ebaf47c"
|
||||
@ -162,34 +178,34 @@ dependencies {
|
||||
kapt "eu.szkolny.selective-dao:codegen:27f8f3f194"
|
||||
|
||||
// Iconics & related
|
||||
implementation "com.mikepenz:iconics-core:5.3.0-b01"
|
||||
implementation "com.mikepenz:iconics-views:5.3.0-b01"
|
||||
implementation "com.mikepenz:iconics-core:5.3.2"
|
||||
implementation "com.mikepenz:iconics-views:5.3.2"
|
||||
implementation "com.mikepenz:community-material-typeface:5.8.55.0-kotlin@aar"
|
||||
implementation "eu.szkolny:szkolny-font:1.3"
|
||||
implementation "eu.szkolny:szkolny-font:77e33acc2a"
|
||||
|
||||
// Other dependencies
|
||||
implementation "cat.ereza:customactivityoncrash:2.3.0"
|
||||
implementation "com.applandeo:material-calendar-view:1.5.0"
|
||||
implementation "com.android.volley:volley:1.2.1"
|
||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2"
|
||||
implementation "com.github.bassaer:chatmessageview:2.0.1"
|
||||
implementation "com.github.CanHub:Android-Image-Cropper:2.2.2"
|
||||
implementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
|
||||
implementation "com.github.jetradarmobile:android-snowfall:1.2.0"
|
||||
implementation "com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31"
|
||||
implementation("com.heinrichreimersoftware:material-intro") { version { strictly "1.5.8" } }
|
||||
implementation "com.hypertrack:hyperlog:0.0.10"
|
||||
implementation "com.github.Applandeo:Material-Calendar-View:15de569cbc" // https://github.com/Applandeo/Material-Calendar-View
|
||||
implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" // https://github.com/CanHub/Android-Image-Cropper
|
||||
implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" // 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.jaredrummler:colorpicker:1.1.0"
|
||||
implementation "com.qifan.powerpermission:powerpermission-coroutines:1.3.0"
|
||||
implementation "com.qifan.powerpermission:powerpermission:1.3.0"
|
||||
implementation "com.yuyh.json:jsonviewer:1.0.6"
|
||||
implementation "io.coil-kt:coil:1.1.1"
|
||||
implementation "me.dm7.barcodescanner:zxing:1.9.8"
|
||||
implementation "me.grantland:autofittextview:0.2.1"
|
||||
implementation "me.leolin:ShortcutBadger:1.1.22@aar"
|
||||
implementation "org.greenrobot:eventbus:3.2.0"
|
||||
implementation("com.heinrichreimersoftware:material-intro") { version { strictly "1.5.8" } }
|
||||
implementation("pl.droidsonroids.gif:android-gif-drawable") { version { strictly "1.2.15" } }
|
||||
|
||||
// Debug-only dependencies
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
||||
debugImplementation "com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:v1.0.6"
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ private def buildGitInfo() {
|
||||
.stream()
|
||||
.map {
|
||||
it.name + "(" + it.URIs.stream()
|
||||
.map { it.rawPath }
|
||||
.map { it.rawPath.stripMargin('/').replace(".git", "") }
|
||||
.toArray()
|
||||
.join(", ") + ")"
|
||||
}
|
||||
@ -97,7 +97,6 @@ private def buildGitInfo() {
|
||||
def tag = getLastTag(repo, git, head)
|
||||
def tagName = tag[1]
|
||||
def tagRevCount = tag[2]
|
||||
def versionName = tagName.replace("v", "")
|
||||
|
||||
def result = [
|
||||
hash : head.objectId.name,
|
||||
@ -108,7 +107,7 @@ private def buildGitInfo() {
|
||||
tag : tagName,
|
||||
revCount : tagRevCount,
|
||||
version : """$tagName-$tagRevCount-g${head.objectId.name.substring(0, 8)}""" + (dirty ? ".dirty" : ""),
|
||||
versionHuman: """$versionName-${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "")
|
||||
versionSuffix : """${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "")
|
||||
]
|
||||
return result
|
||||
}
|
||||
|
8
app/proguard-rules.pro
vendored
8
app/proguard-rules.pro
vendored
@ -25,15 +25,17 @@
|
||||
-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 { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.data.db.entity.Note { *; }
|
||||
-keep class pl.szczodrzynski.edziennik.ui.home.HomeCardModel { *; }
|
||||
-keepclassmembers class pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig { public *; }
|
||||
-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
|
||||
|
||||
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
|
||||
-keepclassmembernames class androidx.appcompat.view.menu.StandardMenuPopup { private *; }
|
||||
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
|
||||
-keepclassmembernames class androidx.appcompat.view.menu.StandardMenuPopup { private *; }
|
||||
-keepclassmembernames class androidx.appcompat.view.menu.MenuItemImpl { private *; }
|
||||
|
||||
-keepclassmembernames class com.mikepenz.materialdrawer.widget.MiniDrawerSliderView { private *; }
|
||||
|
||||
@ -66,7 +68,7 @@
|
||||
|
||||
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
|
||||
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
|
||||
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo$Platform { *; }
|
||||
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.login.LoginInfo$Platform { *; }
|
||||
|
||||
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData { *; }
|
||||
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData$Type { *; }
|
||||
|
2293
app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/97.json
Normal file
2293
app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/97.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,8 @@
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<meta-data android:name="buildTimestamp" android:value="${buildTimestamp}" />
|
||||
|
||||
<!-- __ __ _ _ _ _ _
|
||||
| \/ | (_) /\ | | (_) (_) |
|
||||
| \ / | __ _ _ _ __ / \ ___| |_ ___ ___| |_ _ _
|
||||
@ -119,31 +121,32 @@
|
||||
/ ____ \ (__| |_| |\ V /| | |_| | __/\__ \
|
||||
/_/ \_\___|\__|_| \_/ |_|\__|_|\___||___/
|
||||
-->
|
||||
<activity android:name=".ui.modules.base.CrashActivity"
|
||||
<activity android:name=".ui.base.CrashActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:process=":error_activity"
|
||||
android:theme="@style/DeadTheme" />
|
||||
<activity android:name=".ui.modules.intro.ChangelogIntroActivity"
|
||||
<activity android:name=".ui.intro.ChangelogIntroActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Intro" />
|
||||
<activity android:name=".ui.modules.login.LoginActivity"
|
||||
<activity android:name=".ui.login.LoginActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/AppTheme.Light" />
|
||||
<activity android:name=".ui.modules.home.CounterActivity"
|
||||
<activity android:name=".ui.home.CounterActivity"
|
||||
android:theme="@style/AppTheme.Black" />
|
||||
<activity android:name=".ui.modules.feedback.FeedbackActivity"
|
||||
<activity android:name=".ui.feedback.FeedbackActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||
<activity android:name=".ui.settings.SettingsLicenseActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name="com.canhub.cropper.CropImageActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/Base.Theme.AppCompat" />
|
||||
<activity android:name=".ui.modules.base.BuildInvalidActivity" />
|
||||
<activity android:name=".ui.base.BuildInvalidActivity" />
|
||||
<activity android:name=".ui.settings.contributors.ContributorsActivity" />
|
||||
|
||||
<!-- _____ _
|
||||
| __ \ (_)
|
||||
|
@ -1,14 +1,8 @@
|
||||
<h3>Wersja 4.7-rc.1, 2021-04-01</h3>
|
||||
<h3>Wersja 4.11.2, 2022-02-05</h3>
|
||||
<ul>
|
||||
<li><u>Szkolny.eu jest teraz open source!</u> Zapraszamy na stronę https://szkolny.eu/ po więcej ważnych informacji.</li>
|
||||
<li>Poprawiono wybieranie obrazków (tła nagłówka, tła aplikacji oraz profilu) z dowolnego źródła.</li>
|
||||
<li>Naprawiono zatrzymanie aplikacji na Androidzie 4.4 i starszych.</li>
|
||||
<li>Naprawiono problemy z połączeniem internetowym na Androidzie 4.4 i starszych.</li>
|
||||
<li>Dodano ekran informacji o kompilacji w Ustawieniach.</li>
|
||||
<li>Zaktualizowano ekran licencji open source.</li>
|
||||
<li>Zoptymalizowano wielkość aplikacji.</li>
|
||||
<li>Mobidziennik: naprawiono brak nadawców w liście wiadomości.</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
Dzięki za korzystanie ze Szkolnego!<br>
|
||||
<i>© Kuba Szczodrzyński, Kacper Ziubryniewicz 2021</i>
|
||||
<i>© [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2022</i>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/*secret password - removed for source code publication*/
|
||||
static toys AES_IV[16] = {
|
||||
0xdd, 0x0a, 0x72, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
0x66, 0xae, 0x85, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||
|
||||
|
@ -35,13 +35,17 @@ import okhttp3.OkHttpClient
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
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.db.AppDb
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.ext.DAY
|
||||
import pl.szczodrzynski.edziennik.ext.MS
|
||||
import pl.szczodrzynski.edziennik.ext.setLanguage
|
||||
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
|
||||
import pl.szczodrzynski.edziennik.ui.base.CrashActivity
|
||||
import pl.szczodrzynski.edziennik.utils.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.managers.*
|
||||
@ -58,10 +62,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
val profileId
|
||||
get() = profile.id
|
||||
|
||||
var enableChucker = false
|
||||
var debugMode = false
|
||||
var devMode = false
|
||||
}
|
||||
|
||||
val api by lazy { SzkolnyApi(this) }
|
||||
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
|
||||
val userActionManager by lazy { UserActionManager(this) }
|
||||
val gradesManager by lazy { GradesManager(this) }
|
||||
@ -70,6 +76,10 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
val permissionManager by lazy { PermissionManager(this) }
|
||||
val attendanceManager by lazy { AttendanceManager(this) }
|
||||
val buildManager by lazy { BuildManager(this) }
|
||||
val availabilityManager by lazy { AvailabilityManager(this) }
|
||||
val textStylingManager by lazy { TextStylingManager(this) }
|
||||
val messageManager by lazy { MessageManager(this) }
|
||||
val noteManager by lazy { NoteManager(this) }
|
||||
|
||||
val db
|
||||
get() = App.db
|
||||
@ -115,10 +125,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
if (enableChucker) {
|
||||
val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
|
||||
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
|
||||
builder.addInterceptor(chuckerInterceptor)
|
||||
}
|
||||
}
|
||||
|
||||
http = builder.build()
|
||||
|
||||
@ -171,7 +183,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
App.config = Config(App.db)
|
||||
App.profile = Profile(0, 0, 0, "")
|
||||
debugMode = BuildConfig.DEBUG
|
||||
devMode = config.debugMode || debugMode
|
||||
devMode = config.devMode ?: debugMode
|
||||
enableChucker = config.enableChucker ?: devMode
|
||||
|
||||
if (!profileLoadById(config.lastProfileId)) {
|
||||
db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
|
@ -4,8 +4,11 @@
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.graphics.Paint
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.BindingAdapter
|
||||
import pl.szczodrzynski.edziennik.ext.dp
|
||||
|
||||
object Binding {
|
||||
@JvmStatic
|
||||
@ -17,4 +20,64 @@ object Binding {
|
||||
textView.paintFlags = textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:isVisible")
|
||||
fun isVisible(view: View, isVisible: Boolean) {
|
||||
view.isVisible = isVisible
|
||||
}
|
||||
|
||||
private fun resizeDrawable(textView: TextView, index: Int, size: Int) {
|
||||
val drawables = textView.compoundDrawables
|
||||
drawables[index]?.setBounds(0, 0, size, size)
|
||||
textView.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3])
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:drawableLeftAutoSize")
|
||||
fun drawableLeftAutoSize(textView: TextView, enable: Boolean) = resizeDrawable(
|
||||
textView,
|
||||
index = 0,
|
||||
size = textView.textSize.toInt(),
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:drawableRightAutoSize")
|
||||
fun drawableRightAutoSize(textView: TextView, enable: Boolean) = resizeDrawable(
|
||||
textView,
|
||||
index = 2,
|
||||
size = textView.textSize.toInt(),
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:drawableLeftSize")
|
||||
fun drawableLeftSize(textView: TextView, sizeDp: Int) = resizeDrawable(
|
||||
textView,
|
||||
index = 0,
|
||||
size = sizeDp.dp,
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:drawableTopSize")
|
||||
fun drawableTopSize(textView: TextView, sizeDp: Int) = resizeDrawable(
|
||||
textView,
|
||||
index = 1,
|
||||
size = sizeDp.dp,
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:drawableRightSize")
|
||||
fun drawableRightSize(textView: TextView, sizeDp: Int) = resizeDrawable(
|
||||
textView,
|
||||
index = 2,
|
||||
size = sizeDp.dp,
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@BindingAdapter("android:drawableBottomSize")
|
||||
fun drawableBottomSize(textView: TextView, sizeDp: Int) = resizeDrawable(
|
||||
textView,
|
||||
index = 3,
|
||||
size = sizeDp.dp,
|
||||
)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ import android.provider.OpenableColumns
|
||||
import com.canhub.cropper.CropImage
|
||||
import com.canhub.cropper.CropImageView
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
|
@ -12,10 +12,7 @@ import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.config.utils.ConfigMigration
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.config.utils.toHashMap
|
||||
import pl.szczodrzynski.edziennik.config.utils.*
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@ -75,10 +72,15 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
get() { mPrivacyPolicyAccepted = mPrivacyPolicyAccepted ?: values.get("privacyPolicyAccepted", false); return mPrivacyPolicyAccepted ?: false }
|
||||
set(value) { set("privacyPolicyAccepted", value); mPrivacyPolicyAccepted = value }
|
||||
|
||||
private var mDebugMode: Boolean? = null
|
||||
var debugMode: Boolean
|
||||
get() { mDebugMode = mDebugMode ?: values.get("debugMode", false); return mDebugMode ?: false }
|
||||
set(value) { set("debugMode", value); mDebugMode = value }
|
||||
private var mDevMode: Boolean? = null
|
||||
var devMode: Boolean?
|
||||
get() { mDevMode = mDevMode ?: values.getBooleanOrNull("debugMode"); return mDevMode }
|
||||
set(value) { set("debugMode", value?.toString()); mDevMode = value }
|
||||
|
||||
private var mEnableChucker: Boolean? = null
|
||||
var enableChucker: Boolean?
|
||||
get() { mEnableChucker = mEnableChucker ?: values.getBooleanOrNull("enableChucker"); return mEnableChucker }
|
||||
set(value) { set("enableChucker", value?.toString()); mEnableChucker = value }
|
||||
|
||||
private var mDevModePassword: String? = null
|
||||
var devModePassword: String?
|
||||
@ -120,6 +122,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
get() { mApiInvalidCert = mApiInvalidCert ?: values["apiInvalidCert"]; return mApiInvalidCert }
|
||||
set(value) { set("apiInvalidCert", value); mApiInvalidCert = value }
|
||||
|
||||
private var mApiAvailabilityCheck: Boolean? = null
|
||||
var apiAvailabilityCheck: Boolean
|
||||
get() { mApiAvailabilityCheck = mApiAvailabilityCheck ?: values.get("apiAvailabilityCheck", true); return mApiAvailabilityCheck ?: true }
|
||||
set(value) { set("apiAvailabilityCheck", value); mApiAvailabilityCheck = value }
|
||||
|
||||
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
init {
|
||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
@ -123,6 +124,19 @@ class ConfigSync(private val config: Config) {
|
||||
|
||||
private var mRegisterAvailability: Map<String, RegisterAvailabilityStatus>? = null
|
||||
var registerAvailability: Map<String, RegisterAvailabilityStatus>
|
||||
get() { mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it -> gson.fromJson<Map<String, RegisterAvailabilityStatus>>(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type) }; return mRegisterAvailability ?: mapOf() }
|
||||
set(value) { config.setMap("registerAvailability", value); mRegisterAvailability = value }
|
||||
get() {
|
||||
val flavor = config.values.get("registerAvailabilityFlavor", null as String?)
|
||||
if (BuildConfig.FLAVOR != flavor)
|
||||
return mapOf()
|
||||
|
||||
mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it ->
|
||||
gson.fromJson(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type)
|
||||
}
|
||||
return mRegisterAvailability ?: mapOf()
|
||||
}
|
||||
set(value) {
|
||||
config.setMap("registerAvailability", value)
|
||||
config.set("registerAvailabilityFlavor", BuildConfig.FLAVOR)
|
||||
mRegisterAvailability = value
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,11 @@ class ConfigUI(private val config: Config) {
|
||||
get() { mSnowfall = mSnowfall ?: config.values.get("snowfall", false); return mSnowfall ?: false }
|
||||
set(value) { config.set("snowfall", value); mSnowfall = value }
|
||||
|
||||
private var mEggfall: Boolean? = null
|
||||
var eggfall: Boolean
|
||||
get() { mEggfall = mEggfall ?: config.values.get("eggfall", false); return mEggfall ?: false }
|
||||
set(value) { config.set("eggfall", value); mEggfall = value }
|
||||
|
||||
private var mBottomSheetOpened: Boolean? = null
|
||||
var bottomSheetOpened: Boolean
|
||||
get() { mBottomSheetOpened = mBottomSheetOpened ?: config.values.get("bottomSheetOpened", false); return mBottomSheetOpened ?: false }
|
||||
|
@ -18,7 +18,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEntry>) : CoroutineScope, AbstractConfig {
|
||||
companion object {
|
||||
const val DATA_VERSION = 2
|
||||
const val DATA_VERSION = 3
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
|
||||
class ProfileConfigSync(private val config: ProfileConfig) {
|
||||
private var mNotificationFilter: List<Int>? = null
|
||||
var notificationFilter: List<Int>
|
||||
get() { mNotificationFilter = mNotificationFilter ?: config.values.get("notificationFilter", listOf()); return mNotificationFilter ?: listOf() }
|
||||
get() { mNotificationFilter = mNotificationFilter ?: config.values.getIntList("notificationFilter", listOf()); return mNotificationFilter ?: listOf() }
|
||||
set(value) { config.set("notificationFilter", value); mNotificationFilter = value }
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ package pl.szczodrzynski.edziennik.config
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
|
||||
class ProfileConfigUI(private val config: ProfileConfig) {
|
||||
private var mAgendaViewType: Int? = null
|
||||
@ -15,8 +15,58 @@ class ProfileConfigUI(private val config: ProfileConfig) {
|
||||
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: AGENDA_DEFAULT }
|
||||
set(value) { config.set("agendaViewType", value); mAgendaViewType = value }
|
||||
|
||||
private var mAgendaCompactMode: Boolean? = null
|
||||
var agendaCompactMode: Boolean
|
||||
get() { mAgendaCompactMode = mAgendaCompactMode ?: config.values.get("agendaCompactMode", false); return mAgendaCompactMode ?: false }
|
||||
set(value) { config.set("agendaCompactMode", value); mAgendaCompactMode = value }
|
||||
|
||||
private var mAgendaGroupByType: Boolean? = null
|
||||
var agendaGroupByType: Boolean
|
||||
get() { mAgendaGroupByType = mAgendaGroupByType ?: config.values.get("agendaGroupByType", false); return mAgendaGroupByType ?: false }
|
||||
set(value) { config.set("agendaGroupByType", value); mAgendaGroupByType = value }
|
||||
|
||||
private var mAgendaLessonChanges: Boolean? = null
|
||||
var agendaLessonChanges: Boolean
|
||||
get() { mAgendaLessonChanges = mAgendaLessonChanges ?: config.values.get("agendaLessonChanges", true); return mAgendaLessonChanges ?: true }
|
||||
set(value) { config.set("agendaLessonChanges", value); mAgendaLessonChanges = value }
|
||||
|
||||
private var mAgendaTeacherAbsence: Boolean? = null
|
||||
var agendaTeacherAbsence: Boolean
|
||||
get() { mAgendaTeacherAbsence = mAgendaTeacherAbsence ?: config.values.get("agendaTeacherAbsence", true); return mAgendaTeacherAbsence ?: true }
|
||||
set(value) { config.set("agendaTeacherAbsence", value); mAgendaTeacherAbsence = value }
|
||||
|
||||
private var mAgendaElearningMark: Boolean? = null
|
||||
var agendaElearningMark: Boolean
|
||||
get() { mAgendaElearningMark = mAgendaElearningMark ?: config.values.get("agendaElearningMark", false); return mAgendaElearningMark ?: false }
|
||||
set(value) { config.set("agendaElearningMark", value); mAgendaElearningMark = value }
|
||||
|
||||
private var mAgendaElearningGroup: Boolean? = null
|
||||
var agendaElearningGroup: Boolean
|
||||
get() { mAgendaElearningGroup = mAgendaElearningGroup ?: config.values.get("agendaElearningGroup", true); return mAgendaElearningGroup ?: true }
|
||||
set(value) { config.set("agendaElearningGroup", value); mAgendaElearningGroup = value }
|
||||
|
||||
private var mHomeCards: List<HomeCardModel>? = null
|
||||
var homeCards: List<HomeCardModel>
|
||||
get() { mHomeCards = mHomeCards ?: config.values.get("homeCards", listOf(), HomeCardModel::class.java); return mHomeCards ?: listOf() }
|
||||
set(value) { config.set("homeCards", value); mHomeCards = value }
|
||||
|
||||
private var mMessagesGreetingOnCompose: Boolean? = null
|
||||
var messagesGreetingOnCompose: Boolean
|
||||
get() { mMessagesGreetingOnCompose = mMessagesGreetingOnCompose ?: config.values.get("messagesGreetingOnCompose", true); return mMessagesGreetingOnCompose ?: true }
|
||||
set(value) { config.set("messagesGreetingOnCompose", value); mMessagesGreetingOnCompose = value }
|
||||
|
||||
private var mMessagesGreetingOnReply: Boolean? = null
|
||||
var messagesGreetingOnReply: Boolean
|
||||
get() { mMessagesGreetingOnReply = mMessagesGreetingOnReply ?: config.values.get("messagesGreetingOnReply", true); return mMessagesGreetingOnReply ?: true }
|
||||
set(value) { config.set("messagesGreetingOnReply", value); mMessagesGreetingOnReply = value }
|
||||
|
||||
private var mMessagesGreetingOnForward: Boolean? = null
|
||||
var messagesGreetingOnForward: Boolean
|
||||
get() { mMessagesGreetingOnForward = mMessagesGreetingOnForward ?: config.values.get("messagesGreetingOnForward", false); return mMessagesGreetingOnForward ?: false }
|
||||
set(value) { config.set("messagesGreetingOnForward", value); mMessagesGreetingOnForward = value }
|
||||
|
||||
private var mMessagesGreetingText: String? = null
|
||||
var messagesGreetingText: String?
|
||||
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
||||
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
||||
}
|
||||
|
@ -59,6 +59,9 @@ fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
||||
fun HashMap<String, String?>.get(key: String, default: Boolean): Boolean {
|
||||
return this[key]?.toBoolean() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getBooleanOrNull(key: String): Boolean? {
|
||||
return this[key]?.toBooleanStrictOrNull()
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Int): Int {
|
||||
return this[key]?.toIntOrNull() ?: default
|
||||
}
|
||||
|
@ -5,13 +5,14 @@ package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonParser
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.ext.getInt
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigGsonUtils {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> deserializeList(gson: Gson, str: String?, classOfT: Class<T>): List<T> {
|
||||
val json = JsonParser().parse(str)
|
||||
val json = JsonParser.parseString(str)
|
||||
val list: MutableList<T> = mutableListOf()
|
||||
if (!json.isJsonArray)
|
||||
return list
|
||||
|
@ -7,9 +7,9 @@ package pl.szczodrzynski.edziennik.config.utils
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.HOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.ext.HOUR
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import kotlin.math.abs
|
||||
@ -67,7 +67,7 @@ class ConfigMigration(app: App, config: Config) {
|
||||
if (dataVersion < 3) {
|
||||
update = null
|
||||
privacyPolicyAccepted = false
|
||||
debugMode = false
|
||||
devMode = null
|
||||
devModePassword = null
|
||||
appInstalledTime = 0L
|
||||
appRateSnackbarTime = 0L
|
||||
|
@ -7,6 +7,8 @@ package pl.szczodrzynski.edziennik.config.utils
|
||||
import pl.szczodrzynski.edziennik.config.ProfileConfig
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
|
||||
@ -33,5 +35,15 @@ class ProfileConfigMigration(config: ProfileConfig) {
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
|
||||
if (dataVersion < 3) {
|
||||
if (ui.homeCards.isNotEmpty()) {
|
||||
ui.homeCards = ui.homeCards.toMutableList().also {
|
||||
it.add(HomeCardModel(config.profileId, HomeCard.CARD_NOTES))
|
||||
}
|
||||
}
|
||||
|
||||
dataVersion = 3
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import pl.szczodrzynski.edziennik.data.api.task.ErrorReportTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.api.task.SzkolnyTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.toApiError
|
||||
import pl.szczodrzynski.edziennik.ext.toApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
@ -24,7 +24,7 @@ const val FAKE_LIBRUS_ACCOUNTS = "/synergia_accounts.php"
|
||||
|
||||
val LIBRUS_USER_AGENT = "${SYSTEM_USER_AGENT}LibrusMobileApp"
|
||||
const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0"
|
||||
const val LIBRUS_CLIENT_ID = "0RbsDOkV9tyKEQYzlLv5hs3DM1ukrynFI4p6C1Yc"
|
||||
const val LIBRUS_CLIENT_ID = "VaItV6oRutdo8fnjJwysnTjVlvaswf52ZqmXsJGP"
|
||||
const val LIBRUS_REDIRECT_URL = "app://librus"
|
||||
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/oauth2/authorize?client_id=$LIBRUS_CLIENT_ID&redirect_uri=$LIBRUS_REDIRECT_URL&response_type=code"
|
||||
const val LIBRUS_LOGIN_URL = "https://portal.librus.pl/rodzina/login/action"
|
||||
@ -43,7 +43,7 @@ const val LIBRUS_API_TOKEN_URL = "https://api.librus.pl/OAuth/Token"
|
||||
const val LIBRUS_API_TOKEN_JST_URL = "https://api.librus.pl/OAuth/TokenJST"
|
||||
const val LIBRUS_API_AUTHORIZATION = "Mjg6ODRmZGQzYTg3YjAzZDNlYTZmZmU3NzdiNThiMzMyYjE="
|
||||
const val LIBRUS_API_SECRET_JST = "18b7c1ee08216f636a1b1a2440e68398"
|
||||
const val LIBRUS_API_CLIENT_ID_JST = "49"
|
||||
const val LIBRUS_API_CLIENT_ID_JST = "59"
|
||||
//const val LIBRUS_API_CLIENT_ID_JST_REFRESH = "42"
|
||||
|
||||
const val LIBRUS_JST_DEMO_CODE = "68656A21"
|
||||
@ -109,6 +109,7 @@ const val VULCAN_HEBE_ENDPOINT_PUSH_ALL = "api/mobile/push/all"
|
||||
const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule"
|
||||
const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes"
|
||||
const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook"
|
||||
const val VULCAN_HEBE_ENDPOINT_TEACHERS = "api/mobile/teacher"
|
||||
const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam"
|
||||
const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade"
|
||||
const val VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY = "api/mobile/grade/summary"
|
||||
|
@ -11,8 +11,8 @@ import android.content.Context
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.PRIORITY_MIN
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.Bundle
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.ext.Bundle
|
||||
import pl.szczodrzynski.edziennik.receivers.SzkolnyReceiver
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
@ -195,6 +195,7 @@ const val ERROR_VULCAN_HEBE_FIREBASE_ERROR = 362
|
||||
const val ERROR_VULCAN_HEBE_CERTIFICATE_GONE = 363
|
||||
const val ERROR_VULCAN_HEBE_SERVER_ERROR = 364
|
||||
const val ERROR_VULCAN_HEBE_ENTITY_NOT_FOUND = 365
|
||||
const val ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY = 366
|
||||
const val ERROR_VULCAN_API_DEPRECATED = 390
|
||||
|
||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN = 501
|
||||
|
@ -16,6 +16,10 @@ object Regexes {
|
||||
"""[^0-9]""".toRegex()
|
||||
}
|
||||
|
||||
val HTML_BR by lazy {
|
||||
"""<br\s?/?>""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
||||
@ -50,15 +54,16 @@ object Regexes {
|
||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_WEB_ATTACHMENT by lazy {
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik(_rozwiazania)?=([0-9]+)".+?>(.+?)(?: <small.+?\(([0-9.]+)\s(M|K|G|)B\)</small>)?</a>""".toRegex()
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MESSAGE_READ_DATE by lazy {
|
||||
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_SENT_READ_DATE by lazy {
|
||||
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_ATTACHMENT by lazy {
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_SENT_READ_BY by lazy {
|
||||
"""([0-9]+)/([0-9]+)""".toRegex()
|
||||
}
|
||||
@ -100,22 +105,42 @@ object Regexes {
|
||||
"""<strong>(.+?)</strong>\s*<small>\s*\((.+?),\s*(.+?)\)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_HOMEWORK_ROW by lazy {
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ROW by lazy {
|
||||
"""class="rowRolling">(.+?</div>\s*</td>)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_ITEM by lazy {
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ITEM by lazy {
|
||||
"""<p><b>(.+?):</b>\s*(.+?)\s*</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_BODY by lazy {
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_BODY by lazy {
|
||||
"""Treść:</b>(.+?)<p><b>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_ID by lazy {
|
||||
"""zadanieFormularz\(([0-9]+),""".toRegex(DOT_MATCHES_ALL)
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ID by lazy {
|
||||
"""name="id_zadania" value="([0-9]+)"""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_HOMEWORK_ATTACHMENT by lazy {
|
||||
val MOBIDZIENNIK_MOBILE_HOMEWORK_ATTACHMENT by lazy {
|
||||
"""zalacznik(_zadania)?=([0-9]+)'.+?word-break">(.+?)</td>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_WEB_HOMEWORK_ADDED_DATE by lazy {
|
||||
"""Wpisał\(a\):</td>\s+<th>\s+(.+?), (.+?), ([0-9]{1,2}) (.+?) ([0-9]{4}), godzina ([0-9:]+)""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
val MOBIDZIENNIK_TIMETABLE_TOP by lazy {
|
||||
"""<div class="plansc_top">.+?</div></div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_TIMETABLE_CELL by lazy {
|
||||
"""<div class="plansc_cnt_w" style="(.+?)">.+?style="(.+?)".+?title="(.+?)".+?>\s+(.+?)\s+</div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_TIMETABLE_LEFT by lazy {
|
||||
"""<div class="plansc_godz">.+?</div></div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
val MOBIDZIENNIK_EVENT_CONTENT by lazy {
|
||||
"""<h1>(.+?) <small>\(wpisał\(a\) (.+?) w dniu ([0-9-]{10})\).+?<strong>(.+?)</strong><br""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
|
||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||
|
@ -18,7 +18,6 @@ import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
@ -27,6 +26,7 @@ import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||
|
||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||
companion object {
|
||||
@ -90,35 +90,21 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
||||
return
|
||||
}
|
||||
|
||||
profile.registerName?.also { registerName ->
|
||||
var status = app.config.sync.registerAvailability[registerName]
|
||||
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
||||
val api = SzkolnyApi(app)
|
||||
api.runCatching({
|
||||
val availability = getRegisterAvailability()
|
||||
app.config.sync.registerAvailability = availability
|
||||
status = availability[registerName]
|
||||
}, onError = {
|
||||
val apiError = it.toApiError(TAG)
|
||||
if (apiError.errorCode == ERROR_API_INVALID_SIGNATURE) {
|
||||
return@also
|
||||
}
|
||||
taskCallback.onError(apiError)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
if (status?.available != true
|
||||
|| status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
|
||||
val error = app.availabilityManager.check(profile)
|
||||
when (error?.type) {
|
||||
Type.NOT_AVAILABLE -> {
|
||||
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
||||
EventBus.getDefault().postSticky(
|
||||
RegisterAvailabilityEvent(app.config.sync.registerAvailability)
|
||||
)
|
||||
EventBus.getDefault().postSticky(RegisterAvailabilityEvent())
|
||||
}
|
||||
cancel()
|
||||
taskCallback.onCompleted()
|
||||
return
|
||||
}
|
||||
Type.API_ERROR -> {
|
||||
taskCallback.onError(error.apiError!!)
|
||||
return
|
||||
}
|
||||
else -> return@let
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,9 +6,9 @@ package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||
|
||||
import android.content.Intent
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.Intent
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.ext.Intent
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
|
@ -4,10 +4,13 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
/**
|
||||
* Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
|
||||
@ -111,37 +114,6 @@ class DataEdudziennik(app: App, profile: Profile?, loginStore: LoginStore) : Dat
|
||||
val courseStudentEndpoint: String
|
||||
get() = "Course/$studentId/"
|
||||
|
||||
fun getSubject(longId: String, name: String): Subject {
|
||||
val id = longId.crc32()
|
||||
return subjectList.singleOrNull { it.id == id } ?: run {
|
||||
val subject = Subject(profileId, id, name, name)
|
||||
subjectList.put(id, subject)
|
||||
subject
|
||||
}
|
||||
}
|
||||
|
||||
fun getTeacher(firstName: String, lastName: String, longId: String? = null): Teacher {
|
||||
val name = "$firstName $lastName".fixName()
|
||||
val id = name.crc32()
|
||||
return teacherList.singleOrNull { it.id == id }?.also {
|
||||
if (longId != null && it.loginId == null) it.loginId = longId
|
||||
} ?: run {
|
||||
val teacher = Teacher(profileId, id, firstName, lastName, longId)
|
||||
teacherList.put(id, teacher)
|
||||
teacher
|
||||
}
|
||||
}
|
||||
|
||||
fun getTeacherByFirstLast(nameFirstLast: String, longId: String? = null): Teacher {
|
||||
val nameParts = nameFirstLast.split(" ")
|
||||
return getTeacher(nameParts[0], nameParts[1], longId)
|
||||
}
|
||||
|
||||
fun getTeacherByLastFirst(nameLastFirst: String, longId: String? = null): Teacher {
|
||||
val nameParts = nameLastFirst.split(" ")
|
||||
return getTeacher(nameParts[1], nameParts[0], longId)
|
||||
}
|
||||
|
||||
fun getEventType(longId: String, name: String): EventType {
|
||||
val id = longId.crc16().toLong()
|
||||
return eventTypes.singleOrNull { it.id == id } ?: run {
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ANNOUNCEMENT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS
|
||||
@ -13,7 +12,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.Edudzienni
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
|
||||
@ -40,7 +40,7 @@ class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
|
||||
val teacherName = announcementElement.child(1).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val dateString = announcementElement.getElementsByClass("datetime").first().text()
|
||||
val dateString = announcementElement.getElementsByClass("datetime").first()?.text()
|
||||
val startDate = Date.fromY_m_d(dateString)
|
||||
val addedDate = Date.fromIsoHm(dateString)
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_ENTRIES
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPE
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPES
|
||||
@ -14,8 +13,9 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.Edudzienni
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.ext.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import java.util.*
|
||||
|
||||
@ -44,7 +44,7 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
|
||||
return@map Triple(
|
||||
symbol,
|
||||
name,
|
||||
when (name.toLowerCase(Locale.ROOT)) {
|
||||
when (name.lowercase()) {
|
||||
"obecność" -> Attendance.TYPE_PRESENT
|
||||
"nieobecność" -> Attendance.TYPE_ABSENT
|
||||
"spóźnienie" -> Attendance.TYPE_BELATED
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EVENTS
|
||||
@ -14,7 +13,8 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebEvents(override val data: DataEdudziennik,
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_TYPE_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EXAM_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
@ -16,7 +15,8 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
@ -40,7 +40,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val subjectName = subjectElement.text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
||||
|
||||
val dateString = examElement.child(2).text().trim()
|
||||
if (dateString.isBlank()) return@forEach
|
||||
|
@ -10,7 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
|
||||
class EdudziennikWebGetAnnouncement(override val data: DataEdudziennik,
|
||||
private val announcement: AnnouncementFull,
|
||||
|
@ -1,14 +1,14 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import android.text.Html
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||
|
||||
class EdudziennikWebGetHomework(
|
||||
override val data: DataEdudziennik,
|
||||
@ -26,9 +26,11 @@ class EdudziennikWebGetHomework(
|
||||
webGet(TAG, "Homework/$id") { text ->
|
||||
val description = Regexes.EDUDZIENNIK_HOMEWORK_DESCRIPTION.find(text)?.get(1)?.trim()
|
||||
|
||||
if (description != null) event.topic = Html.fromHtml(description).toString()
|
||||
if (description != null)
|
||||
event.topic = BetterHtml.fromHtml(context = null, description).toString()
|
||||
|
||||
event.homeworkBody = ""
|
||||
event.isDownloaded = true
|
||||
event.attachmentNames = null
|
||||
|
||||
data.eventList += event
|
||||
|
@ -6,8 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import android.graphics.Color
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.colorFromCssName
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_GRADES
|
||||
@ -22,7 +20,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.colorFromCssName
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@ -53,7 +53,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
|
||||
val subjectId = subjectElement.id().trim()
|
||||
val subjectName = subjectElement.child(0).text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
||||
|
||||
val gradeType = when {
|
||||
subjectElement.select("#sum").text().isNotBlank() -> TYPE_POINT_SUM
|
||||
@ -67,13 +67,13 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
|
||||
val gradeValues = if (grades.isNotEmpty()) {
|
||||
subjects.select(".avg-$subjectId .grade-tip > p").first()
|
||||
.text().split('+').map {
|
||||
?.text()?.split('+')?.map {
|
||||
val split = it.split('*')
|
||||
val value = split[1].trim().toFloatOrNull()
|
||||
val weight = value?.let { split[0].trim().toFloatOrNull() } ?: 0f
|
||||
|
||||
Pair(value ?: 0f, weight)
|
||||
}
|
||||
} ?: emptyList()
|
||||
} else emptyList()
|
||||
|
||||
grades.forEachIndexed { index, gradeElement ->
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_HOMEWORK_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
@ -15,7 +14,8 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
@ -32,7 +32,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
|
||||
if (doc.getElementsByClass("message").text().trim() != "Brak prac domowych") {
|
||||
doc.getElementsByTag("tr").forEach { homeworkElement ->
|
||||
val dateElement = homeworkElement.getElementsByClass("date").first().child(0)
|
||||
val dateElement = homeworkElement.getElementsByClass("date").first()?.child(0) ?: return@forEach
|
||||
val idStr = EDUDZIENNIK_HOMEWORK_ID.find(dateElement.attr("href"))?.get(1) ?: return@forEach
|
||||
val id = idStr.crc32()
|
||||
val date = Date.fromY_m_d(dateElement.text())
|
||||
@ -41,7 +41,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val subjectName = subjectElement.text()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
||||
|
||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
||||
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
|
||||
@ -49,7 +49,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
val teacherName = homeworkElement.child(2).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val topic = homeworkElement.child(4).text()?.trim()
|
||||
val topic = homeworkElement.child(4).text().trim()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId = profileId,
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_NOTE_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_NOTES
|
||||
@ -13,7 +12,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.Edudzienni
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebNotes(override val data: DataEdudziennik,
|
||||
@ -29,7 +29,7 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.getElementsByTag("tr").forEach { noteElement ->
|
||||
val dateElement = noteElement.getElementsByClass("date").first().child(0)
|
||||
val dateElement = noteElement.getElementsByClass("date").first()?.child(0) ?: return@forEach
|
||||
val addedDate = Date.fromY_m_d(dateElement.text()).inMillis
|
||||
|
||||
val id = EDUDZIENNIK_NOTE_ID.find(dateElement.attr("href"))?.get(0)?.crc32()
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_EDUDZIENNIK_WEB_TEAM_MISSING
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECTS_START
|
||||
@ -14,8 +12,10 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZI
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.firstLettersName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.MONTH
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.firstLettersName
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
|
||||
class EdudziennikWebStart(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
@ -73,7 +73,7 @@ class EdudziennikWebStart(override val data: DataEdudziennik,
|
||||
EDUDZIENNIK_SUBJECTS_START.findAll(text).forEach {
|
||||
val id = it[1].trim()
|
||||
val name = it[2].trim()
|
||||
data.getSubject(id, name)
|
||||
data.getSubject(id.crc32(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHERS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TEACHERS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.ext.MONTH
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
|
||||
class EdudziennikWebTeachers(override val data: DataEdudziennik,
|
||||
override val lastSync: Long?,
|
||||
|
@ -15,9 +15,10 @@ import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.ext.crc32
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.ext.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
@ -56,7 +57,7 @@ class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
||||
|
||||
val table = doc.select("#Schedule tbody").first()
|
||||
|
||||
if (!table.text().contains("Brak planu lekcji.")) {
|
||||
if (table?.text()?.contains("Brak planu lekcji.") == false) {
|
||||
table.children().forEach { row ->
|
||||
val rowElements = row.children()
|
||||
|
||||
@ -89,7 +90,7 @@ class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEachIndexed
|
||||
val subjectName = subjectElement.text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
||||
|
||||
/* Getting teacher */
|
||||
|
||||
|
@ -13,10 +13,10 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.Edudzienni
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getShortName
|
||||
import pl.szczodrzynski.edziennik.set
|
||||
import pl.szczodrzynski.edziennik.ext.fixName
|
||||
import pl.szczodrzynski.edziennik.ext.get
|
||||
import pl.szczodrzynski.edziennik.ext.getShortName
|
||||
import pl.szczodrzynski.edziennik.ext.set
|
||||
|
||||
class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
|
@ -10,8 +10,8 @@ import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.ext.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_PORTAL
|
||||
@ -13,7 +12,8 @@ import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
||||
|
||||
class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
|
@ -10,7 +10,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.startCoroutineTimer
|
||||
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class LibrusRecaptchaHelper(
|
||||
|
@ -11,7 +11,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
|
@ -182,10 +182,6 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
||||
LibrusApiPtMeetings(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
||||
LibrusApiTeacherFreeDayTypes(data, lastSync, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
||||
LibrusApiTeacherFreeDays(data, lastSync, onSuccess)
|
||||
|
@ -7,7 +7,7 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.AttendanceType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiAttendanceTypes(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiAttendances(override val data: DataLibrus,
|
||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiBehaviourGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiBehaviourGradeComments(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import java.text.DecimalFormat
|
||||
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_CLASSES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.ext.DAY
|
||||
import pl.szczodrzynski.edziennik.ext.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.ext.getLong
|
||||
import pl.szczodrzynski.edziennik.ext.getString
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiClasses(override val data: DataLibrus,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_CLASSROOMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Classroom
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import java.util.*
|
||||
|
||||
class LibrusApiClassrooms(override val data: DataLibrus,
|
||||
@ -25,8 +26,8 @@ class LibrusApiClassrooms(override val data: DataLibrus,
|
||||
|
||||
classrooms?.forEach { classroom ->
|
||||
val id = classroom.getLong("Id") ?: return@forEach
|
||||
val name = classroom.getString("Name")?.toLowerCase(Locale.getDefault()) ?: ""
|
||||
val symbol = classroom.getString("Symbol")?.toLowerCase(Locale.getDefault()) ?: ""
|
||||
val name = classroom.getString("Name")?.lowercase() ?: ""
|
||||
val symbol = classroom.getString("Symbol")?.lowercase() ?: ""
|
||||
val nameShort = name.fixWhiteSpaces().split(" ").onEach { it[0] }.joinToString()
|
||||
val symbolParts = symbol.fixWhiteSpaces().split(" ")
|
||||
|
||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiDescriptiveGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_TEXT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiDescriptiveGrades(override val data: DataLibrus,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_EVENT_TYPES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiEventTypes(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiGradeComments(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPO
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiHomework(override val data: DataLibrus,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_LESSONS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LibrusLesson
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiLessons(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ME
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiMe(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NOTICE_TYPES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.NoticeType
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiNoticeTypes(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiNotices(override val data: DataLibrus,
|
||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiPointGradeCategories(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_AVG
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiPointGrades(override val data: DataLibrus,
|
||||
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.JsonObject
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_PUSH_CONFIG
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.ext.JsonObject
|
||||
import pl.szczodrzynski.edziennik.ext.getInt
|
||||
import pl.szczodrzynski.edziennik.ext.getJsonObject
|
||||
|
||||
class LibrusApiPushConfig(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_SCHOOLS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.util.*
|
||||
|
||||
@ -29,7 +30,7 @@ class LibrusApiSchools(override val data: DataLibrus,
|
||||
// create the school's short name using first letters of each long name's word
|
||||
// append the town name and save to student data
|
||||
val schoolNameShort = schoolNameLong?.firstLettersName
|
||||
val schoolTown = school?.getString("Town")?.toLowerCase(Locale.getDefault())
|
||||
val schoolTown = school?.getString("Town")?.lowercase()
|
||||
data.schoolName = schoolId.toString() + schoolNameShort + "_" + schoolTown
|
||||
|
||||
school?.getJsonArray("LessonsRange")?.let { ranges ->
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_SUBJECTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
|
||||
class LibrusApiSubjects(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-19
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsenceType
|
||||
|
||||
class LibrusApiTeacherFreeDayTypes(override val data: DataLibrus,
|
||||
override val lastSync: Long?,
|
||||
val onSuccess: (endpointId: Int) -> Unit
|
||||
) : LibrusApi(data, lastSync) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiTeacherFreeDayTypes"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "TeacherFreeDays/Types") { json ->
|
||||
val teacherAbsenceTypes = json.getJsonArray("Types")?.asJsonObjectList()
|
||||
|
||||
teacherAbsenceTypes?.forEach { teacherAbsenceType ->
|
||||
val id = teacherAbsenceType.getLong("Id") ?: return@forEach
|
||||
val name = teacherAbsenceType.getString("Name") ?: return@forEach
|
||||
|
||||
val teacherAbsenceTypeObject = TeacherAbsenceType(
|
||||
profileId,
|
||||
id,
|
||||
name
|
||||
)
|
||||
|
||||
data.teacherAbsenceTypes.put(id, teacherAbsenceTypeObject)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES, 7 * DAY)
|
||||
onSuccess(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES)
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsence
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
@ -35,8 +36,6 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
|
||||
val id = teacherAbsence.getLong("Id") ?: return@forEach
|
||||
val teacherId = teacherAbsence.getJsonObject("Teacher")?.getLong("Id")
|
||||
?: return@forEach
|
||||
val type = teacherAbsence.getJsonObject("Type").getLong("Id") ?: return@forEach
|
||||
val name = data.teacherAbsenceTypes.singleOrNull { it.id == type }?.name
|
||||
val dateFrom = Date.fromY_m_d(teacherAbsence.getString("DateFrom"))
|
||||
val dateTo = Date.fromY_m_d(teacherAbsence.getString("DateTo"))
|
||||
val timeFrom = teacherAbsence.getString("TimeFrom")?.let { Time.fromH_m_s(it) }
|
||||
@ -45,8 +44,8 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
|
||||
val teacherAbsenceObject = TeacherAbsence(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
type = type,
|
||||
name = name,
|
||||
type = -1L,
|
||||
name = null,
|
||||
dateFrom = dateFrom,
|
||||
dateTo = dateTo,
|
||||
timeFrom = timeFrom,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user