Use UDL dictionaries to simplify return values

master
Lonami Exo 2022-10-27 18:42:48 +02:00
parent 1a56b03614
commit 004a921299
7 changed files with 85 additions and 163 deletions

View File

@ -1,10 +1,10 @@
package dev.lonami.talaria.data
import dev.lonami.talaria.models.Dialog
import dev.lonami.talaria.models.MessagePreview
import uniffi.talaria.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import uniffi.talaria.Dialog
import uniffi.talaria.MessageAck
import uniffi.talaria.MessagePreview
import uniffi.talaria.getDialogs
import java.time.Instant
interface DialogRepository {
fun loadDialogs(): List<Dialog>
@ -12,34 +12,7 @@ interface DialogRepository {
class NativeDialogRepository : DialogRepository {
override fun loadDialogs(): List<Dialog> {
val dialogs = mutableListOf<Dialog>()
val dialogPtr = getDialogs()
try {
val dialogCount = dialogCount(dialogPtr)
for (i in 0U until dialogCount) {
dialogs.add(
Dialog(
id = dialogPacked(dialogPtr, i),
title = dialogTitle(dialogPtr, i),
lastMessage = MessagePreview(
sender = dialogSender(dialogPtr, i),
text = dialogText(dialogPtr, i),
date = LocalDateTime.parse(
dialogTime(dialogPtr, i),
DateTimeFormatter.ISO_OFFSET_DATE_TIME
),
ack = dialogAck(dialogPtr, i),
),
pinned = dialogPin(dialogPtr, i) != 0U
)
)
}
} finally {
freeDialogs(dialogPtr)
}
return dialogs
return getDialogs()
}
}
@ -65,7 +38,7 @@ class MockDialogRepository : DialogRepository {
} else {
"Sample Message $i"
},
date = LocalDateTime.now(),
date = Instant.now(),
ack = when (i % 3) {
0 -> MessageAck.RECEIVED
1 -> MessageAck.SENT

View File

@ -1,8 +0,0 @@
package dev.lonami.talaria.models
data class Dialog(
val id: String,
val title: String,
val lastMessage: MessagePreview?,
val pinned: Boolean,
)

View File

@ -1,11 +0,0 @@
package dev.lonami.talaria.models
import uniffi.talaria.MessageAck
import java.time.LocalDateTime
data class MessagePreview(
val sender: String,
val text: String,
val date: LocalDateTime,
val ack: MessageAck,
)

View File

@ -23,10 +23,12 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import dev.lonami.talaria.R
import dev.lonami.talaria.data.MockDialogRepository
import dev.lonami.talaria.models.Dialog
import dev.lonami.talaria.ui.state.DialogViewModel
import dev.lonami.talaria.ui.theme.TalariaTheme
import uniffi.talaria.Dialog
import uniffi.talaria.MessageAck
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
@ -54,8 +56,8 @@ fun Dialog(dialog: Dialog, onDialogSelected: () -> Unit, modifier: Modifier = Mo
Text(
stringResource(
R.string.message_preview,
dialog.lastMessage.sender,
dialog.lastMessage.text
dialog.lastMessage!!.sender,
dialog.lastMessage!!.text
),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@ -65,7 +67,7 @@ fun Dialog(dialog: Dialog, onDialogSelected: () -> Unit, modifier: Modifier = Mo
Column {
if (dialog.lastMessage != null) {
Row {
when (dialog.lastMessage.ack) {
when (dialog.lastMessage!!.ack) {
MessageAck.RECEIVED -> {}
MessageAck.SENT -> Icon(
painterResource(R.drawable.sent),
@ -78,7 +80,7 @@ fun Dialog(dialog: Dialog, onDialogSelected: () -> Unit, modifier: Modifier = Mo
}
Spacer(Modifier.width(8.dp))
Text(
dialog.lastMessage.date.format(
LocalDateTime.ofInstant(dialog.lastMessage!!.date, ZoneOffset.UTC).format(
DateTimeFormatter.ofLocalizedTime(
FormatStyle.SHORT
)

View File

@ -1,5 +1,5 @@
package dev.lonami.talaria.ui.state
import dev.lonami.talaria.models.Dialog
import uniffi.talaria.Dialog
data class DialogUiState(val dialogs: List<Dialog> = listOf())

View File

@ -3,7 +3,7 @@
mod db;
use grammers_client::types::{Dialog, LoginToken};
use grammers_client::types::{Dialog as OgDialog, LoginToken};
use grammers_client::{Client, Config, InitParams};
use grammers_session::{PackedChat, Session, UpdateState};
use grammers_tl_types as tl;
@ -15,6 +15,7 @@ use std::future::Future;
use std::net::SocketAddr;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Mutex;
use std::time::SystemTime;
use tokio::runtime;
use tokio::runtime::Runtime;
@ -52,6 +53,22 @@ pub enum MessageAck {
Sent,
}
#[derive(Debug, Clone)]
pub struct MessagePreview {
sender: String,
text: String,
date: SystemTime,
ack: MessageAck,
}
#[derive(Debug, Clone)]
pub struct Dialog {
id: String,
title: String,
lastMessage: Option<MessagePreview>,
pinned: bool,
}
fn block_on<F: Future>(future: F) -> F::Output {
if RUNTIME.get().is_none() {
RUNTIME
@ -199,7 +216,7 @@ async fn sign_in(token: LoginToken, code: &str) -> Result<()> {
Ok(())
}
async fn get_dialogs() -> Result<Vec<Dialog>> {
async fn get_dialogs() -> Result<Vec<OgDialog>> {
let client = CLIENT.get().ok_or("Client not initialized")?;
let mut result = Vec::new();
@ -264,105 +281,49 @@ pub fn signIn(token_ptr: u64, code: String) {
}
}
pub fn getDialogs() -> u64 {
pub fn getDialogs() -> Vec<Dialog> {
match block_on(get_dialogs()) {
Ok(dialogs) => Box::into_raw(Box::new(dialogs)) as u64,
Ok(dialogs) => dialogs
.into_iter()
.map(|d| Dialog {
id: d.chat().pack().to_hex(),
title: d.chat().name().to_string(),
lastMessage: d.last_message.map(|m| MessagePreview {
sender: if let Some(sender) = m.sender() {
sender.name().to_string()
} else {
"unknown".to_string()
},
text: m.text().to_string(),
date: m.date().into(),
ack: if m.outgoing() {
match &d.dialog {
tl::enums::Dialog::Dialog(d) => {
if m.id() <= d.read_inbox_max_id {
MessageAck::Seen
} else {
MessageAck::Sent
}
}
tl::enums::Dialog::Folder(_) => MessageAck::Received,
}
} else {
MessageAck::Received
},
}),
pinned: match d.dialog {
tl::enums::Dialog::Dialog(d) => d.pinned,
tl::enums::Dialog::Folder(f) => f.pinned,
},
})
.collect(),
Err(e) => {
error!("Failed to get dialogs: {}", e);
0 as u64
Vec::new()
}
}
}
pub fn dialogCount(dialogsPtr: u64) -> u32 {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
dialogs.len() as u32
}
pub fn dialogPacked(dialogsPtr: u64, index: u32) -> String {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
dialogs[index as usize].chat().pack().to_hex()
}
pub fn dialogTitle(dialogsPtr: u64, index: u32) -> String {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
dialogs[index as usize].chat().name().to_string()
}
pub fn dialogSender(dialogsPtr: u64, index: u32) -> String {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
if let Some(msg) = dialogs[index as usize].last_message.as_ref() {
if let Some(sender) = msg.sender() {
sender.name().to_string()
} else {
"unknown".to_string()
}
} else {
String::new()
}
}
pub fn dialogText(dialogsPtr: u64, index: u32) -> String {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
if let Some(msg) = dialogs[index as usize].last_message.as_ref() {
msg.text().to_string()
} else {
"".to_string()
}
}
pub fn dialogTime(dialogsPtr: u64, index: u32) -> String {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
if let Some(msg) = dialogs[index as usize].last_message.as_ref() {
msg.date().to_rfc3339().to_string()
} else {
String::new()
}
}
pub fn dialogAck(dialogsPtr: u64, index: u32) -> MessageAck {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
let dialog = &dialogs[index as usize];
if let Some(msg) = dialog.last_message.as_ref() {
if msg.outgoing() {
match &dialog.dialog {
tl::enums::Dialog::Dialog(d) => {
if msg.id() <= d.read_inbox_max_id {
MessageAck::Seen
} else {
MessageAck::Sent
}
}
tl::enums::Dialog::Folder(_) => MessageAck::Received,
}
} else {
MessageAck::Received
}
} else {
MessageAck::Received
}
}
pub fn dialogPin(dialogsPtr: u64, index: u32) -> u32 {
let dialogs = unsafe { &mut *(dialogsPtr as *mut Vec<Dialog>) };
let pinned = match &dialogs[index as usize].dialog {
tl::enums::Dialog::Dialog(d) => d.pinned,
tl::enums::Dialog::Folder(f) => f.pinned,
};
pinned as u32
}
pub fn freeDialogs(dialogsPtr: u64) {
let _ = unsafe { Box::from_raw(dialogsPtr as *mut Vec<Dialog>) };
}
pub fn sendMessage(packed: String, text: String) {
let packed = PackedChat::from_hex(&packed).unwrap();
match block_on(send_message(packed, &text)) {

View File

@ -4,21 +4,26 @@ enum MessageAck {
"Sent",
};
dictionary MessagePreview {
string sender;
string text;
timestamp date;
MessageAck ack;
};
dictionary Dialog {
string id;
string title;
MessagePreview? lastMessage;
boolean pinned;
};
namespace talaria {
void initDatabase(string path);
void initClient();
boolean needLogin();
u64 requestLoginCode(string phone);
void signIn(u64 tokenPtr, string code);
u64 getDialogs();
u32 dialogCount(u64 dialogsPtr);
string dialogPacked(u64 dialogsPtr, u32 index);
string dialogTitle(u64 dialogsPtr, u32 index);
string dialogSender(u64 dialogsPtr, u32 index);
string dialogText(u64 dialogsPtr, u32 index);
string dialogTime(u64 dialogsPtr, u32 index);
MessageAck dialogAck(u64 dialogsPtr, u32 index);
u32 dialogPin(u64 dialogsPtr, u32 index);
void freeDialogs(u64 dialogsPtr);
sequence<Dialog> getDialogs();
void sendMessage(string packed, string text);
};