@@ -11,10 +11,11 @@ use std::any::TypeId;
11
11
use std:: ffi:: OsStr ;
12
12
use std:: path:: PathBuf ;
13
13
use std:: sync:: { Arc , LazyLock , Mutex , mpsc} ;
14
+ use std:: time:: Duration ;
14
15
15
- use iced:: widget :: button :: Style ;
16
- use iced:: widget:: { Column , button, column, container, row, text} ;
17
- use iced:: { Element , Fill , Subscription , Task , Theme , clipboard} ;
16
+ use iced:: task :: Handle ;
17
+ use iced:: widget:: { self , Column , Space , button, column, container, row, text} ;
18
+ use iced:: { Element , Fill , Font , Subscription , Task , Theme , clipboard, font } ;
18
19
use tracing:: { debug, error, trace} ;
19
20
use uuid:: Uuid ;
20
21
@@ -40,6 +41,8 @@ static SERVER_PORT: LazyLock<u16> = LazyLock::new(|| {
40
41
static SERVER_ADDRESS : LazyLock < String > =
41
42
LazyLock :: new ( || format ! ( "{SERVER_HOST}:{}" , * SERVER_PORT ) ) ;
42
43
44
+ const COPIED_TOAST_DURATION : Duration = Duration :: from_secs ( 2 ) ;
45
+
43
46
pub fn main ( ) -> iced:: Result {
44
47
common:: logger:: init_logging ( env ! ( "CARGO_CRATE_NAME" ) ) ;
45
48
@@ -127,7 +130,22 @@ fn update(state: &mut State, message: Message) -> Task<Message> {
127
130
}
128
131
Message :: ShareProfile ( id) => {
129
132
let url = format ! ( "{WEB_ORIGIN}/ow-tracker?profile={id}" ) ;
130
- return clipboard:: write ( url) ;
133
+
134
+ return clipboard:: write ( url)
135
+ . chain ( Task :: done ( Message :: HideProfileShared ) )
136
+ . chain ( Task :: done ( Message :: ShowProfileShared ) ) ;
137
+ }
138
+ Message :: ShowProfileShared => {
139
+ let ( task, abort) = Task :: future ( async {
140
+ std:: thread:: sleep ( COPIED_TOAST_DURATION ) ;
141
+ Message :: HideProfileShared
142
+ } )
143
+ . abortable ( ) ;
144
+ state. copied_toast_hide . replace ( abort) ;
145
+ return task;
146
+ }
147
+ Message :: HideProfileShared => {
148
+ state. copied_toast_hide . take ( ) ;
131
149
}
132
150
Message :: ForgetRegister ( id) => {
133
151
let Some ( config) = & mut state. config else {
@@ -190,9 +208,10 @@ fn view(state: &State) -> Element<'_, Message> {
190
208
. as_ref( )
191
209
. is_some_and( |name| name == p)
192
210
{
193
- Style :: default ( ) . with_background( palette. success)
211
+ widget :: button :: Style :: default ( ) . with_background( palette. success)
194
212
} else {
195
- Style :: default ( ) . with_background( palette. primary. scale_alpha( 0.5 ) )
213
+ widget:: button:: Style :: default ( )
214
+ . with_background( palette. primary. scale_alpha( 0.5 ) )
196
215
}
197
216
} )
198
217
. on_press( Message :: SelectProfile ( p. to_string( ) ) ) ,
@@ -207,6 +226,21 @@ fn view(state: &State) -> Element<'_, Message> {
207
226
. into ( )
208
227
} ) ;
209
228
229
+ let copied_block: Element < _ > = if state. copied_toast_hide . is_some ( ) {
230
+ text ( "Copied" )
231
+ . font ( Font {
232
+ style : font:: Style :: Italic ,
233
+ ..Default :: default ( )
234
+ } )
235
+ . style ( |theme : & Theme | widget:: text:: Style {
236
+ color : Some ( theme. palette ( ) . success ) ,
237
+ } )
238
+ . size ( 20 )
239
+ . into ( )
240
+ } else {
241
+ Space :: new ( 0 , 0 ) . into ( )
242
+ } ;
243
+
210
244
container (
211
245
column ! [
212
246
row![
@@ -217,17 +251,21 @@ fn view(state: &State) -> Element<'_, Message> {
217
251
// todo: show something when no profiles found
218
252
text( "Found profiles:" ) . size( 20 ) ,
219
253
Column :: from_iter( profiles) ,
220
- button( "Register" ) . on_press_maybe(
221
- if state
222
- . selected_profile
223
- . as_ref( )
224
- . is_some_and( |p| config. find_profile( p) . is_none( ) )
225
- {
226
- Some ( Message :: RegisterOnServer )
227
- } else {
228
- None
229
- }
230
- ) ,
254
+ row![
255
+ button( "Register" ) . on_press_maybe(
256
+ if state
257
+ . selected_profile
258
+ . as_ref( )
259
+ . is_some_and( |p| config. find_profile( p) . is_none( ) )
260
+ {
261
+ Some ( Message :: RegisterOnServer )
262
+ } else {
263
+ None
264
+ }
265
+ ) ,
266
+ copied_block,
267
+ ]
268
+ . spacing( 10 ) ,
231
269
]
232
270
. spacing ( 10 ) ,
233
271
)
@@ -259,6 +297,8 @@ enum Message {
259
297
SelectProfile ( String ) ,
260
298
FileUpdated ( FileUpdateEvent ) ,
261
299
ShareProfile ( Uuid ) ,
300
+ ShowProfileShared ,
301
+ HideProfileShared ,
262
302
ForgetRegister ( Uuid ) ,
263
303
}
264
304
@@ -276,6 +316,9 @@ struct State {
276
316
/// Receiver for file watch thread
277
317
file_watches_receiver : Arc < Mutex < mpsc:: Receiver < WatchAction > > > ,
278
318
319
+ /// Handle to hide "copied" toast
320
+ copied_toast_hide : Option < Handle > ,
321
+
279
322
/// App's config
280
323
config : Option < Config > ,
281
324
@@ -334,6 +377,7 @@ impl State {
334
377
selected_profile : None ,
335
378
send_file_watches : tx,
336
379
file_watches_receiver : Arc :: new ( Mutex :: new ( rx) ) ,
380
+ copied_toast_hide : None ,
337
381
config : Some ( config) ,
338
382
error : None ,
339
383
}
0 commit comments