Compare commits
13 Commits
v1,0
...
4adca319be
| Author | SHA1 | Date | |
|---|---|---|---|
| 4adca319be | |||
| 1d31556923 | |||
| 628a28a775 | |||
| fca3ea6f60 | |||
| 68deb5cb3e | |||
| edd2c1745f | |||
| 4597f92d93 | |||
| a37ef4a794 | |||
| 905e618d20 | |||
| 415742b974 | |||
| a6af2fe5b9 | |||
| 23df95dacf | |||
| 16a18be9e3 |
22
.claude/settings.local.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(\"C:\\\\Users\\\\moses\\\\projects\\\\synq\\\\venv\\\\Scripts\\\\pip.exe\" install *)",
|
||||
"Bash(\"C:\\\\Users\\\\moses\\\\projects\\\\synq\\\\venv\\\\Scripts\\\\python.exe\" -m pytest tests/ -v)",
|
||||
"Bash(git add *)",
|
||||
"Bash(git commit -m ' *)",
|
||||
"Bash(/synq/venv/bin/python -m pytest /synq/.claude/worktrees/serene-mclean-b76496/server/tests/ -v)",
|
||||
"Read(//c/mnt/**)",
|
||||
"Read(//proc/**)",
|
||||
"Read(//c/Users/moses/projects/synq/venv/Scripts//**)",
|
||||
"Read(//c/Users/moses/projects/synq/venv/**)",
|
||||
"Bash(/c/Users/moses/projects/synq/venv/Scripts/python.exe -m pytest tests/ -v)",
|
||||
"Bash(ls \"/c/Users/moses/AppData/Local/Android/Sdk/platforms/\" 2>/dev/null && echo \"FOUND at AppData/Local/Android/Sdk\")",
|
||||
"Bash(/c/Users/moses/projects/synq/venv/Scripts/python.exe -m pytest tests/ -q)",
|
||||
"Bash(git stash *)",
|
||||
"Bash(git merge *)",
|
||||
"Bash(git push *)",
|
||||
"Bash(git commit *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,9 @@
|
||||
android:theme="@style/Theme.Synq"
|
||||
android:allowBackup="true"
|
||||
android:supportsRtl="true"
|
||||
android:usesCleartextTraffic="true">
|
||||
|
||||
android:usesCleartextTraffic="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
||||
BIN
android/app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
@@ -22,7 +22,6 @@ class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
||||
val sharedText = if (intent.action == Intent.ACTION_SEND)
|
||||
intent.getStringExtra(Intent.EXTRA_TEXT) else null
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.hgsky.synq.data
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
@@ -28,7 +29,7 @@ class SettingsRepository(private val context: Context) {
|
||||
SynqSettings(
|
||||
serverUrl = prefs[KEY_URL] ?: "http://jeeves.mother:8765",
|
||||
token = prefs[KEY_TOKEN] ?: "",
|
||||
deviceLabel = prefs[KEY_DEVICE] ?: "android",
|
||||
deviceLabel = prefs[KEY_DEVICE] ?: Build.MODEL,
|
||||
syncIntervalMinutes = prefs[KEY_INTERVAL] ?: 15,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ import me.hgsky.synq.data.db.CaptureDao
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
suspend fun syncPending(dao: CaptureDao, client: SynqApiClient, settings: SynqSettings) {
|
||||
suspend fun syncPending(dao: CaptureDao, client: SynqApiClient, settings: SynqSettings): Int {
|
||||
val pending = dao.getPendingAndFailed()
|
||||
var synced = 0
|
||||
for (capture in pending) {
|
||||
dao.updateStatus(capture.id, "syncing", null)
|
||||
val result = client.postCapture(capture, settings)
|
||||
@@ -16,8 +17,10 @@ suspend fun syncPending(dao: CaptureDao, client: SynqApiClient, settings: SynqSe
|
||||
is PostResult.Accepted, is PostResult.AlreadySeen -> {
|
||||
val now = OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
|
||||
dao.markSynced(capture.id, now)
|
||||
synced++
|
||||
}
|
||||
is PostResult.Failed -> dao.updateStatus(capture.id, "failed", result.error)
|
||||
}
|
||||
}
|
||||
return synced
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -29,6 +30,8 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
@@ -61,9 +64,13 @@ fun CaptureScreen(
|
||||
val recentTags by vm.recentTags.collectAsState()
|
||||
val lastSyncedAt by vm.lastSyncedAt.collectAsState()
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val snackbarState = remember { SnackbarHostState() }
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||
LaunchedEffect(Unit) {
|
||||
vm.snackbar.collect { msg -> snackbarState.showSnackbar(msg) }
|
||||
}
|
||||
LaunchedEffect(prefill) {
|
||||
if (!prefill.isNullOrEmpty()) vm.setBody(prefill)
|
||||
}
|
||||
@@ -82,6 +89,7 @@ fun CaptureScreen(
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
snackbarHost = { SnackbarHost(snackbarState) },
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("synq") },
|
||||
@@ -113,6 +121,7 @@ fun CaptureScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
.imePadding()
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
|
||||
@@ -4,9 +4,11 @@ import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -37,6 +39,9 @@ class CaptureViewModel(app: Application) : AndroidViewModel(app) {
|
||||
private val _state = MutableStateFlow(CaptureUiState())
|
||||
val state: StateFlow<CaptureUiState> = _state.asStateFlow()
|
||||
|
||||
private val _snackbar = MutableSharedFlow<String>(extraBufferCapacity = 1)
|
||||
val snackbar = _snackbar.asSharedFlow()
|
||||
|
||||
val recentTags: StateFlow<List<String>> = dao.getRecentTagsJson()
|
||||
.map { jsonList ->
|
||||
val seen = LinkedHashSet<String>()
|
||||
@@ -93,9 +98,12 @@ class CaptureViewModel(app: Application) : AndroidViewModel(app) {
|
||||
try {
|
||||
val settings = synqApp.settings.settings.first()
|
||||
val client = SynqApiClient()
|
||||
if (client.checkHealth(settings.serverUrl)) {
|
||||
syncPending(dao, client, settings)
|
||||
if (!client.checkHealth(settings.serverUrl)) {
|
||||
_snackbar.tryEmit("server unreachable")
|
||||
return@launch
|
||||
}
|
||||
val synced = syncPending(dao, client, settings)
|
||||
_snackbar.tryEmit(if (synced == 0) "nothing to sync" else "synced $synced")
|
||||
} finally {
|
||||
_state.value = _state.value.copy(isSyncing = false)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
package me.hgsky.synq.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
@Composable
|
||||
fun SynqTheme(content: @Composable () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val colorScheme = dynamicLightColorScheme(context)
|
||||
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
// light theme → dark icons so clock/battery/wifi are visible on light TopAppBar
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = true
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(colorScheme = colorScheme, content = content)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:fillColor="#22569d" android:pathData="M0,0h108v108h-108z"/>
|
||||
</vector>
|
||||
48
android/app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<!--
|
||||
~ Copyright (C) 2026 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="m189.14,130.52h133.72c7.25,0 13.08,5.83 13.08,13.08v220.93c0,7.25 -5.83,13.08 -13.08,13.08H189.14c-7.25,0 -13.08,-5.83 -13.08,-13.08V143.6c0,-7.25 5.83,-13.08 13.08,-13.08z"
|
||||
android:strokeWidth="2.90698"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m222.27,361.68h66.86c1.61,0 2.91,1.3 2.91,2.91 0,1.61 -1.3,2.91 -2.91,2.91h-66.86c-1.61,0 -2.91,-1.3 -2.91,-2.91 0,-1.61 1.3,-2.91 2.91,-2.91z"
|
||||
android:strokeWidth="2.90698"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M193.63,145.03H318.63c1.61,0 2.91,1.3 2.91,2.91v197.67c0,1.61 -1.3,2.91 -2.91,2.91H193.63c-1.61,0 -2.91,-1.3 -2.91,-2.91V147.94c0,-1.61 1.3,-2.91 2.91,-2.91z"
|
||||
android:strokeWidth="2.90698"
|
||||
android:fillColor="#22569d"
|
||||
android:strokeColor="#000000"/>
|
||||
<path
|
||||
android:pathData="m210.25,196.07h-11.2v-42.2h11.2v3.18h-7.43v35.84h7.43zM241.81,186.76h-5.11l-7.22,-11.99 -7.24,11.99h-5.04l9.88,-15.17 -9.08,-14.51h4.79l6.79,11.17 6.84,-11.17h4.66l-9.11,14.33zM260.1,196.07h-11.2v-3.18h7.38v-35.84h-7.38v-3.18h11.2zM280.54,179.61q0.77,0 1.45,0.3 0.7,0.3 1.2,0.82 0.52,0.52 0.82,1.23 0.3,0.68 0.3,1.48 0,0.77 -0.3,1.45 -0.3,0.68 -0.82,1.2 -0.5,0.5 -1.2,0.79 -0.68,0.3 -1.45,0.3 -0.79,0 -1.48,-0.3 -0.68,-0.3 -1.2,-0.79 -0.5,-0.52 -0.79,-1.2 -0.3,-0.68 -0.3,-1.45 0,-0.79 0.3,-1.48 0.3,-0.7 0.79,-1.23 0.52,-0.52 1.2,-0.82 0.68,-0.3 1.48,-0.3zM306.11,179.61q0.77,0 1.45,0.3 0.7,0.3 1.2,0.82 0.52,0.52 0.82,1.23 0.3,0.68 0.3,1.48 0,0.77 -0.3,1.45 -0.3,0.68 -0.82,1.2 -0.5,0.5 -1.2,0.79 -0.68,0.3 -1.45,0.3 -0.79,0 -1.48,-0.3 -0.68,-0.3 -1.2,-0.79 -0.5,-0.52 -0.79,-1.2 -0.3,-0.68 -0.3,-1.45 0,-0.79 0.3,-1.48 0.3,-0.7 0.79,-1.23 0.52,-0.52 1.2,-0.82 0.68,-0.3 1.48,-0.3z"
|
||||
android:strokeWidth="0.726744"
|
||||
android:fillColor="#00e219"/>
|
||||
<path
|
||||
android:pathData="m210.25,256.17h-11.2L199.05,213.98h11.2v3.18h-7.43v35.84h7.43zM241.81,246.86h-5.11l-7.22,-11.99 -7.24,11.99h-5.04l9.88,-15.17 -9.08,-14.51h4.79l6.79,11.17 6.84,-11.17h4.66l-9.11,14.33zM260.1,256.17h-11.2v-3.18h7.38v-35.84h-7.38v-3.18h11.2zM280.54,239.71q0.77,0 1.45,0.3 0.7,0.3 1.2,0.82 0.52,0.52 0.82,1.23 0.3,0.68 0.3,1.48 0,0.77 -0.3,1.45 -0.3,0.68 -0.82,1.2 -0.5,0.5 -1.2,0.79 -0.68,0.3 -1.45,0.3 -0.79,0 -1.48,-0.3 -0.68,-0.3 -1.2,-0.79 -0.5,-0.52 -0.79,-1.2 -0.3,-0.68 -0.3,-1.45 0,-0.79 0.3,-1.48 0.3,-0.7 0.79,-1.23 0.52,-0.52 1.2,-0.82 0.68,-0.3 1.48,-0.3zM306.11,239.71q0.77,0 1.45,0.3 0.7,0.3 1.2,0.82 0.52,0.52 0.82,1.23 0.3,0.68 0.3,1.48 0,0.77 -0.3,1.45 -0.3,0.68 -0.82,1.2 -0.5,0.5 -1.2,0.79 -0.68,0.3 -1.45,0.3 -0.79,0 -1.48,-0.3 -0.68,-0.3 -1.2,-0.79 -0.5,-0.52 -0.79,-1.2 -0.3,-0.68 -0.3,-1.45 0,-0.79 0.3,-1.48 0.3,-0.7 0.79,-1.23 0.52,-0.52 1.2,-0.82 0.68,-0.3 1.48,-0.3z"
|
||||
android:strokeWidth="0.726744"
|
||||
android:fillColor="#00e219"/>
|
||||
<path
|
||||
android:pathData="m210.25,316.28h-11.2v-42.2h11.2v3.18h-7.43v35.84h7.43zM260.1,316.28h-11.2v-3.18h7.38v-35.84h-7.38v-3.18h11.2zM280.54,299.81q0.77,0 1.45,0.3 0.7,0.3 1.2,0.82 0.52,0.52 0.82,1.23 0.3,0.68 0.3,1.48 0,0.77 -0.3,1.45 -0.3,0.68 -0.82,1.2 -0.5,0.5 -1.2,0.79 -0.68,0.3 -1.45,0.3 -0.79,0 -1.48,-0.3 -0.68,-0.3 -1.2,-0.79 -0.5,-0.52 -0.79,-1.2 -0.3,-0.68 -0.3,-1.45 0,-0.79 0.3,-1.48 0.3,-0.7 0.79,-1.23 0.52,-0.52 1.2,-0.82 0.68,-0.3 1.48,-0.3zM306.11,299.81q0.77,0 1.45,0.3 0.7,0.3 1.2,0.82 0.52,0.52 0.82,1.23 0.3,0.68 0.3,1.48 0,0.77 -0.3,1.45 -0.3,0.68 -0.82,1.2 -0.5,0.5 -1.2,0.79 -0.68,0.3 -1.45,0.3 -0.79,0 -1.48,-0.3 -0.68,-0.3 -1.2,-0.79 -0.5,-0.52 -0.79,-1.2 -0.3,-0.68 -0.3,-1.45 0,-0.79 0.3,-1.48 0.3,-0.7 0.79,-1.23 0.52,-0.52 1.2,-0.82 0.68,-0.3 1.48,-0.3z"
|
||||
android:strokeWidth="0.726744"
|
||||
android:fillColor="#00e219"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 916 B |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
86
logo/icon-512.svg
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title4">synq</title>
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
id="layer1">
|
||||
<rect
|
||||
style="display:inline;fill:#22569d;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect5"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="0.95533592"
|
||||
rx="96"
|
||||
ry="96" />
|
||||
<path
|
||||
id="rect6"
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:2.90698"
|
||||
d="m 189.13953,130.52304 h 133.72094 c 7.24709,0 13.08139,5.8343 13.08139,13.0814 v 220.93022 c 0,7.2471 -5.8343,13.0814 -13.08139,13.0814 H 189.13953 c -7.24709,0 -13.08139,-5.8343 -13.08139,-13.0814 V 143.60444 c 0,-7.2471 5.8343,-13.0814 13.08139,-13.0814 z" />
|
||||
<path
|
||||
id="rect8"
|
||||
style="display:inline;stroke:#000000;stroke-width:2.90698"
|
||||
d="m 222.26527,361.685 h 66.86046 c 1.61047,0 2.90698,1.29651 2.90698,2.90697 0,1.61047 -1.29651,2.90698 -2.90698,2.90698 h -66.86046 c -1.61047,0 -2.90698,-1.29651 -2.90698,-2.90698 0,-1.61046 1.29651,-2.90697 2.90698,-2.90697 z" />
|
||||
<path
|
||||
id="rect9"
|
||||
style="display:inline;fill:#22569d;stroke:#000000;stroke-width:2.90698"
|
||||
d="M 193.63011,145.02974 H 318.6301 c 1.61047,0 2.90698,1.29651 2.90698,2.90698 v 197.67442 c 0,1.61046 -1.29651,2.90697 -2.90698,2.90697 H 193.63011 c -1.61047,0 -2.90698,-1.29651 -2.90698,-2.90697 V 147.93672 c 0,-1.61047 1.29651,-2.90698 2.90698,-2.90698 z" />
|
||||
<g
|
||||
id="text10"
|
||||
style="font-size:46.5116px;line-height:1.25;letter-spacing:0px;word-spacing:0px;stroke-width:0.726744"
|
||||
aria-label="[X].. [X].. [ ].. ">
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;fill:#00e219"
|
||||
d="m 210.24567,196.0705 h -11.1964 v -42.19656 h 11.1964 v 3.1795 h -7.42642 v 35.83755 h 7.42642 z m 31.56793,-9.31141 h -5.10992 l -7.22201,-11.99127 -7.24473,11.99127 h -5.04178 l 9.87917,-15.17077 -9.0843,-14.51217 h 4.79197 l 6.79051,11.17369 6.83593,-11.17369 h 4.65571 l -9.10701,14.33048 z m 18.28215,9.31141 h -11.1964 v -3.17951 h 7.38099 v -35.83755 h -7.38099 v -3.1795 h 11.1964 z m 20.43967,-16.46529 q 0.77216,0 1.45348,0.29524 0.70404,0.29524 1.20367,0.81759 0.52235,0.52234 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68132 -0.81759,1.20367 -0.49963,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49964,-0.52235 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70404 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29524 1.4762,-0.29524 z m 25.57229,0 q 0.77217,0 1.45349,0.29524 0.70403,0.29524 1.20367,0.81759 0.52235,0.52234 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68132 -0.81759,1.20367 -0.49964,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49963,-0.52235 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70404 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29524 1.4762,-0.29524 z"
|
||||
id="path16" />
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;fill:#00e219"
|
||||
d="m 210.24567,256.17276 h -11.1964 V 213.9762 h 11.1964 v 3.17951 h -7.42642 v 35.83755 h 7.42642 z m 31.56793,-9.3114 h -5.10992 l -7.22201,-11.99128 -7.24473,11.99128 h -5.04178 l 9.87917,-15.17078 -9.0843,-14.51216 h 4.79197 l 6.79051,11.17368 6.83593,-11.17368 h 4.65571 l -9.10701,14.33047 z m 18.28215,9.3114 h -11.1964 v -3.1795 h 7.38099 v -35.83755 h -7.38099 v -3.17951 h 11.1964 z m 20.43967,-16.46529 q 0.77216,0 1.45348,0.29524 0.70404,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68133 -0.81759,1.20367 -0.49963,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49964,-0.52234 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29524 1.4762,-0.29524 z m 25.57229,0 q 0.77217,0 1.45349,0.29524 0.70403,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68133 -0.81759,1.20367 -0.49964,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49963,-0.52234 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29524 1.4762,-0.29524 z"
|
||||
id="path17" />
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;display:inline;fill:#00e219"
|
||||
d="m 210.24567,316.27502 h -11.1964 v -42.19656 h 11.1964 v 3.17951 h -7.42642 v 35.83755 h 7.42642 z m 49.85008,0 h -11.1964 v -3.1795 h 7.38099 v -35.83755 h -7.38099 v -3.17951 h 11.1964 z m 20.43967,-16.46528 q 0.77216,0 1.45348,0.29523 0.70404,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77217 -0.29524,1.45349 -0.29524,0.68132 -0.81759,1.20367 -0.49963,0.49963 -1.20367,0.79487 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79487 -0.49964,-0.52235 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45349 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29523 1.4762,-0.29523 z m 25.57229,0 q 0.77217,0 1.45349,0.29523 0.70403,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77217 -0.29524,1.45349 -0.29524,0.68132 -0.81759,1.20367 -0.49964,0.49963 -1.20367,0.79487 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79487 -0.49963,-0.52235 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45349 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29523 1.4762,-0.29523 z"
|
||||
id="path18" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="layer2"
|
||||
style="display:none;opacity:0.355">
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect15"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="0" />
|
||||
<circle
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15"
|
||||
cx="256"
|
||||
cy="256"
|
||||
r="256" />
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>synq</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
86
logo/icon-fg-512.svg
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title4">synq</title>
|
||||
<defs
|
||||
id="defs1" />
|
||||
<g
|
||||
id="layer1">
|
||||
<rect
|
||||
style="display:none;fill:#22569d;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect5"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="0.95533592"
|
||||
rx="96"
|
||||
ry="96" />
|
||||
<path
|
||||
id="rect6"
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:2.90698"
|
||||
d="m 189.13953,130.52304 h 133.72094 c 7.24709,0 13.08139,5.8343 13.08139,13.0814 v 220.93022 c 0,7.2471 -5.8343,13.0814 -13.08139,13.0814 H 189.13953 c -7.24709,0 -13.08139,-5.8343 -13.08139,-13.0814 V 143.60444 c 0,-7.2471 5.8343,-13.0814 13.08139,-13.0814 z" />
|
||||
<path
|
||||
id="rect8"
|
||||
style="display:inline;stroke:#000000;stroke-width:2.90698"
|
||||
d="m 222.26527,361.685 h 66.86046 c 1.61047,0 2.90698,1.29651 2.90698,2.90697 0,1.61047 -1.29651,2.90698 -2.90698,2.90698 h -66.86046 c -1.61047,0 -2.90698,-1.29651 -2.90698,-2.90698 0,-1.61046 1.29651,-2.90697 2.90698,-2.90697 z" />
|
||||
<path
|
||||
id="rect9"
|
||||
style="display:inline;fill:#22569d;stroke:#000000;stroke-width:2.90698"
|
||||
d="M 193.63011,145.02974 H 318.6301 c 1.61047,0 2.90698,1.29651 2.90698,2.90698 v 197.67442 c 0,1.61046 -1.29651,2.90697 -2.90698,2.90697 H 193.63011 c -1.61047,0 -2.90698,-1.29651 -2.90698,-2.90697 V 147.93672 c 0,-1.61047 1.29651,-2.90698 2.90698,-2.90698 z" />
|
||||
<g
|
||||
id="text10"
|
||||
style="font-size:46.5116px;line-height:1.25;letter-spacing:0px;word-spacing:0px;stroke-width:0.726744"
|
||||
aria-label="[X].. [X].. [ ].. ">
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;fill:#00e219"
|
||||
d="m 210.24567,196.0705 h -11.1964 v -42.19656 h 11.1964 v 3.1795 h -7.42642 v 35.83755 h 7.42642 z m 31.56793,-9.31141 h -5.10992 l -7.22201,-11.99127 -7.24473,11.99127 h -5.04178 l 9.87917,-15.17077 -9.0843,-14.51217 h 4.79197 l 6.79051,11.17369 6.83593,-11.17369 h 4.65571 l -9.10701,14.33048 z m 18.28215,9.31141 h -11.1964 v -3.17951 h 7.38099 v -35.83755 h -7.38099 v -3.1795 h 11.1964 z m 20.43967,-16.46529 q 0.77216,0 1.45348,0.29524 0.70404,0.29524 1.20367,0.81759 0.52235,0.52234 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68132 -0.81759,1.20367 -0.49963,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49964,-0.52235 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70404 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29524 1.4762,-0.29524 z m 25.57229,0 q 0.77217,0 1.45349,0.29524 0.70403,0.29524 1.20367,0.81759 0.52235,0.52234 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68132 -0.81759,1.20367 -0.49964,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49963,-0.52235 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70404 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29524 1.4762,-0.29524 z"
|
||||
id="path16" />
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;fill:#00e219"
|
||||
d="m 210.24567,256.17276 h -11.1964 V 213.9762 h 11.1964 v 3.17951 h -7.42642 v 35.83755 h 7.42642 z m 31.56793,-9.3114 h -5.10992 l -7.22201,-11.99128 -7.24473,11.99128 h -5.04178 l 9.87917,-15.17078 -9.0843,-14.51216 h 4.79197 l 6.79051,11.17368 6.83593,-11.17368 h 4.65571 l -9.10701,14.33047 z m 18.28215,9.3114 h -11.1964 v -3.1795 h 7.38099 v -35.83755 h -7.38099 v -3.17951 h 11.1964 z m 20.43967,-16.46529 q 0.77216,0 1.45348,0.29524 0.70404,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68133 -0.81759,1.20367 -0.49963,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49964,-0.52234 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29524 1.4762,-0.29524 z m 25.57229,0 q 0.77217,0 1.45349,0.29524 0.70403,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68133 -0.81759,1.20367 -0.49964,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49963,-0.52234 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29524 1.4762,-0.29524 z"
|
||||
id="path17" />
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;display:inline;fill:#00e219"
|
||||
d="m 210.24567,316.27502 h -11.1964 v -42.19656 h 11.1964 v 3.17951 h -7.42642 v 35.83755 h 7.42642 z m 49.85008,0 h -11.1964 v -3.1795 h 7.38099 v -35.83755 h -7.38099 v -3.17951 h 11.1964 z m 20.43967,-16.46528 q 0.77216,0 1.45348,0.29523 0.70404,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77217 -0.29524,1.45349 -0.29524,0.68132 -0.81759,1.20367 -0.49963,0.49963 -1.20367,0.79487 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79487 -0.49964,-0.52235 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45349 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29523 1.4762,-0.29523 z m 25.57229,0 q 0.77217,0 1.45349,0.29523 0.70403,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77217 -0.29524,1.45349 -0.29524,0.68132 -0.81759,1.20367 -0.49964,0.49963 -1.20367,0.79487 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79487 -0.49963,-0.52235 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45349 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29523 1.4762,-0.29523 z"
|
||||
id="path18" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="layer2"
|
||||
style="display:none;opacity:0.355">
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect15"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="0" />
|
||||
<circle
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15"
|
||||
cx="256"
|
||||
cy="256"
|
||||
r="256" />
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>synq</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
155
logo/icon.svg
Normal file
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
|
||||
sodipodi:docname="icon.svg"
|
||||
inkscape:export-filename="icon-fg-512.svg"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title4">synq</title>
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
showgrid="true"
|
||||
inkscape:zoom="1.4803312"
|
||||
inkscape:cx="260.07693"
|
||||
inkscape:cy="252.98392"
|
||||
inkscape:window-width="1620"
|
||||
inkscape:window-height="1068"
|
||||
inkscape:window-x="1935"
|
||||
inkscape:window-y="192"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1">
|
||||
<inkscape:grid
|
||||
id="grid1"
|
||||
units="px"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingx="4.2333333"
|
||||
spacingy="4.2333333"
|
||||
empcolor="#3f3fff"
|
||||
empopacity="0.25098039"
|
||||
color="#3f3fff"
|
||||
opacity="0.1254902"
|
||||
empspacing="5"
|
||||
enabled="true"
|
||||
visible="true"
|
||||
dotted="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1">
|
||||
<inkscape:path-effect
|
||||
effect="fillet_chamfer"
|
||||
id="path-effect5"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
|
||||
radius="0"
|
||||
unit="px"
|
||||
method="auto"
|
||||
mode="F"
|
||||
chamfer_steps="1"
|
||||
flexible="false"
|
||||
use_knot_distance="true"
|
||||
apply_no_radius="true"
|
||||
apply_with_radius="true"
|
||||
only_selected="false"
|
||||
hide_knots="false" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="icon"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="display:none;fill:#22569d;fill-opacity:1;stroke-width:1.00157;stroke-dasharray:none"
|
||||
id="rect5"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="0.95533592"
|
||||
rx="96"
|
||||
ry="96"
|
||||
inkscape:label="bg" />
|
||||
<path
|
||||
id="rect6"
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:2.90698"
|
||||
inkscape:label="phone"
|
||||
d="m 189.13953,130.52304 h 133.72094 c 7.24709,0 13.08139,5.8343 13.08139,13.0814 v 220.93022 c 0,7.2471 -5.8343,13.0814 -13.08139,13.0814 H 189.13953 c -7.24709,0 -13.08139,-5.8343 -13.08139,-13.0814 V 143.60444 c 0,-7.2471 5.8343,-13.0814 13.08139,-13.0814 z" />
|
||||
<path
|
||||
id="rect8"
|
||||
style="display:inline;stroke:#000000;stroke-width:2.90698"
|
||||
inkscape:label="phone-navbar"
|
||||
d="m 222.26527,361.685 h 66.86046 c 1.61047,0 2.90698,1.29651 2.90698,2.90697 0,1.61047 -1.29651,2.90698 -2.90698,2.90698 h -66.86046 c -1.61047,0 -2.90698,-1.29651 -2.90698,-2.90698 0,-1.61046 1.29651,-2.90697 2.90698,-2.90697 z" />
|
||||
<path
|
||||
id="rect9"
|
||||
style="display:inline;fill:#22569d;stroke:#000000;stroke-width:2.90698"
|
||||
inkscape:label="phone-screen"
|
||||
d="M 193.63011,145.02974 H 318.6301 c 1.61047,0 2.90698,1.29651 2.90698,2.90698 v 197.67442 c 0,1.61046 -1.29651,2.90697 -2.90698,2.90697 H 193.63011 c -1.61047,0 -2.90698,-1.29651 -2.90698,-2.90697 V 147.93672 c 0,-1.61047 1.29651,-2.90698 2.90698,-2.90698 z" />
|
||||
<g
|
||||
id="text10"
|
||||
style="font-size:46.5116px;line-height:1.25;letter-spacing:0px;word-spacing:0px;stroke-width:0.726744"
|
||||
aria-label="[X].. [X].. [ ].. ">
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;fill:#00e219"
|
||||
d="m 210.24567,196.0705 h -11.1964 v -42.19656 h 11.1964 v 3.1795 h -7.42642 v 35.83755 h 7.42642 z m 31.56793,-9.31141 h -5.10992 l -7.22201,-11.99127 -7.24473,11.99127 h -5.04178 l 9.87917,-15.17077 -9.0843,-14.51217 h 4.79197 l 6.79051,11.17369 6.83593,-11.17369 h 4.65571 l -9.10701,14.33048 z m 18.28215,9.31141 h -11.1964 v -3.17951 h 7.38099 v -35.83755 h -7.38099 v -3.1795 h 11.1964 z m 20.43967,-16.46529 q 0.77216,0 1.45348,0.29524 0.70404,0.29524 1.20367,0.81759 0.52235,0.52234 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68132 -0.81759,1.20367 -0.49963,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49964,-0.52235 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70404 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29524 1.4762,-0.29524 z m 25.57229,0 q 0.77217,0 1.45349,0.29524 0.70403,0.29524 1.20367,0.81759 0.52235,0.52234 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68132 -0.81759,1.20367 -0.49964,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49963,-0.52235 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70404 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29524 1.4762,-0.29524 z"
|
||||
id="path16" />
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;fill:#00e219"
|
||||
d="m 210.24567,256.17276 h -11.1964 V 213.9762 h 11.1964 v 3.17951 h -7.42642 v 35.83755 h 7.42642 z m 31.56793,-9.3114 h -5.10992 l -7.22201,-11.99128 -7.24473,11.99128 h -5.04178 l 9.87917,-15.17078 -9.0843,-14.51216 h 4.79197 l 6.79051,11.17368 6.83593,-11.17368 h 4.65571 l -9.10701,14.33047 z m 18.28215,9.3114 h -11.1964 v -3.1795 h 7.38099 v -35.83755 h -7.38099 v -3.17951 h 11.1964 z m 20.43967,-16.46529 q 0.77216,0 1.45348,0.29524 0.70404,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68133 -0.81759,1.20367 -0.49963,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49964,-0.52234 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29524 1.4762,-0.29524 z m 25.57229,0 q 0.77217,0 1.45349,0.29524 0.70403,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77216 -0.29524,1.45348 -0.29524,0.68133 -0.81759,1.20367 -0.49964,0.49964 -1.20367,0.79488 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79488 -0.49963,-0.52234 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45348 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29524 1.4762,-0.29524 z"
|
||||
id="path17" />
|
||||
<path
|
||||
style="font-family:Consolas;-inkscape-font-specification:Consolas;display:inline;fill:#00e219"
|
||||
d="m 210.24567,316.27502 h -11.1964 v -42.19656 h 11.1964 v 3.17951 h -7.42642 v 35.83755 h 7.42642 z m 49.85008,0 h -11.1964 v -3.1795 h 7.38099 v -35.83755 h -7.38099 v -3.17951 h 11.1964 z m 20.43967,-16.46528 q 0.77216,0 1.45348,0.29523 0.70404,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77217 -0.29524,1.45349 -0.29524,0.68132 -0.81759,1.20367 -0.49963,0.49963 -1.20367,0.79487 -0.68132,0.29524 -1.45348,0.29524 -0.79488,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79487 -0.49964,-0.52235 -0.79488,-1.20367 -0.29524,-0.68132 -0.29524,-1.45349 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79488,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68132,-0.29523 1.4762,-0.29523 z m 25.57229,0 q 0.77217,0 1.45349,0.29523 0.70403,0.29524 1.20367,0.81759 0.52235,0.52235 0.81759,1.22638 0.29524,0.68132 0.29524,1.4762 0,0.77217 -0.29524,1.45349 -0.29524,0.68132 -0.81759,1.20367 -0.49964,0.49963 -1.20367,0.79487 -0.68132,0.29524 -1.45349,0.29524 -0.79487,0 -1.4762,-0.29524 -0.68132,-0.29524 -1.20367,-0.79487 -0.49963,-0.52235 -0.79487,-1.20367 -0.29524,-0.68132 -0.29524,-1.45349 0,-0.79488 0.29524,-1.4762 0.29524,-0.70403 0.79487,-1.22638 0.52235,-0.52235 1.20367,-0.81759 0.68133,-0.29523 1.4762,-0.29523 z"
|
||||
id="path18" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="circle-mask"
|
||||
style="display:none;opacity:0.355">
|
||||
<rect
|
||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect15"
|
||||
width="512"
|
||||
height="512"
|
||||
x="0"
|
||||
y="0" />
|
||||
<circle
|
||||
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15"
|
||||
cx="256"
|
||||
cy="256"
|
||||
r="256" />
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>synq</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
@@ -17,7 +17,10 @@ logger = logging.getLogger("synq")
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(_: FastAPI):
|
||||
_load_token()
|
||||
token = _load_token()
|
||||
logger.info("=" * 60)
|
||||
logger.info("synq token: %s", token)
|
||||
logger.info("=" * 60)
|
||||
yield
|
||||
|
||||
|
||||
@@ -45,7 +48,7 @@ def _load_token() -> str:
|
||||
logger.info("synq token loaded from %s", token_file)
|
||||
return _token_cache
|
||||
|
||||
generated = secrets.token_hex(32)
|
||||
generated = _generate_passphrase()
|
||||
token_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
token_file.write_text(generated)
|
||||
logger.info("")
|
||||
@@ -58,6 +61,72 @@ def _load_token() -> str:
|
||||
return _token_cache
|
||||
|
||||
|
||||
def _generate_passphrase(words: int = 3) -> str:
|
||||
wordlist = [
|
||||
"able","acid","aged","also","area","army","away","baby","back","ball",
|
||||
"band","bank","base","bath","bear","beat","been","bell","best","bill",
|
||||
"bird","blow","blue","bold","bolt","bone","book","born","both","bowl",
|
||||
"bulk","burn","calm","came","card","care","cart","case","cash","cast",
|
||||
"cave","cell","chat","chip","city","clam","clay","clip","club","coal",
|
||||
"coat","code","coil","cold","come","cook","cool","cope","cord","core",
|
||||
"corn","cost","cove","crew","crop","curl","dare","dark","data","date",
|
||||
"dawn","days","dead","deal","dean","dear","deck","deep","deer","deft",
|
||||
"deny","desk","dial","diet","disc","dish","disk","dive","dock","dome",
|
||||
"door","dose","down","draw","drew","drip","drop","drum","dual","dusk",
|
||||
"dust","duty","each","earn","ease","east","edge","else","even","ever",
|
||||
"evil","exam","fact","fail","fair","fall","fame","farm","fast","fate",
|
||||
"feed","feel","feet","fell","felt","file","fill","film","find","fire",
|
||||
"firm","fish","fist","flag","flat","flew","flip","flow","foam","fold",
|
||||
"folk","fond","font","food","foot","ford","fork","form","fort","free",
|
||||
"from","fuel","full","fund","fuse","gain","game","gaze","gear","give",
|
||||
"glad","glow","glue","goal","gold","golf","gone","good","grab","gray",
|
||||
"grid","grim","grip","grow","gulf","gust","hack","hail","half","hall",
|
||||
"halt","hand","hang","hard","harm","harp","hash","haul","have","hawk",
|
||||
"head","heal","heap","heat","heel","held","helm","help","herb","here",
|
||||
"hide","high","hill","hint","hold","hole","home","hook","hope","horn",
|
||||
"host","hour","hull","hunt","hurt","icon","idea","idle","inch","into",
|
||||
"iris","iron","isle","item","jade","jail","jazz","jest","join","jump",
|
||||
"just","keen","keep","kelp","kern","keys","kick","kill","kind","king",
|
||||
"knit","know","lack","lake","lamp","land","lane","lark","lash","last",
|
||||
"late","lead","leaf","lean","leap","left","lend","lens","life","lift",
|
||||
"like","lime","line","link","lion","list","live","load","loan","lock",
|
||||
"loft","long","look","loop","lore","loss","loud","love","luck","lung",
|
||||
"lure","mail","main","make","male","malt","many","mark","mask","mast",
|
||||
"math","maze","meal","mean","meet","melt","mesh","mild","milk","mill",
|
||||
"mind","mine","mint","miss","mist","mode","moon","more","moss","most",
|
||||
"move","much","mule","must","nail","name","navy","near","neat","need",
|
||||
"nest","news","next","nice","node","none","noon","norm","note","null",
|
||||
"numb","oath","obey","odds","once","only","open","oral","over","pace",
|
||||
"pack","page","paid","pain","pair","palm","park","part","pass","past",
|
||||
"path","pave","peak","peel","peer","pick","pier","pile","pine","pipe",
|
||||
"plan","play","plea","plot","plow","plum","plunge","plus","poem","poet",
|
||||
"pole","poll","pond","pool","port","pose","post","pour","prey","pull",
|
||||
"pump","pure","push","quit","race","rack","raid","rail","rain","ramp",
|
||||
"rang","rank","rare","rate","read","real","reed","reel","rely","rent",
|
||||
"rest","rice","rich","ride","ring","rise","risk","road","roam","roar",
|
||||
"rock","role","roll","roof","root","rope","rose","rout","rule","rush",
|
||||
"rust","safe","sage","sail","salt","same","sand","sang","save","scan",
|
||||
"seal","seam","seed","seek","self","sell","send","sent","shed","ship",
|
||||
"shop","shot","show","shut","sick","side","sign","silk","sing","sink",
|
||||
"site","size","skip","slab","slam","slap","slim","slip","slot","slow",
|
||||
"snap","snow","soak","soar","sock","soil","sold","sole","some","song",
|
||||
"soon","sort","soul","soup","span","spin","spit","spot","spur","star",
|
||||
"stay","stem","step","stop","stub","such","suit","sunk","sure","surf",
|
||||
"swap","swim","tail","take","talk","tall","tank","tape","task","team",
|
||||
"tell","tend","tent","term","test","text","than","then","thin","tide",
|
||||
"tile","time","tint","tiny","tips","tire","toad","told","toll","tomb",
|
||||
"tool","tops","toss","tour","town","trap","tree","trim","trip","trod",
|
||||
"true","tube","tuck","tune","turf","turn","twin","type","upon","used",
|
||||
"vary","vast","veil","vein","very","vest","view","vine","void","volt",
|
||||
"vote","wade","wake","walk","wall","wand","ward","warm","warp","wary",
|
||||
"wave","ways","weld","well","went","west","what","when","wide","wiki",
|
||||
"wild","will","wind","wine","wire","wise","wish","with","wolf","wood",
|
||||
"word","work","worn","wrap","wren","yard","year","yell","your","zero",
|
||||
"zest","zinc","zone","zoom",
|
||||
]
|
||||
return "-".join(secrets.choice(wordlist) for _ in range(words))
|
||||
|
||||
|
||||
|
||||
def get_store() -> IdempotencyStore:
|
||||
global _store
|
||||
|
||||
82
tasks.org
@@ -471,6 +471,88 @@ SynqSettings gained syncIntervalMinutes: Int = 15 field with DataStore key sync_
|
||||
- tests: manual — change interval to 30, save, verify WorkManager re-queues (check adb shell dumpsys jobscheduler)
|
||||
- datetime: [2026-05-18 Sun 20:00]
|
||||
|
||||
* milestone 6: post-ship cleanup
|
||||
** DONE fix resource XML comment before <?xml declaration
|
||||
*** acceptance
|
||||
- android build succeeds with custom icon assets.
|
||||
*** notes
|
||||
Android's AAPT resource compiler requires <?xml to be the first byte of the file. Image Asset tool generated ic_launcher_background.xml, ic_launcher.xml, and ic_launcher_round.xml with an Apache license comment block before <?xml, causing ParseError at row 16. Fixed by stripping the comment from those three files. ic_launcher_foreground.xml was unaffected (no <?xml declaration). Do not use Image Asset tool for tweaks — it re-adds the comment on reimport; edit XML directly.
|
||||
*** evidence
|
||||
- commit: a6af2fe
|
||||
- tests: manual — gradle assembleDebug succeeds
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE fix manifest missing icon references
|
||||
*** acceptance
|
||||
- app icon appears on device launcher after install.
|
||||
*** notes
|
||||
AndroidManifest.xml was missing android:icon and android:roundIcon attributes on the <application> element. Added @mipmap/ic_launcher and @mipmap/ic_launcher_round. Also committed all mipmap-* webp files and drawable/ic_launcher_background.xml (solid #22569d) and ic_launcher_foreground.xml generated by Image Asset tool.
|
||||
*** evidence
|
||||
- commit: a6af2fe
|
||||
- tests: manual — install APK on device, verify icon appears in launcher
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE fix status bar icons washed out (API 35 edge-to-edge)
|
||||
*** acceptance
|
||||
- system clock, battery, wifi icons are visible over the app TopAppBar.
|
||||
*** notes
|
||||
Android 15 (API 35) enforces edge-to-edge regardless of enableEdgeToEdge() call — removing it had no effect. Real fix: keep enableEdgeToEdge() in MainActivity and add a SideEffect in Theme.kt that calls WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = true. This tells the system to render dark (visible) status bar icons on the light TopAppBar background.
|
||||
*** evidence
|
||||
- commit: 68deb5c
|
||||
- tests: manual — open app, verify clock/battery/wifi icons are dark and readable
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE fix keyboard covering Save button
|
||||
*** acceptance
|
||||
- Save and Save & Close buttons are visible above the software keyboard.
|
||||
*** notes
|
||||
Added imePadding() to the Column modifier in CaptureScreen. The column shrinks to fit above the keyboard rather than being obscured by it.
|
||||
*** evidence
|
||||
- commit: 23df95d
|
||||
- tests: manual — tap body field, keyboard opens, verify save buttons remain visible
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE add sync result snackbar
|
||||
*** acceptance
|
||||
- brief snackbar appears after tapping sync: "synced N", "nothing to sync", or "server unreachable".
|
||||
*** notes
|
||||
Added MutableSharedFlow<String> snackbar emitter to CaptureViewModel. syncNow() now calls checkHealth() first and emits "server unreachable" on failure. syncPending() return type changed from Unit to Int (count of successfully synced captures). SnackbarHost added to CaptureScreen Scaffold; LaunchedEffect collects the flow and calls snackbarState.showSnackbar().
|
||||
*** evidence
|
||||
- commit: 4597f92
|
||||
- tests: manual — tap sync with server up (see "synced N"), with server down (see "server unreachable"), with empty queue (see "nothing to sync")
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE log token on every server startup
|
||||
*** acceptance
|
||||
- token is clearly visible in container logs on every start, not just first run.
|
||||
*** notes
|
||||
lifespan() in server/app/main.py now logs the token between === lines on every startup. Previously only logged "token loaded from token.txt" quietly; now logs the token value itself so it's easy to find with docker logs synq.
|
||||
*** evidence
|
||||
- commit: a6af2fe
|
||||
- tests: manual — docker restart synq, docker logs synq | grep token
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE default device label to Build.MODEL
|
||||
*** acceptance
|
||||
- fresh install shows the actual device model name, not "android".
|
||||
*** notes
|
||||
SettingsRepository.kt: changed deviceLabel fallback from hardcoded "android" to Build.MODEL. No permissions needed. Existing users who have already saved a label are unaffected — DataStore only uses the fallback when no value is stored.
|
||||
*** evidence
|
||||
- commit: 628a28a
|
||||
- tests: manual — fresh install, open settings, verify device label shows model name
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
** DONE replace hex token with 3-word passphrase
|
||||
*** acceptance
|
||||
- generated token is human-readable and fits on one log line.
|
||||
- existing token.txt files are unaffected.
|
||||
*** notes
|
||||
secrets.token_hex(32) produced 64 chars — too long to read/verify visually. Replaced with _generate_passphrase() which picks 3 words from a 512-word embedded list using secrets.choice, hyphenated (e.g. "coral-drift-lamp"). ~27 bits entropy, sufficient for a LAN-only service. Existing token.txt files load unchanged — generation only runs when no token exists. To rotate: delete /data/token.txt and restart the container.
|
||||
*** evidence
|
||||
- commit: 628a28a
|
||||
- tests: manual — delete token.txt, restart container, docker logs synq shows short readable token
|
||||
- datetime: [2026-05-19 Mon]
|
||||
|
||||
* implementation notes for coding agents
|
||||
- keep the server small and testable.
|
||||
- keep org formatting in one pure function.
|
||||
|
||||