Compare commits

...

5 Commits

Author SHA1 Message Date
Jon Staab 3e832af3e4 Update version 2025-07-17 15:41:30 -07:00
Jon Staab 84b8650fa4 Shorten goals title for mobile 2025-07-17 15:40:07 -07:00
Jon Staab 83abb5aa94 Fix chat notifications so they take nip 29 into account 2025-07-17 15:35:49 -07:00
Jon Staab a12eddb47b Fix zaps on mobile 2025-07-17 15:29:26 -07:00
Jon Staab c87166247c Update zapstore.yaml 2025-07-17 15:21:05 -07:00
10 changed files with 72 additions and 39 deletions
+5
View File
@@ -1,5 +1,10 @@
# Changelog # Changelog
# 1.2.2
* Fix phantom chat notifications
* Fix zaps on mobile
# 1.2.1 # 1.2.1
* Add zaps to chat, threads, and events * Add zaps to chat, threads, and events
+2 -2
View File
@@ -7,8 +7,8 @@ android {
applicationId "social.flotilla" applicationId "social.flotilla"
minSdk rootProject.ext.minSdkVersion minSdk rootProject.ext.minSdkVersion
targetSdk rootProject.ext.targetSdkVersion targetSdk rootProject.ext.targetSdkVersion
versionCode 22 versionCode 23
versionName "1.2.1" versionName "1.2.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions { aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
+4 -4
View File
@@ -354,14 +354,14 @@
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements"; CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 15; CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = S26U9DYW3A; DEVELOPMENT_TEAM = S26U9DYW3A;
INFOPLIST_FILE = App/Info.plist; INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat"; INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 14.0; IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.2.1; MARKETING_VERSION = 1.2.2;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla; PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -380,14 +380,14 @@
CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements"; CODE_SIGN_ENTITLEMENTS = "Flotilla Chat.entitlements";
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 15; CURRENT_PROJECT_VERSION = 16;
DEVELOPMENT_TEAM = S26U9DYW3A; DEVELOPMENT_TEAM = S26U9DYW3A;
INFOPLIST_FILE = App/Info.plist; INFOPLIST_FILE = App/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat"; INFOPLIST_KEY_CFBundleDisplayName = "Flotilla Chat";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 14.0; IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.2.1; MARKETING_VERSION = 1.2.2;
PRODUCT_BUNDLE_IDENTIFIER = social.flotilla; PRODUCT_BUNDLE_IDENTIFIER = social.flotilla;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "flotilla", "name": "flotilla",
"version": "1.2.1", "version": "1.2.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
@@ -5,8 +5,10 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import EmojiPicker from "@lib/components/EmojiPicker.svelte" import EmojiPicker from "@lib/components/EmojiPicker.svelte"
import ZapButton from "@app/components/ZapButton.svelte"
import EventInfo from "@app/components/EventInfo.svelte" import EventInfo from "@app/components/EventInfo.svelte"
import EventDeleteConfirm from "@app/components/EventDeleteConfirm.svelte" import EventDeleteConfirm from "@app/components/EventDeleteConfirm.svelte"
import {ENABLE_ZAPS} from "@app/state"
import {publishReaction} from "@app/commands" import {publishReaction} from "@app/commands"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
@@ -40,6 +42,12 @@
<Icon size={4} icon="smile-circle" /> <Icon size={4} icon="smile-circle" />
Send Reaction Send Reaction
</Button> </Button>
{#if ENABLE_ZAPS}
<ZapButton replaceState {url} {event} class="btn btn-secondary w-full">
<Icon size={4} icon="bolt" />
Send Zap
</ZapButton>
{/if}
<Button class="btn btn-neutral w-full" onclick={sendReply}> <Button class="btn btn-neutral w-full" onclick={sendReply}>
<Icon size={4} icon="reply" /> <Icon size={4} icon="reply" />
Send Reply Send Reply
+2 -2
View File
@@ -116,7 +116,7 @@
<div>To <ProfileLink {pubkey} class="!text-primary" /></div> <div>To <ProfileLink {pubkey} class="!text-primary" /></div>
{/snippet} {/snippet}
</ModalHeader> </ModalHeader>
<FieldInline> <FieldInline class="!grid-cols-3">
{#snippet label()} {#snippet label()}
Emoji Reaction Emoji Reaction
{/snippet} {/snippet}
@@ -128,7 +128,7 @@
</div> </div>
{/snippet} {/snippet}
</FieldInline> </FieldInline>
<FieldInline> <FieldInline class="!grid-cols-3">
{#snippet label()} {#snippet label()}
Amount Amount
{/snippet} {/snippet}
+14 -4
View File
@@ -1,4 +1,6 @@
<script lang="ts"> <script lang="ts">
import type {Snippet} from "svelte"
import type {TrustedEvent} from "@welshman/util"
import {deriveZapperForPubkey} from "@welshman/app" import {deriveZapperForPubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Zap from "@app/components/Zap.svelte" import Zap from "@app/components/Zap.svelte"
@@ -7,17 +9,25 @@
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
import {wallet} from "@app/state" import {wallet} from "@app/state"
const {url, event, children, ...props} = $props() type Props = {
url: string
event: TrustedEvent
children: Snippet
replaceState?: boolean
class?: string
}
const {url, event, children, replaceState, ...props}: Props = $props()
const zapper = deriveZapperForPubkey(event.pubkey) const zapper = deriveZapperForPubkey(event.pubkey)
const onClick = () => { const onClick = () => {
if (!$zapper?.allowsNostr) { if (!$zapper?.allowsNostr) {
pushModal(InfoZapperError, {url, pubkey: event.pubkey, eventId: event.id}) pushModal(InfoZapperError, {url, pubkey: event.pubkey, eventId: event.id}, {replaceState})
} else if ($wallet) { } else if ($wallet) {
pushModal(Zap, {url, pubkey: event.pubkey, eventId: event.id}) pushModal(Zap, {url, pubkey: event.pubkey, eventId: event.id}, {replaceState})
} else { } else {
pushModal(WalletConnect) pushModal(WalletConnect, {}, {replaceState})
} }
} }
</script> </script>
+23 -17
View File
@@ -1,6 +1,6 @@
import {derived} from "svelte/store" import {derived} from "svelte/store"
import {synced, localStorageProvider, throttled} from "@welshman/store" import {synced, localStorageProvider, throttled} from "@welshman/store"
import {pubkey} from "@welshman/app" import {pubkey, relaysByUrl} from "@welshman/app"
import {prop, spec, identity, now, groupBy} from "@welshman/lib" import {prop, spec, identity, now, groupBy} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {EVENT_TIME, MESSAGE, THREAD, COMMENT, getTagValue} from "@welshman/util" import {EVENT_TIME, MESSAGE, THREAD, COMMENT, getTagValue} from "@welshman/util"
@@ -12,7 +12,7 @@ import {
makeSpaceChatPath, makeSpaceChatPath,
makeRoomPath, makeRoomPath,
} from "@app/routes" } from "@app/routes"
import {chats, getUrlsForEvent, userRoomsByUrl, repositoryStore} from "@app/state" import {chats, hasNip29, getUrlsForEvent, userRoomsByUrl, repositoryStore} from "@app/state"
// Checked state // Checked state
@@ -31,9 +31,12 @@ export const setChecked = (key: string) => checked.update(state => ({...state, [
export const notifications = derived( export const notifications = derived(
throttled( throttled(
1000, 1000,
derived([pubkey, checked, chats, userRoomsByUrl, repositoryStore, getUrlsForEvent], identity), derived(
[pubkey, checked, chats, userRoomsByUrl, repositoryStore, getUrlsForEvent, relaysByUrl],
identity,
),
), ),
([$pubkey, $checked, $chats, $userRoomsByUrl, $repository, $getUrlsForEvent]) => { ([$pubkey, $checked, $chats, $userRoomsByUrl, $repository, $getUrlsForEvent, $relaysByUrl]) => {
const hasNotification = (path: string, latestEvent: TrustedEvent | undefined) => { const hasNotification = (path: string, latestEvent: TrustedEvent | undefined) => {
if (!latestEvent || latestEvent.pubkey === $pubkey) { if (!latestEvent || latestEvent.pubkey === $pubkey) {
return false return false
@@ -95,11 +98,6 @@ export const notifications = derived(
paths.add(calendarPath) paths.add(calendarPath)
} }
if (hasNotification(messagesPath, messagesEvents[0])) {
paths.add(spacePath)
paths.add(messagesPath)
}
const commentsByThreadId = groupBy( const commentsByThreadId = groupBy(
e => getTagValue("E", e.tags), e => getTagValue("E", e.tags),
threadEvents.filter(spec({kind: COMMENT})), threadEvents.filter(spec({kind: COMMENT})),
@@ -126,16 +124,24 @@ export const notifications = derived(
} }
} }
for (const room of rooms) { if (hasNip29($relaysByUrl.get(url))) {
const roomPath = makeRoomPath(url, room) for (const room of rooms) {
const latestEvent = allMessageEvents.find( const roomPath = makeRoomPath(url, room)
e => const latestEvent = allMessageEvents.find(
$getUrlsForEvent(e.id).includes(url) && e.tags.find(t => t[0] === "h" && t[1] === room), e =>
) $getUrlsForEvent(e.id).includes(url) &&
e.tags.find(t => t[0] === "h" && t[1] === room),
)
if (hasNotification(roomPath, latestEvent)) { if (hasNotification(roomPath, latestEvent)) {
paths.add(spacePath)
paths.add(roomPath)
}
}
} else {
if (hasNotification(messagesPath, messagesEvents[0])) {
paths.add(spacePath) paths.add(spacePath)
paths.add(roomPath) paths.add(messagesPath)
} }
} }
} }
+1 -1
View File
@@ -81,7 +81,7 @@
</div> </div>
{/snippet} {/snippet}
{#snippet title()} {#snippet title()}
<strong>Fundraising Goals</strong> <strong>Goals</strong>
{/snippet} {/snippet}
{#snippet action()} {#snippet action()}
<div class="row-2"> <div class="row-2">
+12 -8
View File
@@ -1,9 +1,13 @@
flotilla: identifier: social.flotilla
android: name: Flotilla
identifier: social.flotilla tags: nostr nip29 community chat group
name: Flotilla changelog: CHANGELOG.md
description: Self-hosted community chat and threads built on the nostr protocol. homepage: https://flotilla.social
repository: https://github.com/coracle-social/flotilla description: Self-hosted community chat and threads built on the nostr protocol.
artifacts: repository: https://github.com/coracle-social/flotilla
- app-release-signed.apk blossom_servers:
- https://cdn.zapstore.dev
- https://hbr.coracle.social
assets:
- app-release-signed.apk