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 package dev.lonami.talaria.data
import dev.lonami.talaria.models.Dialog import uniffi.talaria.Dialog
import dev.lonami.talaria.models.MessagePreview import uniffi.talaria.MessageAck
import uniffi.talaria.* import uniffi.talaria.MessagePreview
import java.time.LocalDateTime import uniffi.talaria.getDialogs
import java.time.format.DateTimeFormatter import java.time.Instant
interface DialogRepository { interface DialogRepository {
fun loadDialogs(): List<Dialog> fun loadDialogs(): List<Dialog>
@ -12,34 +12,7 @@ interface DialogRepository {
class NativeDialogRepository : DialogRepository { class NativeDialogRepository : DialogRepository {
override fun loadDialogs(): List<Dialog> { override fun loadDialogs(): List<Dialog> {
val dialogs = mutableListOf<Dialog>() return getDialogs()
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
} }
} }
@ -65,7 +38,7 @@ class MockDialogRepository : DialogRepository {
} else { } else {
"Sample Message $i" "Sample Message $i"
}, },
date = LocalDateTime.now(), date = Instant.now(),
ack = when (i % 3) { ack = when (i % 3) {
0 -> MessageAck.RECEIVED 0 -> MessageAck.RECEIVED
1 -> MessageAck.SENT 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 androidx.lifecycle.viewmodel.compose.viewModel
import dev.lonami.talaria.R import dev.lonami.talaria.R
import dev.lonami.talaria.data.MockDialogRepository import dev.lonami.talaria.data.MockDialogRepository
import dev.lonami.talaria.models.Dialog
import dev.lonami.talaria.ui.state.DialogViewModel import dev.lonami.talaria.ui.state.DialogViewModel
import dev.lonami.talaria.ui.theme.TalariaTheme import dev.lonami.talaria.ui.theme.TalariaTheme
import uniffi.talaria.Dialog
import uniffi.talaria.MessageAck import uniffi.talaria.MessageAck
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle import java.time.format.FormatStyle
@ -54,8 +56,8 @@ fun Dialog(dialog: Dialog, onDialogSelected: () -> Unit, modifier: Modifier = Mo
Text( Text(
stringResource( stringResource(
R.string.message_preview, R.string.message_preview,
dialog.lastMessage.sender, dialog.lastMessage!!.sender,
dialog.lastMessage.text dialog.lastMessage!!.text
), ),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
@ -65,7 +67,7 @@ fun Dialog(dialog: Dialog, onDialogSelected: () -> Unit, modifier: Modifier = Mo
Column { Column {
if (dialog.lastMessage != null) { if (dialog.lastMessage != null) {
Row { Row {
when (dialog.lastMessage.ack) { when (dialog.lastMessage!!.ack) {
MessageAck.RECEIVED -> {} MessageAck.RECEIVED -> {}
MessageAck.SENT -> Icon( MessageAck.SENT -> Icon(
painterResource(R.drawable.sent), painterResource(R.drawable.sent),
@ -78,7 +80,7 @@ fun Dialog(dialog: Dialog, onDialogSelected: () -> Unit, modifier: Modifier = Mo
} }
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))
Text( Text(
dialog.lastMessage.date.format( LocalDateTime.ofInstant(dialog.lastMessage!!.date, ZoneOffset.UTC).format(
DateTimeFormatter.ofLocalizedTime( DateTimeFormatter.ofLocalizedTime(
FormatStyle.SHORT FormatStyle.SHORT
) )

View File

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

View File

@ -3,7 +3,7 @@
mod db; mod db;
use grammers_client::types::{Dialog, LoginToken}; use grammers_client::types::{Dialog as OgDialog, LoginToken};
use grammers_client::{Client, Config, InitParams}; use grammers_client::{Client, Config, InitParams};
use grammers_session::{PackedChat, Session, UpdateState}; use grammers_session::{PackedChat, Session, UpdateState};
use grammers_tl_types as tl; use grammers_tl_types as tl;
@ -15,6 +15,7 @@ use std::future::Future;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Mutex; use std::sync::Mutex;
use std::time::SystemTime;
use tokio::runtime; use tokio::runtime;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
@ -52,6 +53,22 @@ pub enum MessageAck {
Sent, 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 { fn block_on<F: Future>(future: F) -> F::Output {
if RUNTIME.get().is_none() { if RUNTIME.get().is_none() {
RUNTIME RUNTIME
@ -199,7 +216,7 @@ async fn sign_in(token: LoginToken, code: &str) -> Result<()> {
Ok(()) 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 client = CLIENT.get().ok_or("Client not initialized")?;
let mut result = Vec::new(); 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()) { 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) => { Err(e) => {
error!("Failed to get dialogs: {}", 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) { pub fn sendMessage(packed: String, text: String) {
let packed = PackedChat::from_hex(&packed).unwrap(); let packed = PackedChat::from_hex(&packed).unwrap();
match block_on(send_message(packed, &text)) { match block_on(send_message(packed, &text)) {

View File

@ -4,21 +4,26 @@ enum MessageAck {
"Sent", "Sent",
}; };
dictionary MessagePreview {
string sender;
string text;
timestamp date;
MessageAck ack;
};
dictionary Dialog {
string id;
string title;
MessagePreview? lastMessage;
boolean pinned;
};
namespace talaria { namespace talaria {
void initDatabase(string path); void initDatabase(string path);
void initClient(); void initClient();
boolean needLogin(); boolean needLogin();
u64 requestLoginCode(string phone); u64 requestLoginCode(string phone);
void signIn(u64 tokenPtr, string code); void signIn(u64 tokenPtr, string code);
u64 getDialogs(); sequence<Dialog> 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);
void sendMessage(string packed, string text); void sendMessage(string packed, string text);
}; };