diff --git a/JS/index.js b/JS/index.js index 1b892dd..e55849a 100644 --- a/JS/index.js +++ b/JS/index.js @@ -154,6 +154,7 @@ const widthFor12ptFont = [ // this is tied to mac_main.c's message window max width const MAX_WIDTH = 304 const SPACE_WIDTH = widthFor12ptFont[32] +let canStart = false const getNextWordLength = (word) => { @@ -325,10 +326,37 @@ if (TEST_MODE) { }, 10000) } -class iMessageClient { +let storedArgsAndResults = { + getMessages: { + args: {}, + output: {} + }, + hasNewMessagesInChat: { + args: {}, + output: {} + }, + getChats: { + args: {}, + output: {} + }, + getChatCounts: { + args: {}, + output: {} + } +} + +// this is our private interface, meant to communicate with our GraphQL server and fill caches +// we want everything cached as much as possible to cut down on perceived perf issues on the +// classic Macintosh end +class iMessageGraphClientClass { async getMessages (chatId, page) { + storedArgsAndResults.getMessages.args = { + chatId, + page + } + if (TEST_MODE) { return splitMessages(TEST_MESSAGES) @@ -361,23 +389,19 @@ class iMessageClient { let messages = result.data.getMessages - return splitMessages(messages) + storedArgsAndResults.getMessages.output = splitMessages(messages) } async hasNewMessagesInChat (chatId) { + storedArgsAndResults.hasNewMessagesInChat.args = { + chatId + } + let currentLastMessageOutput = `${lastMessageOutput}` let messageOutput = await this.getMessages(chatId, 0) - return (currentLastMessageOutput !== messageOutput).toString() - } - - async hasNewMessages (chatId) { - - let currentLastMessageOutput = `${lastMessageOutput}` - let messageOutput = await this.getChats(chatId, 0) - - return (currentLastMessageOutput !== messageOutput).toString() + storedArgsAndResults.hasNewMessagesInChat.output = (currentLastMessageOutput !== messageOutput).toString() } async sendMessage (chatId, message) { @@ -418,6 +442,7 @@ class iMessageClient { } async getChats () { + console.log(`getChats`) if (TEST_MODE) { @@ -452,7 +477,9 @@ class iMessageClient { console.log(`getChats complete`) - return parseChatsToFriendlyNameString(chats) + storedArgsAndResults.getChats.output = parseChatsToFriendlyNameString(chats) + + console.log(storedArgsAndResults.getChats.output) } async getChatCounts () { @@ -512,7 +539,7 @@ class iMessageClient { friendlyNameStrings = friendlyNameStrings.substring(1, friendlyNameStrings.length) console.log(friendlyNameStrings) - return friendlyNameStrings + storedArgsAndResults.getChatCounts.output = friendlyNameStrings } setIPAddress (IPAddress) { @@ -521,6 +548,8 @@ class iMessageClient { if (TEST_MODE) { + canStart = true + return `success` } @@ -543,9 +572,107 @@ class iMessageClient { console.log(`return success`) + canStart = true + return `success` } } +let iMessageGraphClient = new iMessageGraphClientClass() + +// provide the public interface +class iMessageClient { + + constructor () { + + // kick off an update interval + setInterval(async () => { + + console.log(`run interval`) + + if (!canStart) { + + console.log(`can't start yet`) + + return + } + + console.log(`running...`) + + if (Object.keys(storedArgsAndResults.getMessages.args).length > 0) { + + await iMessageGraphClient.getMessages(storedArgsAndResults.getMessages.args.chatId, storedArgsAndResults.getMessages.args.page) + } + + if (Object.keys(storedArgsAndResults.hasNewMessagesInChat.args).length > 0) { + + await iMessageGraphClient.hasNewMessagesInChat(storedArgsAndResults.hasNewMessagesInChat.chatId) + } + + await iMessageGraphClient.getChats() + await iMessageGraphClient.getChatCounts() + + console.log(`complete!`) + }, 2000) + } + + async getMessages (chatId, page) { + + console.log(`iMessageClient.getMessages`) + + if (storedArgsAndResults.getMessages.args.chatId !== chatId || storedArgsAndResults.getMessages.args.page !== page) { + + await iMessageGraphClient.getMessages(chatId, page) + } + + return storedArgsAndResults.getMessages.output + } + + async hasNewMessagesInChat (chatId) { + + console.log(`iMessageClient.hasNewMessagesInChat`) + + if (storedArgsAndResults.hasNewMessagesInChat.args.chatId !== chatId) { + + await iMessageGraphClient.hasNewMessagesInChat(chatId) + } + + return storedArgsAndResults.hasNewMessagesInChat.output + } + + async sendMessage (chatId, message) { + + console.log(`iMessageClient.sendMessage`) + + return await iMessageGraphClient.sendMessage(chatId, message) + } + + async getChats () { + + console.log(`iMessageClient.getChats`) + + if (Object.keys(storedArgsAndResults.getChats.output).length === 0) { + + await iMessageGraphClient.getChats() + } + + return storedArgsAndResults.getChats.output + } + + getChatCounts () { + + console.log(`iMessageClient.getChatCounts`) + + return storedArgsAndResults.getChatCounts.output + } + + setIPAddress (IPAddress) { + + console.log(`iMessageClient.setIPAddress`) + + return iMessageGraphClient.setIPAddress(IPAddress) + } +} + module.exports = iMessageClient diff --git a/mac_main.c b/mac_main.c index f2bd051..58b1496 100644 --- a/mac_main.c +++ b/mac_main.c @@ -682,7 +682,18 @@ void DoMenuCommand(menuResult) case mLight: // note this was co-opted to send new chats instead of the demo functionality. do the // same thing for other menu items as necessary - sendNewChat = 1; + switch (menuItem) { + case 2: + getChats(); + break; + default: + sendNewChat = 1; + break; + } + + char x[255]; + sprintf(x, "MENU %d", menuItem); + writeSerialPortDebug(boutRefNum, x); break; case mHelp: diff --git a/mac_main.r b/mac_main.r index 8ffb864..7350130 100644 --- a/mac_main.r +++ b/mac_main.r @@ -137,6 +137,8 @@ resource 'MENU' (mLight, preload) { { "New Message", noicon, nokey, nomark, plain; + "Refresh Chat List", + noicon, nokey, nomark, plain; } }; diff --git a/nuklear_app.c b/nuklear_app.c index 2eac10c..c1e5297 100644 --- a/nuklear_app.c +++ b/nuklear_app.c @@ -1,6 +1,5 @@ // TODO: -// - IN PROGRESS new message window -- need to figure this out -// - IN PROGRESS need timeout on serial messages in case the computer at the other end dies (prevent hard reset) -- probably possible in coprocessorjs library. made an attempt, needs tested +// - test, bug fixes, write blog posts #define WINDOW_WIDTH 510 #define WINDOW_HEIGHT 302 @@ -49,13 +48,13 @@ char chatFriendlyNames[16][64]; char ip_input_buffer[255]; char jsFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE char chatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE +char tempChatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE char previousChatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE char new_message_input_buffer[255]; int activeMessageCounter = 0; int chatFriendlyNamesCounter = 0; int coprocessorLoaded = 0; int forceRedraw = 2; // this is how many 'iterations' of the UI that we need to see every element for -int haveRun = 0; int ipAddressSet = 0; int mouse_x; int mouse_y; @@ -115,6 +114,25 @@ void sendMessage() { return; } +// set up function to get available chat (fill buttons on the left hand side) +// interval is set by the event loop in mac_main +void getChats() { + + writeSerialPortDebug(boutRefNum, "getChats!"); + + callFunctionOnCoprocessor("getChats", "", jsFunctionResponse); + + char * token = (char *)strtokm(jsFunctionResponse, ","); + // loop through the string to extract all other tokens + while (token != NULL) { + writeSerialPortDebug(boutRefNum, token); + sprintf(chatFriendlyNames[chatFriendlyNamesCounter++], "%s", token); + token = (char *)strtokm(NULL, ","); + } + + return; +} + void sendIPAddressToCoprocessor() { char output[2048]; @@ -123,6 +141,9 @@ void sendIPAddressToCoprocessor() { writeSerialPortDebug(boutRefNum, output); callFunctionOnCoprocessor("setIPAddress", output, jsFunctionResponse); + // now that the IP is set, we can get all of our chats + getChats(); + return; } @@ -170,8 +191,9 @@ void getChatCounts() { #endif SysBeep(1); - char **saveptr; - char *token = strtok_r(chatCountFunctionResponse, ",", saveptr); + char *saveptr; + strcpy(tempChatCountFunctionResponse, chatCountFunctionResponse); + char *token = strtok_r(tempChatCountFunctionResponse, ",", &saveptr); // loop through the string to extract all other tokens while (token != NULL) { @@ -182,9 +204,9 @@ void getChatCounts() { #endif // should be in format NAME:::COUNT - char **saveptr2; - char *name = strtok_r(token, ":::", saveptr2); - char *countString = strtok_r(NULL, ":::", saveptr2); + char *saveptr2; + char *name = strtok_r(token, ":::", &saveptr2); + char *countString = strtok_r(NULL, ":::", &saveptr2); short count = atoi(countString); #ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING @@ -193,13 +215,6 @@ void getChatCounts() { writeSerialPortDebug(boutRefNum, x); #endif - if (count == 0) { - - token = strtok_r(NULL, ",", saveptr); - - continue; - } - for (int i = 0; i < chatFriendlyNamesCounter; i++) { if (strstr(chatFriendlyNames[i], " new) ") != NULL) { @@ -208,9 +223,9 @@ void getChatCounts() { sprintf(chatName, "%s", chatFriendlyNames[i]); // we are throwing out the first token - strtok_r(chatName, " new) ", saveptr2); + strtok_r(chatName, " new) ", &saveptr2); - char *tempChatFriendlyName = strtok_r(NULL, " new) ", saveptr2); + char *tempChatFriendlyName = strtok_r(NULL, " new) ", &saveptr2); if (prefix(tempChatFriendlyName, name)) { @@ -219,7 +234,13 @@ void getChatCounts() { writeSerialPortDebug(boutRefNum, name); #endif - sprintf(chatFriendlyNames[i], "(%d new) %s", count, name); + if (count == 0) { + + sprintf(chatFriendlyNames[i], "%s", name); + } else { + + sprintf(chatFriendlyNames[i], "(%d new) %s", count, name); + } break; } } else { @@ -231,13 +252,19 @@ void getChatCounts() { writeSerialPortDebug(boutRefNum, name); #endif - sprintf(chatFriendlyNames[i], "(%d new) %s", count, name); + if (count == 0) { + + sprintf(chatFriendlyNames[i], "%s", name); + } else { + + sprintf(chatFriendlyNames[i], "(%d new) %s", count, name); + } break; } } } - token = strtok_r(NULL, ",", saveptr); + token = strtok_r(NULL, ",", &saveptr); } strcpy(previousChatCountFunctionResponse, chatCountFunctionResponse); @@ -272,32 +299,6 @@ void getHasNewMessagesInChat(char *thread) { return; } -// set up function to get available chat (fill buttons on right hand side) -// run it on some interval? make sure user is not typing!!! -void getChats() { - - writeSerialPortDebug(boutRefNum, "getChats!"); - - if (haveRun) { - - return; - } - - haveRun = 1; - - callFunctionOnCoprocessor("getChats", "", jsFunctionResponse); - - char * token = (char *)strtokm(jsFunctionResponse, ","); - // loop through the string to extract all other tokens - while (token != NULL) { - writeSerialPortDebug(boutRefNum, token); - sprintf(chatFriendlyNames[chatFriendlyNamesCounter++], "%s", token); - token = (char *)strtokm(NULL, ","); - } - - return; -} - Boolean chatWindowCollision; Boolean messageWindowCollision; @@ -383,9 +384,9 @@ static void nuklearApp(struct nk_context *ctx) { nk_layout_row_begin(ctx, NK_STATIC, 30, 1); { nk_layout_row_push(ctx, WINDOW_WIDTH - 120); - nk_label(ctx, "this is known to be a bit finnicky,", NK_TEXT_ALIGN_LEFT); + nk_label(ctx, "enter contact name as it would appear", NK_TEXT_ALIGN_LEFT); nk_layout_row_push(ctx, WINDOW_WIDTH - 120); - nk_label(ctx, "input exact phone number", NK_TEXT_ALIGN_LEFT); + nk_label(ctx, "on your iPhone, iPad, modern Mac, etc", NK_TEXT_ALIGN_LEFT); } nk_layout_row_end(ctx); @@ -406,6 +407,8 @@ static void nuklearApp(struct nk_context *ctx) { memset(&activeChatMessages[i], '\0', 2048); } + + getMessages(activeChat, 0); } } nk_layout_row_end(ctx); @@ -425,8 +428,6 @@ static void nuklearApp(struct nk_context *ctx) { forceRedraw = 2; } - getChats(); - nk_layout_row_begin(ctx, NK_STATIC, 25, 1); { for (int i = 0; i < chatFriendlyNamesCounter; i++) { @@ -445,16 +446,36 @@ static void nuklearApp(struct nk_context *ctx) { char chatName[96]; sprintf(chatName, "%s", chatFriendlyNames[i]); - writeSerialPortDebug(boutRefNum, chatName); + + #ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING + writeSerialPortDebug(boutRefNum, "clicked1 chatName"); + writeSerialPortDebug(boutRefNum, chatName); + #endif // we are throwing out the first token - strtokm(chatName, " new) "); - char *name = strtokm(NULL, " new) "); + char *name = (char *)strtokm(chatName, " new) "); + + #ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING + writeSerialPortDebug(boutRefNum, "clicked1 portion1 of string, will toss"); + writeSerialPortDebug(boutRefNum, name); + #endif + + name = (char *)strtokm(NULL, " new) "); + + #ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING + writeSerialPortDebug(boutRefNum, "clicked1 have name to assign to activeChat"); + writeSerialPortDebug(boutRefNum, name); + #endif - writeSerialPortDebug(boutRefNum, name); sprintf(activeChat, "%s", name); + sprintf(chatFriendlyNames[i], "%s", name); } else { + #ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING + writeSerialPortDebug(boutRefNum, "clicked2 chatName"); + writeSerialPortDebug(boutRefNum, chatFriendlyNames[i]); + #endif + sprintf(activeChat, "%s", chatFriendlyNames[i]); }