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:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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.** { *; }
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
+3
-3
@@ -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
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.fabledsword.thoughtsync
|
package com.fabledsword.inkwell
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
|
||||||
+9
-9
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+21
-21
@@ -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
|
||||||
+3
-3
@@ -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"
|
||||||
}
|
}
|
||||||
+6
-6
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+9
-9
@@ -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"
|
||||||
+3
-3
@@ -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
|
||||||
+2
-2
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-4
@@ -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
-1
@@ -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
|
||||||
+3
-3
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -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.
|
||||||
+4
-4
@@ -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
|
||||||
+10
-10
@@ -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
-1
@@ -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
-1
@@ -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.
|
||||||
+3
-3
@@ -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.
|
||||||
+3
-3
@@ -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.
|
||||||
+4
-4
@@ -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
|
||||||
+2
-2
@@ -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
-1
@@ -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
-1
@@ -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
|
||||||
+3
-3
@@ -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
|
||||||
|
|
||||||
+7
-7
@@ -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(
|
||||||
+3
-3
@@ -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
-1
@@ -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
|
||||||
+2
-2
@@ -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
-1
@@ -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
|
||||||
+3
-3
@@ -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.
|
||||||
+4
-4
@@ -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.
|
||||||
//
|
//
|
||||||
+5
-5
@@ -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.
|
||||||
+4
-4
@@ -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.
|
||||||
//
|
//
|
||||||
+9
-9
@@ -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 {
|
||||||
+3
-3
@@ -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
|
||||||
+6
-6
@@ -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 {
|
||||||
+3
-3
@@ -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
-1
@@ -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
|
||||||
+4
-4
@@ -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.
|
||||||
+7
-7
@@ -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 {
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
-1
@@ -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
|
||||||
@@ -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
@@ -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));
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user