@@ -371,6 +371,167 @@ pub async fn delete_and_leave_chat(
371371 Ok ( ( ) )
372372}
373373
374+ /// Create a new group chat (basic group)
375+ #[ tauri:: command]
376+ pub async fn create_group (
377+ account_id : String ,
378+ title : String ,
379+ user_ids : Vec < i64 > ,
380+ state : State < ' _ , Arc < RwLock < AppState > > > ,
381+ ) -> Result < i64 , String > {
382+ tracing:: info!( account_id = %account_id, title = %title, "Creating group" ) ;
383+
384+ let wrapper = {
385+ let state_guard = state. read ( ) . await ;
386+ let client_manager = state_guard
387+ . client_manager
388+ . as_ref ( )
389+ . ok_or ( "Client manager not initialized" ) ?;
390+ client_manager
391+ . get_client ( & account_id)
392+ . await
393+ . ok_or ( "Client not found for this account" ) ?
394+ } ;
395+
396+ // Resolve user_ids to InputUser
397+ let mut input_users = Vec :: new ( ) ;
398+ for uid in & user_ids {
399+ let peer = super :: peer_resolve:: resolve_peer ( & wrapper, * uid) . await ?;
400+ let peer_ref = PeerRef :: from ( & peer) ;
401+ let input_user: tl:: enums:: InputUser = peer_ref. into ( ) ;
402+ input_users. push ( input_user) ;
403+ }
404+
405+ let request = tl:: functions:: messages:: CreateChat {
406+ users : input_users,
407+ title,
408+ ttl_period : None ,
409+ } ;
410+
411+ let result = wrapper. client . invoke ( & request)
412+ . await
413+ . map_err ( |e| format ! ( "Failed to create group: {}" , e) ) ?;
414+
415+ // Extract chat ID from InvitedUsers result
416+ let chat_id = match & result {
417+ tl:: enums:: messages:: InvitedUsers :: Users ( invited) => {
418+ // The updates contain the new chat info
419+ match & invited. updates {
420+ tl:: enums:: Updates :: Updates ( u) => {
421+ // Find the chat in the chats list
422+ u. chats . first ( ) . map ( |c| match c {
423+ tl:: enums:: Chat :: Chat ( chat) => -( chat. id as i64 ) , // Bot API format for groups
424+ tl:: enums:: Chat :: Channel ( ch) => {
425+ let id = ch. id as i64 ;
426+ -1_000_000_000_000 - id // Bot API format for channels/supergroups
427+ }
428+ _ => 0 ,
429+ } ) . unwrap_or ( 0 )
430+ }
431+ _ => 0 ,
432+ }
433+ }
434+ } ;
435+
436+ tracing:: info!( account_id = %account_id, chat_id = chat_id, "Group created successfully" ) ;
437+ Ok ( chat_id)
438+ }
439+
440+ /// Create a new channel or supergroup (megagroup)
441+ #[ tauri:: command]
442+ pub async fn create_channel (
443+ account_id : String ,
444+ title : String ,
445+ about : String ,
446+ is_megagroup : bool ,
447+ state : State < ' _ , Arc < RwLock < AppState > > > ,
448+ ) -> Result < i64 , String > {
449+ tracing:: info!( account_id = %account_id, title = %title, is_megagroup = is_megagroup, "Creating channel" ) ;
450+
451+ let wrapper = {
452+ let state_guard = state. read ( ) . await ;
453+ let client_manager = state_guard
454+ . client_manager
455+ . as_ref ( )
456+ . ok_or ( "Client manager not initialized" ) ?;
457+ client_manager
458+ . get_client ( & account_id)
459+ . await
460+ . ok_or ( "Client not found for this account" ) ?
461+ } ;
462+
463+ let request = tl:: functions:: channels:: CreateChannel {
464+ broadcast : !is_megagroup,
465+ megagroup : is_megagroup,
466+ for_import : false ,
467+ forum : false ,
468+ title,
469+ about,
470+ geo_point : None ,
471+ address : None ,
472+ ttl_period : None ,
473+ } ;
474+
475+ let result = wrapper. client . invoke ( & request)
476+ . await
477+ . map_err ( |e| format ! ( "Failed to create channel: {}" , e) ) ?;
478+
479+ // Extract channel ID from Updates
480+ let chat_id = match & result {
481+ tl:: enums:: Updates :: Updates ( u) => {
482+ u. chats . first ( ) . map ( |c| match c {
483+ tl:: enums:: Chat :: Channel ( ch) => {
484+ let id = ch. id as i64 ;
485+ -1_000_000_000_000 - id
486+ }
487+ _ => 0 ,
488+ } ) . unwrap_or ( 0 )
489+ }
490+ _ => 0 ,
491+ } ;
492+
493+ tracing:: info!( account_id = %account_id, chat_id = chat_id, "Channel created successfully" ) ;
494+ Ok ( chat_id)
495+ }
496+
497+ /// Get contacts (users from chat list)
498+ #[ tauri:: command]
499+ pub async fn get_contacts (
500+ account_id : String ,
501+ state : State < ' _ , Arc < RwLock < AppState > > > ,
502+ ) -> Result < Vec < Chat > , String > {
503+ let state_guard = state. read ( ) . await ;
504+ let storage = Arc :: clone (
505+ state_guard
506+ . storage
507+ . as_ref ( )
508+ . ok_or ( "Storage not initialized" ) ?,
509+ ) ;
510+ drop ( state_guard) ;
511+
512+ let records = storage. get_chats ( & account_id) . await
513+ . map_err ( |e| format ! ( "Failed to get chats from storage: {}" , e) ) ?;
514+
515+ // Filter to only user-type chats (contacts)
516+ let contacts = records
517+ . into_iter ( )
518+ . filter ( |r| r. chat_type == "user" )
519+ . map ( |r| Chat {
520+ id : r. id ,
521+ title : r. title ,
522+ username : r. username ,
523+ unread_count : r. unread_count ,
524+ chat_type : r. chat_type ,
525+ last_message : r. last_message ,
526+ avatar_path : r. avatar_path ,
527+ is_forum : r. is_forum ,
528+ is_muted : false ,
529+ } )
530+ . collect ( ) ;
531+
532+ Ok ( contacts)
533+ }
534+
374535/// Helper function to download avatar for a peer.
375536/// The `avatars_dir` must be an absolute path (derived from app_data_dir).
376537/// Uses a semaphore to limit concurrent downloads and handles FLOOD_WAIT.
0 commit comments