Close share picker after consent without a second modal

This commit is contained in:
Samuel Onoja committed 2026-09-29 13:10:24 +01:00
1 parent 7d3a88bef7
commit 96e1b6ac5a
3 files changed
+35 -93

No files matched your search

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="5" y="5" width="14" height="14" rx="3" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 136 B

+6 -27
View File
@@ -364,14 +364,14 @@ impl Backend {
} }
let result = tokio::select! { let result = tokio::select! {
_ = cancel.wait() => Err(StartError::Cancelled), _ = cancel.wait() => Err(StartError::Cancelled),
result = tokio::time::timeout(Duration::from_secs(120), start_streams(if bar_controlled { "Ferese" } else { &app_id }, multiple, cursor, !bar_controlled)) => result.unwrap_or_else(|_| Err(StartError::Failed("Sharing request timed out".into()))), result = tokio::time::timeout(Duration::from_secs(120), start_streams(if bar_controlled { "Ferese" } else { &app_id }, multiple, cursor)) => result.unwrap_or_else(|_| Err(StartError::Failed("Sharing request timed out".into()))),
}; };
let _ = connection let _ = connection
.object_server() .object_server()
.remove::<Request, _>(handle) .remove::<Request, _>(handle)
.await; .await;
match result { match result {
Ok((children, indicator, streams)) if !cancel.stopped.load(Ordering::SeqCst) => { Ok((children, streams)) if !cancel.stopped.load(Ordering::SeqCst) => {
if let Some(session) = self.sessions.lock().await.get_mut(session_handle.as_str()) { if let Some(session) = self.sessions.lock().await.get_mut(session_handle.as_str()) {
session.phase = Phase::Running; session.phase = Phase::Running;
} }
@@ -379,7 +379,7 @@ impl Backend {
let connection = connection.clone(); let connection = connection.clone();
let path = session_handle.to_string(); let path = session_handle.to_string();
tokio::spawn(async move { tokio::spawn(async move {
supervise(children, indicator, cancel).await; supervise(children, cancel).await;
backend.end(&connection, &path).await; backend.end(&connection, &path).await;
}); });
let streams: Vec<(u32, Options)> = streams let streams: Vec<(u32, Options)> = streams
@@ -488,8 +488,7 @@ async fn start_streams(
app: &str, app: &str,
multiple: bool, multiple: bool,
cursor: bool, cursor: bool,
show_indicator: bool, ) -> Result<(Vec<Child>, Vec<Ready>), StartError> {
) -> Result<(Vec<Child>, Option<Child>, Vec<Ready>), StartError> {
let sources = tokio::task::spawn_blocking(|| { let sources = tokio::task::spawn_blocking(|| {
Capture::connect(&AtomicBool::new(false)).map(|capture| capture.sources()) Capture::connect(&AtomicBool::new(false)).map(|capture| capture.sources())
}) })
@@ -499,7 +498,6 @@ async fn start_streams(
app: app.to_owned(), app: app.to_owned(),
sources, sources,
multiple, multiple,
indicator: false,
}; };
let selection = picker(&prompt) let selection = picker(&prompt)
.await? .await?
@@ -544,20 +542,7 @@ async fn start_streams(
streams.push(ready); streams.push(ready);
children.push(child); children.push(child);
} }
let indicator = if show_indicator { Ok((children, streams))
Some(
picker(&Prompt {
app: app.to_owned(),
sources: selected,
multiple,
indicator: true,
})
.await?,
)
} else {
None
};
Ok((children, indicator, streams))
} }
fn validate_selection( fn validate_selection(
sources: &[Source], sources: &[Source],
@@ -582,12 +567,9 @@ fn validate_selection(
} }
Ok(selected) Ok(selected)
} }
async fn supervise(mut children: Vec<Child>, mut indicator: Option<Child>, cancel: Arc<Cancel>) { async fn supervise(mut children: Vec<Child>, cancel: Arc<Cancel>) {
loop { loop {
if cancel.stopped.load(Ordering::SeqCst) if cancel.stopped.load(Ordering::SeqCst)
|| indicator
.as_mut()
.is_some_and(|child| !matches!(child.try_wait(), Ok(None)))
|| children || children
.iter_mut() .iter_mut()
.any(|c| !matches!(c.try_wait(), Ok(None))) .any(|c| !matches!(c.try_wait(), Ok(None)))
@@ -600,9 +582,6 @@ async fn supervise(mut children: Vec<Child>, mut indicator: Option<Child>, cance
for child in &mut children { for child in &mut children {
let _ = child.kill().await; let _ = child.kill().await;
} }
if let Some(indicator) = &mut indicator {
let _ = indicator.kill().await;
}
} }
pub async fn run() -> Result<(), Box<dyn std::error::Error>> { pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
let backend = Backend::default(); let backend = Backend::default();
+29 -65
View File
@@ -13,7 +13,6 @@ pub struct Prompt {
pub app: String, pub app: String,
pub sources: Vec<Source>, pub sources: Vec<Source>,
pub multiple: bool, pub multiple: bool,
pub indicator: bool,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -86,15 +85,10 @@ impl cosmic::Application for Picker {
background, background,
foreground, foreground,
}; };
let title = if app.prompt.indicator {
"Ferese — screen sharing"
} else {
"Ferese — share your screen"
};
let task = app let task = app
.core .core
.main_window_id() .main_window_id()
.map(|id| app.set_window_title(title.into(), id)) .map(|id| app.set_window_title("Ferese — share your screen".into(), id))
.unwrap_or_else(Task::none); .unwrap_or_else(Task::none);
(app, task) (app, task)
@@ -148,18 +142,8 @@ impl cosmic::Application for Picker {
row![ row![
glyph(include_bytes!("../assets/display.svg"), 24), glyph(include_bytes!("../assets/display.svg"), 24),
column![ column![
text(if self.prompt.indicator { text("Choose a display").size(18),
"Screen sharing" text(format!("Share with {app}")).size(12),
} else {
"Choose a display"
})
.size(18),
text(if self.prompt.indicator {
format!("Shared with {app}")
} else {
format!("Share with {app}")
})
.size(12),
] ]
.spacing(2) .spacing(2)
.width(Length::Fill), .width(Length::Fill),
@@ -181,24 +165,20 @@ impl cosmic::Application for Picker {
] ]
.spacing(12) .spacing(12)
.align_y(Alignment::Center); .align_y(Alignment::Center);
if selected || self.prompt.indicator { if selected {
entry = entry.push(glyph(include_bytes!("../assets/check.svg"), 20)); entry = entry.push(glyph(include_bytes!("../assets/check.svg"), 20));
} }
if self.prompt.indicator { sources = sources.push(
sources = sources.push(container(entry).padding(8).width(Length::Fill)); button::custom(entry)
} else { .class(if selected {
sources = sources.push( ferese_theme::accent_button()
button::custom(entry) } else {
.class(if selected { cosmic::theme::Button::Standard
ferese_theme::accent_button() })
} else { .padding(8)
cosmic::theme::Button::Standard .width(Length::Fill)
}) .on_press(Message::Select(index)),
.padding(8) );
.width(Length::Fill)
.on_press(Message::Select(index)),
);
}
} }
content = content.push(scrollable(sources).height(Length::Fixed( content = content.push(scrollable(sources).height(Length::Fixed(
(self.prompt.sources.len().min(4) * 56) as f32, (self.prompt.sources.len().min(4) * 56) as f32,
@@ -208,37 +188,21 @@ impl cosmic::Application for Picker {
.size(12) .size(12)
.width(Length::Fill), .width(Length::Fill),
); );
if self.prompt.indicator { let mut share = button::custom(
content = content.push( row![
button::custom( text("Share"),
row![ glyph(include_bytes!("../assets/arrow.svg"), 16)
glyph(include_bytes!("../assets/stop.svg"), 16), ]
text("Stop sharing") .spacing(8)
] .align_y(Alignment::Center),
.spacing(8) )
.align_y(Alignment::Center), .class(ferese_theme::accent_button())
) .padding([6, 16]);
.class(cosmic::theme::Button::Destructive) if !self.selected.is_empty() {
.padding([6, 16]) share = share.on_press(Message::Share);
.on_press(Message::Cancel),
);
} else {
let mut share = button::custom(
row![
text("Share"),
glyph(include_bytes!("../assets/arrow.svg"), 16)
]
.spacing(8)
.align_y(Alignment::Center),
)
.class(ferese_theme::accent_button())
.padding([6, 16]);
if !self.selected.is_empty() {
share = share.on_press(Message::Share);
}
content = content
.push(row![button::text("Cancel").on_press(Message::Cancel), share].spacing(8));
} }
content =
content.push(row![button::text("Cancel").on_press(Message::Cancel), share].spacing(8));
container(content).padding(14).width(Length::Fill).into() container(content).padding(14).width(Length::Fill).into()
} }
} }