Load filtered home activity streams
This commit is contained in:
@@ -134,7 +134,8 @@ xcrun simctl launch booted de.rfc1437.gotcha
|
|||||||
issue and pull-request icons in turn; each shows only matching recent
|
issue and pull-request icons in turn; each shows only matching recent
|
||||||
activity or the native empty state, then the clock restores all rows.
|
activity or the native empty state, then the clock restores all rows.
|
||||||
- [ ] Pull-request activity includes older creation and close events beyond the
|
- [ ] Pull-request activity includes older creation and close events beyond the
|
||||||
first activity-feed page.
|
first activity-feed page without requiring a manual pull-up; the empty
|
||||||
|
state appears only after every available page has been checked.
|
||||||
- [ ] Tap repository, issue, pull-request, and commit activity. Each opens the
|
- [ ] Tap repository, issue, pull-request, and commit activity. Each opens the
|
||||||
matching native tab and destination.
|
matching native tab and destination.
|
||||||
- [ ] Non-linkable server activity does not navigate or appear tappable.
|
- [ ] Non-linkable server activity does not navigate or appear tappable.
|
||||||
|
|||||||
@@ -355,8 +355,12 @@ pub async fn load_pull_diff(
|
|||||||
Ok(diff::parse_file(&diff, path))
|
Ok(diff::parse_file(&diff, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_home(server: &Server, page: i32) -> Result<HomeData, String> {
|
pub async fn load_home(
|
||||||
client(server)?.home(page).await.map_err(message)
|
server: &Server,
|
||||||
|
page: i32,
|
||||||
|
filter: gotcha_gitea::ActivityFilter,
|
||||||
|
) -> Result<HomeData, String> {
|
||||||
|
client(server)?.home(page, filter).await.map_err(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client(server: &Server) -> Result<Client, String> {
|
fn client(server: &Server) -> Result<Client, String> {
|
||||||
|
|||||||
@@ -171,12 +171,16 @@ impl GotchaCore {
|
|||||||
save_preferences(&state.preferences).map_err(Into::into)
|
save_preferences(&state.preferences).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn home(&self, page: u32) -> Result<HomePage, GotchaError> {
|
pub async fn home(
|
||||||
|
&self,
|
||||||
|
page: u32,
|
||||||
|
filter: HomeActivityFilter,
|
||||||
|
) -> Result<HomePage, GotchaError> {
|
||||||
let server = self.server()?;
|
let server = self.server()?;
|
||||||
let name = server.name.clone();
|
let name = server.name.clone();
|
||||||
Ok(home_page(
|
Ok(home_page(
|
||||||
name,
|
name,
|
||||||
load_home(&server, valid_page(page)?).await?,
|
load_home(&server, valid_page(page)?, filter.into()).await?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -245,6 +245,23 @@ pub struct ActivityRow {
|
|||||||
pub sha: String,
|
pub sha: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, uniffi::Enum)]
|
||||||
|
pub enum HomeActivityFilter {
|
||||||
|
All,
|
||||||
|
Issues,
|
||||||
|
PullRequests,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HomeActivityFilter> for gotcha_gitea::ActivityFilter {
|
||||||
|
fn from(filter: HomeActivityFilter) -> Self {
|
||||||
|
match filter {
|
||||||
|
HomeActivityFilter::All => Self::All,
|
||||||
|
HomeActivityFilter::Issues => Self::Issues,
|
||||||
|
HomeActivityFilter::PullRequests => Self::PullRequests,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, uniffi::Record)]
|
#[derive(Clone, uniffi::Record)]
|
||||||
pub struct HeatCell {
|
pub struct HeatCell {
|
||||||
pub level: u32,
|
pub level: u32,
|
||||||
@@ -255,11 +272,9 @@ pub struct HeatCell {
|
|||||||
pub struct HomePage {
|
pub struct HomePage {
|
||||||
pub server_name: String,
|
pub server_name: String,
|
||||||
pub activities: Vec<ActivityRow>,
|
pub activities: Vec<ActivityRow>,
|
||||||
pub issue_activities: Vec<ActivityRow>,
|
|
||||||
pub pull_activities: Vec<ActivityRow>,
|
|
||||||
pub heat_cells: Vec<HeatCell>,
|
pub heat_cells: Vec<HeatCell>,
|
||||||
pub contribution_count: i64,
|
pub contribution_count: i64,
|
||||||
pub has_more: bool,
|
pub next_page: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repository_rows(
|
pub fn repository_rows(
|
||||||
@@ -776,52 +791,13 @@ pub fn home_page(server_name: String, home: HomeData) -> HomePage {
|
|||||||
let (heat_cells, contribution_count) = heat_cells(&home.heatmap);
|
let (heat_cells, contribution_count) = heat_cells(&home.heatmap);
|
||||||
HomePage {
|
HomePage {
|
||||||
server_name,
|
server_name,
|
||||||
issue_activities: home
|
|
||||||
.activities
|
|
||||||
.iter()
|
|
||||||
.filter(|activity| is_issue_activity(activity))
|
|
||||||
.map(activity_row)
|
|
||||||
.collect(),
|
|
||||||
pull_activities: home
|
|
||||||
.activities
|
|
||||||
.iter()
|
|
||||||
.filter(|activity| is_pull_activity(activity))
|
|
||||||
.map(activity_row)
|
|
||||||
.collect(),
|
|
||||||
activities: home.activities.iter().map(activity_row).collect(),
|
activities: home.activities.iter().map(activity_row).collect(),
|
||||||
heat_cells,
|
heat_cells,
|
||||||
contribution_count,
|
contribution_count,
|
||||||
has_more: home.has_more,
|
next_page: home.next_page.map(|page| page as u32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_issue_activity(activity: &models::Activity) -> bool {
|
|
||||||
use models::activity::OpType;
|
|
||||||
|
|
||||||
matches!(
|
|
||||||
activity.op_type,
|
|
||||||
Some(OpType::CreateIssue | OpType::CloseIssue | OpType::ReopenIssue | OpType::CommentIssue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_pull_activity(activity: &models::Activity) -> bool {
|
|
||||||
use models::activity::OpType;
|
|
||||||
|
|
||||||
matches!(
|
|
||||||
activity.op_type,
|
|
||||||
Some(
|
|
||||||
OpType::CreatePullRequest
|
|
||||||
| OpType::MergePullRequest
|
|
||||||
| OpType::AutoMergePullRequest
|
|
||||||
| OpType::ClosePullRequest
|
|
||||||
| OpType::ReopenPullRequest
|
|
||||||
| OpType::CommentPull
|
|
||||||
| OpType::ApprovePullRequest
|
|
||||||
| OpType::RejectPullRequest
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activity_row(activity: &models::Activity) -> ActivityRow {
|
fn activity_row(activity: &models::Activity) -> ActivityRow {
|
||||||
use models::activity::OpType;
|
use models::activity::OpType;
|
||||||
|
|
||||||
@@ -1263,31 +1239,26 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn categorizes_home_activity_before_crossing_the_bridge() {
|
fn presents_filtered_home_activity_and_continuation() {
|
||||||
use models::activity::OpType;
|
use models::activity::OpType;
|
||||||
|
|
||||||
let page = home_page(
|
let page = home_page(
|
||||||
"Gitea".into(),
|
"Gitea".into(),
|
||||||
HomeData {
|
HomeData {
|
||||||
activities: [
|
activities: [OpType::CreatePullRequest, OpType::ClosePullRequest]
|
||||||
OpType::CreateIssue,
|
.into_iter()
|
||||||
OpType::CreatePullRequest,
|
.map(|op_type| models::Activity {
|
||||||
OpType::CreateRepo,
|
op_type: Some(op_type),
|
||||||
]
|
..Default::default()
|
||||||
.into_iter()
|
})
|
||||||
.map(|op_type| models::Activity {
|
.collect(),
|
||||||
op_type: Some(op_type),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
heatmap: Vec::new(),
|
heatmap: Vec::new(),
|
||||||
has_more: false,
|
next_page: Some(4),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(page.activities.len(), 3);
|
assert_eq!(page.activities.len(), 2);
|
||||||
assert_eq!(page.issue_activities.len(), 1);
|
assert_eq!(page.next_page, Some(4));
|
||||||
assert_eq!(page.pull_activities.len(), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -5,6 +5,48 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use gitea_openapi::apis;
|
use gitea_openapi::apis;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||||
|
pub enum ActivityFilter {
|
||||||
|
#[default]
|
||||||
|
All,
|
||||||
|
Issues,
|
||||||
|
PullRequests,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActivityFilter {
|
||||||
|
fn matches(self, activity: &models::Activity) -> bool {
|
||||||
|
use models::activity::OpType;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Self::All => true,
|
||||||
|
Self::Issues => matches!(
|
||||||
|
activity.op_type,
|
||||||
|
Some(
|
||||||
|
OpType::CreateIssue
|
||||||
|
| OpType::CloseIssue
|
||||||
|
| OpType::ReopenIssue
|
||||||
|
| OpType::CommentIssue
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Self::PullRequests => matches!(
|
||||||
|
activity.op_type,
|
||||||
|
Some(
|
||||||
|
OpType::CreatePullRequest
|
||||||
|
| OpType::MergePullRequest
|
||||||
|
| OpType::AutoMergePullRequest
|
||||||
|
| OpType::ClosePullRequest
|
||||||
|
| OpType::ReopenPullRequest
|
||||||
|
| OpType::CommentPull
|
||||||
|
| OpType::ApprovePullRequest
|
||||||
|
| OpType::RejectPullRequest
|
||||||
|
| OpType::PullReviewDismissed
|
||||||
|
| OpType::PullRequestReadyForReview
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
Repository {
|
Repository {
|
||||||
@@ -29,7 +71,7 @@ pub enum Target {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub async fn home(&self, page: i32) -> Result<HomeData> {
|
pub async fn home(&self, page: i32, filter: ActivityFilter) -> Result<HomeData> {
|
||||||
if page < 1 {
|
if page < 1 {
|
||||||
return Err(Error::InvalidInput("page must be positive".into()));
|
return Err(Error::InvalidInput("page must be positive".into()));
|
||||||
}
|
}
|
||||||
@@ -39,27 +81,51 @@ impl Client {
|
|||||||
.await?
|
.await?
|
||||||
.login
|
.login
|
||||||
.ok_or_else(|| Error::Generated("The server account has no username.".into()))?;
|
.ok_or_else(|| Error::Generated("The server account has no username.".into()))?;
|
||||||
let activities = apis::user_api::user_list_activity_feeds(
|
let activities = activity_page(&configuration, &login, page);
|
||||||
&configuration,
|
|
||||||
&login,
|
|
||||||
Some(true),
|
|
||||||
None,
|
|
||||||
Some(page),
|
|
||||||
Some(DEFAULT_PAGE_SIZE),
|
|
||||||
);
|
|
||||||
let (activities, heatmap) = tokio::join!(
|
let (activities, heatmap) = tokio::join!(
|
||||||
activities,
|
activities,
|
||||||
apis::user_api::user_get_heatmap_data(&configuration, &login),
|
apis::user_api::user_get_heatmap_data(&configuration, &login),
|
||||||
);
|
);
|
||||||
let activities = activities.map_err(Error::generated)?;
|
let mut activities = activities?;
|
||||||
Ok(HomeData {
|
let heatmap = heatmap.map_err(Error::generated)?;
|
||||||
has_more: activities.len() == DEFAULT_PAGE_SIZE as usize,
|
let mut page = page;
|
||||||
activities,
|
|
||||||
heatmap: heatmap.map_err(Error::generated)?,
|
loop {
|
||||||
})
|
let has_more = activities.len() == DEFAULT_PAGE_SIZE as usize;
|
||||||
|
let filtered: Vec<_> = activities
|
||||||
|
.into_iter()
|
||||||
|
.filter(|activity| filter.matches(activity))
|
||||||
|
.collect();
|
||||||
|
if filter == ActivityFilter::All || !filtered.is_empty() || !has_more {
|
||||||
|
return Ok(HomeData {
|
||||||
|
activities: filtered,
|
||||||
|
heatmap,
|
||||||
|
next_page: has_more.then_some(page + 1),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
page += 1;
|
||||||
|
activities = activity_page(&configuration, &login, page).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn activity_page(
|
||||||
|
configuration: &apis::configuration::Configuration,
|
||||||
|
login: &str,
|
||||||
|
page: i32,
|
||||||
|
) -> Result<Vec<models::Activity>> {
|
||||||
|
apis::user_api::user_list_activity_feeds(
|
||||||
|
configuration,
|
||||||
|
login,
|
||||||
|
Some(true),
|
||||||
|
None,
|
||||||
|
Some(page),
|
||||||
|
Some(DEFAULT_PAGE_SIZE),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Error::generated)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn target(activity: &models::Activity) -> Option<Target> {
|
pub fn target(activity: &models::Activity) -> Option<Target> {
|
||||||
use models::activity::OpType;
|
use models::activity::OpType;
|
||||||
|
|
||||||
@@ -205,4 +271,29 @@ mod tests {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn filters_issue_and_pull_request_activity() {
|
||||||
|
let activities = [
|
||||||
|
activity(OpType::CreateIssue, ""),
|
||||||
|
activity(OpType::CreatePullRequest, ""),
|
||||||
|
activity(OpType::PullRequestReadyForReview, ""),
|
||||||
|
activity(OpType::CreateRepo, ""),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
activities
|
||||||
|
.iter()
|
||||||
|
.filter(|activity| ActivityFilter::Issues.matches(activity))
|
||||||
|
.count(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
activities
|
||||||
|
.iter()
|
||||||
|
.filter(|activity| ActivityFilter::PullRequests.matches(activity))
|
||||||
|
.count(),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ pub struct HistoryCommit {
|
|||||||
pub struct HomeData {
|
pub struct HomeData {
|
||||||
pub activities: Vec<models::Activity>,
|
pub activities: Vec<models::Activity>,
|
||||||
pub heatmap: Vec<models::UserHeatmapData>,
|
pub heatmap: Vec<models::UserHeatmapData>,
|
||||||
pub has_more: bool,
|
pub next_page: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PullRefs = HashMap<String, Vec<String>>;
|
pub type PullRefs = HashMap<String, Vec<String>>;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ mod milestones;
|
|||||||
mod pulls;
|
mod pulls;
|
||||||
mod repositories;
|
mod repositories;
|
||||||
|
|
||||||
|
pub use activity::ActivityFilter;
|
||||||
pub use domain::{
|
pub use domain::{
|
||||||
CreateIssue, DEFAULT_PAGE_SIZE, EditIssue, HistoryCommit, HomeData, IssueDetails, IssueDraft,
|
CreateIssue, DEFAULT_PAGE_SIZE, EditIssue, HistoryCommit, HomeData, IssueDetails, IssueDraft,
|
||||||
IssueEditorData, IssueQuery, MilestoneDetails, MilestoneDraft, Page, PullDetails, RepositoryId,
|
IssueEditorData, IssueQuery, MilestoneDetails, MilestoneDraft, Page, PullDetails, RepositoryId,
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ module gotcha_core {
|
|||||||
use "Darwin"
|
use "Darwin"
|
||||||
use "_Builtin_stdbool"
|
use "_Builtin_stdbool"
|
||||||
use "_Builtin_stdint"
|
use "_Builtin_stdint"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ public protocol GotchaCoreProtocol: AnyObject, Sendable {
|
|||||||
|
|
||||||
func commits(owner: String, repository: String, branch: String?, path: String, pages: UInt32) async throws -> CommitPage
|
func commits(owner: String, repository: String, branch: String?, path: String, pages: UInt32) async throws -> CommitPage
|
||||||
|
|
||||||
func home(page: UInt32) async throws -> HomePage
|
func home(page: UInt32, filter: HomeActivityFilter) async throws -> HomePage
|
||||||
|
|
||||||
func issue(owner: String, repository: String, number: Int64, page: UInt32) async throws -> IssuePage
|
func issue(owner: String, repository: String, number: Int64, page: UInt32) async throws -> IssuePage
|
||||||
|
|
||||||
@@ -819,12 +819,12 @@ open func commits(owner: String, repository: String, branch: String?, path: Stri
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func home(page: UInt32)async throws -> HomePage {
|
open func home(page: UInt32, filter: HomeActivityFilter)async throws -> HomePage {
|
||||||
return
|
return
|
||||||
try await uniffiRustCallAsync(
|
try await uniffiRustCallAsync(
|
||||||
rustFutureFunc: {
|
rustFutureFunc: {
|
||||||
uniffi_gotcha_core_fn_method_gotchacore_home(
|
uniffi_gotcha_core_fn_method_gotchacore_home(
|
||||||
self.uniffiCloneHandle(),FfiConverterUInt32.lower(page)
|
self.uniffiCloneHandle(),FfiConverterUInt32.lower(page),FfiConverterTypeHomeActivityFilter_lower(filter)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
pollFunc: ffi_gotcha_core_rust_future_poll_rust_buffer,
|
pollFunc: ffi_gotcha_core_rust_future_poll_rust_buffer,
|
||||||
@@ -1839,22 +1839,18 @@ public func FfiConverterTypeHeatCell_lower(_ value: HeatCell) -> RustBuffer {
|
|||||||
public struct HomePage: Equatable, Hashable {
|
public struct HomePage: Equatable, Hashable {
|
||||||
public var serverName: String
|
public var serverName: String
|
||||||
public var activities: [ActivityRow]
|
public var activities: [ActivityRow]
|
||||||
public var issueActivities: [ActivityRow]
|
|
||||||
public var pullActivities: [ActivityRow]
|
|
||||||
public var heatCells: [HeatCell]
|
public var heatCells: [HeatCell]
|
||||||
public var contributionCount: Int64
|
public var contributionCount: Int64
|
||||||
public var hasMore: Bool
|
public var nextPage: UInt32?
|
||||||
|
|
||||||
// Default memberwise initializers are never public by default, so we
|
// Default memberwise initializers are never public by default, so we
|
||||||
// declare one manually.
|
// declare one manually.
|
||||||
public init(serverName: String, activities: [ActivityRow], issueActivities: [ActivityRow], pullActivities: [ActivityRow], heatCells: [HeatCell], contributionCount: Int64, hasMore: Bool) {
|
public init(serverName: String, activities: [ActivityRow], heatCells: [HeatCell], contributionCount: Int64, nextPage: UInt32?) {
|
||||||
self.serverName = serverName
|
self.serverName = serverName
|
||||||
self.activities = activities
|
self.activities = activities
|
||||||
self.issueActivities = issueActivities
|
|
||||||
self.pullActivities = pullActivities
|
|
||||||
self.heatCells = heatCells
|
self.heatCells = heatCells
|
||||||
self.contributionCount = contributionCount
|
self.contributionCount = contributionCount
|
||||||
self.hasMore = hasMore
|
self.nextPage = nextPage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1875,22 +1871,18 @@ public struct FfiConverterTypeHomePage: FfiConverterRustBuffer {
|
|||||||
try HomePage(
|
try HomePage(
|
||||||
serverName: FfiConverterString.read(from: &buf),
|
serverName: FfiConverterString.read(from: &buf),
|
||||||
activities: FfiConverterSequenceTypeActivityRow.read(from: &buf),
|
activities: FfiConverterSequenceTypeActivityRow.read(from: &buf),
|
||||||
issueActivities: FfiConverterSequenceTypeActivityRow.read(from: &buf),
|
|
||||||
pullActivities: FfiConverterSequenceTypeActivityRow.read(from: &buf),
|
|
||||||
heatCells: FfiConverterSequenceTypeHeatCell.read(from: &buf),
|
heatCells: FfiConverterSequenceTypeHeatCell.read(from: &buf),
|
||||||
contributionCount: FfiConverterInt64.read(from: &buf),
|
contributionCount: FfiConverterInt64.read(from: &buf),
|
||||||
hasMore: FfiConverterBool.read(from: &buf)
|
nextPage: FfiConverterOptionUInt32.read(from: &buf)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func write(_ value: HomePage, into buf: inout [UInt8]) {
|
public static func write(_ value: HomePage, into buf: inout [UInt8]) {
|
||||||
FfiConverterString.write(value.serverName, into: &buf)
|
FfiConverterString.write(value.serverName, into: &buf)
|
||||||
FfiConverterSequenceTypeActivityRow.write(value.activities, into: &buf)
|
FfiConverterSequenceTypeActivityRow.write(value.activities, into: &buf)
|
||||||
FfiConverterSequenceTypeActivityRow.write(value.issueActivities, into: &buf)
|
|
||||||
FfiConverterSequenceTypeActivityRow.write(value.pullActivities, into: &buf)
|
|
||||||
FfiConverterSequenceTypeHeatCell.write(value.heatCells, into: &buf)
|
FfiConverterSequenceTypeHeatCell.write(value.heatCells, into: &buf)
|
||||||
FfiConverterInt64.write(value.contributionCount, into: &buf)
|
FfiConverterInt64.write(value.contributionCount, into: &buf)
|
||||||
FfiConverterBool.write(value.hasMore, into: &buf)
|
FfiConverterOptionUInt32.write(value.nextPage, into: &buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3352,6 +3344,79 @@ public func FfiConverterTypeGotchaError_lower(_ value: GotchaError) -> RustBuffe
|
|||||||
return FfiConverterTypeGotchaError.lower(value)
|
return FfiConverterTypeGotchaError.lower(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public enum HomeActivityFilter: Equatable, Hashable {
|
||||||
|
|
||||||
|
case all
|
||||||
|
case issues
|
||||||
|
case pullRequests
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension HomeActivityFilter: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeHomeActivityFilter: FfiConverterRustBuffer {
|
||||||
|
typealias SwiftType = HomeActivityFilter
|
||||||
|
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> HomeActivityFilter {
|
||||||
|
let variant: Int32 = try readInt(&buf)
|
||||||
|
switch variant {
|
||||||
|
|
||||||
|
case 1: return .all
|
||||||
|
|
||||||
|
case 2: return .issues
|
||||||
|
|
||||||
|
case 3: return .pullRequests
|
||||||
|
|
||||||
|
default: throw UniffiInternalError.unexpectedEnumCase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: HomeActivityFilter, into buf: inout [UInt8]) {
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
|
||||||
|
case .all:
|
||||||
|
writeInt(&buf, Int32(1))
|
||||||
|
|
||||||
|
|
||||||
|
case .issues:
|
||||||
|
writeInt(&buf, Int32(2))
|
||||||
|
|
||||||
|
|
||||||
|
case .pullRequests:
|
||||||
|
writeInt(&buf, Int32(3))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeHomeActivityFilter_lift(_ buf: RustBuffer) throws -> HomeActivityFilter {
|
||||||
|
return try FfiConverterTypeHomeActivityFilter.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeHomeActivityFilter_lower(_ value: HomeActivityFilter) -> RustBuffer {
|
||||||
|
return FfiConverterTypeHomeActivityFilter.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if swift(>=5.8)
|
#if swift(>=5.8)
|
||||||
@_documentation(visibility: private)
|
@_documentation(visibility: private)
|
||||||
#endif
|
#endif
|
||||||
@@ -3955,7 +4020,7 @@ private let initializationResult: InitializationResult = {
|
|||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_commits() != 60062) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_commits() != 60062) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_home() != 38990) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_home() != 2797) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_issue() != 3108) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_issue() != 3108) {
|
||||||
@@ -4065,4 +4130,4 @@ public func uniffiEnsureGotchaCoreInitialized() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:enable all
|
// swiftlint:enable all
|
||||||
@@ -291,7 +291,7 @@ uint64_t uniffi_gotcha_core_fn_method_gotchacore_commits(uint64_t ptr, RustBuffe
|
|||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_HOME
|
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_HOME
|
||||||
#define UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_HOME
|
#define UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_HOME
|
||||||
uint64_t uniffi_gotcha_core_fn_method_gotchacore_home(uint64_t ptr, uint32_t page
|
uint64_t uniffi_gotcha_core_fn_method_gotchacore_home(uint64_t ptr, uint32_t page, RustBuffer filter
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_ISSUE
|
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_ISSUE
|
||||||
|
|||||||
@@ -321,21 +321,21 @@ final class HomeViewController: RefreshingTableViewController {
|
|||||||
case all
|
case all
|
||||||
case issues
|
case issues
|
||||||
case pulls
|
case pulls
|
||||||
|
|
||||||
|
var coreValue: HomeActivityFilter {
|
||||||
|
switch self {
|
||||||
|
case .all: return .all
|
||||||
|
case .issues: return .issues
|
||||||
|
case .pulls: return .pullRequests
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let context: AppContext
|
private let context: AppContext
|
||||||
private var page: HomePage?
|
private var page: HomePage?
|
||||||
private var filter = ActivityFilter.all
|
private var filter = ActivityFilter.all
|
||||||
private var currentPage: UInt32 = 0
|
private var nextPage: UInt32?
|
||||||
|
private var activities: [ActivityRow] { page?.activities ?? [] }
|
||||||
private var activities: [ActivityRow] {
|
|
||||||
guard let page else { return [] }
|
|
||||||
switch filter {
|
|
||||||
case .all: return page.activities
|
|
||||||
case .issues: return page.issueActivities
|
|
||||||
case .pulls: return page.pullActivities
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(context: AppContext) {
|
init(context: AppContext) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@@ -381,7 +381,8 @@ final class HomeViewController: RefreshingTableViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func loadMoreContent() {
|
override func loadMoreContent() {
|
||||||
loadPage(currentPage + 1, refreshing: false)
|
guard let nextPage else { return }
|
||||||
|
loadPage(nextPage, refreshing: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadPage(_ requestedPage: UInt32, refreshing: Bool) {
|
private func loadPage(_ requestedPage: UInt32, refreshing: Bool) {
|
||||||
@@ -392,23 +393,25 @@ final class HomeViewController: RefreshingTableViewController {
|
|||||||
loadingTask?.cancel()
|
loadingTask?.cancel()
|
||||||
loadingTask = Task {
|
loadingTask = Task {
|
||||||
do {
|
do {
|
||||||
let result = try await context.core.home(page: requestedPage)
|
let result = try await context.core.home(
|
||||||
|
page: requestedPage,
|
||||||
|
filter: filter.coreValue
|
||||||
|
)
|
||||||
if requestedPage == 1 {
|
if requestedPage == 1 {
|
||||||
page = result
|
page = result
|
||||||
} else {
|
} else {
|
||||||
page?.activities.append(contentsOf: result.activities)
|
page?.activities.append(contentsOf: result.activities)
|
||||||
page?.issueActivities.append(contentsOf: result.issueActivities)
|
page?.nextPage = result.nextPage
|
||||||
page?.pullActivities.append(contentsOf: result.pullActivities)
|
|
||||||
page?.hasMore = result.hasMore
|
|
||||||
}
|
}
|
||||||
currentPage = requestedPage
|
nextPage = result.nextPage
|
||||||
finishPagination(hasMore: result.hasMore)
|
finishPagination(hasMore: result.nextPage != nil)
|
||||||
title = page?.serverName
|
title = page?.serverName
|
||||||
if requestedPage == 1 { tableView.tableHeaderView = page.map { page in
|
if requestedPage == 1 { tableView.tableHeaderView = page.map { page in
|
||||||
HeatmapView(page: page, selectedFilter: filter.rawValue) { [weak self] index in
|
HeatmapView(page: page, selectedFilter: filter.rawValue) { [weak self] index in
|
||||||
guard let self, let filter = ActivityFilter(rawValue: index) else { return }
|
guard let self, let filter = ActivityFilter(rawValue: index) else { return }
|
||||||
|
guard filter != self.filter else { return }
|
||||||
self.filter = filter
|
self.filter = filter
|
||||||
self.updateActivities()
|
self.loadPage(1, refreshing: false)
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
updateActivities()
|
updateActivities()
|
||||||
|
|||||||
Reference in New Issue
Block a user