@@ -39,24 +39,44 @@ pub struct ChatInfo {
3939 pub message_count : usize ,
4040}
4141
42- /// Get message counts per chat using custom SQL
43- fn get_message_counts (
42+ /// Chat statistics (message count and last message timestamp)
43+ struct ChatStats {
44+ message_count : usize ,
45+ last_message_date : i64 ,
46+ }
47+
48+ /// Get message counts and last message date per chat using custom SQL
49+ fn get_chat_stats (
4450 db : & rusqlite:: Connection ,
45- ) -> Result < HashMap < i32 , usize > , imessage_database:: error:: table:: TableError > {
46- let mut counts = HashMap :: new ( ) ;
51+ ) -> Result < HashMap < i32 , ChatStats > , imessage_database:: error:: table:: TableError > {
52+ let mut stats = HashMap :: new ( ) ;
4753
48- let mut stmt =
49- db. prepare ( "SELECT chat_id, COUNT(*) as count FROM chat_message_join GROUP BY chat_id" ) ?;
54+ let mut stmt = db. prepare (
55+ "SELECT cmj.chat_id, COUNT(*) as count, MAX(m.date) as last_date
56+ FROM chat_message_join cmj
57+ JOIN message m ON cmj.message_id = m.ROWID
58+ GROUP BY cmj.chat_id" ,
59+ ) ?;
5060
5161 let rows = stmt. query_map ( [ ] , |row| {
52- Ok ( ( row. get :: < _ , i32 > ( 0 ) ?, row. get :: < _ , usize > ( 1 ) ?) )
62+ Ok ( (
63+ row. get :: < _ , i32 > ( 0 ) ?,
64+ row. get :: < _ , usize > ( 1 ) ?,
65+ row. get :: < _ , i64 > ( 2 ) . unwrap_or ( 0 ) ,
66+ ) )
5367 } ) ?;
5468
55- for ( chat_id, count) in rows. flatten ( ) {
56- counts. insert ( chat_id, count) ;
69+ for ( chat_id, count, last_date) in rows. flatten ( ) {
70+ stats. insert (
71+ chat_id,
72+ ChatStats {
73+ message_count : count,
74+ last_message_date : last_date,
75+ } ,
76+ ) ;
5777 }
5878
59- Ok ( counts )
79+ Ok ( stats )
6080}
6181
6282/// Resolve a display name for a chat, using contacts if available
@@ -96,61 +116,86 @@ pub fn resolve_chat_display_name(
96116
97117/// List available iMessage chats
98118pub fn list_chats ( ) -> Result < Vec < ChatInfo > , String > {
119+ eprintln ! ( "[list_chats] Starting..." ) ;
120+
99121 // Get database path
100122 let db_path = default_db_path ( ) ;
123+ eprintln ! ( "[list_chats] DB path: {:?}" , db_path) ;
101124
102125 // Connect to database
103126 let db = get_connection ( & db_path) . map_err ( |e| format ! ( "Failed to connect to database: {e}" ) ) ?;
127+ eprintln ! ( "[list_chats] Connected to database" ) ;
104128
105129 // Build contacts index for name resolution
130+ eprintln ! ( "[list_chats] Building contacts index..." ) ;
106131 let contacts_index = ContactsIndex :: build ( None ) . unwrap_or_default ( ) ;
132+ eprintln ! ( "[list_chats] Contacts index built" ) ;
107133
108134 // Cache all chats
135+ eprintln ! ( "[list_chats] Loading chats..." ) ;
109136 let chats = Chat :: cache ( & db) . map_err ( |e| format ! ( "Failed to load chats: {e}" ) ) ?;
137+ eprintln ! ( "[list_chats] Loaded {} chats" , chats. len( ) ) ;
110138
111139 // Cache handles (contacts)
140+ eprintln ! ( "[list_chats] Loading handles..." ) ;
112141 let handles = Handle :: cache ( & db) . map_err ( |e| format ! ( "Failed to load handles: {e}" ) ) ?;
113142 let deduped_handles = Handle :: dedupe ( & handles) ;
143+ eprintln ! ( "[list_chats] Loaded {} handles" , handles. len( ) ) ;
114144
115145 // Build participants map with resolved names
116146 let participants_map = contacts_index. build_participants_map ( & handles, & deduped_handles) ;
117147
118148 // Cache chat participants (chat_id -> set of handle_ids)
149+ eprintln ! ( "[list_chats] Loading chat participants..." ) ;
119150 let chat_participants =
120151 ChatToHandle :: cache ( & db) . map_err ( |e| format ! ( "Failed to load participants: {e}" ) ) ?;
121-
122- // Get message counts
123- let message_counts =
124- get_message_counts ( & db) . map_err ( |e| format ! ( "Failed to get message counts: {e}" ) ) ?;
125-
126- // Build result
127- let mut result: Vec < ChatInfo > = chats
152+ eprintln ! (
153+ "[list_chats] Loaded participants for {} chats" ,
154+ chat_participants. len( )
155+ ) ;
156+
157+ // Get chat stats (message counts and last message dates)
158+ eprintln ! ( "[list_chats] Getting chat stats..." ) ;
159+ let chat_stats = get_chat_stats ( & db) . map_err ( |e| format ! ( "Failed to get chat stats: {e}" ) ) ?;
160+ eprintln ! ( "[list_chats] Got chat stats" ) ;
161+
162+ // Build result with last_message_date for sorting
163+ let mut result: Vec < ( ChatInfo , i64 ) > = chats
128164 . into_iter ( )
129165 . map ( |( id, chat) | {
130166 let participants = chat_participants. get ( & id) ;
131167 let participant_count = participants. map ( |p| p. len ( ) ) . unwrap_or ( 0 ) ;
132- let message_count = message_counts. get ( & id) . copied ( ) . unwrap_or ( 0 ) ;
168+ let stats = chat_stats. get ( & id) ;
169+ let message_count = stats. map ( |s| s. message_count ) . unwrap_or ( 0 ) ;
170+ let last_message_date = stats. map ( |s| s. last_message_date ) . unwrap_or ( 0 ) ;
133171
134172 let display_name =
135173 resolve_chat_display_name ( & chat, participants, & participants_map, & deduped_handles) ;
136174
137- ChatInfo {
138- id,
139- display_name,
140- chat_identifier : chat. chat_identifier . clone ( ) ,
141- service : chat
142- . service_name
143- . as_deref ( )
144- . unwrap_or ( "Unknown" )
145- . to_string ( ) ,
146- participant_count,
147- message_count,
148- }
175+ (
176+ ChatInfo {
177+ id,
178+ display_name,
179+ chat_identifier : chat. chat_identifier . clone ( ) ,
180+ service : chat
181+ . service_name
182+ . as_deref ( )
183+ . unwrap_or ( "Unknown" )
184+ . to_string ( ) ,
185+ participant_count,
186+ message_count,
187+ } ,
188+ last_message_date,
189+ )
149190 } )
150191 . collect ( ) ;
151192
152- // Sort by message count descending (most active chats first)
153- result. sort_by ( |a, b| b. message_count . cmp ( & a. message_count ) ) ;
193+ // Sort by last message date descending (most recent first)
194+ result. sort_by ( |a, b| b. 1 . cmp ( & a. 1 ) ) ;
195+
196+ // Extract just the ChatInfo
197+ let result: Vec < ChatInfo > = result. into_iter ( ) . map ( |( info, _) | info) . collect ( ) ;
154198
199+ eprintln ! ( "[list_chats] Done! Returning {} chats" , result. len( ) ) ;
155200 Ok ( result)
156201}
0 commit comments