Add full-server activity to iOS home (#65)

This commit is contained in:
Georg Bauer
2026-08-15 17:25:25 +02:00
parent 6d271e7402
commit f84ab774e6
15 changed files with 492 additions and 15 deletions

View File

@@ -459,6 +459,21 @@ pub async fn load_activities(server: &Server, page: i32) -> Result<Page<models::
.map_err(message)
}
pub async fn load_server_activities(
pager: &mut gotcha_gitea::ServerActivityPager,
) -> Result<Page<models::Activity>, String> {
pager.next_page().await.map_err(message)
}
pub async fn server_activity_pager(
server: &Server,
) -> Result<gotcha_gitea::ServerActivityPager, String> {
client(server)?
.server_activity_pager()
.await
.map_err(message)
}
fn client(server: &Server) -> Result<Client, String> {
Client::with_provider(&server.url, Some(&server.token), server.provider).map_err(message)
}

View File

@@ -22,6 +22,7 @@ impl GotchaCore {
active_server,
..Default::default()
}),
server_activity: tokio::sync::Mutex::new(None),
startup_error,
})
}
@@ -275,6 +276,35 @@ impl GotchaCore {
load_home(&server, valid_page(page)?, filter.into()).await?,
))
}
pub async fn server_activity(&self, page: u32) -> Result<ServerActivityPage, GotchaError> {
valid_page(page)?;
let server = self.server()?;
let mut session = self.server_activity.lock().await;
if page == 1
|| session
.as_ref()
.is_none_or(|session| session.server_id != server.credential_account)
{
*session = Some(ServerActivitySession {
server_id: server.credential_account.clone(),
next_page: 1,
pager: server_activity_pager(&server).await?,
});
}
let session = session.as_mut().unwrap();
if session.next_page != page {
return Err("Refresh server activity before loading this page.".into());
}
let result = load_server_activities(&mut session.pager).await?;
if result.has_more {
session.next_page = session
.next_page
.checked_add(1)
.ok_or("Invalid page number.")?;
}
Ok(server_activity_page(result))
}
}
fn rollback_added_server_token(server: &Server, error: String) -> String {

View File

@@ -86,9 +86,16 @@ pub struct Settings {
#[derive(uniffi::Object)]
pub struct GotchaCore {
state: Mutex<State>,
server_activity: tokio::sync::Mutex<Option<ServerActivitySession>>,
startup_error: Option<String>,
}
struct ServerActivitySession {
server_id: String,
next_page: u32,
pager: gotcha_gitea::ServerActivityPager,
}
fn validate_repository<'a>(
owner: &'a str,
repository: &'a str,

View File

@@ -359,6 +359,12 @@ pub struct HomePage {
pub next_page: Option<u32>,
}
#[derive(Clone, uniffi::Record)]
pub struct ServerActivityPage {
pub rows: Vec<ActivityRow>,
pub has_more: bool,
}
#[derive(Clone, Copy, Debug, uniffi::Enum)]
pub enum NotificationStatus {
Open,

View File

@@ -15,6 +15,26 @@ pub fn activity_rows(activities: &[models::Activity]) -> Vec<ActivityRow> {
activities.iter().map(activity_row).collect()
}
pub fn server_activity_page(page: gotcha_gitea::Page<models::Activity>) -> ServerActivityPage {
ServerActivityPage {
rows: page
.items
.iter()
.map(|activity| {
let mut row = activity_row(activity);
let actor = activity
.act_user
.as_ref()
.and_then(|user| user.login.as_deref())
.unwrap_or("unknown user");
row.title = format!("@{actor} · {}", row.title);
row
})
.collect(),
has_more: page.has_more,
}
}
fn activity_row(activity: &models::Activity) -> ActivityRow {
use models::activity::OpType;

View File

@@ -157,6 +157,38 @@ fn presents_filtered_home_activity_and_continuation() {
assert_eq!(page.next_page, Some(4));
}
#[test]
fn presents_server_activity_with_actor_and_navigation_target() {
use models::activity::OpType;
let page = server_activity_page(gotcha_gitea::Page {
items: vec![models::Activity {
act_user: Some(Box::new(models::User {
login: Some("apple".into()),
..Default::default()
})),
op_type: Some(OpType::CreateIssue),
content: Some("1|Test issue".into()),
repo: Some(Box::new(models::Repository {
full_name: Some("apple/SimpleDemoRepo".into()),
..Default::default()
})),
..Default::default()
}],
has_more: true,
});
assert_eq!(
page.rows[0].title,
"@apple · Opened an issue in apple/SimpleDemoRepo"
);
assert_eq!(page.rows[0].target, ActivityTargetKind::Issue);
assert_eq!(page.rows[0].owner, "apple");
assert_eq!(page.rows[0].repository, "SimpleDemoRepo");
assert_eq!(page.rows[0].number, 1);
assert!(page.has_more);
}
#[test]
fn issue_page_exposes_state_and_owned_comment_editing() {
let page = issue_page(IssueDetails {