mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-14 06:30:18 +02:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
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=1&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")
|
59
.github/utils/extract_changelogs.py
vendored
Normal file
59
.github/utils/extract_changelogs.py
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
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")
|
||||
with open(dir + "whatsnew-pl-PL", "w", encoding="utf-8") as f:
|
||||
f.write(changelog)
|
||||
print("::set-output name=changelogPlainFile::" + dir + "whatsnew-pl-PL")
|
||||
|
||||
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)
|
||||
|
||||
(_, 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")
|
||||
|
||||
(_, 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,
|
||||
)
|
151
.github/workflows/build-nightly-apk.yml
vendored
Normal file
151
.github/workflows/build-nightly-apk.yml
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
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
|
||||
outputs:
|
||||
androidHome: ${{ env.ANDROID_HOME }}
|
||||
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
|
||||
steps:
|
||||
- name: Setup JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- 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
|
||||
run: ./gradlew 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
|
129
.github/workflows/build-release-aab-play.yml
vendored
Normal file
129
.github/workflows/build-release-aab-play.yml
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
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 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- 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
|
||||
run: ./gradlew 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 }}
|
||||
userFraction: 1.0
|
||||
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
|
||||
|
||||
- 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
|
151
.github/workflows/build-release-apk.yml
vendored
Normal file
151
.github/workflows/build-release-apk.yml
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
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 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- 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
|
||||
run: ./gradlew 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
|
36
README.md
36
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,11 +10,15 @@ 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
|
||||
|
||||
Jak zapewne już wiecie, we wrześniu 2020r. **firma Librus zabroniła nam** publikowania w sklepie Google Play naszej aplikacji z obsługą dziennika Librus® Synergia. Prowadziliśmy rozmowy, aby **umożliwić Wam wygodny, bezpłatny dostęp do Waszych ocen, wiadomości, zadań domowych**, jednak oczekiwania firmy Librus zdecydowanie przekroczyły wszelkie nasze możliwości finansowe. Mając na uwadze powyższe względy, zdecydowaliśmy się opublikować kod źródłowy aplikacji Szkolny.eu. Liczymy, że dzięki temu aplikacja będzie mogła dalej funkcjonować, być rozwijana, pomagając Wam w czasie zdalnego nauczania i przez kolejne lata nauki.
|
||||
Jak zapewne już wiecie, we wrześniu 2020 r. **firma Librus zabroniła nam** publikowania w sklepie Google Play naszej aplikacji z obsługą dziennika Librus® Synergia. Prowadziliśmy rozmowy, aby **umożliwić Wam wygodny, bezpłatny dostęp do Waszych ocen, wiadomości, zadań domowych**, jednak oczekiwania firmy Librus zdecydowanie przekroczyły wszelkie nasze możliwości finansowe. Mając na uwadze powyższe względy, zdecydowaliśmy się opublikować kod źródłowy aplikacji Szkolny.eu. Liczymy, że dzięki temu aplikacja będzie mogła dalej funkcjonować, być rozwijana, pomagając Wam w czasie zdalnego nauczania i przez kolejne lata nauki.
|
||||
|
||||
__Zachęcamy do [przeczytania całej informacji](https://szkolny.eu/informacja) na naszej stronie.__
|
||||
|
||||
@ -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.**
|
||||
|
||||
|
@ -18,8 +18,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
|
||||
|
||||
@ -98,7 +100,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'
|
||||
|
@ -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(", ") + ")"
|
||||
}
|
||||
|
@ -29,6 +29,8 @@
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<meta-data android:name="buildTimestamp" android:value="${buildTimestamp}" />
|
||||
|
||||
<!-- __ __ _ _ _ _ _
|
||||
| \/ | (_) /\ | | (_) (_) |
|
||||
| \ / | __ _ _ _ __ / \ ___| |_ ___ ___| |_ _ _
|
||||
|
@ -1,14 +1,15 @@
|
||||
<h3>Wersja 4.7-rc.1, 2021-04-01</h3>
|
||||
<h3>Wersja 4.7-rc.2, 2021-04-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><u>Szkolny.eu jest teraz open source!</u> Zapraszamy na stronę <a href="https://szkolny.eu/">https://szkolny.eu/</a> 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>Zaktualizowano tłumaczenie na język angielski. @MarcinK50</li>
|
||||
<li>Dodano ekran informacji o kompilacji w Ustawieniach.</li>
|
||||
<li>Zaktualizowano ekran licencji open source.</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>Zoptymalizowano wielkość aplikacji.</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) 2021</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 };
|
||||
0x25, 0x68, 0xd4, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||
|
||||
|
@ -46,6 +46,6 @@ object Signing {
|
||||
|
||||
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
||||
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
||||
return "$param1.MTIzNDU2Nzg5MDy+5jm3L0===.$param2".sha256()
|
||||
return "$param1.MTIzNDU2Nzg5MD+7y77uUm===.$param2".sha256()
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.dp
|
||||
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ChangelogDialog(
|
||||
@ -43,9 +44,14 @@ class ChangelogDialog(
|
||||
val textView = TextView(activity)
|
||||
textView.setPadding(24.dp, 24.dp, 24.dp, 0)
|
||||
|
||||
val text = app.assets.open("pl-changelog.html").bufferedReader().use {
|
||||
var text = app.assets.open("pl-changelog.html").bufferedReader().use {
|
||||
it.readText()
|
||||
}
|
||||
|
||||
val commitsUrlPrefix = "https://github.com/szkolny-eu/szkolny-android/commits?author="
|
||||
text = text.replace("""\[(.+?)]\(@([A-z0-9-]+)\)""".toRegex(), "<a href=\"$commitsUrlPrefix$2\">$1</a>")
|
||||
text = text.replace("""\s@([A-z0-9-]+)""".toRegex(), " <a href=\"$commitsUrlPrefix$1\">@$1</a>")
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
textView.text = Html.fromHtml(text)
|
||||
}
|
||||
@ -53,6 +59,8 @@ class ChangelogDialog(
|
||||
textView.text = Html.fromHtml(text.replace("<li>", "<br><li> - "))
|
||||
}
|
||||
|
||||
textView.movementMethod = BetterLinkMovementMethod.getInstance()
|
||||
|
||||
val scrollView = ScrollView(activity)
|
||||
scrollView.addView(textView)
|
||||
|
||||
@ -67,4 +75,4 @@ class ChangelogDialog(
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,14 @@ import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.RotateAnimation
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
@ -29,6 +31,7 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailability
|
||||
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
|
||||
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@ -203,6 +206,23 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
||||
return
|
||||
}
|
||||
|
||||
if (!app.config.privacyPolicyAccepted) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.privacy_policy)
|
||||
.setMessage(Html.fromHtml(activity.getString(R.string.privacy_policy_dialog_html)))
|
||||
.setPositiveButton(R.string.i_agree) { _, _ ->
|
||||
app.config.privacyPolicyAccepted = true
|
||||
onLoginModeClicked(loginType, loginMode)
|
||||
}
|
||||
.setNegativeButton(R.string.i_disagree, null)
|
||||
.show()
|
||||
.also { dialog ->
|
||||
dialog.findViewById<TextView>(android.R.id.message)?.movementMethod =
|
||||
BetterLinkMovementMethod.getInstance()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
launch {
|
||||
if (!checkAvailability(loginType.loginType))
|
||||
return@launch
|
||||
|
@ -5,7 +5,6 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -75,19 +74,6 @@ class LoginSummaryFragment : Fragment(), CoroutineScope {
|
||||
}
|
||||
|
||||
b.finishButton.onClick {
|
||||
if (!app.config.privacyPolicyAccepted) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.privacy_policy)
|
||||
.setMessage(Html.fromHtml("Korzystając z aplikacji potwierdzasz <a href=\"http://szkolny.eu/privacy-policy\">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia."))
|
||||
.setPositiveButton(R.string.i_agree) { _, _ ->
|
||||
app.config.privacyPolicyAccepted = true
|
||||
b.finishButton.performClick()
|
||||
}
|
||||
.setNegativeButton(R.string.i_disagree, null)
|
||||
.show()
|
||||
return@onClick
|
||||
}
|
||||
|
||||
val args = Bundle(
|
||||
"registrationAllowed" to b.registerMeSwitch.isChecked
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.ui.modules.settings.cards
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import eu.szkolny.font.SzkolnyFont
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.after
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS
|
||||
@ -141,12 +142,15 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
|
||||
else
|
||||
null,
|
||||
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_hide_sticks_from_old,
|
||||
icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline,
|
||||
value = configProfile.grades.hideSticksFromOld
|
||||
) { _, it ->
|
||||
configProfile.grades.hideSticksFromOld = it
|
||||
}
|
||||
if (App.devMode)
|
||||
util.createPropertyItem(
|
||||
text = R.string.settings_register_hide_sticks_from_old,
|
||||
icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline,
|
||||
value = configProfile.grades.hideSticksFromOld
|
||||
) { _, it ->
|
||||
configProfile.grades.hideSticksFromOld = it
|
||||
}
|
||||
else
|
||||
null
|
||||
)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.utils.managers
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.text.TextUtils
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@ -26,12 +27,18 @@ class BuildManager(val app: App) : CoroutineScope {
|
||||
|
||||
val buildFlavor = BuildConfig.FLAVOR
|
||||
val buildType = BuildConfig.BUILD_TYPE
|
||||
val buildTimestamp = BuildConfig.BUILD_TIMESTAMP
|
||||
val isRelease = !BuildConfig.DEBUG
|
||||
val isDebug = BuildConfig.DEBUG
|
||||
val isNightly = BuildConfig.VERSION_NAME.contains("nightly")
|
||||
val isDaily = BuildConfig.VERSION_NAME.contains("daily")
|
||||
|
||||
val buildTimestamp: Long
|
||||
get() {
|
||||
val info = app.packageManager.getApplicationInfo(app.packageName, PackageManager.GET_META_DATA)
|
||||
val metadata = info.metaData
|
||||
return metadata?.getFloat("buildTimestamp")?.toLong() ?: 0
|
||||
}
|
||||
|
||||
val gitHash = BuildConfig.GIT_INFO["hash"]
|
||||
val gitVersion = BuildConfig.GIT_INFO["version"]
|
||||
val gitBranch = BuildConfig.GIT_INFO["branch"]
|
||||
@ -56,9 +63,9 @@ class BuildManager(val app: App) : CoroutineScope {
|
||||
}
|
||||
|
||||
val versionBadge = when {
|
||||
isOfficial && isNightly ->
|
||||
isSigned && isNightly ->
|
||||
"Nightly\n" + BuildConfig.VERSION_NAME.substringAfterLast('.')
|
||||
isOfficial && isDaily ->
|
||||
isSigned && isDaily ->
|
||||
"Daily\n" + BuildConfig.VERSION_NAME.substringAfterLast('.')
|
||||
isDebug ->
|
||||
"Debug\n" + BuildConfig.VERSION_BASE
|
||||
@ -78,10 +85,22 @@ class BuildManager(val app: App) : CoroutineScope {
|
||||
|
||||
val fields = mapOf(
|
||||
R.string.build_version to BuildConfig.VERSION_BASE,
|
||||
R.string.build_official to if (isOfficial)
|
||||
yes.asColoredSpannable(mtrlGreen)
|
||||
else
|
||||
no.asColoredSpannable(mtrlRed),
|
||||
R.string.build_official to when {
|
||||
isOfficial -> yes.asColoredSpannable(mtrlGreen)
|
||||
isSigned -> TextUtils.concat(
|
||||
yes.asColoredSpannable(mtrlYellow),
|
||||
when {
|
||||
isNightly -> " (nightly build)"
|
||||
isDaily -> " (daily build)"
|
||||
else -> no.asColoredSpannable(mtrlYellow)
|
||||
}
|
||||
)
|
||||
isDebug -> no
|
||||
else -> TextUtils.concat(
|
||||
no.asColoredSpannable(mtrlRed),
|
||||
if (gitAuthor.isNotNullNorBlank()) " ($gitAuthor)" else ""
|
||||
)
|
||||
},
|
||||
R.string.build_platform to when {
|
||||
isPlayRelease -> activity.getString(R.string.build_platform_play)
|
||||
isApkRelease -> activity.getString(R.string.build_platform_apk)
|
||||
@ -229,8 +248,10 @@ class BuildManager(val app: App) : CoroutineScope {
|
||||
val validation = Signing.appCertificate + gitHash + gitRemotes?.join(";")
|
||||
|
||||
// app already validated
|
||||
if (app.config.validation == validation.md5())
|
||||
if (app.config.validation?.substringBefore(":") == validation.md5()){
|
||||
gitAuthor = app.config.validation?.substringAfter(":")
|
||||
return@launch
|
||||
}
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.please_wait)
|
||||
@ -251,7 +272,7 @@ class BuildManager(val app: App) : CoroutineScope {
|
||||
}
|
||||
|
||||
// release, unofficial, published build
|
||||
app.config.validation = validation.md5()
|
||||
app.config.validation = validation.md5() + ":" + gitAuthor
|
||||
invalidateBuild(activity, dialog, InvalidBuildReason.VALID)
|
||||
}
|
||||
}
|
||||
|
@ -1235,5 +1235,135 @@
|
||||
<string name="permissions_attachment">In order to download the file, you have to grant file storage permission for the application.\n\nClick OK to grant the permission.</string>
|
||||
<string name="permissions_denied">You denied the required permissions for the application.\n\nIn order to grant the permission, open the Permissions screen for Szkolny.eu in phone settings.\n\nClick OK to open app settings now.</string>
|
||||
<string name="permissions_required">Required permissions</string>
|
||||
<string name="settings_register_hide_sticks_from_old">Your mother won\'t see your F grades</string>
|
||||
<string name="settings_register_hide_sticks_from_old">Hide sticks from old</string>
|
||||
<string name="build_official">Official build</string>
|
||||
<string name="build_platform_play">Google Play</string>
|
||||
<string name="login_chooser_testing_title">Testing version</string>
|
||||
<string name="login_chooser_mode_recommended">{cmd-information-outline} Recommended</string>
|
||||
<string name="login_chooser_mode_dev_only">{cmd-android-studio} Developer version</string>
|
||||
<string name="login_chooser_mode_testing">{cmd-alert-circle-outline} Testing version</string>
|
||||
<string name="eggs">\???</string>
|
||||
<string name="see_also">See also</string>
|
||||
<string name="settings_about_github_text">Source code</string>
|
||||
<string name="build_branch">Git branch</string>
|
||||
<string name="build_platform_apk">.APK</string>
|
||||
<string name="build_platform_unofficial">Unofficial (.APK)</string>
|
||||
<string name="build_commit">Commit hash</string>
|
||||
<string name="build_dirty">Unsaved changes</string>
|
||||
<string name="build_tag">Last tag</string>
|
||||
<string name="build_rev_count">Commits since last tag</string>
|
||||
<string name="build_remote">Remote repository</string>
|
||||
<string name="build_details">Build details</string>
|
||||
<string name="build_dialog_open_repo">Check code</string>
|
||||
<string name="profile_config_name_hint">Profile name</string>
|
||||
<string name="profile_config_logout">Logout</string>
|
||||
<string name="profile_config_sync_enabled">Synchronize this profile</string>
|
||||
<string name="home_availability_update">Update</string>
|
||||
<string name="update_available_later">Not now</string>
|
||||
<string name="update_available_button">Update</string>
|
||||
<string name="login_type_edudziennik">EduDziennik</string>
|
||||
<string name="login_form_title_format">Log in - %s</string>
|
||||
<string name="attendance_details_date">Date</string>
|
||||
<string name="attendance_details_teacher">Teacher</string>
|
||||
<string name="attendance_tab_days">By days</string>
|
||||
<string name="attendance_tab_list">List</string>
|
||||
<string name="attendance_lesson_number_format">lesson %d</string>
|
||||
<string name="attendance_tab_types">By type</string>
|
||||
<string name="settings_add_student_text">Add new student</string>
|
||||
<string name="attendance_details_lesson_topic">Lesson subject</string>
|
||||
<string name="register_unavailable_read_more">Read more</string>
|
||||
<string name="build_version">App version</string>
|
||||
<string name="settings_about_version_details_text">Version details</string>
|
||||
<string name="build_date">Build date</string>
|
||||
<string name="error_no_api_access">No API access</string>
|
||||
<string name="attendance_details_time">Time</string>
|
||||
<string name="settings_about_github_subtext">Help with app development on GitHub</string>
|
||||
<string name="build_platform">Distribution</string>
|
||||
<string name="build_validate_progress">Build verification in progress...</string>
|
||||
<string name="attendance_tab_months">By months</string>
|
||||
<string name="attendance_tab_summary">Summary</string>
|
||||
<string name="attendance_details_type">Type</string>
|
||||
<string name="home_availability_info">See more</string>
|
||||
<string name="home_availability_title">Update available</string>
|
||||
<string name="settings_about_version_details_subtext">Build details</string>
|
||||
<string name="home_availability_text">Update app to the latest version - %s.</string>
|
||||
<string name="update_available_title">App update available</string>
|
||||
<string name="home_archive_close">Close archive</string>
|
||||
<string name="home_archive_title">Archived profile</string>
|
||||
<string name="profile_archived_title">Profile is archived</string>
|
||||
<string name="profile_year_not_started_title">Holiday ;)</string>
|
||||
<string name="profile_archiving_title">The end of the school year</string>
|
||||
<string name="login_podlasie_logout_devices">Logout from other devices</string>
|
||||
<string name="event_manual_no_profile">Student profile not found.</string>
|
||||
<string name="settings_about_homepage_text">Go to application website</string>
|
||||
<string name="settings_about_homepage_subtext">Get help or support authors</string>
|
||||
<string name="build_invalid_title">Information about application version</string>
|
||||
<string name="home_archive_close_no_target_title">No current profile</string>
|
||||
<string name="login_platform_list_loading">Loading e-registers list...</string>
|
||||
<string name="login_mode_podlasie_api">Log in using token</string>
|
||||
<string name="login_mode_podlasie_api_guide">Provide mobile app token.</string>
|
||||
<string name="attendance_config_title">Attendance configuration</string>
|
||||
<string name="attendance_config_use_symbols">Show symbols and colors from e-register config</string>
|
||||
<string name="attendance_empty_text">There are no absences here.</string>
|
||||
<string name="grades_empty_text">There are no grades in this semester</string>
|
||||
<string name="menu_attendance_config">Attendance settings</string>
|
||||
<string name="login_chooser_title">What is your e-register at school?</string>
|
||||
<string name="login_mode_librus_synergia">Log in using login and password</string>
|
||||
<string name="login_mode_librus_synergia_hint">Use a login in form of \"9874123u\"</string>
|
||||
<string name="login_mode_vulcan_api">Use token, symbol and PIN code</string>
|
||||
<string name="login_mode_vulcan_api_hint">Register device on journal VULCAN® page</string>
|
||||
<string name="login_mode_vulcan_web">Use e-mail/username and password</string>
|
||||
<string name="edziennik_progress_login_podlasie_api">Logging in to PPE...</string>
|
||||
<string name="login_type_podlasie">Podlaska Platforma Edukacyjna</string>
|
||||
<string name="login_mode_edudziennik_web">Log in using e-mail and password</string>
|
||||
<string name="edziennik_progress_login_vulcan_web_main">Logging in to VULCAN® register...</string>
|
||||
<string name="login_mode_librus_jst">Login via VULCAN® platform</string>
|
||||
<string name="login_mode_librus_email">Log in using e-mail</string>
|
||||
<string name="attendance_details_id">Attendance ID</string>
|
||||
<string name="login_mode_mobidziennik_web">Log in with the server name, login and password</string>
|
||||
<string name="login_mode_vulcan_web_hint">Log in with the data that you provide on VULCAN® e-register website</string>
|
||||
<string name="login_mode_mobidziennik_web_hint">Provide data, that you use on e-register website</string>
|
||||
<string name="attendance_details_type_id">Base type ID</string>
|
||||
<string name="attendance_details_is_counted">Counted to the stats?</string>
|
||||
<string name="login_chooser_subtitle">Choose which e-register your school uses. If you have several accounts in different e-registers, you will be able to add them later.</string>
|
||||
<string name="login_mode_librus_email_hint">You must have a LIBRUS® Rodzina account</string>
|
||||
<string name="login_mode_librus_jst_hint">Only Oświata w Radomiu and Innowacyjny Tarnobrzeg</string>
|
||||
<string name="login_platform_list_title">How do you log into the e-register?</string>
|
||||
<string name="attendance_config_group_consecutive_days">Group consecutive days on the list</string>
|
||||
<string name="attendance_config_use_symbols_hint">Visible when the list is expanded</string>
|
||||
<string name="attendance_config_show_presence_in_month">Display attendance in months view</string>
|
||||
<string name="attendance_percentage_format">%.2f%%</string>
|
||||
<string name="attendance_period_summary_format">Attendance during this period: %.2%%</string>
|
||||
<string name="settings_add_student_subtext">Log in child/parent account in app</string>
|
||||
<string name="login_mode_edudziennik_web_guide">Enter the e-mail address and password that you use to log in to the browser on the EduDziennik website.</string>
|
||||
<string name="profile_year_not_started_format">Probably the school year for this student has not yet started (will start %s). Please try to sync later.</string>
|
||||
<string name="profile_archiving_format">The school year ended on %s. Student data from the previous year will be moved to the archive for later review.</string>
|
||||
<string name="login_copyright_notice">Trademarks featured in this application belong to their rightful owners and are used for informational purposes only.</string>
|
||||
<string name="home_archive_text">You are viewing a student\'s data from the school year %d/%d.</string>
|
||||
<string name="login_mode_edudziennik_web_hint">Use data, that you enter on the e-register website</string>
|
||||
<string name="permissions_qr_scanner">To be able to scan the QR code, you need to grant access to the camera.\n\nClick OK to grant permissions.</string>
|
||||
<string name="rate_snackbar_negative_message">It\'s a pity, the opinions of others help me develop the application.</string>
|
||||
<string name="login_chooser_testing_text">The selected login method is still being tested and may not work properly. If you have problems with the app, please choose the recommended login method.</string>
|
||||
<string name="update_available_fallback">You have an outdated version of the Szkolny.eu application. You need to update the app to continue to sync data.</string>
|
||||
<string name="update_available_format">You are using an old version of the Szkolny.eu application (%s). To use the app and ensure the best performance, please upgrade to %s. Change log: %s</string>
|
||||
<string name="profile_archived_text">You are viewing a student\'s data from the previous school year (%d /%d). Syncing and downloading of messages and some homework have been disabled. To open a student\'s profile for the current year, select Close Archive on the home page.</string>
|
||||
<string name="login_mode_librus_jst_guide">Log in to LIBRUS® Synergia on your computer, select the Mobile Applications tab, then enter the received Token and PIN below.</string>
|
||||
<string name="login_mode_librus_synergia_guide">Enter the login received from the school with which you log into LIBRUS® Synergia (purple form).\n\nIt is recommended to log in with the LIBRUS® Family account (using e-mail) in the previous step.</string>
|
||||
<string name="login_mode_librus_email_guide">Log in with your LIBRUS® Rodzina account, which works in the official LIBRUS® application and on the website portal.librus.pl, in the blue form. \n\nIf you do not have a LIBRUS® Rodzina account, you can create one at https://portal.librus.pl/rodzina/register.</string>
|
||||
<string name="login_platform_list_loading_timeout">If it takes too long, please check your internet connection and restart the application.</string>
|
||||
<string name="login_platform_list_subtitle">Select which image corresponds to the one you see when logging in to your log website. If your school doesn\'t use any of these city platforms, choose the first option.</string>
|
||||
<string name="build_invalid_remote_no_commit">You have an application build with unpublished changes. The build is in the repository:\n%1$s (%2$s)\nwhich is private or does not contain the latest changes.\n\nFor security reasons and compliance with the license, the use of the application has been blocked.</string>
|
||||
<string name="login_mode_vulcan_api_guide">Log in to the VULCAN® log on your computer, select the Mobile Access tab, click the Register mobile device button. Enter the received Token, Symbol and PIN in the fields below.</string>
|
||||
<string name="login_mode_vulcan_web_guide">Enter the data that you log in to the VULCAN® log website or the city platform.</string>
|
||||
<string name="build_invalid_official_unsigned">You cannot modify this type of compilation of the Szkolny.eu application.\n\nTo make your own changes, please use the source code available on GitHub and see the README and license information.\n\nhttps://szkolny.eu/github/android</string>
|
||||
<string name="build_invalid_unstaged_changes">This build contains changes not committed to any revision. Save and publish all changes before \"release\".\n\nFor security reasons and for compliance with the license, the use of the application has been blocked.</string>
|
||||
<string name="build_invalid_debug">You are using a \"debug\" build. This information will only be displayed once for the current device.</string>
|
||||
<string name="build_valid_unofficial">You are using an unofficial compilation of the Szkolny.eu application. We recommend that you use only the official versions of the application.\n\nLast changes in this version were made by:\n%3$s\nin the repository:\n%1$s (%2$s).\n\nThis window will not reappear.</string>
|
||||
<string name="build_invalid_no_commit_hash">The hash of the current commit was not found. Check Gradle configuration.</string>
|
||||
<string name="home_archive_close_no_target_text">Child %s does not have a profile on this account in the current school year. Probably this profile has been deleted or the student no longer attends this class.\n\nTo go to the current profile, select a student from the list or log in to their account with the Add student button.</string>
|
||||
<string name="build_invalid_no_remote_repo">A reference to a remote repository was not found. Make sure you are using the official repository fork and verify your Gradle configuration.</string>
|
||||
<string name="login_mode_mobidziennik_web_guide">"Enter the data you use to log in to the MobiDziennik website. As the server address, you can enter the address of the website where you have MobiDziennik. "</string>
|
||||
<string name="permissions_generate_timetable">In order to be able to save the generated timetable, you must grant access rights to the device\'s memory.\n\nClick OK to grant permissions.</string>
|
||||
<string name="login_summary_account_child">(Child)</string>
|
||||
<string name="login_summary_account_parent">(Parent)</string>
|
||||
</resources>
|
||||
|
@ -1346,10 +1346,6 @@
|
||||
<string name="login_mode_vulcan_web_guide">Podaj dane, którymi logujesz się na stronie internetowej dziennika VULCAN® lub na miejskiej platformie.</string>
|
||||
<string name="login_mode_mobidziennik_web_guide">Podaj dane, których używasz do logowania na stronie MobiDziennika. Jako adres serwera możesz wpisać adres strony internetowej, na której masz MobiDziennik.</string>
|
||||
<string name="edziennik_progress_login_vulcan_web_main">Logowanie do dziennika VULCAN®...</string>
|
||||
<string name="login_type_idziennik">iDziennik Progman / iUczniowie</string>
|
||||
<string name="login_mode_idziennik_web">Zaloguj używając nazwy użytkownika i hasła</string>
|
||||
<string name="login_mode_idziennik_web_hint">Podaj dane, których używasz na stronie internetowej e-dziennika</string>
|
||||
<string name="login_mode_idziennik_web_guide">Użyj danych, które wpisujesz w formularz na stronie iDziennika. Jeśli nie pamiętasz hasła, wejdź na http://iuczniowie.progman.pl/ i kliknij przycisk \"Zapomniałem hasła\".</string>
|
||||
<string name="login_type_edudziennik">EduDziennik</string>
|
||||
<string name="login_mode_edudziennik_web">Zaloguj używając e-maila i hasła</string>
|
||||
<string name="login_mode_edudziennik_web_hint">Użyj danych, które podajesz na stronie internetowej e-dziennika</string>
|
||||
@ -1419,7 +1415,7 @@
|
||||
<string name="build_invalid_official_unsigned">Nie możesz modyfikować tego rodzaju kompilacji aplikacji Szkolny.eu.\n\nAby wprowadzić własne zmiany, skorzystaj z kodu źródłowego dostępnego na GitHubie oraz zapoznaj się z README i informacją o licencji.\n\nhttps://szkolny.eu/github/android</string>
|
||||
<string name="build_invalid_unstaged_changes">Ta kompilacja zawiera zmiany niezatwierdzone do żadnej rewizji. Zapisz oraz opublikuj wszystkie zmiany przed wydaniem wersji \"release\".\n\nDla bezpieczeństwa oraz ze względów zgodności z licencją, korzystanie z aplikacji zostało zablokowane.</string>
|
||||
<string name="build_invalid_debug">Korzystasz z kompilacji typu \"debug\". Ta informacja zostanie wyświetlona tylko jeden raz dla aktualnego urządzenia.</string>
|
||||
<string name="build_valid_unofficial">Korzystasz z nieoficjalnej kompilacji aplikacji Szkolny.eu. Zalecamy używanie wyłącznie oficjalnych wersji aplikacji.\n\nOstatnie zmiany w tej wersji zostały wprowadzone przez %3$s w repozytorium %2$s (%1$s).\n\nTo okno nie wyświetli się ponownie.</string>
|
||||
<string name="build_valid_unofficial">Korzystasz z nieoficjalnej kompilacji aplikacji Szkolny.eu. Zalecamy używanie wyłącznie oficjalnych wersji aplikacji.\n\nOstatnie zmiany w tej wersji zostały wprowadzone przez:\n%3$s\nw repozytorium:\n%1$s (%2$s).\n\nTo okno nie wyświetli się ponownie.</string>
|
||||
<string name="build_invalid_title">Informacja dotycząca wersji aplikacji</string>
|
||||
<string name="settings_about_version_details_text">Szczegóły wersji</string>
|
||||
<string name="settings_about_version_details_subtext">Informacje o kompilacji</string>
|
||||
@ -1427,4 +1423,5 @@
|
||||
<string name="error_no_api_access">Brak dostępu do API</string>
|
||||
<string name="build_date">Data kompilacji</string>
|
||||
<string name="permissions_generate_timetable">Aby móc zapisać wygenerowany plan lekcji musisz przyznać uprawnienia dostępu do pamięci urządzenia.\n\nKliknij OK, aby przyznać uprawnienia.</string>
|
||||
<string name="privacy_policy_dialog_html"><![CDATA[Korzystając z aplikacji potwierdzasz <a href="https://szkolny.eu/privacy-policy">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia.<br /><br />Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]></string>
|
||||
</resources>
|
||||
|
@ -5,8 +5,8 @@ buildscript {
|
||||
kotlin_version = '1.4.31'
|
||||
|
||||
release = [
|
||||
versionName: "4.7-rc.1",
|
||||
versionCode: 4070010
|
||||
versionName: "4.7-rc.2",
|
||||
versionCode: 4070020
|
||||
]
|
||||
|
||||
setup = [
|
||||
|
Reference in New Issue
Block a user