Scope repository favorites by pane
This commit is contained in:
@@ -146,7 +146,8 @@ xcrun simctl launch booted de.rfc1437.gotcha
|
|||||||
|
|
||||||
- [ ] The repository list shows name, description, language, open count, update
|
- [ ] The repository list shows name, description, language, open count, update
|
||||||
date, and current favorite state.
|
date, and current favorite state.
|
||||||
- [ ] Toggle a favorite and confirm it remains after refresh and relaunch.
|
- [ ] Toggle a favorite and confirm it remains after refresh and relaunch but
|
||||||
|
does not change the same repository's favorite in Repos or Milestones.
|
||||||
- [ ] Open a repository; the issue list defaults to the saved Open/Closed filter.
|
- [ ] Open a repository; the issue list defaults to the saved Open/Closed filter.
|
||||||
- [ ] Repository issue rows and issue rows inside a milestone show a green open
|
- [ ] Repository issue rows and issue rows inside a milestone show a green open
|
||||||
or purple closed icon beside the title; mixed milestone results use the
|
or purple closed icon beside the title; mixed milestone results use the
|
||||||
@@ -197,7 +198,8 @@ xcrun simctl launch booted de.rfc1437.gotcha
|
|||||||
|
|
||||||
## Repositories and commits
|
## Repositories and commits
|
||||||
|
|
||||||
- [ ] The repository list and favorite behavior match the Issues tab.
|
- [ ] The repository list and favorite behavior match the Issues tab. Toggle a
|
||||||
|
favorite and confirm it persists without affecting Issues or Milestones.
|
||||||
- [ ] Open a repository; commit history initially selects **All**, visibly shows
|
- [ ] Open a repository; commit history initially selects **All**, visibly shows
|
||||||
All in the navigation bar, and includes commits from multiple branches.
|
All in the navigation bar, and includes commits from multiple branches.
|
||||||
- [ ] Open the branch menu; All is checked. Select a branch and verify the label,
|
- [ ] Open the branch menu; All is checked. Select a branch and verify the label,
|
||||||
@@ -273,6 +275,8 @@ xcrun simctl launch booted de.rfc1437.gotcha
|
|||||||
|
|
||||||
- [ ] Milestones uses the server → repository → milestone flow and includes
|
- [ ] Milestones uses the server → repository → milestone flow and includes
|
||||||
both open and closed milestones.
|
both open and closed milestones.
|
||||||
|
- [ ] Toggle a repository favorite and confirm it persists after refresh and
|
||||||
|
relaunch without affecting the same repository in Issues or Repos.
|
||||||
- [ ] Each milestone shows its title, description, state, due date, issue
|
- [ ] Each milestone shows its title, description, state, due date, issue
|
||||||
counts, and a green/amber closed/open progress bar.
|
counts, and a green/amber closed/open progress bar.
|
||||||
- [ ] Open a milestone and verify every assigned issue and pull request is
|
- [ ] Open a milestone and verify every assigned issue and pull request is
|
||||||
|
|||||||
@@ -15,6 +15,25 @@ use storage::*;
|
|||||||
|
|
||||||
uniffi::setup_scaffolding!();
|
uniffi::setup_scaffolding!();
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, uniffi::Enum)]
|
||||||
|
pub enum RepositoryPane {
|
||||||
|
Issues,
|
||||||
|
Commits,
|
||||||
|
Milestones,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepositoryPane {
|
||||||
|
const ALL: [Self; 3] = [Self::Issues, Self::Commits, Self::Milestones];
|
||||||
|
|
||||||
|
const fn key(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Issues => "issues",
|
||||||
|
Self::Commits => "commits",
|
||||||
|
Self::Milestones => "milestones",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error, uniffi::Error)]
|
#[derive(Debug, Error, uniffi::Error)]
|
||||||
pub enum GotchaError {
|
pub enum GotchaError {
|
||||||
#[error("{message}")]
|
#[error("{message}")]
|
||||||
@@ -184,7 +203,11 @@ impl GotchaCore {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn repositories(&self, page: u32) -> Result<RepositoryListPage, GotchaError> {
|
pub async fn repositories(
|
||||||
|
&self,
|
||||||
|
page: u32,
|
||||||
|
pane: RepositoryPane,
|
||||||
|
) -> Result<RepositoryListPage, GotchaError> {
|
||||||
let server = self.server()?;
|
let server = self.server()?;
|
||||||
let page_number = valid_page(page)?;
|
let page_number = valid_page(page)?;
|
||||||
let repositories = load_repositories(&server, page_number).await?;
|
let repositories = load_repositories(&server, page_number).await?;
|
||||||
@@ -202,7 +225,7 @@ impl GotchaCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(RepositoryListPage {
|
Ok(RepositoryListPage {
|
||||||
rows: self.repository_rows(&state),
|
rows: self.repository_rows(&state, pane),
|
||||||
has_more: repositories.has_more,
|
has_more: repositories.has_more,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -211,18 +234,19 @@ impl GotchaCore {
|
|||||||
&self,
|
&self,
|
||||||
owner: String,
|
owner: String,
|
||||||
repository: String,
|
repository: String,
|
||||||
|
pane: RepositoryPane,
|
||||||
) -> Result<Vec<RepositoryRow>, GotchaError> {
|
) -> Result<Vec<RepositoryRow>, GotchaError> {
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
let server = state
|
let server = state
|
||||||
.active_server
|
.active_server
|
||||||
.and_then(|index| state.preferences.servers.get(index))
|
.and_then(|index| state.preferences.servers.get(index))
|
||||||
.ok_or("Select a server first.")?;
|
.ok_or("Select a server first.")?;
|
||||||
let key = favorite_key(&server.url, &owner, &repository);
|
let key = favorite_key(pane, &server.url, &owner, &repository);
|
||||||
if !state.preferences.favorites.remove(&key) {
|
if !state.preferences.favorites.remove(&key) {
|
||||||
state.preferences.favorites.insert(key);
|
state.preferences.favorites.insert(key);
|
||||||
}
|
}
|
||||||
save_preferences(&state.preferences)?;
|
save_preferences(&state.preferences)?;
|
||||||
Ok(self.repository_rows(&state))
|
Ok(self.repository_rows(&state, pane))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn issues(
|
pub async fn issues(
|
||||||
@@ -755,7 +779,7 @@ impl GotchaCore {
|
|||||||
.ok_or_else(|| "Select a server first.".to_string().into())
|
.ok_or_else(|| "Select a server first.".to_string().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repository_rows(&self, state: &State) -> Vec<RepositoryRow> {
|
fn repository_rows(&self, state: &State, pane: RepositoryPane) -> Vec<RepositoryRow> {
|
||||||
let server_url = state
|
let server_url = state
|
||||||
.active_server
|
.active_server
|
||||||
.and_then(|index| state.preferences.servers.get(index))
|
.and_then(|index| state.preferences.servers.get(index))
|
||||||
@@ -763,6 +787,7 @@ impl GotchaCore {
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
repository_rows(&state.repositories, |repository| {
|
repository_rows(&state.repositories, |repository| {
|
||||||
state.preferences.favorites.contains(&favorite_key(
|
state.preferences.favorites.contains(&favorite_key(
|
||||||
|
pane,
|
||||||
server_url,
|
server_url,
|
||||||
&repository.owner,
|
&repository.owner,
|
||||||
&repository.name,
|
&repository.name,
|
||||||
|
|||||||
@@ -3,10 +3,17 @@ use std::{env, fs, path::PathBuf};
|
|||||||
use gotcha_gitea::Client;
|
use gotcha_gitea::Client;
|
||||||
use security_framework::passwords::{get_generic_password, set_generic_password};
|
use security_framework::passwords::{get_generic_password, set_generic_password};
|
||||||
|
|
||||||
use crate::domain::{Preferences, Server, open_status};
|
use crate::{
|
||||||
|
RepositoryPane,
|
||||||
|
domain::{Preferences, Server, open_status},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn favorite_key(server: &str, owner: &str, repository: &str) -> String {
|
pub fn favorite_key(pane: RepositoryPane, server: &str, owner: &str, repository: &str) -> String {
|
||||||
repository_key(server, owner, repository)
|
format!(
|
||||||
|
"{}|{}",
|
||||||
|
pane.key(),
|
||||||
|
repository_key(server, owner, repository)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repository_key(server: &str, owner: &str, repository: &str) -> String {
|
pub fn repository_key(server: &str, owner: &str, repository: &str) -> String {
|
||||||
@@ -39,6 +46,7 @@ pub fn load_preferences() -> Result<Preferences, String> {
|
|||||||
let mut preferences: Preferences =
|
let mut preferences: Preferences =
|
||||||
serde_json::from_slice(&fs::read(&path).map_err(|error| error.to_string())?)
|
serde_json::from_slice(&fs::read(&path).map_err(|error| error.to_string())?)
|
||||||
.map_err(|error| format!("Cannot read {}: {error}", path.display()))?;
|
.map_err(|error| format!("Cannot read {}: {error}", path.display()))?;
|
||||||
|
let favorites_migrated = migrate_favorites(&mut preferences.favorites);
|
||||||
if !matches!(preferences.issue_status.as_str(), "open" | "closed") {
|
if !matches!(preferences.issue_status.as_str(), "open" | "closed") {
|
||||||
preferences.issue_status = open_status();
|
preferences.issue_status = open_status();
|
||||||
}
|
}
|
||||||
@@ -52,9 +60,29 @@ pub fn load_preferences() -> Result<Preferences, String> {
|
|||||||
)
|
)
|
||||||
.map_err(|_| format!("The token for {} is not valid text.", server.name))?;
|
.map_err(|_| format!("The token for {} is not valid text.", server.name))?;
|
||||||
}
|
}
|
||||||
|
if favorites_migrated {
|
||||||
|
save_preferences(&preferences)?;
|
||||||
|
}
|
||||||
Ok(preferences)
|
Ok(preferences)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn migrate_favorites(favorites: &mut std::collections::BTreeSet<String>) -> bool {
|
||||||
|
let legacy: Vec<_> = favorites
|
||||||
|
.iter()
|
||||||
|
.filter(|favorite| {
|
||||||
|
!RepositoryPane::ALL
|
||||||
|
.iter()
|
||||||
|
.any(|pane| favorite.starts_with(&format!("{}|", pane.key())))
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
for favorite in &legacy {
|
||||||
|
favorites.remove(favorite);
|
||||||
|
favorites.extend(RepositoryPane::ALL.map(|pane| format!("{}|{favorite}", pane.key())));
|
||||||
|
}
|
||||||
|
!legacy.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save_preferences(preferences: &Preferences) -> Result<(), String> {
|
pub fn save_preferences(preferences: &Preferences) -> Result<(), String> {
|
||||||
let path = preferences_path()?;
|
let path = preferences_path()?;
|
||||||
let parent = path.parent().ok_or("Invalid app data directory.")?;
|
let parent = path.parent().ok_or("Invalid app data directory.")?;
|
||||||
@@ -96,8 +124,13 @@ mod tests {
|
|||||||
assert!(validate_server("", "https://gitea.example.com", "secret").is_err());
|
assert!(validate_server("", "https://gitea.example.com", "secret").is_err());
|
||||||
assert!(validate_server("Work", "file:///tmp/gitea", "secret").is_err());
|
assert!(validate_server("Work", "file:///tmp/gitea", "secret").is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
favorite_key("https://gitea.example.com", "octo", "demo"),
|
favorite_key(
|
||||||
"https://gitea.example.com|octo/demo"
|
RepositoryPane::Issues,
|
||||||
|
"https://gitea.example.com",
|
||||||
|
"octo",
|
||||||
|
"demo"
|
||||||
|
),
|
||||||
|
"issues|https://gitea.example.com|octo/demo"
|
||||||
);
|
);
|
||||||
let preferences: Preferences = serde_json::from_str(
|
let preferences: Preferences = serde_json::from_str(
|
||||||
r#"{"issue_filters":{"server|octo/demo":{"milestone":"v1","labels":["bug"]}},"pull_filters":{"server":{"milestone":"v2"}}}"#,
|
r#"{"issue_filters":{"server|octo/demo":{"milestone":"v1","labels":["bug"]}},"pull_filters":{"server":{"milestone":"v2"}}}"#,
|
||||||
@@ -136,4 +169,24 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(crate::domain::AppearanceMode::from_index(3), None);
|
assert_eq!(crate::domain::AppearanceMode::from_index(3), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn migrates_global_favorites_to_each_repository_pane() {
|
||||||
|
let mut favorites = ["https://gitea.example.com|octo/demo".to_string()]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert!(migrate_favorites(&mut favorites));
|
||||||
|
assert_eq!(
|
||||||
|
favorites,
|
||||||
|
[
|
||||||
|
"commits|https://gitea.example.com|octo/demo".to_string(),
|
||||||
|
"issues|https://gitea.example.com|octo/demo".to_string(),
|
||||||
|
"milestones|https://gitea.example.com|octo/demo".to_string(),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
assert!(!migrate_favorites(&mut favorites));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -647,7 +647,7 @@ public protocol GotchaCoreProtocol: AnyObject, Sendable {
|
|||||||
|
|
||||||
func pulls(page: UInt32) async throws -> PullListPage
|
func pulls(page: UInt32) async throws -> PullListPage
|
||||||
|
|
||||||
func repositories(page: UInt32) async throws -> RepositoryListPage
|
func repositories(page: UInt32, pane: RepositoryPane) async throws -> RepositoryListPage
|
||||||
|
|
||||||
func repositoryContents(owner: String, repository: String, path: String) async throws -> [RepositoryContentRow]
|
func repositoryContents(owner: String, repository: String, path: String) async throws -> [RepositoryContentRow]
|
||||||
|
|
||||||
@@ -677,7 +677,7 @@ public protocol GotchaCoreProtocol: AnyObject, Sendable {
|
|||||||
|
|
||||||
func startupError() -> String?
|
func startupError() -> String?
|
||||||
|
|
||||||
func toggleFavorite(owner: String, repository: String) throws -> [RepositoryRow]
|
func toggleFavorite(owner: String, repository: String, pane: RepositoryPane) throws -> [RepositoryRow]
|
||||||
|
|
||||||
}
|
}
|
||||||
open class GotchaCore: GotchaCoreProtocol, @unchecked Sendable {
|
open class GotchaCore: GotchaCoreProtocol, @unchecked Sendable {
|
||||||
@@ -1053,12 +1053,12 @@ open func pulls(page: UInt32)async throws -> PullListPage {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func repositories(page: UInt32)async throws -> RepositoryListPage {
|
open func repositories(page: UInt32, pane: RepositoryPane)async throws -> RepositoryListPage {
|
||||||
return
|
return
|
||||||
try await uniffiRustCallAsync(
|
try await uniffiRustCallAsync(
|
||||||
rustFutureFunc: {
|
rustFutureFunc: {
|
||||||
uniffi_gotcha_core_fn_method_gotchacore_repositories(
|
uniffi_gotcha_core_fn_method_gotchacore_repositories(
|
||||||
self.uniffiCloneHandle(),FfiConverterUInt32.lower(page)
|
self.uniffiCloneHandle(),FfiConverterUInt32.lower(page),FfiConverterTypeRepositoryPane_lower(pane)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
pollFunc: ffi_gotcha_core_rust_future_poll_rust_buffer,
|
pollFunc: ffi_gotcha_core_rust_future_poll_rust_buffer,
|
||||||
@@ -1233,13 +1233,14 @@ open func startupError() -> String? {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
open func toggleFavorite(owner: String, repository: String)throws -> [RepositoryRow] {
|
open func toggleFavorite(owner: String, repository: String, pane: RepositoryPane)throws -> [RepositoryRow] {
|
||||||
return try FfiConverterSequenceTypeRepositoryRow.lift(try rustCallWithError(FfiConverterTypeGotchaError_lift) {
|
return try FfiConverterSequenceTypeRepositoryRow.lift(try rustCallWithError(FfiConverterTypeGotchaError_lift) {
|
||||||
uniffiCallStatus in
|
uniffiCallStatus in
|
||||||
uniffi_gotcha_core_fn_method_gotchacore_toggle_favorite(
|
uniffi_gotcha_core_fn_method_gotchacore_toggle_favorite(
|
||||||
self.uniffiCloneHandle(),
|
self.uniffiCloneHandle(),
|
||||||
FfiConverterString.lower(owner),
|
FfiConverterString.lower(owner),
|
||||||
FfiConverterString.lower(repository),uniffiCallStatus
|
FfiConverterString.lower(repository),
|
||||||
|
FfiConverterTypeRepositoryPane_lower(pane),uniffiCallStatus
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -3443,6 +3444,79 @@ public func FfiConverterTypeHomeActivityFilter_lower(_ value: HomeActivityFilter
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public enum RepositoryPane: Equatable, Hashable {
|
||||||
|
|
||||||
|
case issues
|
||||||
|
case commits
|
||||||
|
case milestones
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension RepositoryPane: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeRepositoryPane: FfiConverterRustBuffer {
|
||||||
|
typealias SwiftType = RepositoryPane
|
||||||
|
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> RepositoryPane {
|
||||||
|
let variant: Int32 = try readInt(&buf)
|
||||||
|
switch variant {
|
||||||
|
|
||||||
|
case 1: return .issues
|
||||||
|
|
||||||
|
case 2: return .commits
|
||||||
|
|
||||||
|
case 3: return .milestones
|
||||||
|
|
||||||
|
default: throw UniffiInternalError.unexpectedEnumCase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: RepositoryPane, into buf: inout [UInt8]) {
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
|
||||||
|
case .issues:
|
||||||
|
writeInt(&buf, Int32(1))
|
||||||
|
|
||||||
|
|
||||||
|
case .commits:
|
||||||
|
writeInt(&buf, Int32(2))
|
||||||
|
|
||||||
|
|
||||||
|
case .milestones:
|
||||||
|
writeInt(&buf, Int32(3))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeRepositoryPane_lift(_ buf: RustBuffer) throws -> RepositoryPane {
|
||||||
|
return try FfiConverterTypeRepositoryPane.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeRepositoryPane_lower(_ value: RepositoryPane) -> RustBuffer {
|
||||||
|
return FfiConverterTypeRepositoryPane.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if swift(>=5.8)
|
#if swift(>=5.8)
|
||||||
@_documentation(visibility: private)
|
@_documentation(visibility: private)
|
||||||
#endif
|
#endif
|
||||||
@@ -4094,7 +4168,7 @@ private let initializationResult: InitializationResult = {
|
|||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_pulls() != 37027) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_pulls() != 37027) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_repositories() != 31164) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_repositories() != 4035) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_repository_contents() != 8454) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_repository_contents() != 8454) {
|
||||||
@@ -4139,7 +4213,7 @@ private let initializationResult: InitializationResult = {
|
|||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_startup_error() != 56765) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_startup_error() != 56765) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
if (uniffi_gotcha_core_checksum_method_gotchacore_toggle_favorite() != 26694) {
|
if (uniffi_gotcha_core_checksum_method_gotchacore_toggle_favorite() != 24958) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
if (uniffi_gotcha_core_checksum_constructor_gotchacore_new() != 35775) {
|
if (uniffi_gotcha_core_checksum_constructor_gotchacore_new() != 35775) {
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ uint64_t uniffi_gotcha_core_fn_method_gotchacore_pulls(uint64_t ptr, uint32_t pa
|
|||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_REPOSITORIES
|
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_REPOSITORIES
|
||||||
#define UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_REPOSITORIES
|
#define UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_REPOSITORIES
|
||||||
uint64_t uniffi_gotcha_core_fn_method_gotchacore_repositories(uint64_t ptr, uint32_t page
|
uint64_t uniffi_gotcha_core_fn_method_gotchacore_repositories(uint64_t ptr, uint32_t page, RustBuffer pane
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_REPOSITORY_CONTENTS
|
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_REPOSITORY_CONTENTS
|
||||||
@@ -446,7 +446,7 @@ RustBuffer uniffi_gotcha_core_fn_method_gotchacore_startup_error(uint64_t ptr, R
|
|||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_TOGGLE_FAVORITE
|
#ifndef UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_TOGGLE_FAVORITE
|
||||||
#define UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_TOGGLE_FAVORITE
|
#define UNIFFI_FFIDEF_UNIFFI_GOTCHA_CORE_FN_METHOD_GOTCHACORE_TOGGLE_FAVORITE
|
||||||
RustBuffer uniffi_gotcha_core_fn_method_gotchacore_toggle_favorite(uint64_t ptr, RustBuffer owner, RustBuffer repository, RustCallStatus *_Nonnull out_status
|
RustBuffer uniffi_gotcha_core_fn_method_gotchacore_toggle_favorite(uint64_t ptr, RustBuffer owner, RustBuffer repository, RustBuffer pane, RustCallStatus *_Nonnull out_status
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_FFI_GOTCHA_CORE_RUSTBUFFER_ALLOC
|
#ifndef UNIFFI_FFIDEF_FFI_GOTCHA_CORE_RUSTBUFFER_ALLOC
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ final class AppContext {
|
|||||||
UIImage(systemName: name)
|
UIImage(systemName: name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func repositoryRoot(mode: RepositoryMode) -> UIViewController {
|
private func repositoryRoot(mode: RepositoryPane) -> UIViewController {
|
||||||
if core.activeServerIndex() == nil {
|
if core.activeServerIndex() == nil {
|
||||||
return ServersViewController(context: self)
|
return ServersViewController(context: self)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
enum RepositoryMode {
|
|
||||||
case issues
|
|
||||||
case commits
|
|
||||||
case milestones
|
|
||||||
}
|
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
final class ServersViewController: UITableViewController {
|
final class ServersViewController: UITableViewController {
|
||||||
private let context: AppContext
|
private let context: AppContext
|
||||||
@@ -186,11 +180,11 @@ final class AddServerViewController: UITableViewController, UITextFieldDelegate
|
|||||||
@MainActor
|
@MainActor
|
||||||
final class RepositoriesViewController: RefreshingTableViewController {
|
final class RepositoriesViewController: RefreshingTableViewController {
|
||||||
private let context: AppContext
|
private let context: AppContext
|
||||||
private let mode: RepositoryMode
|
private let mode: RepositoryPane
|
||||||
private var rows: [RepositoryRow] = []
|
private var rows: [RepositoryRow] = []
|
||||||
private var currentPage: UInt32 = 0
|
private var currentPage: UInt32 = 0
|
||||||
|
|
||||||
init(context: AppContext, mode: RepositoryMode) {
|
init(context: AppContext, mode: RepositoryPane) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
super.init()
|
super.init()
|
||||||
@@ -231,7 +225,7 @@ final class RepositoriesViewController: RefreshingTableViewController {
|
|||||||
loadingTask?.cancel()
|
loadingTask?.cancel()
|
||||||
loadingTask = Task {
|
loadingTask = Task {
|
||||||
do {
|
do {
|
||||||
let result = try await context.core.repositories(page: page)
|
let result = try await context.core.repositories(page: page, pane: mode)
|
||||||
rows = result.rows
|
rows = result.rows
|
||||||
currentPage = page
|
currentPage = page
|
||||||
finishPagination(hasMore: result.hasMore)
|
finishPagination(hasMore: result.hasMore)
|
||||||
@@ -307,7 +301,11 @@ final class RepositoriesViewController: RefreshingTableViewController {
|
|||||||
|
|
||||||
private func toggleFavorite(_ row: RepositoryRow) {
|
private func toggleFavorite(_ row: RepositoryRow) {
|
||||||
do {
|
do {
|
||||||
rows = try context.core.toggleFavorite(owner: row.owner, repository: row.name)
|
rows = try context.core.toggleFavorite(
|
||||||
|
owner: row.owner,
|
||||||
|
repository: row.name,
|
||||||
|
pane: mode
|
||||||
|
)
|
||||||
tableView.reloadData()
|
tableView.reloadData()
|
||||||
} catch {
|
} catch {
|
||||||
show(error: error)
|
show(error: error)
|
||||||
|
|||||||
Reference in New Issue
Block a user