From db265fa12b247fbf31dfae6cff0a01ab4499482b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 12:53:01 +0100 Subject: [PATCH 01/26] [Gradle] Include Git info in build config. --- app/build.gradle | 4 ++ app/git-info.gradle | 125 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 app/git-info.gradle diff --git a/app/build.gradle b/app/build.gradle index 0e83e107..42960308 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,8 @@ apply plugin: 'kotlin-kapt' apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' +apply from: 'git-info.gradle' + android { compileSdkVersion setup.compileSdk @@ -15,6 +17,8 @@ android { versionCode release.versionCode versionName release.versionName + buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap + multiDexEnabled = true externalNativeBuild { diff --git a/app/git-info.gradle b/app/git-info.gradle new file mode 100644 index 00000000..929d5307 --- /dev/null +++ b/app/git-info.gradle @@ -0,0 +1,125 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-27. + */ + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath "org.eclipse.jgit:org.eclipse.jgit:5.5.+" + } +} + +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.errors.RepositoryNotFoundException +import org.eclipse.jgit.lib.Constants +import org.eclipse.jgit.lib.Ref +import org.eclipse.jgit.lib.Repository +import org.eclipse.jgit.revwalk.RevCommit +import org.eclipse.jgit.revwalk.RevTag +import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.storage.file.FileRepositoryBuilder + +private def getGit() { + Repository repo + try { + repo = new FileRepositoryBuilder() + .readEnvironment() + .findGitDir(project.projectDir) + .build() + } catch (IllegalArgumentException | RepositoryNotFoundException ignore) { + def logger = LoggerFactory.getLogger("androidGitVersion") + logger.error("No git repository reachable from ${project.projectDir}") + return results + } + return Git.wrap(repo) +} + +private static def getTags(Repository repo, Git git) { + RevWalk walk = new RevWalk(repo) + def tags = git.tagList().call().findResults { ref -> + def obj = walk.parseAny(ref.getObjectId()) + def name = null + if (obj instanceof RevTag) { + name = obj.getTagName() + } else if (obj instanceof RevCommit) { + name = Repository.shortenRefName(ref.name) + } + [obj.id, name] + } + walk.close() + return tags +} + +private static def getLastTag(Repository repo, Git git, Ref head) { + def tags = getTags(repo, git) + + RevWalk revs = new RevWalk(repo) + revs.markStart(revs.parseCommit(head.getObjectId())) + def revCount = 0 + Collection commitTags = null + for (RevCommit commit : revs) { + def tagsHere = tags.findAll { (it[0] == commit.id) } + if (tagsHere) { + commitTags = tagsHere.stream().map { + [it[0].name, it[1], revCount] + }.toArray() + break + } + revCount++ + } + + return commitTags.last() +} + +private def buildGitInfo() { + Git git = getGit() + Repository repo = git.repository + + def head = repo.findRef(Constants.HEAD).target + + def remotes = git.remoteList().call() + .stream() + .map { + it.name + "(" + it.URIs.stream() + .map { it.rawPath } + .toArray() + .join(", ") + ")" + } + .toArray() + .join("; ") + + def status = git.status().call() + def dirty = status.hasUncommittedChanges() + + 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, + branch : repo.branch, + dirty : dirty, + remotes : remotes, + unstaged : status.uncommittedChanges.join("; "), + tag : tagName, + revCount : tagRevCount, + version : """$tagName-$tagRevCount-g${head.objectId.name.substring(0, 8)}""" + (dirty ? ".dirty" : ""), + versionHuman: """$versionName-${repo.branch.replace("/", "_")}""" + (dirty ? ".dirty" : "") + ] + return result +} + +private static def getMapString(map) { + def hashMap = "new java.util.HashMap() { {\n" + map.each { k, v -> hashMap += """\tput("${k}", "${v}");\n""" } + return hashMap + "} }" +} + +ext { + gitInfo = buildGitInfo() + gitInfoMap = getMapString(gitInfo) +} From 06407ee43985526fc24d8f82ea03edb96f081625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:00:06 +0100 Subject: [PATCH 02/26] [Gradle] Add build flavors. --- app/build.gradle | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 42960308..c39adb71 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,6 +18,8 @@ android { versionName release.versionName buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap + buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis()) + buildConfigField "String", "VERSION_BASE", release.versionName multiDexEnabled = true @@ -27,6 +29,7 @@ android { } } } + buildTypes { applicationVariants.all { variant -> variant.outputs.all { @@ -47,6 +50,19 @@ android { proguardFiles fileTree('proguard').asList().toArray() } } + flavorDimensions "platform" + productFlavors { + main { + versionName gitInfo.versionHuman + } + official {} + play {} + } + variantFilter { variant -> + def flavors = variant.flavors*.name + setIgnore(variant.buildType.name == "debug" && !flavors.contains("main")) + } + defaultConfig { vectorDrawables.useSupportLibrary = true } From 1af65de548acc51e2b2d5d845d3c2e9f9ec66880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:01:37 +0100 Subject: [PATCH 03/26] [App] Implement BuildManager. --- .../java/pl/szczodrzynski/edziennik/App.kt | 1 + .../edziennik/utils/managers/BuildManager.kt | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 0bc6f2e0..43a8b921 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -67,6 +67,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { val eventManager by lazy { EventManager(this) } val permissionManager by lazy { PermissionManager(this) } val attendanceManager by lazy { AttendanceManager(this) } + val buildManager by lazy { BuildManager(this) } val db get() = App.db diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt new file mode 100644 index 00000000..a05a9491 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2021-3-27. + */ + +package pl.szczodrzynski.edziennik.utils.managers + +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.BuildConfig +import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing +import pl.szczodrzynski.edziennik.md5 + +class BuildManager(val app: App) { + + 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 gitHash = BuildConfig.GIT_INFO["hash"] + val gitVersion = BuildConfig.GIT_INFO["version"] + val gitBranch = BuildConfig.GIT_INFO["branch"] + val gitUnstaged = BuildConfig.GIT_INFO["unstaged"]?.split("; ") + val gitRevCount = BuildConfig.GIT_INFO["revCount"] + val gitTag = BuildConfig.GIT_INFO["tag"] + val gitIsDirty = BuildConfig.GIT_INFO["dirty"] !== "false" + val gitRemotes = BuildConfig.GIT_INFO["remotes"]?.split("; ") + + val isSigned = Signing.appCertificate.md5() == "d8bab5259fda7d72121fe5db526a3d4d" + + val isPlayRelease = isRelease && buildFlavor == "play" + val isApkRelease = isRelease && buildFlavor == "official" + val isOfficial = isSigned && (isPlayRelease || isApkRelease) + + val versionName = when { + isOfficial -> BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE + isRelease -> "$gitVersion\n$gitBranch" + else -> BuildConfig.VERSION_NAME + } + + val versionBadge = when { + isOfficial && isNightly -> + "Nightly\n" + BuildConfig.VERSION_NAME.substringAfterLast('.') + isOfficial && isDaily -> + "Daily\n" + BuildConfig.VERSION_NAME.substringAfterLast('.') + isDebug -> + "Debug\n" + BuildConfig.VERSION_BASE + !isOfficial -> + "Unofficial\n" + BuildConfig.VERSION_BASE + else -> null + } +} From bf5fb5f6236511b7098f5d7296ba8fe7f3120a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:06:30 +0100 Subject: [PATCH 04/26] [UI] Update main activity badge. --- app/build.gradle | 2 +- .../pl/szczodrzynski/edziennik/MainActivity.kt | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c39adb71..c9751c52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,7 +19,7 @@ android { buildConfigField "java.util.Map", "GIT_INFO", gitInfoMap buildConfigField "long", "BUILD_TIMESTAMP", String.valueOf(System.currentTimeMillis()) - buildConfigField "String", "VERSION_BASE", release.versionName + buildConfigField "String", "VERSION_BASE", "\"${release.versionName}\"" multiDexEnabled = true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index de9b5f85..3e953239 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -302,21 +302,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope { mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) - when { - BuildConfig.VERSION_NAME.contains("nightly") -> { - b.nightlyText.isVisible = true - b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".") - } - BuildConfig.VERSION_NAME.contains("daily") -> { - b.nightlyText.isVisible = true - b.nightlyText.text = "Daily\n"+BuildConfig.VERSION_NAME.substringAfterLast(".") - } - BuildConfig.DEBUG -> { - b.nightlyText.isVisible = true - b.nightlyText.text = "Debug\n"+BuildConfig.VERSION_NAME - } - else -> b.nightlyText.isVisible = false - } + val versionBadge = app.buildManager.versionBadge + b.nightlyText.isVisible = versionBadge != null + b.nightlyText.text = versionBadge navLoading = true From 704a55d789539c40573a9b3743d9cbd639959552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:09:38 +0100 Subject: [PATCH 05/26] [UI] Update version info in Settings. --- .../edziennik/ui/modules/settings/SettingsNewFragment.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index d009cdf1..09625333 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -43,7 +43,6 @@ import java.util.List; import eu.szkolny.font.SzkolnyFont; import kotlin.Unit; import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.BuildConfig; import pl.szczodrzynski.edziennik.ExtensionsKt; import pl.szczodrzynski.edziennik.MainActivity; import pl.szczodrzynski.edziennik.R; @@ -1021,7 +1020,7 @@ public class SettingsNewFragment extends MaterialAboutFragment { pref_about_version = new MaterialAboutActionItem.Builder() .text(R.string.settings_about_version_text) - .subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE) + .subText(app.getBuildManager().getVersionName()) .icon(icon(CommunityMaterial.Icon2.cmd_information_outline, iconSizeDp, primaryTextOnPrimaryBg)) .build(); final int[] clickCounter = {0}; From 726a37d5d6fde2570981519eb27c68b98bb0d057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 14:33:10 +0100 Subject: [PATCH 06/26] [UI] Add build details dialog. --- .../edziennik/utils/managers/BuildManager.kt | 40 +++++++++++++++++-- app/src/main/res/values/strings.xml | 13 ++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt index a05a9491..1b8c2453 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/BuildManager.kt @@ -4,10 +4,10 @@ package pl.szczodrzynski.edziennik.utils.managers -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.BuildConfig +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing -import pl.szczodrzynski.edziennik.md5 class BuildManager(val app: App) { @@ -51,4 +51,38 @@ class BuildManager(val app: App) { "Unofficial\n" + BuildConfig.VERSION_BASE else -> null } + + fun showVersionDialog(activity: AppCompatActivity) { + val yes = activity.getString(R.string.yes) + val no = activity.getString(R.string.no) + + val fields = mapOf( + R.string.build_version to BuildConfig.VERSION_BASE, + R.string.build_official to if (isOfficial) yes else no, + R.string.build_platform to when { + isPlayRelease -> activity.getString(R.string.build_platform_play) + isApkRelease -> activity.getString(R.string.build_platform_apk) + else -> activity.getString(R.string.build_platform_unofficial) + }, + R.string.build_branch to gitBranch, + R.string.build_commit to gitHash?.substring(0, 8), + R.string.build_dirty to if (gitUnstaged?.isEmpty() == true) + "-" + else + "\t" + gitUnstaged?.join("\n\t"), + R.string.build_tag to gitTag, + R.string.build_rev_count to gitRevCount, + R.string.build_remote to gitRemotes?.join("\n") + ) + + val message = fields.map { (key, value) -> + activity.getString(key) + ":\n" + value + }.join("\n\n") + + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.build_details) + .setMessage(message) + .setPositiveButton(R.string.ok, null) + .show() + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ea45e49..08c76e90 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1387,4 +1387,17 @@ {cmd-android-studio} Wersja deweloperska \??? Szkoda, opinie innych pomagają mi rozwijać aplikację. + Wersja aplikacji + Wydanie oficjalne + Dystrybucja + Google Play + .APK + Nieoficjalnie (.APK) + Gałąź Git + Identyfikator rewizji + Niezapisane zmiany + Ostatni tag + Rewizje od ostatniego tagu + Repozytorium zdalne + Informacje o kompilacji From 6824960731bfcbebe18a864fc2bc9b8790dd6fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 Mar 2021 16:28:09 +0100 Subject: [PATCH 07/26] [App] Implement basic app validation and related UI. --- app/src/main/AndroidManifest.xml | 1 + .../szczodrzynski/edziennik/MainActivity.kt | 2 + .../szczodrzynski/edziennik/config/Config.kt | 5 + .../ui/modules/base/BuildInvalidActivity.kt | 33 +++++ .../ui/modules/login/LoginActivity.kt | 2 + .../edziennik/utils/managers/BuildManager.kt | 137 +++++++++++++++++- .../res/layout/activity_build_invalid.xml | 65 +++++++++ app/src/main/res/values/strings.xml | 9 ++ 8 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/base/BuildInvalidActivity.kt create mode 100644 app/src/main/res/layout/activity_build_invalid.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e8fc491..c5bfa07f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -147,6 +147,7 @@ + + + + + + + + + + + + + + + + +