rename: Android is Inkwell — package, applicationId, uniffi class, assets

Step 4 of milestone 481 (Scribe note 5071: a full rename).

- namespace and applicationId com.fabledsword.inkwell; the Kotlin package moves
  with them, and ktlint re-sorted the imports the rename reordered (checked
  locally with CI's ktlint 1.4.0 and detekt 1.23.7, both clean)
- uniffi: class Inkwell in com.fabledsword.inkwell.core, InkwellApplication,
  InkwellTheme, Theme.Inkwell, log tags, prefs and work names, client agent
  inkwell-android
- the lane publishes inkwell.apk / inkwell-android.json; fetch-clients,
  guard-forward, publish-release and write-manifest read the same names

A new applicationId is a new app. The old ThoughtSync app keeps its own store
and stays installed beside it. Notes cross over by syncing, and the old app is
then removed by hand.

Kept: the signing keyAlias is still "thoughtsync". It names the key inside the
existing keystore, and the key, and so the certificate, are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 14:34:02 -04:00
co-authored by Claude Opus 5.5
parent 256fba3610
commit 81cd719327
55 changed files with 222 additions and 219 deletions
+13 -13
View File
@@ -134,7 +134,7 @@ jobs:
echo "code=$code" >> $GITHUB_OUTPUT echo "code=$code" >> $GITHUB_OUTPUT
if [ -n "${ANDROID_KEYSTORE_BASE64:-}" ]; then if [ -n "${ANDROID_KEYSTORE_BASE64:-}" ]; then
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > /tmp/thoughtsync-release.jks printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 -d > /tmp/inkwell-release.jks
echo "variant=Release" >> $GITHUB_OUTPUT echo "variant=Release" >> $GITHUB_OUTPUT
echo "label=release" >> $GITHUB_OUTPUT echo "label=release" >> $GITHUB_OUTPUT
# DEBUG profile, in a release APK, deliberately — see the note above # DEBUG profile, in a release APK, deliberately — see the note above
@@ -143,7 +143,7 @@ jobs:
# outright (run 4077). Unpicking that is worth doing and is not worth # outright (run 4077). Unpicking that is worth doing and is not worth
# blocking signed builds on. # blocking signed builds on.
echo "profile=debug" >> $GITHUB_OUTPUT echo "profile=debug" >> $GITHUB_OUTPUT
echo "keystore=/tmp/thoughtsync-release.jks" >> $GITHUB_OUTPUT echo "keystore=/tmp/inkwell-release.jks" >> $GITHUB_OUTPUT
echo "apk=android/app/build/outputs/apk/release/app-release.apk" >> $GITHUB_OUTPUT echo "apk=android/app/build/outputs/apk/release/app-release.apk" >> $GITHUB_OUTPUT
echo "Signed release build — $version (versionCode $code)" echo "Signed release build — $version (versionCode $code)"
else else
@@ -167,7 +167,7 @@ jobs:
# from the built .so. Run as its own step so a Rust failure is legible as a # from the built .so. Run as its own step so a Rust failure is legible as a
# Rust failure instead of arriving inside a Gradle stack trace. # Rust failure instead of arriving inside a Gradle stack trace.
- name: Build the native library and bindings - name: Build the native library and bindings
run: ./gradlew generateUniffiBindings -PTHOUGHTSYNC_CARGO_PROFILE=${{ steps.build.outputs.profile }} run: ./gradlew generateUniffiBindings -PINKWELL_CARGO_PROFILE=${{ steps.build.outputs.profile }}
# The image's PINNED CLIs, not Gradle plugins. ci-rust-android carries both # The image's PINNED CLIs, not Gradle plugins. ci-rust-android carries both
# (M12 step 3) precisely so this lane needs no second image, and going # (M12 step 3) precisely so this lane needs no second image, and going
@@ -193,7 +193,7 @@ jobs:
# not exist (run 4082). It costs one extra Kotlin compile and buys the # not exist (run 4082). It costs one extra Kotlin compile and buys the
# type-check on the debug variant, which is the one an emulator build # type-check on the debug variant, which is the one an emulator build
# would use. # would use.
run: ./gradlew testDebugUnitTest -PTHOUGHTSYNC_CARGO_PROFILE=${{ steps.build.outputs.profile }} run: ./gradlew testDebugUnitTest -PINKWELL_CARGO_PROFILE=${{ steps.build.outputs.profile }}
- name: Assemble the APK - name: Assemble the APK
env: env:
@@ -203,9 +203,9 @@ jobs:
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
run: | run: |
./gradlew assemble${{ steps.build.outputs.variant }} \ ./gradlew assemble${{ steps.build.outputs.variant }} \
-PTHOUGHTSYNC_CARGO_PROFILE=${{ steps.build.outputs.profile }} \ -PINKWELL_CARGO_PROFILE=${{ steps.build.outputs.profile }} \
-PTHOUGHTSYNC_VERSION_NAME=${{ steps.build.outputs.name }} \ -PINKWELL_VERSION_NAME=${{ steps.build.outputs.name }} \
-PTHOUGHTSYNC_VERSION_CODE=${{ steps.build.outputs.code }} -PINKWELL_VERSION_CODE=${{ steps.build.outputs.code }}
# Prints the certificate the APK was actually signed with, so the operator # Prints the certificate the APK was actually signed with, so the operator
# can compare it against the fingerprint recorded when the key was # can compare it against the fingerprint recorded when the key was
@@ -226,10 +226,10 @@ jobs:
if: steps.build.outputs.keystore != '' if: steps.build.outputs.keystore != ''
run: | run: |
mkdir -p dist mkdir -p dist
cp "app/build/outputs/apk/release/app-release.apk" dist/thoughtsync.apk cp "app/build/outputs/apk/release/app-release.apk" dist/inkwell.apk
size="$(wc -c < dist/thoughtsync.apk | tr -d ' ')" size="$(wc -c < dist/inkwell.apk | tr -d ' ')"
sha="$(sha256sum dist/thoughtsync.apk | cut -d' ' -f1)" sha="$(sha256sum dist/inkwell.apk | cut -d' ' -f1)"
cat > dist/thoughtsync-android.json <<JSON cat > dist/inkwell-android.json <<JSON
{ {
"version_name": "${{ steps.build.outputs.name }}", "version_name": "${{ steps.build.outputs.name }}",
"version_code": ${{ steps.build.outputs.code }}, "version_code": ${{ steps.build.outputs.code }},
@@ -237,7 +237,7 @@ jobs:
"sha256": "$sha" "sha256": "$sha"
} }
JSON JSON
cat dist/thoughtsync-android.json cat dist/inkwell-android.json
# The rolling channel for this branch, the same fixed-tag releases the desktop # The rolling channel for this branch, the same fixed-tag releases the desktop
# bundles use. CI artifacts are per-run and auth-gated, so they are no use as a # bundles use. CI artifacts are per-run and auth-gated, so they are no use as a
@@ -276,7 +276,7 @@ jobs:
with: with:
# The APK's variant, NOT the Cargo profile — those are the same word # The APK's variant, NOT the Cargo profile — those are the same word
# for different things and the profile is pinned to debug (#2810). # for different things and the profile is pinned to debug (#2810).
name: thoughtsync-android-${{ steps.build.outputs.label }}-${{ github.sha }} name: inkwell-android-${{ steps.build.outputs.label }}-${{ github.sha }}
path: ${{ steps.build.outputs.apk }} path: ${{ steps.build.outputs.apk }}
if-no-files-found: error if-no-files-found: error
+9 -6
View File
@@ -141,7 +141,7 @@ val rustInputs =
* build, and neither is worth holding signed APKs up for. Scribe #2810. * build, and neither is worth holding signed APKs up for. Scribe #2810.
*/ */
val rustProfile = val rustProfile =
(project.findProperty("THOUGHTSYNC_CARGO_PROFILE") as String?)?.takeIf { it.isNotBlank() } (project.findProperty("INKWELL_CARGO_PROFILE") as String?)?.takeIf { it.isNotBlank() }
?: "debug" ?: "debug"
val jniLibsOut = layout.buildDirectory.dir("rustJniLibs") val jniLibsOut = layout.buildDirectory.dir("rustJniLibs")
@@ -169,11 +169,11 @@ val generateBindings =
} }
android { android {
namespace = "com.fabledsword.thoughtsync" namespace = "com.fabledsword.inkwell"
compileSdk = 36 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "com.fabledsword.thoughtsync" applicationId = "com.fabledsword.inkwell"
// 26 (Android 8, 2017) matches Minstrel and clears the NDK's floor with // 26 (Android 8, 2017) matches Minstrel and clears the NDK's floor with
// room to spare. // room to spare.
minSdk = 26 minSdk = 26
@@ -181,9 +181,9 @@ android {
// Injected by CI from the git tag + commit count for a release; "dev" // Injected by CI from the git tag + commit count for a release; "dev"
// locally so the About screen reads honestly rather than claiming 1.0. // locally so the About screen reads honestly rather than claiming 1.0.
val nameOverride = val nameOverride =
(project.findProperty("THOUGHTSYNC_VERSION_NAME") as String?)?.takeIf { it.isNotBlank() } (project.findProperty("INKWELL_VERSION_NAME") as String?)?.takeIf { it.isNotBlank() }
val codeOverride = val codeOverride =
(project.findProperty("THOUGHTSYNC_VERSION_CODE") as String?)?.toIntOrNull() (project.findProperty("INKWELL_VERSION_CODE") as String?)?.toIntOrNull()
versionCode = codeOverride ?: 1 versionCode = codeOverride ?: 1
versionName = nameOverride ?: "dev" versionName = nameOverride ?: "dev"
@@ -215,7 +215,10 @@ android {
// Hardcoded, and NOT a secret: the alias is fixed for the life of // Hardcoded, and NOT a secret: the alias is fixed for the life of
// this app and is written into the certificate every install // this app and is written into the certificate every install
// already carries. Hiding it would buy nothing and stop this file // already carries. Hiding it would buy nothing and stop this file
// describing its own signing setup. // describing its own signing setup. It still says `thoughtsync`
// after the rename to Inkwell, because it names the key inside the
// existing keystore, and renaming it would only stop that key being
// found. Same key, so the signing certificate did not change either.
keyAlias = "thoughtsync" keyAlias = "thoughtsync"
// PKCS12 cannot hold a key password distinct from the store // PKCS12 cannot hold a key password distinct from the store
// password — keytool refuses to set one — so this is the same // password — keytool refuses to set one — so this is the same
+1 -1
View File
@@ -4,4 +4,4 @@
# is the worst possible time to learn it. # is the worst possible time to learn it.
-keep class com.sun.jna.** { *; } -keep class com.sun.jna.** { *; }
-keepclassmembers class * extends com.sun.jna.** { public *; } -keepclassmembers class * extends com.sun.jna.** { public *; }
-keep class com.fabledsword.thoughtsync.core.** { *; } -keep class com.fabledsword.inkwell.core.** { *; }
+3 -3
View File
@@ -91,13 +91,13 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application <application
android:name=".ThoughtSyncApplication" android:name=".InkwellApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.ThoughtSync" android:theme="@style/Theme.Inkwell"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<!-- <!--
launchMode="singleTop" exists for the SHARE filters below. launchMode="singleTop" exists for the SHARE filters below.
@@ -115,7 +115,7 @@
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.ThoughtSync"> android:theme="@style/Theme.Inkwell">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -42,7 +42,7 @@ import java.io.File
* [UpdateReceiver], which is why a failure can be shown rather than guessed at. * [UpdateReceiver], which is why a failure can be shown rather than guessed at.
*/ */
object AppUpdate { object AppUpdate {
private const val TAG = "ThoughtSyncUpdate" private const val TAG = "InkwellUpdate"
/** This build's versionCode — what the server's is compared against. */ /** This build's versionCode — what the server's is compared against. */
fun installedVersionCode(context: Context): Long = fun installedVersionCode(context: Context): Long =
@@ -173,5 +173,5 @@ object AppUpdate {
.intentSender .intentSender
} }
private const val WRITE_NAME = "thoughtsync-update" private const val WRITE_NAME = "inkwell-update"
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.Context import android.content.Context
@@ -1,9 +1,9 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.app.Application import android.app.Application
import android.util.Log import android.util.Log
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.Inkwell
import com.fabledsword.thoughtsync.core.setClientAgent import com.fabledsword.inkwell.core.setClientAgent
/** /**
* Opens the shared Rust core once, for the process lifetime. * Opens the shared Rust core once, for the process lifetime.
@@ -16,14 +16,14 @@ import com.fabledsword.thoughtsync.core.setClientAgent
* removed on uninstall, and never on external media. The core does not guess at * removed on uninstall, and never on external media. The core does not guess at
* platform paths; Android is the only thing that knows where this is. * platform paths; Android is the only thing that knows where this is.
*/ */
class ThoughtSyncApplication : Application() { class InkwellApplication : Application() {
/** /**
* Null only if the store could not be opened — a corrupt or unwritable * Null only if the store could not be opened — a corrupt or unwritable
* database. The UI reports that honestly rather than crashing on first * database. The UI reports that honestly rather than crashing on first
* touch, because a user whose notes won't open needs a message, not a * touch, because a user whose notes won't open needs a message, not a
* stack trace. * stack trace.
*/ */
var core: ThoughtSync? = null var core: Inkwell? = null
private set private set
var openFailure: String? = null var openFailure: String? = null
@@ -34,13 +34,13 @@ class ThoughtSyncApplication : Application() {
// Introduce this app to any server it links to, before anything can sync. // Introduce this app to any server it links to, before anything can sync.
// The core cannot name us — the same crate is compiled into the desktop app, // The core cannot name us — the same crate is compiled into the desktop app,
// and it used to announce every phone as `thoughtsync-desktop` carrying the // and it used to announce every phone as `inkwell-desktop` carrying the
// core crate's own version. "unknown" rather than a guess when the package // core crate's own version. "unknown" rather than a guess when the package
// manager will not say (note 3127 §5). // manager will not say (note 3127 §5).
setClientAgent("thoughtsync-android", installedVersionName() ?: "unknown") setClientAgent("inkwell-android", installedVersionName() ?: "unknown")
try { try {
val handle = ThoughtSync(filesDir.absolutePath) val handle = Inkwell(filesDir.absolutePath)
core = handle core = handle
Log.i(TAG, "local store ready — ${handle.summary()}") Log.i(TAG, "local store ready — ${handle.summary()}")
} catch (e: Exception) { } catch (e: Exception) {
@@ -53,6 +53,6 @@ class ThoughtSyncApplication : Application() {
} }
private companion object { private companion object {
const val TAG = "ThoughtSync" const val TAG = "Inkwell"
} }
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.Manifest import android.Manifest
import android.content.Intent import android.content.Intent
@@ -22,22 +22,22 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.Inkwell
import com.fabledsword.thoughtsync.ui.BoardScreen import com.fabledsword.inkwell.ui.BoardScreen
import com.fabledsword.thoughtsync.ui.BoardSync import com.fabledsword.inkwell.ui.BoardSync
import com.fabledsword.thoughtsync.ui.BoardUpdate import com.fabledsword.inkwell.ui.BoardUpdate
import com.fabledsword.thoughtsync.ui.BoardViewModel import com.fabledsword.inkwell.ui.BoardViewModel
import com.fabledsword.thoughtsync.ui.ForegroundTransitions import com.fabledsword.inkwell.ui.ForegroundTransitions
import com.fabledsword.thoughtsync.ui.NoteEditorScreen import com.fabledsword.inkwell.ui.InkwellTheme
import com.fabledsword.thoughtsync.ui.StoreUnavailableScreen import com.fabledsword.inkwell.ui.NoteEditorScreen
import com.fabledsword.thoughtsync.ui.SyncScreen import com.fabledsword.inkwell.ui.StoreUnavailableScreen
import com.fabledsword.thoughtsync.ui.SyncState import com.fabledsword.inkwell.ui.SyncScreen
import com.fabledsword.thoughtsync.ui.SyncViewModel import com.fabledsword.inkwell.ui.SyncState
import com.fabledsword.thoughtsync.ui.TagsScreen import com.fabledsword.inkwell.ui.SyncViewModel
import com.fabledsword.thoughtsync.ui.TagsViewModel import com.fabledsword.inkwell.ui.TagsScreen
import com.fabledsword.thoughtsync.ui.ThoughtSyncTheme import com.fabledsword.inkwell.ui.TagsViewModel
import com.fabledsword.thoughtsync.ui.UpdateViewModel import com.fabledsword.inkwell.ui.UpdateViewModel
import com.fabledsword.thoughtsync.ui.olderThan import com.fabledsword.inkwell.ui.olderThan
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -68,12 +68,12 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
val app = application as ThoughtSyncApplication val app = application as InkwellApplication
requestedNote.value = takeRequestedNote(intent) requestedNote.value = takeRequestedNote(intent)
sharedText.value = takeSharedText(intent) sharedText.value = takeSharedText(intent)
setContent { setContent {
ThoughtSyncTheme { InkwellTheme {
val core = app.core val core = app.core
if (core == null) { if (core == null) {
// The store never opened. There is no board to show and no // The store never opened. There is no board to show and no
@@ -174,7 +174,7 @@ private enum class Screen { BOARD, EDITOR, SYNC, TAGS }
*/ */
@Composable @Composable
private fun App( private fun App(
core: ThoughtSync, core: Inkwell,
requestedNote: MutableState<String?>, requestedNote: MutableState<String?>,
sharedText: MutableState<String?>, sharedText: MutableState<String?>,
) { ) {
@@ -360,7 +360,7 @@ private fun App(
* notifications this app would send — is spending it on nothing. * notifications this app would send — is spending it on nothing.
*/ */
@Composable @Composable
private fun ReminderAlarms(core: ThoughtSync) { private fun ReminderAlarms(core: Inkwell) {
val context = LocalContext.current val context = LocalContext.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
// Off the main thread: this reads every note that has a reminder, and a phone // Off the main thread: this reads every note that has a reminder, and a phone
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
@@ -8,7 +8,7 @@ import android.content.Intent
import android.util.Log import android.util.Log
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
/** /**
* What a due reminder looks like in the shade. * What a due reminder looks like in the shade.
@@ -117,5 +117,5 @@ internal object ReminderNotification {
) )
private const val CHANNEL = "reminders" private const val CHANNEL = "reminders"
private const val TAG = "ThoughtSyncReminders" private const val TAG = "InkwellReminders"
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
@@ -36,7 +36,7 @@ class ReminderReceiver : BroadcastReceiver() {
context: Context, context: Context,
intent: Intent, intent: Intent,
) { ) {
val core = (context.applicationContext as? ThoughtSyncApplication)?.core ?: return val core = (context.applicationContext as? InkwellApplication)?.core ?: return
val action = intent.action val action = intent.action
val noteId = intent.getStringExtra(Reminders.EXTRA_NOTE_ID) val noteId = intent.getStringExtra(Reminders.EXTRA_NOTE_ID)
val app = context.applicationContext val app = context.applicationContext
@@ -64,9 +64,9 @@ class ReminderReceiver : BroadcastReceiver() {
} }
companion object { companion object {
const val ACTION_DUE = "com.fabledsword.thoughtsync.REMINDER_DUE" const val ACTION_DUE = "com.fabledsword.inkwell.REMINDER_DUE"
const val ACTION_DONE = "com.fabledsword.thoughtsync.REMINDER_DONE" const val ACTION_DONE = "com.fabledsword.inkwell.REMINDER_DONE"
const val ACTION_SNOOZE = "com.fabledsword.thoughtsync.REMINDER_SNOOZE" const val ACTION_SNOOZE = "com.fabledsword.inkwell.REMINDER_SNOOZE"
private const val TAG = "ThoughtSyncReminders" private const val TAG = "InkwellReminders"
} }
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.app.AlarmManager import android.app.AlarmManager
import android.app.PendingIntent import android.app.PendingIntent
@@ -7,8 +7,8 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Inkwell
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.Note
import java.time.OffsetDateTime import java.time.OffsetDateTime
/** /**
@@ -52,7 +52,7 @@ object Reminders {
private const val MISSED_WINDOW_MS = 24L * 60 * 60 * 1000 private const val MISSED_WINDOW_MS = 24L * 60 * 60 * 1000
private const val SNOOZE_MINUTES = 60L private const val SNOOZE_MINUTES = 60L
private const val TAG = "ThoughtSyncReminders" private const val TAG = "InkwellReminders"
/** /**
* Announce what is due, then schedule the next one. * Announce what is due, then schedule the next one.
@@ -63,7 +63,7 @@ object Reminders {
*/ */
fun refresh( fun refresh(
context: Context, context: Context,
core: ThoughtSync, core: Inkwell,
) { ) {
ReminderNotification.ensureChannel(context) ReminderNotification.ensureChannel(context)
val notes = val notes =
@@ -111,7 +111,7 @@ object Reminders {
*/ */
fun promptToNotifyDue( fun promptToNotifyDue(
context: Context, context: Context,
core: ThoughtSync, core: Inkwell,
): Boolean = ): Boolean =
!Announced(context).askedToNotify && !Announced(context).askedToNotify &&
!NotificationManagerCompat.from(context).areNotificationsEnabled() && !NotificationManagerCompat.from(context).areNotificationsEnabled() &&
@@ -123,7 +123,7 @@ object Reminders {
/** Clear the reminder, as the notification's Done action. */ /** Clear the reminder, as the notification's Done action. */
fun complete( fun complete(
context: Context, context: Context,
core: ThoughtSync, core: Inkwell,
noteId: String, noteId: String,
) { ) {
runCatching { core.completeReminder(noteId) } runCatching { core.completeReminder(noteId) }
@@ -134,7 +134,7 @@ object Reminders {
/** Push the reminder an hour out, as the notification's Snooze action. */ /** Push the reminder an hour out, as the notification's Snooze action. */
fun snooze( fun snooze(
context: Context, context: Context,
core: ThoughtSync, core: Inkwell,
noteId: String, noteId: String,
) { ) {
runCatching { core.snoozeReminder(noteId, SNOOZE_MINUTES) } runCatching { core.snoozeReminder(noteId, SNOOZE_MINUTES) }
@@ -237,7 +237,7 @@ private class Announced(
fun markAsked() = prefs.edit().putBoolean(KEY_ASKED, true).apply() fun markAsked() = prefs.edit().putBoolean(KEY_ASKED, true).apply()
private companion object { private companion object {
const val FILE = "thoughtsync-reminders" const val FILE = "inkwell-reminders"
const val KEY_SEEN = "announced" const val KEY_SEEN = "announced"
const val KEY_PRIMED = "primed" const val KEY_PRIMED = "primed"
const val KEY_ASKED = "asked_to_notify" const val KEY_ASKED = "asked_to_notify"
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.Context import android.content.Context
import androidx.work.BackoffPolicy import androidx.work.BackoffPolicy
@@ -85,8 +85,8 @@ object SyncSchedule {
.setRequiredNetworkType(NetworkType.CONNECTED) .setRequiredNetworkType(NetworkType.CONNECTED)
.build() .build()
private const val PERIODIC = "thoughtsync-periodic-sync" private const val PERIODIC = "inkwell-periodic-sync"
private const val PUSH = "thoughtsync-push-pending" private const val PUSH = "inkwell-push-pending"
/** WorkManager's own minimum for periodic work. Asking for less gets this. */ /** WorkManager's own minimum for periodic work. Asking for less gets this. */
private const val PERIOD_MINUTES = 15L private const val PERIOD_MINUTES = 15L
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.Context import android.content.Context
@@ -38,7 +38,7 @@ class SyncSettings(
} }
private companion object { private companion object {
const val FILE = "thoughtsync-sync" const val FILE = "inkwell-sync"
const val KEY_AUTOMATIC = "automatic" const val KEY_AUTOMATIC = "automatic"
} }
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
@@ -8,7 +8,7 @@ import androidx.work.WorkerParameters
/** /**
* One sync cycle, run by the system rather than by a person. * One sync cycle, run by the system rather than by a person.
* *
* WorkManager may start the process to run this, which means [ThoughtSyncApplication.onCreate] * WorkManager may start the process to run this, which means [InkwellApplication.onCreate]
* has already opened the store by the time [doWork] is called — the same handle * has already opened the store by the time [doWork] is called — the same handle
* the UI uses, so there is never a second SQLite connection racing the first. * the UI uses, so there is never a second SQLite connection racing the first.
* *
@@ -30,7 +30,7 @@ class SyncWorker(
params: WorkerParameters, params: WorkerParameters,
) : CoroutineWorker(context, params) { ) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val core = (applicationContext as? ThoughtSyncApplication)?.core val core = (applicationContext as? InkwellApplication)?.core
// Both of these are "nothing to do", not "something went wrong", so both // Both of these are "nothing to do", not "something went wrong", so both
// report success and let the run retire quietly: // report success and let the run retire quietly:
@@ -67,6 +67,6 @@ class SyncWorker(
} }
private companion object { private companion object {
const val TAG = "ThoughtSyncWorker" const val TAG = "InkwellWorker"
} }
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync package com.fabledsword.inkwell
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
@@ -71,7 +71,7 @@ class UpdateReceiver : BroadcastReceiver() {
} }
companion object { companion object {
const val ACTION_INSTALLED = "com.fabledsword.thoughtsync.UPDATE_INSTALLED" const val ACTION_INSTALLED = "com.fabledsword.inkwell.UPDATE_INSTALLED"
private const val TAG = "ThoughtSyncUpdate" private const val TAG = "InkwellUpdate"
} }
} }
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -33,7 +33,7 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
/** /**
* The note's body, as fields and checkboxes rather than as markup. * The note's body, as fields and checkboxes rather than as markup.
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@@ -63,9 +63,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.Label import com.fabledsword.inkwell.core.Label
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -6,12 +6,12 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.fabledsword.thoughtsync.core.Label import com.fabledsword.inkwell.core.Inkwell
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Label
import com.fabledsword.thoughtsync.core.NoteDraft import com.fabledsword.inkwell.core.Note
import com.fabledsword.thoughtsync.core.NoteEdit import com.fabledsword.inkwell.core.NoteDraft
import com.fabledsword.thoughtsync.core.NoteQuery import com.fabledsword.inkwell.core.NoteEdit
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.NoteQuery
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -99,7 +99,7 @@ data class BoardState(
*/ */
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class BoardViewModel( class BoardViewModel(
private val core: ThoughtSync, private val core: Inkwell,
/** /**
* Called after any write that could have moved a reminder. * Called after any write that could have moved a reminder.
* *
@@ -482,7 +482,7 @@ class BoardViewModel(
*/ */
private fun mutate( private fun mutate(
closeEditor: Boolean = false, closeEditor: Boolean = false,
block: (ThoughtSync) -> Note?, block: (Inkwell) -> Note?,
) { ) {
viewModelScope.launch { viewModelScope.launch {
state = state.copy(saving = true) state = state.copy(saving = true)
@@ -547,7 +547,7 @@ class BoardViewModel(
private const val VIEW_TRASH = "trash" private const val VIEW_TRASH = "trash"
fun factory( fun factory(
core: ThoughtSync, core: Inkwell,
onRemindersChanged: () -> Unit, onRemindersChanged: () -> Unit,
): ViewModelProvider.Factory = ): ViewModelProvider.Factory =
object : ViewModelProvider.Factory { object : ViewModelProvider.Factory {
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
// The colour a LABEL wears when nobody picked one for it. // The colour a LABEL wears when nobody picked one for it.
// //
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
/** /**
* Everything the editor can ask for, as one type. * Everything the editor can ask for, as one type.
@@ -1,10 +1,10 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.saveable.Saver
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import com.fabledsword.thoughtsync.core.checklistItems import com.fabledsword.inkwell.core.checklistItems
import com.fabledsword.thoughtsync.core.checklistRender import com.fabledsword.inkwell.core.checklistRender
/** /**
* One piece of a note body, as the editor DRAWS it. * One piece of a note body, as the editor DRAWS it.
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import android.text.format.DateUtils import android.text.format.DateUtils
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -41,8 +41,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
/** /**
* The editor's action bar, along the top of the surface. * The editor's action bar, along the top of the surface.
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -36,9 +36,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.Label import com.fabledsword.inkwell.core.Label
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
import java.time.DayOfWeek import java.time.DayOfWeek
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@@ -16,7 +16,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
// Shared by the board and the editor. // Shared by the board and the editor.
// //
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.core.LinkPreview import com.fabledsword.inkwell.core.LinkPreview
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
private val PREVIEW_RADIUS = 8.dp private val PREVIEW_RADIUS = 8.dp
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@@ -38,12 +38,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.BodyItem import com.fabledsword.inkwell.core.BodyItem
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
import com.fabledsword.thoughtsync.core.NoteLabel import com.fabledsword.inkwell.core.NoteLabel
import com.fabledsword.thoughtsync.core.bodyTags import com.fabledsword.inkwell.core.bodyTags
import com.fabledsword.thoughtsync.core.checklistItems import com.fabledsword.inkwell.core.checklistItems
@Composable @Composable
fun NoteCard( fun NoteCard(
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
@@ -25,8 +25,8 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.core.Label import com.fabledsword.inkwell.core.Label
import com.fabledsword.thoughtsync.core.Note import com.fabledsword.inkwell.core.Note
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
/** /**
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.ReadOnlyComposable
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -20,7 +20,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
/** /**
* A bordered block, tinted from the same table the notes use. * A bordered block, tinted from the same table the notes use.
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import android.app.AlarmManager import android.app.AlarmManager
import android.content.Context import android.content.Context
@@ -17,8 +17,8 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.Reminders import com.fabledsword.inkwell.Reminders
/** /**
* Says so when a reminder would not actually reach anyone. * Says so when a reminder would not actually reach anyone.
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import android.os.Build import android.os.Build
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -27,9 +27,9 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.Compatibility import com.fabledsword.inkwell.core.Compatibility
import com.fabledsword.thoughtsync.core.RevokeOutcome import com.fabledsword.inkwell.core.RevokeOutcome
// Becoming linked: the probe-then-sign-in flow, and the notices around it. // Becoming linked: the probe-then-sign-in flow, and the notices around it.
// //
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -36,15 +36,15 @@ import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.UpdateOutcome import com.fabledsword.inkwell.UpdateOutcome
import com.fabledsword.thoughtsync.installedVersionName import com.fabledsword.inkwell.installedVersionName
/** /**
* Opt-in server pairing. * Opt-in server pairing.
* *
* The whole screen is written around one idea: **being unlinked is not a * The whole screen is written around one idea: **being unlinked is not a
* problem.** ThoughtSync is local-first and completely usable having never opened * problem.** Inkwell is local-first and completely usable having never opened
* this screen, so the unlinked state leads with "Working offline on this device" * this screen, so the unlinked state leads with "Working offline on this device"
* and explains what connecting would ADD, rather than presenting an empty form as * and explains what connecting would ADD, rather than presenting an empty form as
* unfinished setup. * unfinished setup.
@@ -1,11 +1,11 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.Compatibility import com.fabledsword.inkwell.core.Compatibility
import com.fabledsword.thoughtsync.core.SyncOutcome import com.fabledsword.inkwell.core.SyncOutcome
// Turning sync results into sentences. // Turning sync results into sentences.
// //
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -6,12 +6,12 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.fabledsword.thoughtsync.core.Compatibility import com.fabledsword.inkwell.core.Compatibility
import com.fabledsword.thoughtsync.core.ProbeResult import com.fabledsword.inkwell.core.Inkwell
import com.fabledsword.thoughtsync.core.RevokeOutcome import com.fabledsword.inkwell.core.ProbeResult
import com.fabledsword.thoughtsync.core.SyncOutcome import com.fabledsword.inkwell.core.RevokeOutcome
import com.fabledsword.thoughtsync.core.SyncStatus import com.fabledsword.inkwell.core.SyncOutcome
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.SyncStatus
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -113,7 +113,7 @@ data class SyncState(
* stored cursor next time (Scribe #2736). * stored cursor next time (Scribe #2736).
*/ */
class SyncViewModel( class SyncViewModel(
private val core: ThoughtSync, private val core: Inkwell,
/** /**
* Called after a sync that changed the store. * Called after a sync that changed the store.
* *
@@ -316,7 +316,7 @@ class SyncViewModel(
companion object { companion object {
fun factory( fun factory(
core: ThoughtSync, core: Inkwell,
onStoreChanged: () -> Unit, onStoreChanged: () -> Unit,
): ViewModelProvider.Factory = ): ViewModelProvider.Factory =
object : ViewModelProvider.Factory { object : ViewModelProvider.Factory {
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@@ -43,8 +43,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.core.Label import com.fabledsword.inkwell.core.Label
/** The swatch shown beside a tag, and tapped to change its colour. */ /** The swatch shown beside a tag, and tapped to change its colour. */
private val SWATCH = 22.dp private val SWATCH = 22.dp
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -6,8 +6,8 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.fabledsword.thoughtsync.core.Label import com.fabledsword.inkwell.core.Inkwell
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.Label
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -57,7 +57,7 @@ data class TagsState(
* the core marks the rows dirty and the next sync carries them. * the core marks the rows dirty and the next sync carries them.
*/ */
class TagsViewModel( class TagsViewModel(
private val core: ThoughtSync, private val core: Inkwell,
/** /**
* Called after any write that landed. * Called after any write that landed.
* *
@@ -140,7 +140,7 @@ class TagsViewModel(
* `busy` is cleared in the same assignment that stores the result, so no path * `busy` is cleared in the same assignment that stores the result, so no path
* out of here can leave the screen stuck with its controls disabled. * out of here can leave the screen stuck with its controls disabled.
*/ */
private fun write(block: (ThoughtSync) -> Unit) { private fun write(block: (Inkwell) -> Unit) {
if (state.busy) return if (state.busy) return
state = state.copy(busy = true, error = null) state = state.copy(busy = true, error = null)
viewModelScope.launch { viewModelScope.launch {
@@ -164,7 +164,7 @@ class TagsViewModel(
companion object { companion object {
fun factory( fun factory(
core: ThoughtSync, core: Inkwell,
onStoreChanged: () -> Unit, onStoreChanged: () -> Unit,
): ViewModelProvider.Factory = ): ViewModelProvider.Factory =
object : ViewModelProvider.Factory { object : ViewModelProvider.Factory {
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -59,7 +59,7 @@ private val DarkColors =
) )
/** /**
* Material 3 in ThoughtSync's own colours, following the system light/dark setting. * Material 3 in Inkwell's own colours, following the system light/dark setting.
* *
* DELIBERATELY NOT Material You dynamic colour, which this used until the operator * DELIBERATELY NOT Material You dynamic colour, which this used until the operator
* saw the first build. Dynamic colour is the more Android-native choice and it * saw the first build. Dynamic colour is the more Android-native choice and it
@@ -72,7 +72,7 @@ private val DarkColors =
* If dynamic colour is ever wanted it belongs behind a setting, not as the default. * If dynamic colour is ever wanted it belongs behind a setting, not as the default.
*/ */
@Composable @Composable
fun ThoughtSyncTheme( fun InkwellTheme(
darkTheme: Boolean = isSystemInDarkTheme(), darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.OffsetDateTime import java.time.OffsetDateTime
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
@@ -25,9 +25,9 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.fabledsword.thoughtsync.AppUpdate import com.fabledsword.inkwell.AppUpdate
import com.fabledsword.thoughtsync.R import com.fabledsword.inkwell.R
import com.fabledsword.thoughtsync.UpdateOutcome import com.fabledsword.inkwell.UpdateOutcome
/** /**
* Updating the app from the server it is linked to. * Updating the app from the server it is linked to.
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import android.content.Context import android.content.Context
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -7,10 +7,10 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.fabledsword.thoughtsync.AppUpdate import com.fabledsword.inkwell.AppUpdate
import com.fabledsword.thoughtsync.UpdateOutcome import com.fabledsword.inkwell.UpdateOutcome
import com.fabledsword.thoughtsync.core.ClientUpdate import com.fabledsword.inkwell.core.ClientUpdate
import com.fabledsword.thoughtsync.core.ThoughtSync import com.fabledsword.inkwell.core.Inkwell
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -61,7 +61,7 @@ data class UpdateState(
* secret this app holds across two languages for no gain. * secret this app holds across two languages for no gain.
*/ */
class UpdateViewModel( class UpdateViewModel(
private val core: ThoughtSync, private val core: Inkwell,
/** /**
* MUST be the application context — it outlives this view model, and holding an * MUST be the application context — it outlives this view model, and holding an
* Activity here is the textbook way to leak a window. * Activity here is the textbook way to leak a window.
@@ -207,7 +207,7 @@ class UpdateViewModel(
companion object { companion object {
fun factory( fun factory(
core: ThoughtSync, core: Inkwell,
context: Context, context: Context,
): ViewModelProvider.Factory = ): ViewModelProvider.Factory =
object : ViewModelProvider.Factory { object : ViewModelProvider.Factory {
+1 -1
View File
@@ -2,6 +2,6 @@
<resources> <resources>
<!-- The product's brand colour, same value the web app's manifest and <!-- The product's brand colour, same value the web app's manifest and
<meta name="theme-color"> already use. One source of truth for "what <meta name="theme-color"> already use. One source of truth for "what
colour is ThoughtSync" across the three surfaces. --> colour is Inkwell" across the three surfaces. -->
<color name="ic_launcher_background">#F5C518</color> <color name="ic_launcher_background">#F5C518</color>
</resources> </resources>
+1 -1
View File
@@ -6,5 +6,5 @@
truth in XML — the same reason the desktop reads its live theme rather truth in XML — the same reason the desktop reads its live theme rather
than hardcoding a window colour. than hardcoding a window colour.
--> -->
<style name="Theme.ThoughtSync" parent="android:Theme.Material.NoActionBar" /> <style name="Theme.Inkwell" parent="android:Theme.Material.NoActionBar" />
</resources> </resources>
@@ -1,4 +1,4 @@
package com.fabledsword.thoughtsync.ui package com.fabledsword.inkwell.ui
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotEquals
+1 -1
View File
@@ -74,7 +74,7 @@ exceptions:
# right and still applies. # right and still applies.
excludes: excludes:
- "**/ui/**" - "**/ui/**"
- "**/ThoughtSyncApplication.kt" - "**/InkwellApplication.kt"
- "**/SyncWorker.kt" - "**/SyncWorker.kt"
- "**/ReminderReceiver.kt" - "**/ReminderReceiver.kt"
- "**/AppUpdate.kt" - "**/AppUpdate.kt"
+19 -19
View File
@@ -7,7 +7,7 @@
//! //!
//! ## Shape //! ## Shape
//! //!
//! One `ThoughtSync` object holds the store and the blob directory, mirroring how //! One `Inkwell` object holds the store and the blob directory, mirroring how
//! Tauri manages them as app state. Kotlin constructs it once, keeps it for the //! Tauri manages them as app state. Kotlin constructs it once, keeps it for the
//! process lifetime, and calls methods on it. //! process lifetime, and calls methods on it.
//! //!
@@ -108,13 +108,13 @@ impl CoreError {
/// behind its mutex, the blob store being a path — which is what lets uniffi share /// behind its mutex, the blob store being a path — which is what lets uniffi share
/// one instance across coroutines. /// one instance across coroutines.
#[derive(uniffi::Object)] #[derive(uniffi::Object)]
pub struct ThoughtSync { pub struct Inkwell {
db: Db, db: Db,
blobs: BlobStore, blobs: BlobStore,
} }
#[uniffi::export] #[uniffi::export]
impl ThoughtSync { impl Inkwell {
/// Open (creating on first run) the store under `data_dir`, and the attachment /// Open (creating on first run) the store under `data_dir`, and the attachment
/// directory beside it. /// directory beside it.
/// ///
@@ -131,7 +131,7 @@ impl ThoughtSync {
log::info!("local store ready — {}", local::summary(&db)); log::info!("local store ready — {}", local::summary(&db));
let blobs = BlobStore::new(dir.join("blobs")).map_err(CoreError::store)?; let blobs = BlobStore::new(dir.join("blobs")).map_err(CoreError::store)?;
Ok(Arc::new(ThoughtSync { db, blobs })) Ok(Arc::new(Inkwell { db, blobs }))
} }
/// A one-line count summary, for the boot log. /// A one-line count summary, for the boot log.
@@ -413,7 +413,7 @@ impl ThoughtSync {
/// functions. Split into its own impl block so the runtime attribute — and the fact /// functions. Split into its own impl block so the runtime attribute — and the fact
/// that everything in here touches the network — is visible at a glance. /// that everything in here touches the network — is visible at a glance.
#[uniffi::export(async_runtime = "tokio")] #[uniffi::export(async_runtime = "tokio")]
impl ThoughtSync { impl Inkwell {
/// Ask a server who it is, without committing to anything. Called as the user /// Ask a server who it is, without committing to anything. Called as the user
/// finishes typing an address, so they see what answered before handing over /// finishes typing an address, so they see what answered before handing over
/// credentials. /// credentials.
@@ -525,7 +525,7 @@ impl ThoughtSync {
/// ///
/// Takes the destination rather than choosing one: only Android knows a /// Takes the destination rather than choosing one: only Android knows a
/// directory its own package installer can read from, and the core has no /// directory its own package installer can read from, and the core has no
/// business guessing at platform paths — the same reason `ThoughtSync::new` /// business guessing at platform paths — the same reason `Inkwell::new`
/// takes a data dir. /// takes a data dir.
pub async fn download_client_update(&self, dest_path: String) -> Result<(), CoreError> { pub async fn download_client_update(&self, dest_path: String) -> Result<(), CoreError> {
let (base_url, token) = self.credentials()?; let (base_url, token) = self.credentials()?;
@@ -587,7 +587,7 @@ pub fn checklist_render(text: String, checked: bool) -> String {
/// stamps and nobody has seen. The honest value is the installed package's own /// stamps and nobody has seen. The honest value is the installed package's own
/// `versionName`, which is what Kotlin passes here. /// `versionName`, which is what Kotlin passes here.
/// ///
/// Called once from `ThoughtSyncApplication.onCreate`, before anything can sync. /// Called once from `InkwellApplication.onCreate`, before anything can sync.
#[uniffi::export] #[uniffi::export]
pub fn set_client_agent(name: String, version: String) { pub fn set_client_agent(name: String, version: String) {
compat::set_client_agent(&name, &version); compat::set_client_agent(&name, &version);
@@ -620,7 +620,7 @@ pub fn body_tags(body: String) -> Vec<BodyTag> {
/// Helpers, deliberately NOT exported — uniffi only binds what an `#[uniffi::export]` /// Helpers, deliberately NOT exported — uniffi only binds what an `#[uniffi::export]`
/// block names, so these stay Rust-side. /// block names, so these stay Rust-side.
impl ThoughtSync { impl Inkwell {
/// Apply a `{text}` or `{checked}` patch to one checklist item. /// Apply a `{text}` or `{checked}` patch to one checklist item.
/// ///
/// The two public setters differ only in the key they write, and the lock + /// The two public setters differ only in the key they write, and the lock +
@@ -701,7 +701,7 @@ mod tests {
#[test] #[test]
fn creates_a_store_and_round_trips_a_note() { fn creates_a_store_and_round_trips_a_note() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let created = app let created = app
.create_note(draft("Groceries\nmilk")) .create_note(draft("Groceries\nmilk"))
@@ -723,7 +723,7 @@ mod tests {
#[test] #[test]
fn a_note_is_named_by_its_first_line() { fn a_note_is_named_by_its_first_line() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let created = app let created = app
.create_note(draft("just a thought")) .create_note(draft("just a thought"))
@@ -738,7 +738,7 @@ mod tests {
#[test] #[test]
fn a_note_with_only_items_is_named_by_its_first_item() { fn a_note_with_only_items_is_named_by_its_first_item() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let created = app let created = app
.create_note(NoteDraft { .create_note(NoteDraft {
@@ -757,7 +757,7 @@ mod tests {
#[test] #[test]
fn syncing_unlinked_reports_not_linked() { fn syncing_unlinked_reports_not_linked() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let status = app.sync_status().expect("status should read"); let status = app.sync_status().expect("status should read");
assert!(!status.linked); assert!(!status.linked);
@@ -774,7 +774,7 @@ mod tests {
#[test] #[test]
fn checklist_items_can_be_added_ticked_retitled_and_removed() { fn checklist_items_can_be_added_ticked_retitled_and_removed() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let note = app let note = app
.create_note(NoteDraft { .create_note(NoteDraft {
body: "Packing".to_string(), body: "Packing".to_string(),
@@ -828,7 +828,7 @@ mod tests {
#[test] #[test]
fn setting_labels_leaves_tag_derived_ones_alone() { fn setting_labels_leaves_tag_derived_ones_alone() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let note = app let note = app
.create_note(draft("Trip\nbook the ferry #travel")) .create_note(draft("Trip\nbook the ferry #travel"))
@@ -869,7 +869,7 @@ mod tests {
#[test] #[test]
fn deleting_forever_removes_the_note() { fn deleting_forever_removes_the_note() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let note = app.create_note(draft("Ephemeral\nbody")).expect("create"); let note = app.create_note(draft("Ephemeral\nbody")).expect("create");
app.delete_note_forever(note.id.clone()) app.delete_note_forever(note.id.clone())
@@ -886,7 +886,7 @@ mod tests {
#[test] #[test]
fn reminders_can_be_snoozed_and_completed() { fn reminders_can_be_snoozed_and_completed() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let note = app.create_note(draft("Call back")).expect("create"); let note = app.create_note(draft("Call back")).expect("create");
assert_eq!(note.remind_at, None); assert_eq!(note.remind_at, None);
@@ -912,7 +912,7 @@ mod tests {
#[test] #[test]
fn completing_a_recurring_reminder_moves_it_rather_than_ending_it() { fn completing_a_recurring_reminder_moves_it_rather_than_ending_it() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let note = app.create_note(draft("Water the plants")).expect("create"); let note = app.create_note(draft("Water the plants")).expect("create");
let armed = app let armed = app
@@ -974,7 +974,7 @@ mod tests {
#[test] #[test]
fn renaming_onto_an_existing_tag_merges_into_the_older_one() { fn renaming_onto_an_existing_tag_merges_into_the_older_one() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let older = app.create_label("grocery".to_string()).expect("older"); let older = app.create_label("grocery".to_string()).expect("older");
// `created_at` is RFC3339 to the MILLISECOND. Without a gap the two rows can // `created_at` is RFC3339 to the MILLISECOND. Without a gap the two rows can
@@ -1019,7 +1019,7 @@ mod tests {
#[test] #[test]
fn the_rename_merge_survivor_does_not_depend_on_the_direction() { fn the_rename_merge_survivor_does_not_depend_on_the_direction() {
let dir = scratch_dir(); let dir = scratch_dir();
let app = ThoughtSync::new(dir.clone()).expect("a fresh data dir should open"); let app = Inkwell::new(dir.clone()).expect("a fresh data dir should open");
let older = app.create_label("grocery".to_string()).expect("older"); let older = app.create_label("grocery".to_string()).expect("older");
std::thread::sleep(std::time::Duration::from_millis(5)); std::thread::sleep(std::time::Duration::from_millis(5));
+2 -2
View File
@@ -1,5 +1,5 @@
# Where the generated Kotlin lands. Matches the app's package so the bindings are # Where the generated Kotlin lands. Matches the app's package so the bindings are
# `com.fabledsword.thoughtsync.core.*` rather than something the app has to alias. # `com.fabledsword.inkwell.core.*` rather than something the app has to alias.
[bindings.kotlin] [bindings.kotlin]
package_name = "com.fabledsword.thoughtsync.core" package_name = "com.fabledsword.inkwell.core"
cdylib_name = "inkwell_ffi" cdylib_name = "inkwell_ffi"
+1 -1
View File
@@ -18,7 +18,7 @@ dependencyResolutionManagement {
mavenCentral() mavenCentral()
} }
} }
rootProject.name = "ThoughtSync" rootProject.name = "Inkwell"
// `ffi/` sits beside `app/` but is deliberately NOT a Gradle module: it is a Rust // `ffi/` sits beside `app/` but is deliberately NOT a Gradle module: it is a Rust
// crate belonging to the Cargo workspace at the repo root. Gradle reaches it by // crate belonging to the Cargo workspace at the repo root. Gradle reaches it by
+2 -2
View File
@@ -72,8 +72,8 @@ ASSETS=(
"$BUNDLE_ROOT"/arch/*.pkg.tar.* "$BUNDLE_ROOT"/arch/*.pkg.tar.*
"$WIN_BUNDLE_ROOT"/nsis/*.exe "$WIN_BUNDLE_ROOT"/nsis/*.exe
"$WIN_BUNDLE_ROOT"/nsis/*.exe.sig "$WIN_BUNDLE_ROOT"/nsis/*.exe.sig
"$REPO_ROOT"/android/dist/thoughtsync.apk "$REPO_ROOT"/android/dist/inkwell.apk
"$REPO_ROOT"/android/dist/thoughtsync-android.json "$REPO_ROOT"/android/dist/inkwell-android.json
) )
# nullglob drops PATTERNS that match nothing — it does nothing for a path with no # nullglob drops PATTERNS that match nothing — it does nothing for a path with no
# wildcard in it, which stays in the array as a literal and reaches curl as a file # wildcard in it, which stays in the array as a literal and reaches curl as a file
+1 -1
View File
@@ -229,7 +229,7 @@ if [ "${PRUNE_OLD_ASSETS:-false}" = "true" ]; then
# every desktop push regardless. That is exactly what happened on run # every desktop push regardless. That is exactly what happened on run
# 4098, which swept the APK run 4092 had just published. # 4098, which swept the APK run 4092 had just published.
case "$asset_name" in case "$asset_name" in
latest.json|inkwell-desktop.json|thoughtsync.apk|thoughtsync-android.json) continue ;; latest.json|inkwell-desktop.json|inkwell.apk|inkwell-android.json) continue ;;
*"$APP_VERSION"*) continue ;; *"$APP_VERSION"*) continue ;;
esac esac
echo " removing $asset_name" echo " removing $asset_name"
+2 -2
View File
@@ -88,8 +88,8 @@ echo "==> Collecting the $channel clients"
# Its sidecar is published whole by the Android lane — an APK keeps its version in # Its sidecar is published whole by the Android lane — an APK keeps its version in
# a binary AXML manifest, so the values are recorded where they were already known. # a binary AXML manifest, so the values are recorded where they were already known.
# Copied verbatim rather than rebuilt here. # Copied verbatim rather than rebuilt here.
if fetch "$BASE/thoughtsync.apk" "$dest/inkwell.apk" && if fetch "$BASE/inkwell.apk" "$dest/inkwell.apk" &&
fetch "$BASE/thoughtsync-android.json" "$dest/inkwell-android.json"; then fetch "$BASE/inkwell-android.json" "$dest/inkwell-android.json"; then
echo " android $(field "$dest/inkwell-android.json" version_name)" echo " android $(field "$dest/inkwell-android.json" version_name)"
else else
# Both or neither. Half a pair is worse than none: the server would read a # Both or neither. Half a pair is worse than none: the server would read a
+2 -2
View File
@@ -110,7 +110,7 @@ published_for() {
| sed -E 's/.*"([^"]+)"$/\1/'; } || true | sed -E 's/.*"([^"]+)"$/\1/'; } || true
;; ;;
android) android)
{ fetch "$SERVER/$REPO/releases/download/$_tag/thoughtsync-android.json" \ { fetch "$SERVER/$REPO/releases/download/$_tag/inkwell-android.json" \
| grep -oE '"version_code"[[:space:]]*:[[:space:]]*[0-9]+' | head -1 \ | grep -oE '"version_code"[[:space:]]*:[[:space:]]*[0-9]+' | head -1 \
| grep -oE '[0-9]+$'; } || true | grep -oE '[0-9]+$'; } || true
;; ;;
@@ -126,7 +126,7 @@ published_name() {
case "$1" in case "$1" in
desktop) published_for desktop "$2" ;; desktop) published_for desktop "$2" ;;
android) android)
{ fetch "$SERVER/$REPO/releases/download/$_tag/thoughtsync-android.json" \ { fetch "$SERVER/$REPO/releases/download/$_tag/inkwell-android.json" \
| grep -oE '"version_name"[[:space:]]*:[[:space:]]*"[^"]+"' | head -1 \ | grep -oE '"version_name"[[:space:]]*:[[:space:]]*"[^"]+"' | head -1 \
| sed -E 's/.*"([^"]+)"$/\1/'; } || true | sed -E 's/.*"([^"]+)"$/\1/'; } || true
;; ;;