Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ uses semantic versioning (`MAJOR.MINOR.PATCH`).

### Added

- **About has a screen of its own.** The settings row squeezed the version,
commit, build time and flavour onto one line, so on a narrow screen the
commit was cut off and the only way to read it was to turn the phone
sideways. Tapping it now opens a screen where each fact gets its own row and
copies to the clipboard, including the full commit hash rather than the short
one. It also reports what the server says it is: version, tag, commit, build
time and mode.

- **Announcements can be scheduled with a date picker.** Admin only. The start
and expiry wanted a hand-typed `2026-12-31T00:00:00Z`, where one typo meant
the server rejected the whole announcement. Both are now a date picker and a
time field, as is the expiry on an invite code.

- **Announcements can be set to show on the login page.** Admin only. The
server has supported this for a long time and the setting simply wasn't on
the phone, so it could only be set from the web client.

### Changed

- **The admin account list is its own screen.** It rendered every account
inline, which pushed invite codes, announcements and maintenance several
screens down and left the search field scrolled off above its own results.
Searching also waits for a pause in typing now, instead of asking the server
again on every keystroke.
- **A share view can show everyone set to Public.** Instead of adding members
one at a time, turn on "Show everyone set to Public" and the view follows
each member's privacy setting from then on. The list you picked by hand is
Expand Down
11 changes: 11 additions & 0 deletions sheaf/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ val gitCommitShort: String = runCatching {
.inputStream.bufferedReader().readText().trim()
}.getOrNull()?.takeIf { it.isNotBlank() } ?: "unknown"

// Full SHA of the same commit. The short one identifies a build at a glance;
// this is the one you paste into a bug report or hand to `git show`, which is
// why About offers it as a copyable field rather than only on screen.
val gitCommitFull: String = runCatching {
ProcessBuilder("git", "rev-parse", "HEAD")
.redirectErrorStream(true)
.start()
.inputStream.bufferedReader().readText().trim()
}.getOrNull()?.takeIf { it.isNotBlank() } ?: "unknown"

// Build timestamp (UTC) at configure time, also surfaced via BuildConfig.
// Same purpose as gitCommitShort but answers "when was this APK compiled" —
// useful for the "wait, did I actually install the new build" moment when
Expand Down Expand Up @@ -79,6 +89,7 @@ android {
versionName = providers.gradleProperty("versionName").orNull
?: "$latestReleaseTag-dev"
buildConfigField("String", "GIT_COMMIT", "\"$gitCommitShort\"")
buildConfigField("String", "GIT_COMMIT_FULL", "\"$gitCommitFull\"")
buildConfigField("String", "BUILD_TIME", "\"$buildTimestamp\"")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ data class AuthConfig(
data class ServerVersion(
val version: String? = null,
@Json(name = "git_tag") val gitTag: String? = null,
@Json(name = "git_commit") val gitCommit: String? = null,
@Json(name = "build_time") val buildTime: String? = null,
val mode: String? = null,
) {
Expand Down Expand Up @@ -1351,6 +1352,7 @@ data class AnnouncementRead(
val severity: String,
val dismissible: Boolean,
val active: Boolean,
@Json(name = "visible_while_logged_out") val visibleWhileLoggedOut: Boolean = false,
@Json(name = "starts_at") val startsAt: String?,
@Json(name = "expires_at") val expiresAt: String?,
@Json(name = "created_at") val createdAt: String,
Expand All @@ -1365,6 +1367,7 @@ data class AnnouncementCreate(
val severity: String = "info",
val dismissible: Boolean = true,
val active: Boolean = true,
@Json(name = "visible_while_logged_out") val visibleWhileLoggedOut: Boolean = false,
@Json(name = "starts_at") val startsAt: String? = null,
@Json(name = "expires_at") val expiresAt: String? = null,
)
Expand All @@ -1376,6 +1379,7 @@ data class AnnouncementUpdate(
val severity: String? = null,
val dismissible: Boolean? = null,
val active: Boolean? = null,
@Json(name = "visible_while_logged_out") val visibleWhileLoggedOut: Boolean? = null,
@Json(name = "starts_at") val startsAt: String? = null,
@Json(name = "expires_at") val expiresAt: String? = null,
@Json(name = "clear_starts_at") val clearStartsAt: Boolean = false,
Expand Down
14 changes: 14 additions & 0 deletions sheaf/app/src/main/java/systems/lupine/sheaf/ui/SheafApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ object Routes {
const val ADMIN_PANEL = "settings/admin"
const val ADMIN_AUDIT = "settings/admin/audit"
const val ADMIN_JOBS = "settings/admin/jobs"
const val ADMIN_USERS = "settings/admin/users"
const val ABOUT = "settings/about"
const val ADMIN_USER_DETAIL = "settings/admin/user/{userId}"
const val SYSTEM_SAFETY = "settings/safety"
const val SHARING = "settings/sharing"
Expand Down Expand Up @@ -531,6 +533,7 @@ fun SheafApp(
onNavigateToAdminPanel = { navController.navigate(Routes.ADMIN_PANEL) },
onNavigateToSupport = { navController.navigate(Routes.SUPPORT) },
onNavigateToDebug = { navController.navigate(Routes.DEBUG) },
onNavigateToAbout = { navController.navigate(Routes.ABOUT) },
)
}
composable(Routes.SETTINGS_ACCOUNT) {
Expand Down Expand Up @@ -769,6 +772,17 @@ fun SheafApp(
onNavigateUp = { navController.navigateUp() },
onNavigateToAudit = { navController.navigate(Routes.ADMIN_AUDIT) },
onNavigateToJobs = { navController.navigate(Routes.ADMIN_JOBS) },
onNavigateToUsers = { navController.navigate(Routes.ADMIN_USERS) },
)
}
composable(Routes.ABOUT) {
systems.lupine.sheaf.ui.settings.AboutScreen(
onNavigateUp = { navController.navigateUp() },
)
}
composable(Routes.ADMIN_USERS) {
systems.lupine.sheaf.ui.admin.AdminUsersScreen(
onNavigateUp = { navController.navigateUp() },
onNavigateToUserDetail = { id -> navController.navigate("settings/admin/user/$id") },
)
}
Expand Down
Loading
Loading