Compare commits

...

3 commits

Author SHA1 Message Date
Badri Sunderarajan d69179fa9d
Don't capitalise the first letter of a list item
This "feature" of capitalising the first letter came from the
kaios-native-ui project, but in this case it's more like a bug
than a feature because case is important in things like usernames
and JIDs (as well as conversation titles, since people deserve the
right to be fancy).
2024-03-23 17:50:04 +05:30
Badri Sunderarajan f24483df3a
A little formatting for the import
If we decide to import more things in future, it'll be neater to
change it. (Full disclosure: I did in fact attempt to import an
arrowsStore; when that was abandoned I decided to retain the
formatting anyway so I didn't have to do it next time. The time
thus saved has been utilised in the composition of this commit
message.)
2024-03-23 17:38:16 +05:30
Badri Sunderarajan c8f5240332
Add roster screen
This allows you to view and start new conversations with contacts,
although it doesn't let implement a sliding window or allow you to
search through then.
2024-03-23 17:36:53 +05:30
5 changed files with 140 additions and 4 deletions

View file

@ -7,10 +7,14 @@
import Home from './routes/Home.svelte'
import Login from './routes/Login.svelte'
import Messages from './routes/Messages.svelte'
import Contacts from './routes/Contacts.svelte'
import Chat from './routes/Chat.svelte'
import Redirect from './routes/Redirect.svelte'
import { titleStore, softkeysStore } from './stores.ts'
import {
titleStore,
softkeysStore,
} from './stores.ts'
let title
titleStore.subscribe(value => title = value)
@ -23,6 +27,7 @@
'/': Home,
'/login': Login,
'/messages': Messages,
'/contacts': Contacts,
'/chat/:chatID': Chat,
'*': Redirect,
}

View file

@ -42,4 +42,10 @@
white-space: normal;
overflow: auto;
}
/* Override the first-letter capitalisation of kaios-native-ui */
.list-item-indicator__text::first-letter,
.list-item-indicator__subtext::first-letter {
text-transform: none;
}
</style>

122
src/routes/Contacts.svelte Normal file
View file

@ -0,0 +1,122 @@
<script lang="ts">
import Text from '../components/Text.svelte'
import ListItem from '../components/ListItem.svelte'
import { push, replace } from 'svelte-spa-router'
import { _converse } from '@converse/headless/core'
import {
titleStore,
softkeysStore,
xmppConnected,
} from '../stores.ts'
titleStore.update(() => 'Contacts')
softkeysStore.update((k) => {
k.left.label = 'Search'
k.left.callback = () => {}
k.center.label = 'Chat'
k.center.callback = () => {
document.activeElement.click()
}
k.right.label = 'Options'
k.right.callback = () => {}
return k
})
// Main function for this view: get a conversation going!
function createChat(contactJID) {
_converse.api.listen.on('chatBoxInitialized', model => {
replace(`/chat/${model.id}`)
})
_converse.api.chats.create(contactJID)
}
// Run this and unsubscribe after one
// second. (The xmppConnected.subscribe function
// returns the unsubscribe callback, which we
// then call with setTimeout after 1000 ms)
setTimeout(xmppConnected.subscribe(value => {
if (!value) {
push('/redirect') // redirects to home
}
}), 1000)
// Stores information on the rendered contacts
let contacts = []
let contactsRenderedAt = 0 // a very, very long time ago
let contactsRendering = false // is a rendering scheduled?
// TODO: use a sliding window so that only the contacts
// that are in view get rendered
// Helper function to convert contacts list into
// (exceedingly lightweight) object array for
// final rendering
function contactsToArray(contacts) {
return contacts.map(c => ({
jid: c.attributes.jid,
name: c.attributes.nickname || c.attributes.user_id,
}))
}
function renderContacts() {
// If there are no contacts, just render an empty array
if (!_converse?.roster?.models) {
contacts = []
return
}
// If the contacts were updated more than 5 seconds ago,
// render them again immediately
if (new Date() - contactsRenderedAt > 5000) {
contacts = contactsToArray(_converse?.roster?.models)
} else {
// If they were updated less than 5 seconds ago, check
// if a re-render has been scheduled
if (contactsRendering) {
return
} else {
contactsRendering = true
// Render them after a gap
setTimeout(function () {
contactsRendering = false
contactsRenderedAt = new Date()
renderContacts()
}, 5000)
}
}
}
// Render them once
renderContacts()
_converse.on('rosterContactsFetched', () => {
renderContacts()
})
_converse.on('presence', () => {
renderContacts()
})
</script>
{#if !contacts.length}
<Text>
<p>You have no contacts. How about adding one?</p>
</Text>
{:else}
{#each contacts as contact, index (contact.jid)}
<ListItem
text={contact.name}
subtext={contact.jid}
tabindex={index}
onclick={() => createChat(contact.jid)}
/>
{/each}
{/if}

View file

@ -54,7 +54,8 @@
forward_messages: false,
enable_smacks: true,
allow_chat_pending_contacts: true,
allow_non_roster_messaging: true,
allow_non_roster_messaging: false,
roster_groups: false,
// Special optimisations to reduce memory usage on KaiOS
mam_request_all_pages: false,

View file

@ -14,8 +14,10 @@
titleStore.update(() => 'Convo')
softkeysStore.update((k) => {
k.left.label = 'new'
k.left.callback = () => {}
k.left.label = 'New'
k.left.callback = () => {
push('/contacts')
}
k.center.label = 'Open'
k.center.callback = () => {