Compare commits
20 Commits
v0.0.30
...
f1ced31f69
Author | SHA1 | Date | |
---|---|---|---|
f1ced31f69 | |||
b3cedf2baa | |||
3bf19fabda | |||
cf81ebe8ad | |||
278b5566a1 | |||
e8c1390f09 | |||
3c04abda45 | |||
2597f99ccf | |||
9d3a07c1cf | |||
bdfd8925b5 | |||
1a4d1985f4 | |||
6273f3ea53 | |||
5bdc6fa471 | |||
3ba41291db | |||
0867811952 | |||
8d961cd805 | |||
97cea7b40b | |||
4106834db8 | |||
a4a8f7cab2 | |||
9e209ee800 |
33
GNUmakefile
33
GNUmakefile
@@ -16,9 +16,9 @@ MAKEFLAGS += --no-builtin-rules
|
|||||||
## LD := Linker.
|
## LD := Linker.
|
||||||
## ANDROID_SDK := Path to the Android SDK.
|
## ANDROID_SDK := Path to the Android SDK.
|
||||||
|
|
||||||
VERSION_CODE := 35
|
VERSION_CODE := 37
|
||||||
VERSION_CODE_IOS := 12
|
VERSION_CODE_IOS := 13
|
||||||
VERSION_NUMBER := 0.0.30
|
VERSION_NUMBER := 0.0.31-wip
|
||||||
VERSION_NAME := This program kills fascists.
|
VERSION_NAME := This program kills fascists.
|
||||||
|
|
||||||
IPHONEOS_VERSION_MIN=14.0
|
IPHONEOS_VERSION_MIN=14.0
|
||||||
@@ -614,15 +614,16 @@ $(UV_OBJS): CFLAGS += \
|
|||||||
-Ideps/libuv/include \
|
-Ideps/libuv/include \
|
||||||
-Ideps/libuv/src \
|
-Ideps/libuv/src \
|
||||||
-Wno-dangling-pointer \
|
-Wno-dangling-pointer \
|
||||||
|
-Wno-format-truncation \
|
||||||
-Wno-incompatible-pointer-types \
|
-Wno-incompatible-pointer-types \
|
||||||
-Wno-maybe-uninitialized \
|
-Wno-maybe-uninitialized \
|
||||||
|
-Wno-nonnull \
|
||||||
-Wno-sign-compare \
|
-Wno-sign-compare \
|
||||||
-Wno-unknown-attributes \
|
-Wno-unknown-attributes \
|
||||||
-Wno-unused-but-set-parameter \
|
-Wno-unused-but-set-parameter \
|
||||||
-Wno-unused-but-set-variable \
|
-Wno-unused-but-set-variable \
|
||||||
-Wno-unused-result \
|
-Wno-unused-result \
|
||||||
-Wno-unused-variable \
|
-Wno-unused-variable
|
||||||
-Wno-nonnull
|
|
||||||
$(filter out/win%,$(UV_OBJS)): \
|
$(filter out/win%,$(UV_OBJS)): \
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-Wno-cast-function-type \
|
-Wno-cast-function-type \
|
||||||
@@ -742,7 +743,7 @@ $(SQLITE_OBJS): CFLAGS += \
|
|||||||
|
|
||||||
QUICKJS_SOURCES := \
|
QUICKJS_SOURCES := \
|
||||||
deps/quickjs/cutils.c \
|
deps/quickjs/cutils.c \
|
||||||
deps/quickjs/libbf.c \
|
deps/quickjs/dtoa.c \
|
||||||
deps/quickjs/libregexp.c \
|
deps/quickjs/libregexp.c \
|
||||||
deps/quickjs/libunicode.c \
|
deps/quickjs/libunicode.c \
|
||||||
deps/quickjs/quickjs.c
|
deps/quickjs/quickjs.c
|
||||||
@@ -1015,7 +1016,7 @@ $(BUNDLETOOL):
|
|||||||
@curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL)
|
@curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL)
|
||||||
|
|
||||||
out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL)
|
out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL)
|
||||||
@rm -rf out/aab/staging/
|
@rm -rf out/aab/staging/ out/aab/base.zip
|
||||||
@mkdir -p out/aab/staging
|
@mkdir -p out/aab/staging
|
||||||
@$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \
|
@$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \
|
||||||
-I $(ANDROID_PLATFORM)/android.jar \
|
-I $(ANDROID_PLATFORM)/android.jar \
|
||||||
@@ -1035,14 +1036,11 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
|
|||||||
@cp out/apk/classes.dex out/aab/staging/dex/
|
@cp out/apk/classes.dex out/aab/staging/dex/
|
||||||
@rm -fv out/base.zip
|
@rm -fv out/base.zip
|
||||||
@mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86
|
@mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86
|
||||||
@cp out/androidrelease/tildefriends out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
@mkdir -p out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64 out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86
|
||||||
@cp out/androidrelease-armv7a/tildefriends out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease/tildefriends -o out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
||||||
@cp out/androidrelease-x86_64/tildefriends out/aab/staging/lib/x86_64/libtildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-armv7a/tildefriends -o out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
||||||
@cp out/androidrelease-x86/tildefriends out/aab/staging/lib/x86/libtildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-x86_64/tildefriends -o out/aab/staging/lib/x86_64/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/arm64-v8a/libtildefriends.so
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-x86/tildefriends -o out/aab/staging/lib/x86/libtildefriends.so
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/armeabi-v7a/libtildefriends.so
|
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86_64/libtildefriends.so
|
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86/libtildefriends.so
|
|
||||||
@cp -r apps/ out/aab/staging/root/
|
@cp -r apps/ out/aab/staging/root/
|
||||||
@rm -rf out/aab/staging/root/apps/welcome*
|
@rm -rf out/aab/staging/root/apps/welcome*
|
||||||
@cp -r core/ out/aab/staging/root/
|
@cp -r core/ out/aab/staging/root/
|
||||||
@@ -1051,6 +1049,11 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
|
|||||||
@cp -r deps/codemirror/ out/aab/staging/root/deps/
|
@cp -r deps/codemirror/ out/aab/staging/root/deps/
|
||||||
@cd out/aab/staging/; zip -r ../base.zip *; cd ../../../
|
@cd out/aab/staging/; zip -r ../base.zip *; cd ../../../
|
||||||
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
|
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-armv7a/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/libtildefriends.so.sym
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86_64/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym
|
||||||
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym
|
||||||
|
@cd out/aab/staging; zip -u ../../../$@ BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym; cd ../../../
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign -ks .keys/android.jks --ks-key-alias androidKey -ks-pass pass:android --min-sdk-version=$(ANDROID_MIN_SDK_VERSION) $@
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign -ks .keys/android.jks --ks-key-alias androidKey -ks-pass pass:android --min-sdk-version=$(ANDROID_MIN_SDK_VERSION) $@
|
||||||
|
|
||||||
aab: out/TildeFriends.aab ## Build an Android App Bundle.
|
aab: out/TildeFriends.aab ## Build an Android App Bundle.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🦀",
|
"emoji": "🦀",
|
||||||
"previous": "&Zv/eOewtUPxYuALmYV8v+JDKwH4+aN8zCTYFwB7oYEw=.sha256"
|
"previous": "&RkHUl/WRe0UpvTB2W6cw0f4AeupL/2PEI1pXg5PDXBg=.sha256"
|
||||||
}
|
}
|
||||||
|
@@ -14,23 +14,8 @@ function get_emojis() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get_recent(author) {
|
export async function picker(callback, anchor, author, recent) {
|
||||||
let recent = await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT DISTINCT content ->> '$.vote.expression' AS value
|
|
||||||
FROM messages
|
|
||||||
WHERE author = ? AND
|
|
||||||
content ->> '$.type' = 'vote'
|
|
||||||
ORDER BY timestamp DESC LIMIT 10
|
|
||||||
`,
|
|
||||||
[author]
|
|
||||||
);
|
|
||||||
return recent.map((x) => x.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function picker(callback, anchor, author) {
|
|
||||||
let json = await get_emojis();
|
let json = await get_emojis();
|
||||||
let recent = await get_recent(author);
|
|
||||||
|
|
||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
div.id = 'emoji_picker';
|
div.id = 'emoji_picker';
|
||||||
|
@@ -21,6 +21,7 @@ class TfElement extends LitElement {
|
|||||||
guest: {type: Boolean},
|
guest: {type: Boolean},
|
||||||
url: {type: String},
|
url: {type: String},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ class TfElement extends LitElement {
|
|||||||
this.channels_latest = {};
|
this.channels_latest = {};
|
||||||
this.loading_latest = 0;
|
this.loading_latest = 0;
|
||||||
this.loading_latest_scheduled = 0;
|
this.loading_latest_scheduled = 0;
|
||||||
|
this.recent_reactions = [];
|
||||||
tfrpc.rpc.getBroadcasts().then((b) => {
|
tfrpc.rpc.getBroadcasts().then((b) => {
|
||||||
self.broadcasts = b || [];
|
self.broadcasts = b || [];
|
||||||
});
|
});
|
||||||
@@ -175,6 +177,7 @@ class TfElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const k_account_chunk_size = 4096;
|
||||||
const k_chunk_size = 1024;
|
const k_chunk_size = 1024;
|
||||||
let min_row_id = 0;
|
let min_row_id = 0;
|
||||||
console.log(
|
console.log(
|
||||||
@@ -187,54 +190,62 @@ class TfElement extends LitElement {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
let abouts = await tfrpc.rpc.query(
|
|
||||||
`
|
|
||||||
SELECT * FROM (
|
|
||||||
SELECT
|
|
||||||
messages.rowid AS rowid, messages.author, json(messages.content) AS content, messages.sequence
|
|
||||||
FROM
|
|
||||||
messages,
|
|
||||||
json_each(?1) AS following
|
|
||||||
WHERE
|
|
||||||
messages.author = following.value AND
|
|
||||||
messages.content ->> 'type' = 'about' AND
|
|
||||||
messages.rowid > ?3 AND
|
|
||||||
messages.rowid <= ?4
|
|
||||||
UNION
|
|
||||||
SELECT
|
|
||||||
messages.rowid AS rowid, messages.author, json(messages.content) AS content, messages.sequence
|
|
||||||
FROM
|
|
||||||
messages,
|
|
||||||
json_each(?2) AS following
|
|
||||||
WHERE
|
|
||||||
messages.author = following.value AND
|
|
||||||
messages.content ->> 'type' = 'about' AND
|
|
||||||
messages.rowid > ?6 AND
|
|
||||||
messages.rowid <= ?4
|
|
||||||
)
|
|
||||||
ORDER BY rowid LIMIT ?5
|
|
||||||
`,
|
|
||||||
[
|
|
||||||
JSON.stringify(ids.filter((id) => cache.about[id])),
|
|
||||||
JSON.stringify(ids.filter((id) => !cache.about[id])),
|
|
||||||
cache.last_row_id,
|
|
||||||
max_row_id,
|
|
||||||
k_chunk_size,
|
|
||||||
min_row_id,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
let max_seen;
|
let max_seen;
|
||||||
for (let about of abouts) {
|
for (let account_chunk = 0; account_chunk < ids.length; account_chunk += k_account_chunk_size) {
|
||||||
let content = JSON.parse(about.content);
|
let ids_chunk = ids.slice(account_chunk, account_chunk + k_account_chunk_size);
|
||||||
if (content.about === about.author) {
|
let abouts = await tfrpc.rpc.query(
|
||||||
delete content.type;
|
`
|
||||||
delete content.about;
|
WITH
|
||||||
cache.about[about.author] = Object.assign(
|
past AS (
|
||||||
cache.about[about.author] || {},
|
SELECT
|
||||||
content
|
messages.rowid AS rowid, messages.author, json(messages.content) AS content, messages.sequence
|
||||||
);
|
FROM
|
||||||
|
messages
|
||||||
|
WHERE
|
||||||
|
messages.rowid > ?3 AND
|
||||||
|
messages.rowid <= ?4 AND
|
||||||
|
messages.content ->> 'type' = 'about'
|
||||||
|
),
|
||||||
|
current AS (
|
||||||
|
SELECT
|
||||||
|
messages.rowid AS rowid, messages.author, json(messages.content) AS content, messages.sequence
|
||||||
|
FROM
|
||||||
|
messages
|
||||||
|
WHERE
|
||||||
|
messages.rowid > ?6 AND
|
||||||
|
messages.rowid <= ?4 AND
|
||||||
|
messages.content ->> 'type' = 'about'
|
||||||
|
)
|
||||||
|
SELECT * FROM past
|
||||||
|
JOIN json_each(?1) AS following
|
||||||
|
ON past.author = following.value
|
||||||
|
UNION SELECT * FROM current
|
||||||
|
JOIN json_each(?2) AS following
|
||||||
|
ON current.author = following.value
|
||||||
|
ORDER BY rowid LIMIT ?5
|
||||||
|
`,
|
||||||
|
[
|
||||||
|
JSON.stringify(ids_chunk.filter((id) => cache.about[id])),
|
||||||
|
JSON.stringify(ids_chunk.filter((id) => !cache.about[id])),
|
||||||
|
cache.last_row_id,
|
||||||
|
max_row_id,
|
||||||
|
k_chunk_size,
|
||||||
|
min_row_id,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
for (let about of abouts) {
|
||||||
|
let content = JSON.parse(about.content);
|
||||||
|
if (content.about === about.author) {
|
||||||
|
delete content.type;
|
||||||
|
delete content.about;
|
||||||
|
cache.about[about.author] = Object.assign(
|
||||||
|
cache.about[about.author] || {},
|
||||||
|
content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
max_seen = about.rowid;
|
||||||
}
|
}
|
||||||
max_seen = about.rowid;
|
console.log(account_chunk, '/', ids.length, 'accounts');
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
'cache =',
|
'cache =',
|
||||||
@@ -452,6 +463,19 @@ class TfElement extends LitElement {
|
|||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async load_recent_reactions() {
|
||||||
|
this.recent_reactions = (await tfrpc.rpc.query(
|
||||||
|
`
|
||||||
|
SELECT DISTINCT content ->> '$.vote.expression' AS value
|
||||||
|
FROM messages
|
||||||
|
WHERE author = ? AND
|
||||||
|
content ->> '$.type' = 'vote'
|
||||||
|
ORDER BY timestamp DESC LIMIT 10
|
||||||
|
`,
|
||||||
|
[this.whoami]
|
||||||
|
)).map((x) => x.value);
|
||||||
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.loading_latest = true;
|
this.loading_latest = true;
|
||||||
try {
|
try {
|
||||||
@@ -469,6 +493,7 @@ class TfElement extends LitElement {
|
|||||||
};
|
};
|
||||||
by_count.push({count: v.of, id: id});
|
by_count.push({count: v.of, id: id});
|
||||||
}
|
}
|
||||||
|
let reactions = this.load_recent_reactions();
|
||||||
this.load_channels_latest(Object.keys(following));
|
this.load_channels_latest(Object.keys(following));
|
||||||
this.channels_unread = JSON.parse(
|
this.channels_unread = JSON.parse(
|
||||||
(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
|
(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
|
||||||
@@ -494,6 +519,7 @@ class TfElement extends LitElement {
|
|||||||
console.log(
|
console.log(
|
||||||
`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
|
`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
|
||||||
);
|
);
|
||||||
|
await reactions;
|
||||||
this.whoami = whoami;
|
this.whoami = whoami;
|
||||||
this.loaded = whoami;
|
this.loaded = whoami;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -551,6 +577,7 @@ class TfElement extends LitElement {
|
|||||||
@channelsetunread=${this.channel_set_unread}
|
@channelsetunread=${this.channel_set_unread}
|
||||||
.connections=${this.connections}
|
.connections=${this.connections}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-tab-news>
|
></tf-tab-news>
|
||||||
`;
|
`;
|
||||||
} else if (this.tab === 'connections') {
|
} else if (this.tab === 'connections') {
|
||||||
|
@@ -16,6 +16,7 @@ class TfMessageElement extends LitElement {
|
|||||||
expanded: {type: Object},
|
expanded: {type: Object},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
channel_unread: {type: Number},
|
channel_unread: {type: Number},
|
||||||
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ class TfMessageElement extends LitElement {
|
|||||||
this.format = 'message';
|
this.format = 'message';
|
||||||
this.expanded = {};
|
this.expanded = {};
|
||||||
this.channel_unread = -1;
|
this.channel_unread = -1;
|
||||||
|
this.recent_reactions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@@ -84,9 +86,9 @@ class TfMessageElement extends LitElement {
|
|||||||
|
|
||||||
render_votes() {
|
render_votes() {
|
||||||
function normalize_expression(expression) {
|
function normalize_expression(expression) {
|
||||||
if (expression === 'Like' || !expression) {
|
if (expression === 'Like' || expression === 'like' || !expression) {
|
||||||
return '👍';
|
return '👍';
|
||||||
} else if (expression === 'Unlike') {
|
} else if (expression === 'Unlike' || expression === 'unlike') {
|
||||||
return '👎';
|
return '👎';
|
||||||
} else if (expression === 'heart') {
|
} else if (expression === 'heart') {
|
||||||
return '❤️';
|
return '❤️';
|
||||||
@@ -95,9 +97,10 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.message?.votes?.length) {
|
if (this.message?.votes?.length) {
|
||||||
return html` <div class="w3-container">
|
return html` <footer class="w3-container">
|
||||||
<div
|
<div
|
||||||
class="w3-button w3-bar w3-padding-small"
|
class="w3-button w3-bar"
|
||||||
|
style="padding: 0"
|
||||||
@click=${this.show_reactions}
|
@click=${this.show_reactions}
|
||||||
>
|
>
|
||||||
${(this.message.votes || []).map(
|
${(this.message.votes || []).map(
|
||||||
@@ -112,7 +115,7 @@ class TfMessageElement extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</footer>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +158,12 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
react(event) {
|
react(event) {
|
||||||
emojis.picker((x) => this.vote(x), null, this.whoami);
|
emojis.picker(
|
||||||
|
(x) => this.vote(x),
|
||||||
|
null,
|
||||||
|
this.whoami,
|
||||||
|
this.recent_reactions
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
show_image(link) {
|
show_image(link) {
|
||||||
@@ -306,6 +314,10 @@ class TfMessageElement extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_expanded(tag) {
|
||||||
|
return this.expanded[(this.message.id || '') + (tag || '')];
|
||||||
|
}
|
||||||
|
|
||||||
render_children() {
|
render_children() {
|
||||||
let self = this;
|
let self = this;
|
||||||
if (this.message.child_messages?.length) {
|
if (this.message.child_messages?.length) {
|
||||||
@@ -333,6 +345,7 @@ class TfMessageElement extends LitElement {
|
|||||||
.expanded=${this.expanded}
|
.expanded=${this.expanded}
|
||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-message>`
|
></tf-message>`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -441,7 +454,7 @@ class TfMessageElement extends LitElement {
|
|||||||
${this.drafts[this.message?.id] === undefined
|
${this.drafts[this.message?.id] === undefined
|
||||||
? html`
|
? html`
|
||||||
<button class="w3-button w3-bar-item" @click=${this.show_reply}>
|
<button class="w3-button w3-bar-item" @click=${this.show_reply}>
|
||||||
⮢ Reply
|
↩️ Reply
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
: undefined}
|
: undefined}
|
||||||
@@ -529,6 +542,7 @@ class TfMessageElement extends LitElement {
|
|||||||
.expanded=${self.expanded}
|
.expanded=${self.expanded}
|
||||||
channel=${self.channel}
|
channel=${self.channel}
|
||||||
channel_unread=${self.channel_unread}
|
channel_unread=${self.channel_unread}
|
||||||
|
.recent_reactions=${self.recent_reactions}
|
||||||
></tf-message>
|
></tf-message>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@@ -540,19 +554,22 @@ class TfMessageElement extends LitElement {
|
|||||||
let reply =
|
let reply =
|
||||||
this.drafts[this.message?.id] !== undefined
|
this.drafts[this.message?.id] !== undefined
|
||||||
? html`
|
? html`
|
||||||
<tf-compose
|
<div class="w3-section w3-container">
|
||||||
whoami=${this.whoami}
|
<tf-compose
|
||||||
.users=${this.users}
|
whoami=${this.whoami}
|
||||||
root=${content.root || this.message.id}
|
.users=${this.users}
|
||||||
branch=${this.message.id}
|
root=${content.root || this.message.id}
|
||||||
.drafts=${this.drafts}
|
branch=${this.message.id}
|
||||||
@tf-discard=${this.discard_reply}
|
.drafts=${this.drafts}
|
||||||
author=${this.message.author}
|
@tf-discard=${this.discard_reply}
|
||||||
></tf-compose>
|
author=${this.message.author}
|
||||||
|
.recent_reactions=${this.recent_reactions}
|
||||||
|
></tf-compose>
|
||||||
|
</div>
|
||||||
`
|
`
|
||||||
: undefined;
|
: undefined;
|
||||||
return html`
|
return html`
|
||||||
<div class="w3-section w3-container">${reply}</div>
|
${reply}
|
||||||
<footer>${this.render_children()}</footer>
|
<footer>${this.render_children()}</footer>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -678,11 +695,14 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
let content_warning = html`
|
let content_warning = html`
|
||||||
<div
|
<div
|
||||||
class="w3-panel w3-round-xlarge w3-theme-l4"
|
class="w3-panel w3-round-xlarge w3-theme-l4 w3"
|
||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
@click=${(x) => this.toggle_expanded(':cw')}
|
@click=${(x) => this.toggle_expanded(':cw')}
|
||||||
>
|
>
|
||||||
<p>${content.contentWarning}</p>
|
<p>${content.contentWarning}</p>
|
||||||
|
<p class="w3-small">
|
||||||
|
${this.is_expanded(':cw') ? 'Show less' : 'Show more'}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
let content_html = html`
|
let content_html = html`
|
||||||
|
@@ -13,6 +13,7 @@ class TfNewsElement extends LitElement {
|
|||||||
expanded: {type: Object},
|
expanded: {type: Object},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
channel_unread: {type: Number},
|
channel_unread: {type: Number},
|
||||||
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ class TfNewsElement extends LitElement {
|
|||||||
this.drafts = {};
|
this.drafts = {};
|
||||||
this.expanded = {};
|
this.expanded = {};
|
||||||
this.channel_unread = -1;
|
this.channel_unread = -1;
|
||||||
|
this.recent_reactions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
process_messages(messages) {
|
process_messages(messages) {
|
||||||
@@ -211,6 +213,7 @@ class TfNewsElement extends LitElement {
|
|||||||
collapsed="true"
|
collapsed="true"
|
||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-message>
|
></tf-message>
|
||||||
${x.rowid == unread_rowid
|
${x.rowid == unread_rowid
|
||||||
? html`<div style="display: flex; flex-direction: row">
|
? html`<div style="display: flex; flex-direction: row">
|
||||||
|
@@ -18,6 +18,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
time_range: {type: Array},
|
time_range: {type: Array},
|
||||||
time_loading: {type: Array},
|
time_loading: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
this.start_time = new Date().valueOf();
|
this.start_time = new Date().valueOf();
|
||||||
this.time_range = [0, 0];
|
this.time_range = [0, 0];
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
|
this.recent_reactions = [];
|
||||||
this.loading = 0;
|
this.loading = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,6 +454,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
.expanded=${this.expanded}
|
.expanded=${this.expanded}
|
||||||
channel=${this.channel()}
|
channel=${this.channel()}
|
||||||
channel_unread=${this.channels_unread?.[this.channel()]}
|
channel_unread=${this.channels_unread?.[this.channel()]}
|
||||||
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-news>
|
></tf-news>
|
||||||
${more}
|
${more}
|
||||||
`);
|
`);
|
||||||
|
@@ -24,6 +24,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
channels_latest: {type: Object},
|
channels_latest: {type: Object},
|
||||||
connections: {type: Array},
|
connections: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
this.channels_latest = {};
|
this.channels_latest = {};
|
||||||
this.channels = [];
|
this.channels = [];
|
||||||
this.connections = [];
|
this.connections = [];
|
||||||
|
this.recent_reactions = [];
|
||||||
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
|
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
|
||||||
self.drafts = JSON.parse(d || '{}');
|
self.drafts = JSON.parse(d || '{}');
|
||||||
});
|
});
|
||||||
@@ -223,7 +225,9 @@ class TfTabNewsElement extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<h4 class="w3-bar-item w3-theme-d2">Connections</h4>
|
<a class="w3-bar-item w3-theme-d2 w3-button" href="#connections">
|
||||||
|
<h4 style="margin: 0">Connections</h4>
|
||||||
|
</a>
|
||||||
${this.connections
|
${this.connections
|
||||||
.filter((x) => x.id && !x.destroy_reason)
|
.filter((x) => x.id && !x.destroy_reason)
|
||||||
.map(
|
.map(
|
||||||
@@ -340,6 +344,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.channels_unread=${this.channels_unread}
|
.channels_unread=${this.channels_unread}
|
||||||
.channels_latest=${this.channels_latest}
|
.channels_latest=${this.channels_latest}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-tab-news-feed>
|
></tf-tab-news-feed>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "👋",
|
"emoji": "👋",
|
||||||
"previous": "&wAb7J6E35xEXpiXsQ6t1RaWTGIvlatUnyH8ipF6pVic=.sha256"
|
"previous": "&1o8MrBHfH42NnO+ruajwCmW/DUCb+IT1qtnAZI/agyo=.sha256"
|
||||||
}
|
}
|
||||||
|
@@ -45,6 +45,11 @@
|
|||||||
<i class="fa fa-mobile-screen w3-xlarge"></i>
|
<i class="fa fa-mobile-screen w3-xlarge"></i>
|
||||||
<i class="fa-brands fa-windows w3-xlarge"></i>
|
<i class="fa-brands fa-windows w3-xlarge"></i>
|
||||||
</p>
|
</p>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-blue w3-padding-large"
|
||||||
|
href="https://www.tildefriends.net/~core/ssb/"
|
||||||
|
>🦀 Try It</a
|
||||||
|
>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
||||||
@@ -52,12 +57,7 @@
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://www.tildefriends.net/~core/ssb/"
|
href="https://dev.tildefriends.net/cory/tildefriends"
|
||||||
><i class="fa fa-link"></i> Try It</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="w3-button w3-black w3-padding-large"
|
|
||||||
href="https://dev.tildefriends.net/"
|
|
||||||
><i class="fa fa-mug-hot"></i> Development</a
|
><i class="fa fa-mug-hot"></i> Development</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
@@ -65,6 +65,11 @@
|
|||||||
href="https://docs.tildefriends.net/"
|
href="https://docs.tildefriends.net/"
|
||||||
><i class="fa fa-book"></i> Documentation</a
|
><i class="fa fa-book"></i> Documentation</a
|
||||||
>
|
>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-black w3-padding-large"
|
||||||
|
href="https://www.tildefriends.net/~cory/tildeblog/"
|
||||||
|
><i class="fa fa-solid fa-square-rss"></i> Blog</a
|
||||||
|
>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||||
@@ -86,6 +91,13 @@
|
|||||||
<img src="googleplay.svg" style="height: 2em; margin: 0" />
|
<img src="googleplay.svg" style="height: 2em; margin: 0" />
|
||||||
Get it on Google Play (Open Testing)
|
Get it on Google Play (Open Testing)
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||||
|
href="https://testflight.apple.com/join/tXxgtSpE"
|
||||||
|
>
|
||||||
|
<img src="ios.svg" style="height: 2em; margin: 0" />
|
||||||
|
Get it on iOS (TestFlight)
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-col l4 m6">
|
<div class="w3-col l4 m6">
|
||||||
@@ -222,9 +234,9 @@
|
|||||||
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
|
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
|
||||||
<h1 class="w3-jumbo"><b>Built the Old Fashioned Way</b></h1>
|
<h1 class="w3-jumbo"><b>Built the Old Fashioned Way</b></h1>
|
||||||
<p>
|
<p>
|
||||||
Tilde Friends strives to use only simple and widely adopted dependencies
|
Tilde Friends strives to use only simple and widely adopted
|
||||||
in order to keep it easy to build for all sorts of platforms and
|
dependencies in order to keep it easy to build for all sorts of
|
||||||
maintainable for a very long time.
|
platforms and maintainable for a very long time.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Though of course for building Tilde Friends apps, you are free to use
|
Though of course for building Tilde Friends apps, you are free to use
|
||||||
|
3
apps/welcome/ios.svg
Normal file
3
apps/welcome/ios.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="814" height="1000">
|
||||||
|
<path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 660 B |
Binary file not shown.
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
@@ -1,4 +1,4 @@
|
|||||||
/* W3.CSS 5.01 March 14 2025 by Jan Egil and Borge Refsnes */
|
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
@@ -108,10 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
|
|
||||||
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
|
||||||
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
|
||||||
|
|
||||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
@@ -153,9 +149,9 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
.w3-hover-none:hover{box-shadow:none!important}
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
/* Colors */
|
/* Colors */
|
||||||
.w3-amber,.w3-hover-amber:hover,.w3-warning{color:#000!important;background-color:#ffc107!important}
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
.w3-blue,.w3-hover-blue:hover,.w3-info,.w3-primary{color:#fff!important;background-color:#2196F3!important}
|
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||||
@@ -170,24 +166,15 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||||
.w3-red,.w3-hover-red:hover,.w3-danger{color:#fff!important;background-color:#f44336!important}
|
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||||
.w3-yellow,.w3-hover-yellow:hover,.w3-note{color:#000!important;background-color:#ffeb3b!important}
|
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||||
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover,.w3-secondary{color:#000!important;background-color:#9e9e9e!important}
|
|
||||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
|
|
||||||
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
|
||||||
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
|
||||||
.w3-emerald,.w3-hover-emerald:hover,.w3-success{color:#fff!important;background-color:#008a00!important}
|
|
||||||
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
|
||||||
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
|
||||||
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
|
||||||
|
|
||||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
@@ -245,4 +232,4 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
|||||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
@@ -411,6 +411,7 @@ class TfFilesElement extends LitElement {
|
|||||||
current: {type: String},
|
current: {type: String},
|
||||||
files: {type: Object},
|
files: {type: Object},
|
||||||
dropping: {type: Number},
|
dropping: {type: Number},
|
||||||
|
drop_target: {type: String},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,6 +450,9 @@ class TfFilesElement extends LitElement {
|
|||||||
if (!this.files[file].clean) {
|
if (!this.files[file].clean) {
|
||||||
classes.push('dirty');
|
classes.push('dirty');
|
||||||
}
|
}
|
||||||
|
if (this.drop_target == file) {
|
||||||
|
classes.push('drop');
|
||||||
|
}
|
||||||
return html`<div
|
return html`<div
|
||||||
class="${classes.join(' ')}"
|
class="${classes.join(' ')}"
|
||||||
@click=${(x) => this.file_click(file)}
|
@click=${(x) => this.file_click(file)}
|
||||||
@@ -465,11 +469,12 @@ class TfFilesElement extends LitElement {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.dropping = 0;
|
this.dropping = 0;
|
||||||
|
this.drop_target = undefined;
|
||||||
for (let file of event.dataTransfer.files) {
|
for (let file of event.dataTransfer.files) {
|
||||||
let buffer = await file.arrayBuffer();
|
let buffer = await file.arrayBuffer();
|
||||||
let text = new TextDecoder('latin1').decode(buffer);
|
let text = new TextDecoder('latin1').decode(buffer);
|
||||||
gFiles[file.name] = {
|
gFiles[file.name] = {
|
||||||
doc: new cm6.EditorState.create({
|
doc: cm6.EditorState.create({
|
||||||
doc: text,
|
doc: text,
|
||||||
extensions: cm6.extensions,
|
extensions: cm6.extensions,
|
||||||
}),
|
}),
|
||||||
@@ -488,6 +493,7 @@ class TfFilesElement extends LitElement {
|
|||||||
*/
|
*/
|
||||||
drag_enter(event) {
|
drag_enter(event) {
|
||||||
this.dropping++;
|
this.dropping++;
|
||||||
|
this.drop_target = event.srcElement.innerText.trim();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,6 +503,13 @@ class TfFilesElement extends LitElement {
|
|||||||
*/
|
*/
|
||||||
drag_leave(event) {
|
drag_leave(event) {
|
||||||
this.dropping--;
|
this.dropping--;
|
||||||
|
if (this.dropping == 0) {
|
||||||
|
this.drop_target = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drag_over(event) {
|
||||||
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -523,6 +536,10 @@ class TfFilesElement extends LitElement {
|
|||||||
background-color: #2aa198;
|
background-color: #2aa198;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.file.drop {
|
||||||
|
border: 4px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
div.file.dirty::after {
|
div.file.dirty::after {
|
||||||
content: '*';
|
content: '*';
|
||||||
}
|
}
|
||||||
@@ -531,20 +548,12 @@ class TfFilesElement extends LitElement {
|
|||||||
@drop=${this.drop}
|
@drop=${this.drop}
|
||||||
@dragenter=${this.drag_enter}
|
@dragenter=${this.drag_enter}
|
||||||
@dragleave=${this.drag_leave}
|
@dragleave=${this.drag_leave}
|
||||||
|
@dragover=${this.drag_over}
|
||||||
>
|
>
|
||||||
${Object.keys(this.files)
|
${Object.keys(this.files)
|
||||||
.sort()
|
.sort()
|
||||||
.map((x) => self.render_file(x))}
|
.map((x) => self.render_file(x))}
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
?hidden=${this.dropping == 0}
|
|
||||||
@drop=${this.drop}
|
|
||||||
@dragenter=${this.drag_enter}
|
|
||||||
@dragleave=${this.drag_leave}
|
|
||||||
style="text-align: center; vertical-align: middle; outline: 16px solid red; margin: -8px; background-color: rgba(255, 0, 0, 0.5); position: absolute; left: 16px; top: 16px; width: calc(100% - 16px); height: calc(100% - 16px); z-index: 1000"
|
|
||||||
>
|
|
||||||
Drop File(s)
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,14 +25,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.0.29";
|
version = "0.0.30";
|
||||||
|
|
||||||
src = pkgs.fetchFromGitea {
|
src = pkgs.fetchFromGitea {
|
||||||
domain = "dev.tildefriends.net";
|
domain = "dev.tildefriends.net";
|
||||||
owner = "cory";
|
owner = "cory";
|
||||||
repo = "tildefriends";
|
repo = "tildefriends";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
hash = "sha256-bQXFpocOYOlFmVj9OZeQhNrgFuTJ8sx2RSw1tgmelOM=";
|
hash = "sha256-t5yvouzSL2j/ge1VHLqzIZ+Avqj4iEDt7L+yrHoTZAQ=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
deps/codemirror/cm6.js
vendored
2
deps/codemirror/cm6.js
vendored
File diff suppressed because one or more lines are too long
6
deps/codemirror_src/package-lock.json
generated
vendored
6
deps/codemirror_src/package-lock.json
generated
vendored
@@ -144,9 +144,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.36.5",
|
"version": "6.36.6",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.5.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.6.tgz",
|
||||||
"integrity": "sha512-cd+FZEUlu3GQCYnguYm3EkhJ8KJVisqqUsCOKedBoAt/d9c76JUUap6U0UrpElln5k6VyrEOYliMuDAKIeDQLg==",
|
"integrity": "sha512-uxugGLet+Nzp0Jcit8Hn3LypM8ioMLKTsdf8FRoT3HWvZtb9GhaWMe0Cc15rz90Ljab4YFJiAulmIVB74OY0IQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
"style-mod": "^4.1.0",
|
"style-mod": "^4.1.0",
|
||||||
|
2
deps/libuv
vendored
2
deps/libuv
vendored
Submodule deps/libuv updated: 8fb9cb9194...5152db2cbf
2
deps/quickjs
vendored
2
deps/quickjs
vendored
Submodule deps/quickjs updated: 3f81070e57...19abf1888d
6
flake.lock
generated
6
flake.lock
generated
@@ -20,11 +20,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1739758141,
|
"lastModified": 1745279238,
|
||||||
"narHash": "sha256-uq6A2L7o1/tR6VfmYhZWoVAwb3gTy7j4Jx30MIrH0rE=",
|
"narHash": "sha256-AQ7M9wTa/Pa/kK5pcGTgX/DGqMHyzsyINfN7ktsI7Fo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c618e28f70257593de75a7044438efc1c1fc0791",
|
"rev": "9684b53175fc6c09581e94cc85f05ab77464c7e3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.unprompted.tildefriends"
|
package="com.unprompted.tildefriends"
|
||||||
android:versionCode="35"
|
android:versionCode="37"
|
||||||
android:versionName="0.0.30">
|
android:versionName="0.0.31-wip">
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
|
@@ -13,13 +13,13 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.0.30</string>
|
<string>0.0.31</string>
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
<array>
|
<array>
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>12</string>
|
<string>13</string>
|
||||||
<key>DTPlatformName</key>
|
<key>DTPlatformName</key>
|
||||||
<string>iphoneos</string>
|
<string>iphoneos</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
18
src/main.c
18
src/main.c
@@ -531,7 +531,7 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
|
|||||||
{ "id", required_argument, NULL, 'i' },
|
{ "id", required_argument, NULL, 'i' },
|
||||||
{ "recipients", required_argument, NULL, 'r' },
|
{ "recipients", required_argument, NULL, 'r' },
|
||||||
{ "db-path", required_argument, NULL, 'd' },
|
{ "db-path", required_argument, NULL, 'd' },
|
||||||
{ "text", required_argument, NULL, 'c' },
|
{ "text", required_argument, NULL, 't' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
};
|
};
|
||||||
@@ -566,11 +566,11 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_usage || !user || !identity || !recipients || !text)
|
if (show_usage || !identity || !recipients || !text)
|
||||||
{
|
{
|
||||||
tf_printf("\n%s private [options]\n\n", file);
|
tf_printf("\n%s private [options]\n\n", file);
|
||||||
tf_printf("options:\n");
|
tf_printf("options:\n");
|
||||||
tf_printf(" -u, --user user User owning identity with which to publish.\n");
|
tf_printf(" -u, --user user User owning identity with which to publish (optional).\n");
|
||||||
tf_printf(" -i, --id identity Identity with which to publish message.\n");
|
tf_printf(" -i, --id identity Identity with which to publish message.\n");
|
||||||
tf_printf(" -r, --recipients recipients Recipient identities.\n");
|
tf_printf(" -r, --recipients recipients Recipient identities.\n");
|
||||||
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
|
||||||
@@ -591,6 +591,13 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
|
|||||||
|
|
||||||
recipient_list[recipient_count++] = identity;
|
recipient_list[recipient_count++] = identity;
|
||||||
|
|
||||||
|
bool free_user = false;
|
||||||
|
if (!user)
|
||||||
|
{
|
||||||
|
user = tf_ssb_db_get_user_for_identity(ssb, identity);
|
||||||
|
free_user = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
|
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
|
||||||
{
|
{
|
||||||
char* copy = tf_strdup(recipients);
|
char* copy = tf_strdup(recipients);
|
||||||
@@ -642,6 +649,11 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
|
tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (free_user)
|
||||||
|
{
|
||||||
|
tf_free((void*)user);
|
||||||
|
}
|
||||||
done:
|
done:
|
||||||
tf_ssb_destroy(ssb);
|
tf_ssb_destroy(ssb);
|
||||||
tf_free((void*)default_db_path);
|
tf_free((void*)default_db_path);
|
||||||
|
12
src/mem.c
12
src/mem.c
@@ -386,29 +386,17 @@ size_t tf_mem_get_uv_malloc_size()
|
|||||||
return s_uv_malloc_size;
|
return s_uv_malloc_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__OpenBSD__)
|
|
||||||
static void* _tf_tls_alloc(size_t size)
|
|
||||||
#else
|
|
||||||
static void* _tf_tls_alloc(size_t size, const char* file, int line)
|
static void* _tf_tls_alloc(size_t size, const char* file, int line)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
return _tf_alloc(&s_tls_malloc_size, size);
|
return _tf_alloc(&s_tls_malloc_size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__OpenBSD__)
|
|
||||||
static void* _tf_tls_realloc(void* ptr, size_t size)
|
|
||||||
#else
|
|
||||||
static void* _tf_tls_realloc(void* ptr, size_t size, const char* file, int line)
|
static void* _tf_tls_realloc(void* ptr, size_t size, const char* file, int line)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
return _tf_realloc(&s_tls_malloc_size, ptr, size);
|
return _tf_realloc(&s_tls_malloc_size, ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__OpenBSD__)
|
|
||||||
static void _tf_tls_free(void* ptr)
|
|
||||||
#else
|
|
||||||
static void _tf_tls_free(void* ptr, const char* file, int line)
|
static void _tf_tls_free(void* ptr, const char* file, int line)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
_tf_free(&s_tls_malloc_size, ptr);
|
_tf_free(&s_tls_malloc_size, ptr);
|
||||||
}
|
}
|
||||||
|
@@ -4630,6 +4630,10 @@ void tf_ssb_sync_start(tf_ssb_t* ssb)
|
|||||||
|
|
||||||
bool tf_ssb_tunnel_create(tf_ssb_t* ssb, const char* portal_id, const char* target_id, int connect_flags)
|
bool tf_ssb_tunnel_create(tf_ssb_t* ssb, const char* portal_id, const char* target_id, int connect_flags)
|
||||||
{
|
{
|
||||||
|
if (!portal_id || !target_id)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id);
|
tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id);
|
||||||
if (connection && !tf_ssb_connection_get(ssb, target_id))
|
if (connection && !tf_ssb_connection_get(ssb, target_id))
|
||||||
{
|
{
|
||||||
|
28
src/ssb.db.c
28
src/ssb.db.c
@@ -1398,6 +1398,34 @@ void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* id
|
|||||||
tf_ssb_release_db_reader(ssb, db);
|
tf_ssb_release_db_reader(ssb, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* tf_ssb_db_get_user_for_identity(tf_ssb_t* ssb, const char* public_key)
|
||||||
|
{
|
||||||
|
const char* result = NULL;
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||||
|
sqlite3_stmt* statement = NULL;
|
||||||
|
if (sqlite3_prepare(db, "SELECT user FROM identities WHERE public_key = ?", -1, &statement, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_bind_text(statement, 1, (public_key && *public_key == '@') ? public_key + 1 : public_key, -1, NULL) == SQLITE_OK)
|
||||||
|
{
|
||||||
|
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
result = tf_strdup((const char*)sqlite3_column_text(statement, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("Bind failed: %s.\n", sqlite3_errmsg(db));
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tf_printf("Prepare failed: %s.\n", sqlite3_errmsg(db));
|
||||||
|
}
|
||||||
|
tf_ssb_release_db_reader(ssb, db);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size)
|
bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
@@ -249,6 +249,14 @@ void tf_ssb_db_identity_visit(tf_ssb_t* ssb, const char* user, void (*callback)(
|
|||||||
*/
|
*/
|
||||||
void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data);
|
void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get the user owning an identity.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param public_key the identity.
|
||||||
|
** @return The username of the owner of the identity or NULL.
|
||||||
|
*/
|
||||||
|
const char* tf_ssb_db_get_user_for_identity(tf_ssb_t* ssb, const char* public_key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get the private key for an identity in the database.
|
** Get the private key for an identity in the database.
|
||||||
** @param ssb The SSB instance.
|
** @param ssb The SSB instance.
|
||||||
|
@@ -1788,7 +1788,7 @@ static JSValue _tf_ssb_createTunnel(JSContext* context, JSValueConst this_val, i
|
|||||||
const char* portal_id = JS_ToCString(context, argv[0]);
|
const char* portal_id = JS_ToCString(context, argv[0]);
|
||||||
const char* target_id = JS_ToCString(context, argv[1]);
|
const char* target_id = JS_ToCString(context, argv[1]);
|
||||||
|
|
||||||
bool result = tf_ssb_tunnel_create(ssb, portal_id, target_id, 0);
|
bool result = portal_id && target_id && tf_ssb_tunnel_create(ssb, portal_id, target_id, 0);
|
||||||
|
|
||||||
JS_FreeCString(context, target_id);
|
JS_FreeCString(context, target_id);
|
||||||
JS_FreeCString(context, portal_id);
|
JS_FreeCString(context, portal_id);
|
||||||
|
@@ -1478,4 +1478,97 @@ void tf_ssb_test_triggers(const tf_test_options_t* options)
|
|||||||
uv_loop_close(&loop);
|
uv_loop_close(&loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _subprocess_check_call(const char* command)
|
||||||
|
{
|
||||||
|
int result = system(command);
|
||||||
|
if (!WIFEXITED(result))
|
||||||
|
{
|
||||||
|
tf_printf("Command did not report exit: %s.\n", command);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (WEXITSTATUS(result) != 0)
|
||||||
|
{
|
||||||
|
tf_printf("Command returned %d: %s.\n", WEXITSTATUS(result), command);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* _subprocess_check_output(const char* command)
|
||||||
|
{
|
||||||
|
FILE* proc = popen(command, "r");
|
||||||
|
if (!proc)
|
||||||
|
{
|
||||||
|
tf_printf("Command failed (%s): %s.\n", strerror(errno), command);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
char* result = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
if (proc)
|
||||||
|
{
|
||||||
|
const int k_block_size = 1024;
|
||||||
|
result = tf_realloc(result, size + k_block_size);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
size_t bytes = fread(result + size, 1, k_block_size, proc);
|
||||||
|
if (bytes > 0)
|
||||||
|
{
|
||||||
|
size += bytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(proc);
|
||||||
|
}
|
||||||
|
result = tf_realloc(result, size + 1);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
result[size] = '\0';
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _isspace(char c)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
c == ' ' ||
|
||||||
|
c == '\t' ||
|
||||||
|
c == '\r' ||
|
||||||
|
c == '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* _trim(char* p)
|
||||||
|
{
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = strlen(p);
|
||||||
|
while (length > 0 && _isspace(p[length - 1]))
|
||||||
|
{
|
||||||
|
p[length - 1] = '\0';
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tf_ssb_test_cli(const tf_test_options_t* options)
|
||||||
|
{
|
||||||
|
tf_printf("Testing CLI.\n");
|
||||||
|
unlink("out/test_db0.sqlite");
|
||||||
|
|
||||||
|
char command[1024];
|
||||||
|
snprintf(command, sizeof(command), "%s get_identity -d out/test_db0.sqlite", options->exe_path);
|
||||||
|
_subprocess_check_call(command);
|
||||||
|
char* id = _trim(_subprocess_check_output(command));
|
||||||
|
tf_printf("id = [%s]\n", id);
|
||||||
|
|
||||||
|
snprintf(command, sizeof(command), "%s private -i %s -r %s -d out/test_db0.sqlite -t '{\"type\": \"post\", \"text\": \"hello world\"}'", options->exe_path, id, id);
|
||||||
|
_subprocess_check_call(command);
|
||||||
|
|
||||||
|
tf_free(id);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -89,4 +89,10 @@ void tf_ssb_test_invite(const tf_test_options_t* options);
|
|||||||
*/
|
*/
|
||||||
void tf_ssb_test_triggers(const tf_test_options_t* options);
|
void tf_ssb_test_triggers(const tf_test_options_t* options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Test command-line interface.
|
||||||
|
** @param options The test options.
|
||||||
|
*/
|
||||||
|
void tf_ssb_test_cli(const tf_test_options_t* options);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@@ -1869,15 +1869,15 @@ void tf_task_destroy(tf_task_t* task)
|
|||||||
uv_close((uv_handle_t*)&timeout->_timer, _timeout_closed);
|
uv_close((uv_handle_t*)&timeout->_timer, _timeout_closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task->_ssb)
|
|
||||||
{
|
|
||||||
tf_ssb_destroy(task->_ssb);
|
|
||||||
}
|
|
||||||
if (task->_http)
|
if (task->_http)
|
||||||
{
|
{
|
||||||
tf_httpd_destroy(task->_http);
|
tf_httpd_destroy(task->_http);
|
||||||
task->_http = NULL;
|
task->_http = NULL;
|
||||||
}
|
}
|
||||||
|
if (task->_ssb)
|
||||||
|
{
|
||||||
|
tf_ssb_destroy(task->_ssb);
|
||||||
|
}
|
||||||
|
|
||||||
JS_FreeContext(task->_context);
|
JS_FreeContext(task->_context);
|
||||||
JS_FreeRuntime(task->_runtime);
|
JS_FreeRuntime(task->_runtime);
|
||||||
|
@@ -1079,6 +1079,7 @@ void tf_tests(const tf_test_options_t* options)
|
|||||||
_tf_test_run(options, "connect_str", tf_ssb_test_connect_str, false);
|
_tf_test_run(options, "connect_str", tf_ssb_test_connect_str, false);
|
||||||
_tf_test_run(options, "invite", tf_ssb_test_invite, false);
|
_tf_test_run(options, "invite", tf_ssb_test_invite, false);
|
||||||
_tf_test_run(options, "triggers", tf_ssb_test_triggers, false);
|
_tf_test_run(options, "triggers", tf_ssb_test_triggers, false);
|
||||||
|
_tf_test_run(options, "cli", tf_ssb_test_cli, false);
|
||||||
tf_printf("Tests completed.\n");
|
tf_printf("Tests completed.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
#define VERSION_NUMBER "0.0.30"
|
#define VERSION_NUMBER "0.0.31-wip"
|
||||||
#define VERSION_NAME "This program kills fascists."
|
#define VERSION_NAME "This program kills fascists."
|
||||||
|
Reference in New Issue
Block a user