├── .gitignore ├── LICENSE ├── README.md ├── helper.sh ├── helper ├── dynamicisland.h ├── islandhelper.c ├── makefile ├── notificationhelper.h └── sketchybar.h ├── images ├── demo.gif └── fullupdated.png ├── item.sh ├── listener.sh ├── process.sh ├── scripts └── islands │ ├── appswitch │ ├── appswitch_island.sh │ ├── creator.sh │ ├── handler.sh │ └── reset.sh │ ├── brightness │ ├── brightness_island.sh │ ├── creator.sh │ ├── handler.sh │ └── reset.sh │ ├── clear.sh │ ├── music │ ├── cava.conf │ ├── cava.sh │ ├── creator.sh │ ├── handler.sh │ ├── music_island.sh │ ├── pause_island.sh │ ├── reset-resume.sh │ └── reset.sh │ ├── notification │ ├── creator.sh │ ├── notification_island.sh │ └── reset.sh │ ├── power │ ├── creator.sh │ ├── handler.sh │ ├── power_island.sh │ └── reset.sh │ ├── restore.sh │ ├── volume │ ├── creator.sh │ ├── handler.sh │ ├── reset.sh │ └── volume_island.sh │ └── wifi │ ├── creator.sh │ ├── handler.sh │ ├── reset.sh │ └── wifi_island.sh ├── sketchybarrc └── userconfigs └── mbp2021_14.sh /.gitignore: -------------------------------------------------------------------------------- 1 | artwork* 2 | queued.bak 3 | islandhelper 4 | 5 | # macos files 6 | .DS_Store 7 | scripts/islands/music/cache 8 | scripts/islands/previous_island 9 | userconfig.sh 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 crissNb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dynamic Island on macOS using SketchyBar 2 | 3 | Dynamic Island on iPhone 14 Pro implementation on Mac using SketchyBar 4 | 5 | ## If you're interested in supporting me and want a completely written in Swift version (with more features and GUI), then checkout my [FluidNoti](https://fluidnoti.vercel.app/) app. 6 | 7 | I will still be updating this sketchybar version of dynamic island as well, but FluidNoti will be more actively developed. 8 | 9 | ![](images/fullupdated.png) 10 | 11 | DEMO 12 | ==== 13 | 14 | ![](images/demo.gif) 15 | 16 | Table of Contents 17 | ================= 18 | 19 | [Installation](#installation) 20 | 21 | [Updating](#updating) 22 | 23 | [Uninstallation](#uninstallation) 24 | 25 | [Optimal Setup](#optimal-setup) 26 | 27 | [Configuration](#configuration) 28 | 29 | [Features](#features) 30 | 31 | [Todo](#todo) 32 | 33 | [Bugs](#bugs) 34 | 35 | [FAQ](#faq) 36 | 37 | [Credits](#credits) 38 | 39 | Installation 40 | ============ 41 | 42 | ### Requirements 43 | 44 | - [Homebrew](https://brew.sh/) 45 | - [SketchyBar](https://github.com/FelixKratz/SketchyBar) 46 | - sf-symbols (`brew install --cask sf-symbols`) 47 | - jq (`brew install jq`) 48 | 49 | For music island to work properly you need the following additional requirements 50 | 51 | - [cava](https://github.com/karlstav/cava) (`brew install cava`) 52 | - [Background Music](https://github.com/kyleneideck/BackgroundMusic) (`brew install --cask background-music`) 53 | 54 | ### Getting Started 55 | 56 | Installation can be done with `brew`: 57 | 58 | ```bash 59 | brew tap crissnb/dynamicisland 60 | brew install DynamicIslandSketchybar 61 | ``` 62 | 63 | Now a `userconfig.sh` file must be copied to `~/.config/dynamic-island-sketchybar/` directory. This can be done by copying an appropriate config file for your machine. 64 | 65 | E.g. for 2021 MacBook Pro 14 Inch: 66 | 67 | ```bash 68 | cp ~/.config/dynamic-island-sketchybar/userconfigs/mbp2021_14.sh ~/.config/dynamic-island-sketchybar/userconfig.sh 69 | ``` 70 | 71 | The file must be called `userconfig.sh` and located right under dynamic-island-sketchybar directory for dynamic island to function. 72 | 73 | Finally, the Dynamic Island can be opened via 74 | 75 | ```bash 76 | dynamic-island 77 | ``` 78 | 79 | NOTE: There appears to be a bug that dynamic island helper program does not run the first time it is installed (after restarting sketchybar). If this is the case, simply restart the program. 80 | 81 | If you'd like to have the `dynamic-island` run automatically, then have the command at the end of `sketchybarrc` (in case you are using sketchybar). 82 | 83 | ## 84 | 85 | Updating 86 | ============= 87 | 88 | Just go into the `dynamic-island-sketchybar` directory and pull the changes from this repository. 89 | 90 | ```bash 91 | cd ~/.config/dynamic-island-sketchybar 92 | git pull 93 | ``` 94 | 95 | Uninstallation 96 | ============== 97 | 98 | Uninstalling this project can be done by removing the symlink and the config folder (this repository). 99 | 100 | ```bash 101 | rm $(which dynamic-island-sketchybar) 102 | rm -r ~/.config/dynamic-island-sketchybar/ 103 | ``` 104 | 105 | This will remove dynamic-island-sketchybar. Note that this will not remove sketchybar (see sketchybar documentation for sketchybar uninstallation guide). 106 | 107 | Configuration 108 | ============= 109 | 110 | All Dynamic Island configuration can be done in `~/.config/dynamic-island-sketchybar/userconfig.sh`. There are `userconfig.sh` presets created in `~/.config/dynamic-island-sketchybar/userconfigs/`, so copy the appropriate config for your machine during installation for best results. 111 | 112 | By default, dynamic island will take input from Apple Music. If you would like to use Spotify instead, change `P_DYNAMIC_ISLAND_MUSIC_SOURCE` variable in `userconfig.sh` to "Spotify" instead. 113 | 114 | As of right now, users need to manually adjust the notch size in pixels. If you have found an optimal notch size for MacBook with a notch, please let me know. Once enough data has been gathered, preset system will be implemented. 115 | 116 | ### Disabling features 117 | 118 | Set the option for the island you want to disable to `0` in your `userconfig.sh` 119 | 120 | ```bash 121 | P_DYNAMIC_ISLAND_MUSIC_ENABLED=0 122 | P_DYNAMIC_ISLAND_APPSWITCH_ENABLED=0 123 | P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED=0 124 | P_DYNAMIC_ISLAND_VOLUME_ENABLED=0 125 | ``` 126 | 127 | Notifications are disabled by default. 128 | 129 | You need to restart sketchybar service in order for the changes to take effect. 130 | 131 | ### Screen resolutions 132 | In order for the dynamic island to properly scale with your monitor's resolution, you need to specify your monitor's resolution manually by changing `P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION` variable in `userconfig.sh`. If you are using an external 1080p monitor, you would set this value to the following: 133 | 134 | ```bash 135 | P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION=1920 136 | ``` 137 | 138 | In case of built-in display, it must be divded by 2, e.g.: MBP 14 has 3024 resolution, so 3024/2=1512. 139 | 140 | Features 141 | ======== 142 | 143 | The following is a list of features that this dynamic island project (working islands) has. Some islands do not work properly just yet. Thus, you may experience some glitches when using them. 144 | 145 | - General Notifications (experimental) 146 | 147 | - Volume/Brightness 148 | 149 | - Music 150 | 151 | - Pause/Resume 152 | 153 | - App Switch 154 | 155 | - Power Source 156 | 157 | - WIFI 158 | 159 | Enabling notifications may have performance impact. 160 | Music island saves the artwork 'temporarily' (this artwork file is then replaced with a newer artwork file, if requested) to display it on the dynamic island. It also creates a cache file. 161 | 162 | ### Recommended Features 163 | 164 | For "general notifications" feature, I suggest you to turn on the "Do Not Disturb" on your macOS settings. This way the notifications will only be shown via the dynamic island. 165 | 166 | If you would like to purely rely on the dynamic island interface for your volume and brightness levels, type the following command in terminal: 167 | 168 | ```bash 169 | launchctl unload -F /System/Library/LaunchAgents/com.apple.OSDUIHelper.plist 170 | ``` 171 | 172 | This requires you to disable system integrity protection (SIP). 173 | 174 | Todo 175 | ==== 176 | 177 | - Code cleanup for notification helper 178 | - Make GitHub Wiki 179 | - Hide the notch on non-notched laptops 180 | 181 | ### Upcoming Features / Upcoming Islands 182 | 183 | - Lock / Unlock 184 | - Bluetooth status 185 | - Do not disturb 186 | - ...and more! 187 | 188 | Bugs 189 | ==== 190 | 191 | If you encounter any bugs, feel free to open up an issue! 192 | 193 | Contributing 194 | ============ 195 | 196 | Pull requests are also welcome. 197 | 198 | ## 199 | 200 | The following terms/system may be relevant when looking at the code: 201 | 202 | There are mainly three parts of this implementation of dynamic island: `dynamic island item`, `dynamic island helper` (written in C, communicates with sketchybar) and `island scripts` (written in shell script) 203 | 204 | The dynamic island has its own event items. These event items are subscribed to sketchybar's specific events, e.g. "volume event", "brightness event", etc. These event items will cast a trigger called `dynamic_island_queue` with environment variables provided (details). 205 | 206 | The `dynamic island helper` receives a trigger `dynamic_island_queue` and processes the islands in a queue (first come, first serve). An item from the queue gets removed when the dynamic island item is not handling any islands. 207 | To remove an item from the dynamic island queue, the dynamic island helper program calls another trigger, `di_helper_listener_event` with environment variables that describe the island (i.e. identifier of the island, args). This event will then call `process.sh`, which will then call the correct island from `island scripts` depending on the environment variables provided. 208 | 209 | The `island scripts` also contain delays and get automatically reset (`reset.sh`) after a set amount of duration. After `reset.sh` script runs, the island item's process is finished. 210 | 211 | When an island item finishes its process, it tells the helper program to process the next item in the queue. 212 | 213 | Tested devices 214 | ============== 215 | 216 | - 2021 MacBook Pro 14 217 | 218 | FAQ 219 | === 220 | 221 | **Q:** Can I use this on MacBook without a notch? 222 | 223 | **A:** Yes, it should work, using this config will create a notch on your device. 224 | 225 | ## 226 | 227 | **Q:** Can I use this with multi monitors? 228 | 229 | **A:** It's possible. You can either configure it to show in specific displays (e.g. main display) or all displays. However, unexpected results might occur if you attempt to use this project with multiple monitors of different resolutions. 230 | 231 | ## 232 | 233 | Credits 234 | ======= 235 | 236 | Base sketchybarrc was taken from FelixKratz's [dotfiles](https://github.com/FelixKratz/dotfiles). 237 | 238 | Base visualizer config was taken from @ColaMint 239 | -------------------------------------------------------------------------------- /helper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DYNAMIC_ISLAND_DIR=$( 3 | cd "$(dirname "${BASH_SOURCE[0]}")" || exit 4 | pwd -P 5 | ) 6 | 7 | # run helper program 8 | ISLANDHELPER=git.crissnb.islandhelper 9 | killall islandhelper 10 | cd "$DYNAMIC_ISLAND_DIR"/helper/ && make 11 | "$DYNAMIC_ISLAND_DIR"/helper/islandhelper "$ISLANDHELPER" & 12 | -------------------------------------------------------------------------------- /helper/dynamicisland.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_QUEUE_SIZE 16 6 | 7 | struct dynamicIsland { 8 | char command[2048]; 9 | }; 10 | 11 | struct islandItem { 12 | char identifier[32]; 13 | char args[2048]; 14 | }; 15 | 16 | struct islandItemNode { 17 | struct islandItem *data; 18 | struct islandItemNode *nextNode; 19 | }; 20 | 21 | struct islandItemNode *head = NULL; 22 | struct islandItemNode *current = NULL; 23 | char currentDisplaying[32]; 24 | int isDisplaying = 0; 25 | 26 | static inline void dynamic_island_init(struct dynamicIsland *dynamic_island) { 27 | snprintf(dynamic_island->command, 512, ""); 28 | } 29 | 30 | static inline void pop_head() { 31 | if (head == NULL) { 32 | return; 33 | } 34 | 35 | // Redirect head to the second item 36 | struct islandItemNode *nextNode = NULL; 37 | nextNode = head->nextNode; 38 | 39 | free(head); 40 | 41 | head = nextNode; 42 | if (head == NULL) { 43 | current = NULL; 44 | } 45 | } 46 | 47 | char* remove_newlines_and_spaces(const char* json) { 48 | int len = strlen(json); 49 | char* result = (char*)malloc(len + 1); // Allocate memory for the result string 50 | if (result == NULL) { 51 | printf("Memory allocation failed!\n"); 52 | exit(EXIT_FAILURE); 53 | } 54 | 55 | int j = 0; // Index for the result string 56 | 57 | for (int i = 0; i < len; i++) { 58 | if (json[i] != '\n' && json[i] != '\t') { 59 | result[j++] = json[i]; // Copy non-newline and non-space characters 60 | } 61 | } 62 | result[j] = '\0'; // Null-terminate the result string 63 | return result; 64 | } 65 | 66 | static inline void sendCommand(struct dynamicIsland *dynamic_island, 67 | int overrideSetting) { 68 | if (head == NULL) { 69 | return; 70 | } 71 | 72 | snprintf(dynamic_island->command, 512, 73 | "--trigger di_helper_listener_event IDENTIFIER=\"%s\" OVERRIDE=%d " 74 | "ARGS=\'%s\'", 75 | head->data->identifier, overrideSetting, remove_newlines_and_spaces(head->data->args)); 76 | strcpy(currentDisplaying, head->data->identifier); 77 | isDisplaying = 1; 78 | } 79 | 80 | static inline int display(struct dynamicIsland *dynamic_island) { 81 | if (head == NULL) { 82 | // Do not apply any command 83 | return 0; 84 | } 85 | 86 | if (isDisplaying == 0) { 87 | sendCommand(dynamic_island, 0); 88 | return 1; 89 | } else { 90 | if (head->nextNode != NULL) { 91 | if (strcmp(currentDisplaying, head->nextNode->data->identifier) == 0) { 92 | pop_head(); 93 | sendCommand(dynamic_island, 1); 94 | return 1; 95 | } 96 | } 97 | } 98 | 99 | return 0; 100 | } 101 | 102 | static inline int queue_island(struct dynamicIsland *dynamic_island, 103 | struct islandItem *itemToQueue) { 104 | // Create a new node and attach to the latest node 105 | struct islandItemNode *newNode = 106 | (struct islandItemNode *)malloc(sizeof(struct islandItemNode)); 107 | newNode->data = itemToQueue; 108 | 109 | if (currentDisplaying[0] != 0) { 110 | if (strcmp(currentDisplaying, newNode->data->identifier) == 0) { 111 | // Redirect the node 112 | newNode->nextNode = head->nextNode; 113 | 114 | // Insert right after head 115 | head->nextNode = newNode; 116 | } else { 117 | if (current != NULL) { 118 | struct islandItemNode *temp = head->nextNode; 119 | 120 | while (temp != NULL) { 121 | if (strcmp(temp->data->identifier, newNode->data->identifier) == 0) { 122 | temp->data = newNode->data; 123 | free(newNode); 124 | return 0; 125 | } 126 | temp = temp->nextNode; 127 | } 128 | current->nextNode = newNode; 129 | } 130 | } 131 | } 132 | current = newNode; 133 | 134 | if (head == NULL) { 135 | head = current; 136 | } 137 | 138 | return display(dynamic_island); 139 | } 140 | -------------------------------------------------------------------------------- /helper/islandhelper.c: -------------------------------------------------------------------------------- 1 | #include "notificationhelper.h" 2 | #include "sketchybar.h" 3 | #include 4 | 5 | struct dynamicIsland g_dynamic_island; 6 | struct notificationHelper g_notification_helper; 7 | 8 | void handler(env env) { 9 | // Environment variables passed from sketchybar can be accessed as seen below 10 | char *name = env_get_value_for_key(env, "NAME"); 11 | char *sender = env_get_value_for_key(env, "SENDER"); 12 | char *id = env_get_value_for_key(env, "INFO"); 13 | char *args = env_get_value_for_key(env, "ISLAND_ARGS"); 14 | 15 | if (strcmp(sender, "dynamic_island_request") == 0) { 16 | // Request to deliver new island 17 | isDisplaying = 0; 18 | 19 | // clear current displaying 20 | memset(currentDisplaying, 0, 32); 21 | snprintf(g_dynamic_island.command, 512, ""); 22 | 23 | pop_head(); 24 | 25 | if (display(&g_dynamic_island) == 1) { 26 | sketchybar(g_dynamic_island.command); 27 | } 28 | } else if (strcmp(sender, "dynamic_island_queue") == 0) { 29 | // Check data is not null 30 | if (args[0] == '\0' || id[0] == '\0') { 31 | return; 32 | } 33 | 34 | // Create new queuable item 35 | struct islandItem *newItem = 36 | (struct islandItem *)malloc(sizeof(struct islandItem)); 37 | sprintf(newItem->identifier, "%s", id); 38 | sprintf(newItem->args, "%s", args); 39 | 40 | // Get item from queue and apply to dynamic island 41 | if (queue_island(&g_dynamic_island, newItem) == 1) { 42 | sketchybar(g_dynamic_island.command); 43 | } 44 | } else if ((strcmp(sender, "routine") == 0) || 45 | (strcmp(sender, "forced") == 0)) { 46 | // Check notifications 47 | 48 | // check environment variable exists to prevent seg fault 49 | if (getenv("P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED") == NULL) { 50 | return; 51 | } 52 | 53 | if (*getenv("P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED") == (char)'1') { 54 | struct islandItem *notificationItem = 55 | check_notifications(&g_notification_helper); 56 | 57 | if (notificationItem != NULL) { 58 | // Queue notification item to display 59 | if (queue_island(&g_dynamic_island, notificationItem) == 1) { 60 | sketchybar(g_dynamic_island.command); 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | int main(int argc, char **argv) { 68 | if (argc < 2) { 69 | printf("Usage: provider \"\"\n"); 70 | exit(1); 71 | } 72 | 73 | dynamic_island_init(&g_dynamic_island); 74 | 75 | if (getenv("P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED") == NULL && 76 | *getenv("P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED") == (char)'1') { 77 | database_init(&g_notification_helper); 78 | } 79 | 80 | event_server_begin(handler, argv[1]); 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /helper/makefile: -------------------------------------------------------------------------------- 1 | islandhelper: islandhelper.c dynamicisland.h sketchybar.h notificationhelper.h 2 | clang -std=c99 -O3 islandhelper.c -o islandhelper -l sqlite3 -framework CoreFoundation 3 | -------------------------------------------------------------------------------- /helper/notificationhelper.h: -------------------------------------------------------------------------------- 1 | #include "CoreFoundation/CFPropertyList.h" 2 | #include "dynamicisland.h" 3 | #include "sqlite3.h" 4 | #include "stdio.h" 5 | #include "stdlib.h" 6 | #include "string.h" 7 | 8 | static const char DBPATH_CMD[256] = { 9 | "lsof -p $(ps aux | grep -m1 usernoted | awk '{ print $2 }')| awk '{ print " 10 | "$NF }' | grep 'db2/db$'"}; 11 | char DBPATH[256]; 12 | 13 | struct notificationHelper { 14 | char command[512]; 15 | }; 16 | 17 | sqlite3 *db; 18 | sqlite3_stmt *stmt; 19 | 20 | int rc; 21 | char *error_message = 0; 22 | 23 | int lastNotifCount = 0; 24 | 25 | static inline void 26 | database_init(struct notificationHelper *notificationHelper) { 27 | // get notification database location 28 | FILE *output; 29 | output = popen(DBPATH_CMD, "r"); 30 | if (!output) { 31 | return; 32 | } 33 | fgets(DBPATH, sizeof(DBPATH), output); 34 | // Remove trailing new line character from fgets 35 | DBPATH[strcspn(DBPATH, "\n")] = 0; 36 | } 37 | 38 | static inline void parse_notification_details(const UInt8 *rawData, int dataLen, 39 | char **title, char **subtitle, 40 | char **body) { 41 | CFDataRef ref = CFDataCreate(kCFAllocatorDefault, rawData, dataLen); 42 | 43 | if (ref) { 44 | CFDictionaryRef detailsPlist = 45 | (CFDictionaryRef)CFPropertyListCreateWithData( 46 | NULL, ref, kCFPropertyListMutableContainers, NULL, NULL); 47 | if (detailsPlist) { 48 | // First access req value dictionary 49 | CFStringRef key = 50 | CFStringCreateWithCString(NULL, "req", kCFStringEncodingUTF8); 51 | 52 | CFDictionaryRef req_dict = 53 | (CFDictionaryRef)CFDictionaryGetValue(detailsPlist, key); 54 | 55 | // Prepare to read values 56 | CFStringRef titl_key = 57 | CFStringCreateWithCString(NULL, "titl", kCFStringEncodingUTF8); 58 | CFStringRef subt_key = 59 | CFStringCreateWithCString(NULL, "subt", kCFStringEncodingUTF8); 60 | CFStringRef body_key = 61 | CFStringCreateWithCString(NULL, "body", kCFStringEncodingUTF8); 62 | 63 | // Read values 64 | CFStringRef titl_value = 65 | (CFStringRef)CFDictionaryGetValue(req_dict, titl_key); 66 | CFStringRef subt_value = 67 | (CFStringRef)CFDictionaryGetValue(req_dict, subt_key); 68 | CFStringRef body_value = 69 | (CFStringRef)CFDictionaryGetValue(req_dict, body_key); 70 | 71 | char titl_buffer[1024]; 72 | if (titl_value) { 73 | if (CFStringGetCString(titl_value, titl_buffer, sizeof(titl_buffer), 74 | kCFStringEncodingUTF8)) { 75 | *title = titl_buffer; 76 | } 77 | } 78 | 79 | char subt_buffer[1024]; 80 | if (subt_value) { 81 | if (CFStringGetCString(subt_value, subt_buffer, sizeof(subt_buffer), 82 | kCFStringEncodingUTF8)) { 83 | *subtitle = subt_buffer; 84 | } 85 | } 86 | 87 | char body_buffer[1024]; 88 | if (body_value) { 89 | if (CFStringGetCString(body_value, body_buffer, sizeof(body_buffer), 90 | kCFStringEncodingUTF8)) { 91 | *body = body_buffer; 92 | } 93 | } 94 | 95 | // Release 96 | CFRelease(titl_key); 97 | CFRelease(subt_key); 98 | CFRelease(body_key); 99 | CFRelease(key); 100 | CFRelease(detailsPlist); 101 | } else { 102 | // Failed to create plist with provided data 103 | fprintf(stderr, "Failed to create plist with provided data!"); 104 | 105 | CFRelease(detailsPlist); 106 | } 107 | } else { 108 | fprintf(stderr, "Failed to create data ref with provided data!"); 109 | } 110 | 111 | CFRelease(ref); 112 | } 113 | 114 | static inline struct islandItem * 115 | check_notifications(struct notificationHelper *notificationHelper) { 116 | // Open the database 117 | rc = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READONLY, NULL); 118 | if (rc != SQLITE_OK) { 119 | fprintf(stderr, "Error opening database: %s\n", sqlite3_errmsg(db)); 120 | 121 | rc = sqlite3_close(db); 122 | if (rc != SQLITE_OK) { 123 | fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db)); 124 | } 125 | return NULL; 126 | } 127 | 128 | // Check notification count 129 | if (sqlite3_prepare_v2(db, "SELECT Count(*) FROM record", -1, &stmt, NULL) != 130 | SQLITE_OK) { 131 | fprintf(stderr, "Error accessing database entry counts: %s\n", 132 | sqlite3_errmsg(db)); 133 | 134 | sqlite3_finalize(stmt); 135 | 136 | // Close the database 137 | rc = sqlite3_close(db); 138 | if (rc != SQLITE_OK) { 139 | fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db)); 140 | } 141 | 142 | return NULL; 143 | } 144 | 145 | // Get notificatoin count 146 | if (sqlite3_step(stmt) != SQLITE_DONE) { 147 | int notifCount = sqlite3_column_int(stmt, 0); 148 | 149 | if (notifCount > lastNotifCount) { 150 | 151 | // finalize previous statement 152 | sqlite3_finalize(stmt); 153 | 154 | // Prepare statement 155 | if (sqlite3_prepare_v2( 156 | db, 157 | "SELECT (SELECT identifier from app where " 158 | "app.app_id=record.app_id) " 159 | "as " 160 | "app, uuid, data, presented, delivered_date FROM record ORDER BY " 161 | "delivered_date DESC LIMIT 1", 162 | -1, &stmt, NULL) != SQLITE_OK) { 163 | 164 | fprintf(stderr, "Error preparing database: %s\n", sqlite3_errmsg(db)); 165 | 166 | sqlite3_finalize(stmt); 167 | 168 | // Close the database 169 | rc = sqlite3_close(db); 170 | if (rc != SQLITE_OK) { 171 | fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db)); 172 | } 173 | 174 | return NULL; 175 | } 176 | 177 | if (sqlite3_step(stmt) != SQLITE_DONE) { 178 | // Extract the desired information from the result set 179 | const char *app = (const char *)sqlite3_column_text(stmt, 0); 180 | 181 | const void *plist_data = sqlite3_column_blob(stmt, 2); 182 | int plist_data_len = sqlite3_column_bytes(stmt, 2); 183 | 184 | int presented = sqlite3_column_int(stmt, 3); 185 | const char *delivered_date = (const char *)sqlite3_column_text(stmt, 4); 186 | 187 | // TODO: HANDLE EXCEPTIONS PROPERLY 188 | if (strcmp(app, "com.apple.controlcenter.notifications.focus") == 0) { 189 | sqlite3_finalize(stmt); 190 | 191 | // Close the database 192 | rc = sqlite3_close(db); 193 | if (rc != SQLITE_OK) { 194 | fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db)); 195 | } 196 | 197 | return NULL; 198 | } 199 | 200 | char *title; 201 | char *subtitle; 202 | char *body; 203 | parse_notification_details((const UInt8 *)plist_data, plist_data_len, 204 | &title, &subtitle, &body); 205 | 206 | // Queue to dynamic island 207 | struct islandItem *newNotificationItem = 208 | (struct islandItem *)malloc(sizeof(struct islandItem)); 209 | 210 | snprintf(newNotificationItem->identifier, 32, "notifications"); 211 | snprintf(newNotificationItem->args, 512, "%s|%s|%s|%s", title, subtitle, 212 | body, app); 213 | 214 | lastNotifCount = notifCount; 215 | 216 | sqlite3_finalize(stmt); 217 | 218 | // Close the database 219 | rc = sqlite3_close(db); 220 | if (rc != SQLITE_OK) { 221 | fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db)); 222 | } 223 | 224 | return newNotificationItem; 225 | } 226 | } 227 | lastNotifCount = notifCount; 228 | } 229 | 230 | sqlite3_finalize(stmt); 231 | 232 | // Close the database 233 | rc = sqlite3_close(db); 234 | if (rc != SQLITE_OK) { 235 | fprintf(stderr, "Error closing database: %s\n", sqlite3_errmsg(db)); 236 | } 237 | return NULL; 238 | } 239 | -------------------------------------------------------------------------------- /helper/sketchybar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef char* env; 11 | 12 | #define MACH_HANDLER(name) void name(env env) 13 | typedef MACH_HANDLER(mach_handler); 14 | 15 | struct mach_message { 16 | mach_msg_header_t header; 17 | mach_msg_size_t msgh_descriptor_count; 18 | mach_msg_ool_descriptor_t descriptor; 19 | }; 20 | 21 | struct mach_buffer { 22 | struct mach_message message; 23 | mach_msg_trailer_t trailer; 24 | }; 25 | 26 | struct mach_server { 27 | bool is_running; 28 | mach_port_name_t task; 29 | mach_port_t port; 30 | mach_port_t bs_port; 31 | 32 | pthread_t thread; 33 | mach_handler* handler; 34 | }; 35 | 36 | static struct mach_server g_mach_server; 37 | static mach_port_t g_mach_port = 0; 38 | 39 | static inline char* env_get_value_for_key(env env, char* key) { 40 | uint32_t caret = 0; 41 | for(;;) { 42 | if (!env[caret]) break; 43 | if (strcmp(&env[caret], key) == 0) 44 | return &env[caret + strlen(&env[caret]) + 1]; 45 | 46 | caret += strlen(&env[caret]) 47 | + strlen(&env[caret + strlen(&env[caret]) + 1]) 48 | + 2; 49 | } 50 | return (char*)""; 51 | } 52 | 53 | static inline mach_port_t mach_get_bs_port() { 54 | mach_port_name_t task = mach_task_self(); 55 | 56 | mach_port_t bs_port; 57 | if (task_get_special_port(task, 58 | TASK_BOOTSTRAP_PORT, 59 | &bs_port ) != KERN_SUCCESS) { 60 | return 0; 61 | } 62 | 63 | mach_port_t port; 64 | if (bootstrap_look_up(bs_port, 65 | "git.felix.dynamic-island-sketchybar", 66 | &port ) != KERN_SUCCESS) { 67 | return 0; 68 | } 69 | 70 | return port; 71 | } 72 | 73 | static inline void mach_receive_message(mach_port_t port, struct mach_buffer* buffer, bool timeout) { 74 | *buffer = (struct mach_buffer) { 0 }; 75 | mach_msg_return_t msg_return; 76 | if (timeout) 77 | msg_return = mach_msg(&buffer->message.header, 78 | MACH_RCV_MSG | MACH_RCV_TIMEOUT, 79 | 0, 80 | sizeof(struct mach_buffer), 81 | port, 82 | 100, 83 | MACH_PORT_NULL ); 84 | else 85 | msg_return = mach_msg(&buffer->message.header, 86 | MACH_RCV_MSG, 87 | 0, 88 | sizeof(struct mach_buffer), 89 | port, 90 | MACH_MSG_TIMEOUT_NONE, 91 | MACH_PORT_NULL ); 92 | 93 | if (msg_return != MACH_MSG_SUCCESS) { 94 | buffer->message.descriptor.address = NULL; 95 | } 96 | } 97 | 98 | static inline char* mach_send_message(mach_port_t port, char* message, uint32_t len) { 99 | if (!message || !port) { 100 | return NULL; 101 | } 102 | 103 | mach_port_t response_port; 104 | mach_port_name_t task = mach_task_self(); 105 | if (mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, 106 | &response_port ) != KERN_SUCCESS) { 107 | return NULL; 108 | } 109 | 110 | if (mach_port_insert_right(task, response_port, 111 | response_port, 112 | MACH_MSG_TYPE_MAKE_SEND)!= KERN_SUCCESS) { 113 | return NULL; 114 | } 115 | 116 | struct mach_message msg = { 0 }; 117 | msg.header.msgh_remote_port = port; 118 | msg.header.msgh_local_port = response_port; 119 | msg.header.msgh_id = response_port; 120 | msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 121 | MACH_MSG_TYPE_MAKE_SEND, 122 | 0, 123 | MACH_MSGH_BITS_COMPLEX ); 124 | 125 | msg.header.msgh_size = sizeof(struct mach_message); 126 | msg.msgh_descriptor_count = 1; 127 | msg.descriptor.address = message; 128 | msg.descriptor.size = len * sizeof(char); 129 | msg.descriptor.copy = MACH_MSG_VIRTUAL_COPY; 130 | msg.descriptor.deallocate = false; 131 | msg.descriptor.type = MACH_MSG_OOL_DESCRIPTOR; 132 | 133 | mach_msg(&msg.header, 134 | MACH_SEND_MSG, 135 | sizeof(struct mach_message), 136 | 0, 137 | MACH_PORT_NULL, 138 | MACH_MSG_TIMEOUT_NONE, 139 | MACH_PORT_NULL ); 140 | 141 | struct mach_buffer buffer = { 0 }; 142 | mach_receive_message(response_port, &buffer, true); 143 | if (buffer.message.descriptor.address) 144 | return (char*)buffer.message.descriptor.address; 145 | mach_msg_destroy(&buffer.message.header); 146 | 147 | return NULL; 148 | } 149 | 150 | #pragma clang diagnostic push 151 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 152 | static inline bool mach_server_begin(struct mach_server* mach_server, mach_handler handler, char* bootstrap_name) { 153 | mach_server->task = mach_task_self(); 154 | 155 | if (mach_port_allocate(mach_server->task, 156 | MACH_PORT_RIGHT_RECEIVE, 157 | &mach_server->port ) != KERN_SUCCESS) { 158 | return false; 159 | } 160 | 161 | if (mach_port_insert_right(mach_server->task, 162 | mach_server->port, 163 | mach_server->port, 164 | MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) { 165 | return false; 166 | } 167 | 168 | if (task_get_special_port(mach_server->task, 169 | TASK_BOOTSTRAP_PORT, 170 | &mach_server->bs_port) != KERN_SUCCESS) { 171 | return false; 172 | } 173 | 174 | if (bootstrap_register(mach_server->bs_port, 175 | bootstrap_name, 176 | mach_server->port ) != KERN_SUCCESS) { 177 | return false; 178 | } 179 | 180 | mach_server->handler = handler; 181 | mach_server->is_running = true; 182 | struct mach_buffer buffer; 183 | while (mach_server->is_running) { 184 | mach_receive_message(mach_server->port, &buffer, false); 185 | mach_server->handler((env)buffer.message.descriptor.address); 186 | mach_msg_destroy(&buffer.message.header); 187 | } 188 | 189 | return true; 190 | } 191 | #pragma clang diagnostic pop 192 | 193 | static inline char* sketchybar(char* message) { 194 | uint32_t message_length = strlen(message) + 1; 195 | char formatted_message[message_length + 1]; 196 | 197 | char quote = '\0'; 198 | uint32_t caret = 0; 199 | for (int i = 0; i < message_length; ++i) { 200 | if (message[i] == '"' || message[i] == '\'') { 201 | if (quote == message[i]) quote = '\0'; 202 | else quote = message[i]; 203 | continue; 204 | } 205 | formatted_message[caret] = message[i]; 206 | if (message[i] == ' ' && !quote) formatted_message[caret] = '\0'; 207 | caret++; 208 | } 209 | 210 | if (caret > 0 && formatted_message[caret] == '\0' 211 | && formatted_message[caret - 1] == '\0') { 212 | caret--; 213 | } 214 | 215 | formatted_message[caret] = '\0'; 216 | if (!g_mach_port) g_mach_port = mach_get_bs_port(); 217 | char* response = mach_send_message(g_mach_port, 218 | formatted_message, 219 | caret + 1 ); 220 | 221 | if (response) return response; 222 | else return (char*)""; 223 | } 224 | 225 | static inline void event_server_begin(mach_handler event_handler, char* bootstrap_name) { 226 | mach_server_begin(&g_mach_server, event_handler, bootstrap_name); 227 | } 228 | -------------------------------------------------------------------------------- /images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crissNb/Dynamic-Island-Sketchybar/93c59069b308bdd86b1353353eafa21eaeb14703/images/demo.gif -------------------------------------------------------------------------------- /images/fullupdated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crissNb/Dynamic-Island-Sketchybar/93c59069b308bdd86b1353353eafa21eaeb14703/images/fullupdated.png -------------------------------------------------------------------------------- /item.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source "$DYNAMIC_ISLAND_DIR/helper.sh" 4 | sleep 0.5 5 | 6 | # Load user config overrides 7 | USER_CONFIG="$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 8 | test -f "$USER_CONFIG" && source "$USER_CONFIG" 9 | 10 | # clear cache 11 | PREVIOUS_ISLAND_CACHE="$DYNAMIC_ISLAND_DIR/scripts/islands/previous_island" 12 | true > "$PREVIOUS_ISLAND_CACHE" 13 | 14 | PADDING=3 15 | 16 | sketchy_bar=( 17 | height="$P_DYNAMIC_ISLAND_DEFAULT_HEIGHT" 18 | color="$P_DYNAMIC_ISLAND_COLOR_BLACK" 19 | shadow=off 20 | position=top 21 | sticky=off 22 | topmost=on 23 | padding_left=0 24 | padding_right=0 25 | corner_radius="$P_DYNAMIC_ISLAND_CORNER_RADIUS" 26 | y_offset="-$P_DYNAMIC_ISLAND_CORNER_RADIUS" 27 | margin=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH)) 28 | notch_width=0 29 | ) 30 | 31 | sketchy_default=( 32 | updates=when_shown 33 | icon.font="$P_DYNAMIC_ISLAND_FONT:Bold:14.0" 34 | icon.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 35 | icon.padding_left="$PADDING" 36 | icon.padding_right="$PADDING" 37 | label.font="$P_DYNAMIC_ISLAND_FONT:Semibold:13.0" 38 | label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 39 | label.padding_left="$PADDING" 40 | label.padding_right="$PADDING" 41 | background.padding_right="$PADDING" 42 | background.padding_left="$PADDING" 43 | ) 44 | 45 | dynamic-island-sketchybar --bar "${sketchy_bar[@]}" 46 | 47 | dynamic-island-sketchybar --default "${sketchy_default[@]}" 48 | 49 | island=( 50 | drawing=on 51 | mach_helper=git.crissnb.islandhelper 52 | update_freq=5 53 | width=0 54 | ) 55 | 56 | dynamic-island-sketchybar --add event dynamic_island_queue \ 57 | --add event dynamic_island_request \ 58 | --add item island center \ 59 | --set island "${island[@]}" 60 | 61 | dynamic-island-sketchybar --bar display="$P_DYNAMIC_ISLAND_DISPLAY" 62 | 63 | # subscribe to events to communicate with helper 64 | dynamic-island-sketchybar --subscribe island dynamic_island_queue \ 65 | --subscribe island dynamic_island_request 66 | 67 | # module initalization 68 | if [[ $P_DYNAMIC_ISLAND_MUSIC_ENABLED == 1 ]]; then 69 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/music/creator.sh" 70 | 71 | dynamic-island-sketchybar --add item musicListener center \ 72 | --set musicListener script="$DYNAMIC_ISLAND_DIR/scripts/islands/music/handler.sh" \ 73 | width=0 \ 74 | --subscribe musicListener media_change 75 | fi 76 | 77 | if [[ $P_DYNAMIC_ISLAND_APPSWITCH_ENABLED == 1 ]]; then 78 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/appswitch/creator.sh" 79 | dynamic-island-sketchybar --add item frontAppSwitchListener center \ 80 | --set frontAppSwitchListener script="$DYNAMIC_ISLAND_DIR/scripts/islands/appswitch/handler.sh" \ 81 | width=0 \ 82 | --subscribe frontAppSwitchListener front_app_switched 83 | fi 84 | 85 | if [[ $P_DYNAMIC_ISLAND_VOLUME_ENABLED == 1 ]]; then 86 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/volume/creator.sh" 87 | dynamic-island-sketchybar --add item volumeChangeListener center \ 88 | --set volumeChangeListener script="$DYNAMIC_ISLAND_DIR/scripts/islands/volume/handler.sh" \ 89 | width=0 \ 90 | --subscribe volumeChangeListener volume_change 91 | fi 92 | 93 | if [[ $P_DYNAMIC_ISLAND_BRIGHTNESS_ENABLED == 1 ]]; then 94 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/brightness/creator.sh" 95 | dynamic-island-sketchybar --add item brightnessChangeListener center \ 96 | --set brightnessChangeListener script="$DYNAMIC_ISLAND_DIR/scripts/islands/brightness/handler.sh" \ 97 | width=0 \ 98 | --subscribe brightnessChangeListener brightness_change 99 | fi 100 | 101 | if [[ $P_DYNAMIC_ISLAND_WIFI_ENABLED == 1 ]]; then 102 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/wifi/creator.sh" 103 | dynamic-island-sketchybar --add item wifiChangeListener center \ 104 | --set wifiChangeListener script="$DYNAMIC_ISLAND_DIR/scripts/islands/wifi/handler.sh" \ 105 | width=0 \ 106 | --subscribe wifiChangeListener wifi_change 107 | fi 108 | 109 | if [[ $P_DYNAMIC_ISLAND_POWER_ENABLED == 1 ]]; then 110 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/power/creator.sh" 111 | dynamic-island-sketchybar --add item powerChangeListener center \ 112 | --set powerChangeListener script="$DYNAMIC_ISLAND_DIR/scripts/islands/power/handler.sh" \ 113 | width=0 \ 114 | --subscribe powerChangeListener power_source_change 115 | fi 116 | 117 | if [[ $P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED == 1 ]]; then 118 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/notification/creator.sh" 119 | fi 120 | 121 | # initialize listener to communicate with helper 122 | source "$DYNAMIC_ISLAND_DIR/listener.sh" 123 | -------------------------------------------------------------------------------- /listener.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | listener=( 3 | script="$DYNAMIC_ISLAND_DIR/process.sh" 4 | width=0 5 | ) 6 | 7 | dynamic-island-sketchybar --add item di_helper_listener center \ 8 | --add event di_helper_listener_event \ 9 | --subscribe di_helper_listener di_helper_listener_event \ 10 | --set di_helper_listener "${listener[@]}" 11 | -------------------------------------------------------------------------------- /process.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # provided "arguments": 3 | # $IDENTIFIER - identifier of the dynamic island element 4 | # $OVERRIDE - whether or not to override the existing dynamic island element 5 | # $ARGS - necessary arguments to activate the dynamic island element 6 | export DYNAMIC_ISLAND_DIR 7 | DYNAMIC_ISLAND_DIR=$( 8 | cd "$(dirname "${BASH_SOURCE[0]}")" || exit 9 | pwd -P 10 | ) 11 | 12 | ISLAND_DIR="$DYNAMIC_ISLAND_DIR/scripts/islands" 13 | 14 | case $IDENTIFIER in 15 | "appswitch") 16 | if [[ $OVERRIDE == 1 ]]; then 17 | pkill -f "$ISLAND_DIR/appswitch/appswitch_island.sh" 18 | fi 19 | # arg: app name 20 | bash "$ISLAND_DIR/appswitch/appswitch_island.sh" "$OVERRIDE|$ARGS" 21 | ;; 22 | "volume") 23 | if [[ $OVERRIDE == 1 ]]; then 24 | pkill -f "$ISLAND_DIR/volume/volume_island.sh" 25 | fi 26 | # arg: volume amt 27 | bash "$ISLAND_DIR/volume/volume_island.sh" "$OVERRIDE|$ARGS" 28 | ;; 29 | "brightness") 30 | if [[ $OVERRIDE == 1 ]]; then 31 | pkill -f "$ISLAND_DIR/brightness/brightness_island.sh" 32 | fi 33 | # arg: volume amt 34 | bash "$ISLAND_DIR/brightness/brightness_island.sh" "$OVERRIDE|$ARGS" 35 | ;; 36 | "pause") 37 | if [[ $OVERRIDE == 1 ]]; then 38 | pkill -f "$ISLAND_DIR/music/pause_island.sh" 39 | fi 40 | # arg: pause status 41 | bash "$ISLAND_DIR/music/pause_island.sh" "$OVERRIDE|$ARGS" 42 | ;; 43 | "wifi") 44 | if [[ $OVERRIDE == 1 ]]; then 45 | pkill -f "$ISLAND_DIR/wifi/wifi_island.sh" 46 | fi 47 | # arg: wifi details 48 | bash "$ISLAND_DIR/wifi/wifi_island.sh" "$OVERRIDE|$ARGS" 49 | ;; 50 | "power") 51 | if [[ $OVERRIDE == 1 ]]; then 52 | pkill -f "$ISLAND_DIR/power/power_island.sh" 53 | fi 54 | # arg: connection type 55 | bash "$ISLAND_DIR/power/power_island.sh" "$OVERRIDE|$ARGS" 56 | ;; 57 | "music") 58 | if [[ $OVERRIDE == 1 ]]; then 59 | pkill -f "$ISLAND_DIR/music/music_island.sh" 60 | fi 61 | # arg: playback details 62 | bash "$ISLAND_DIR/music/music_island.sh" "$OVERRIDE|$ARGS" 63 | ;; 64 | "notifications") 65 | if [[ $OVERRIDE == 1 ]]; then 66 | pkill -f "$ISLAND_DIR/notification/notification_island.sh" 67 | fi 68 | # args: notification details 69 | bash "$ISLAND_DIR/notification/notification_island.sh" "$OVERRIDE|$ARGS" 70 | ;; 71 | esac 72 | -------------------------------------------------------------------------------- /scripts/islands/appswitch/appswitch_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_APPSWITCH_EXPAND_HEIGHT + ($P_DYNAMIC_ISLAND_SQUISH_AMOUNT / 2))) 6 | 7 | args=$* 8 | IFS='|' 9 | read -ra strarr <<<"$args" 10 | unset IFS 11 | 12 | # $1 - override 13 | # $2 - front app name 14 | override="${strarr[0]}" 15 | appName="${strarr[1]}" 16 | BUNDLENAME=$(osascript -e "id of app \"$appName\"") 17 | 18 | if [[ $override == "0" ]]; then 19 | dynamic-island-sketchybar --set island.appname drawing=on \ 20 | --set island.applogo drawing=on 21 | fi 22 | 23 | dynamic-island-sketchybar --set island.applogo background.image.string="app.$BUNDLENAME" 24 | 25 | dynamic-island-sketchybar --set island.appname label="$appName" 26 | 27 | # determine expand width based on the character length 28 | char_length=${#appName} 29 | expand_size=$(bc -l <<<"$P_DYNAMIC_ISLAND_APPSWITCH_MAX_EXPAND_WIDTH+$char_length*7") 30 | expand_squish=$(($expand_size + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 31 | 32 | expand_size_margin=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $expand_size)) 33 | expand_squish_margin=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $expand_squish)) 34 | 35 | 36 | if [[ $override == "0" ]]; then 37 | 38 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 39 | 40 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$expand_squish_margin" margin="$expand_size_margin" \ 41 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_APPSWITCH_EXPAND_HEIGHT" \ 42 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_APPSWITCH_CORNER_RAD" 43 | else 44 | dynamic-island-sketchybar --animate tanh 10 --bar margin="$expand_squish_margin" margin="$expand_size_margin" \ 45 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_APPSWITCH_EXPAND_HEIGHT" \ 46 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_APPSWITCH_CORNER_RAD" 47 | fi 48 | 49 | sleep 0.1 50 | 51 | dynamic-island-sketchybar --animate sin 15 --set island.appname label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 52 | 53 | sleep 0.8 54 | 55 | dynamic-island-sketchybar --animate tanh 15 --set island.appname label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 56 | --set island.applogo drawing=off 57 | 58 | 59 | sleep 0.1 60 | 61 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 62 | sleep 0.4 63 | 64 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/appswitch/reset.sh" 65 | -------------------------------------------------------------------------------- /scripts/islands/appswitch/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/bash 2 | 3 | appname=( 4 | width=10 5 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 6 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:12.0" 7 | label.y_offset=-5 8 | label.align=right 9 | padding_left=0 10 | padding_right=10 11 | drawing=off 12 | ) 13 | 14 | applogo=( 15 | background.color="$P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN" 16 | padding_left=10 17 | padding_right=5 18 | background.image.scale="$P_DYNAMIC_ISLAND_APPSWITCH_ICON_SIZE" 19 | y_offset=-5 20 | drawing=off 21 | ) 22 | 23 | dynamic-island-sketchybar --add item island.appname right \ 24 | --set island.appname "${appname[@]}" \ 25 | --add item island.applogo left \ 26 | --set island.applogo "${applogo[@]}" 27 | -------------------------------------------------------------------------------- /scripts/islands/appswitch/handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | case "$SENDER" in 3 | "front_app_switched") 4 | echo "front_app_switched" 5 | echo "$INFO" 6 | 7 | dynamic-island-sketchybar --trigger dynamic_island_queue INFO="appswitch" ISLAND_ARGS="$INFO" 8 | ;; 9 | esac 10 | -------------------------------------------------------------------------------- /scripts/islands/appswitch/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.applogo drawing=off \ 3 | --set island.appname drawing=off 4 | sleep 0.1 5 | 6 | # call end event 7 | dynamic-island-sketchybar --trigger dynamic_island_request 8 | -------------------------------------------------------------------------------- /scripts/islands/brightness/brightness_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_BRIGHTNESS_EXPAND_HEIGHT + ($P_DYNAMIC_ISLAND_SQUISH_AMOUNT / 2))) 6 | EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_BRIGHTNESS_MAX_EXPAND_WIDTH)) 7 | 8 | args=$* 9 | IFS='|' 10 | read -ra strarr <<<"$args" 11 | unset IFS 12 | 13 | # $1 - override 14 | # $2 - front app name 15 | override="${strarr[0]}" 16 | brightness="${strarr[1]}" 17 | 18 | # calculate brightness logo 19 | case $brightness in 20 | 100) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 21 | 9[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 22 | 8[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 23 | 7[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 24 | 6[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 25 | 5[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 26 | 4[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH ;; 27 | 3[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_LOW ;; 28 | 2[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_LOW ;; 29 | 1[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_LOW ;; 30 | [0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_LOW ;; 31 | *) ICON=$P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_LOW ;; 32 | esac 33 | 34 | if [[ $override == "0" ]]; then 35 | dynamic-island-sketchybar --set island.brightness_icon drawing=on icon="$ICON" \ 36 | --set island.brightness_bar drawing=on 37 | fi 38 | 39 | if [[ $override == "0" ]]; then 40 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 41 | 42 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 43 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_BRIGHTNESS_CORNER_RAD" \ 44 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_BRIGHTNESS_EXPAND_HEIGHT" 45 | else 46 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 47 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_BRIGHTNESS_CORNER_RAD" \ 48 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_BRIGHTNESS_EXPAND_HEIGHT" 49 | fi 50 | 51 | # subtract 20, because we're using padding value of 10. 52 | barWidth=$(bc -l <<<"$brightness/100*$(($P_DYNAMIC_ISLAND_BRIGHTNESS_MAX_EXPAND_WIDTH * 2 - 20))") 53 | barWidth=$(printf "%.0f" "$barWidth") 54 | dynamic-island-sketchybar --animate tanh 15 --set island.brightness_bar width="$barWidth" 55 | 56 | dynamic-island-sketchybar --animate sin 10 --set island.brightness_bar background.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 57 | --animate sin 10 --set island.brightness_bar background.border_color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 58 | --animate sin 10 --set island.brightness_icon icon.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 59 | 60 | sleep 0.8 61 | 62 | dynamic-island-sketchybar --animate tanh 15 --set island.brightness_icon icon.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 63 | --animate tanh 15 --set island.brightness_bar background.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 64 | 65 | sleep 0.1 66 | 67 | dynamic-island-sketchybar --animate tanh 5 --set island.brightness_bar width=0 68 | 69 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 70 | sleep 0.4 71 | 72 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/brightness/reset.sh" 73 | -------------------------------------------------------------------------------- /scripts/islands/brightness/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | icon=( 4 | icon="$ICON" 5 | icon.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 6 | icon.font="$P_DYNAMIC_ISLAND_FONT:Bold:14.0" 7 | icon.y_offset=2 8 | padding_left=10 9 | padding_right=0 10 | width=0 11 | drawing=off 12 | ) 13 | 14 | bar=( 15 | background.height=2 16 | background.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 17 | background.border_color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 18 | background.y_offset=0 19 | background.shadow.drawing=off 20 | drawing=off 21 | y_offset=-19 22 | padding_left=10 23 | ) 24 | 25 | #create brightness items 26 | dynamic-island-sketchybar --add item island.brightness_icon left \ 27 | --set island.brightness_icon "${icon[@]}" \ 28 | --add item island.brightness_bar left \ 29 | --set island.brightness_bar "${bar[@]}" 30 | -------------------------------------------------------------------------------- /scripts/islands/brightness/handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | echo "brightness" 3 | echo "$INFO" 4 | 5 | dynamic-island-sketchybar --trigger dynamic_island_queue INFO="brightness" ISLAND_ARGS="$INFO" 6 | -------------------------------------------------------------------------------- /scripts/islands/brightness/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # call end event 3 | dynamic-island-sketchybar --trigger dynamic_island_request 4 | 5 | dynamic-island-sketchybar --set island.brightness_icon drawing=off \ 6 | --set island.brightness_bar drawing=off \ 7 | 8 | sleep 0.1 9 | 10 | dynamic-island-sketchybar --set island popup.drawing=false 11 | -------------------------------------------------------------------------------- /scripts/islands/clear.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/bash 2 | if [[ $P_DYNAMIC_ISLAND_MUSIC_ENABLED == 1 ]]; then 3 | dynamic-island-sketchybar --animate tanh 10 --set island.small_artwork background.image.scale=0 \ 4 | --animate tanh 10 --set island.music_visualizer label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 5 | fi 6 | 7 | sleep 0.2 8 | 9 | if [[ $P_DYNAMIC_ISLAND_MUSIC_ENABLED == 1 ]]; then 10 | dynamic-island-sketchybar --set island.music_visualizer drawing=off \ 11 | --set island.small_artwork drawing=off 12 | fi 13 | -------------------------------------------------------------------------------- /scripts/islands/music/cava.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | framerate=60 3 | bars=6 4 | [input] 5 | method = portaudio 6 | source = "Background Music" 7 | [output] 8 | method=raw 9 | data_format=ascii 10 | ascii_max_range=8 11 | bar_delimiter=32 12 | channels=mono 13 | mono_option=average 14 | -------------------------------------------------------------------------------- /scripts/islands/music/cava.sh: -------------------------------------------------------------------------------- 1 | CURR_DIR=$( 2 | cd "$(dirname "${BASH_SOURCE[0]}")" || exit 3 | pwd -P 4 | ) 5 | 6 | CONF_FILE="$CURR_DIR/cava.conf" 7 | 8 | 9 | while true 10 | do 11 | cava -p "$CONF_FILE" | sed -u 's/ //g; s/0/▁/g; s/1/▂/g; s/2/▃/g; s/3/▄/g; s/4/▅/g; s/5/▆/g; s/6/▇/g; s/7/█/g; s/8/█/g' | while read line; do 12 | dynamic-island-sketchybar --set $NAME label=$line 13 | done 14 | sleep 5 15 | done 16 | -------------------------------------------------------------------------------- /scripts/islands/music/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | artwork=( 3 | background.color="$P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN" 4 | padding_left=10 5 | padding_right=0 6 | background.image.scale=2.0 7 | background.image.corner_radius="$P_DYNAMIC_ISLAND_MUSIC_INFO_CORNER_RAD" 8 | y_offset=0 9 | drawing=off 10 | width=50 11 | background.image.string="media.artwork" 12 | ) 13 | 14 | title=( 15 | width=0 16 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 17 | label.padding_left=0 18 | label.padding_right=0 19 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:14.0" 20 | y_offset=-10 21 | padding_left=-80 22 | padding_right=0 23 | label.width=550 24 | drawing=off 25 | ) 26 | 27 | artist=( 28 | width=0 29 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 30 | label.padding_left=0 31 | label.padding_right=0 32 | padding_left=-80 33 | padding_right=0 34 | label.width=550 35 | label.font="$P_DYNAMIC_ISLAND_FONT:Semibold:12.0" 36 | label.y_offset=-30 37 | drawing=off 38 | ) 39 | 40 | resume_text=( 41 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 42 | label.padding_right=0 43 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:12.0" 44 | padding_left=0 45 | padding_right=10 46 | width=30 47 | y_offset=-5 48 | drawing=off 49 | ) 50 | 51 | visualizer=( 52 | drawing=off 53 | update_freq=0 54 | y_offset=-10 55 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:10.0" 56 | script="$DYNAMIC_ISLAND_DIR/scripts/islands/music/cava.sh" 57 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 58 | ) 59 | 60 | small_artwork=( 61 | background.color="$P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN" 62 | padding_left=10 63 | padding_right=0 64 | background.image.corner_radius=10 65 | background.image.scale=1.0 66 | y_offset=-5 67 | drawing=off 68 | width=50 69 | background.image.string="media.artwork" 70 | ) 71 | 72 | # music island 73 | dynamic-island-sketchybar --add item island.music_artwork left \ 74 | --set island.music_artwork "${artwork[@]}" \ 75 | --add item island.music_title center \ 76 | --set island.music_title "${title[@]}" \ 77 | --add item island.music_artist center \ 78 | --set island.music_artist "${artist[@]}" \ 79 | 80 | # pause island 81 | dynamic-island-sketchybar --add item island.resume_text right \ 82 | --set island.resume_text "${resume_text[@]}" 83 | 84 | # idle island 85 | dynamic-island-sketchybar --add item island.music_visualizer right \ 86 | --set island.music_visualizer "${visualizer[@]}" \ 87 | --add item island.small_artwork left \ 88 | --set island.small_artwork "${small_artwork[@]}" 89 | -------------------------------------------------------------------------------- /scripts/islands/music/handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | TITLE=$(jq -r '.title' <<< "$INFO") 3 | ARTIST=$(jq -r '.artist' <<< "$INFO") 4 | STATE=$(jq -r '.state' <<< "$INFO") 5 | 6 | dynamic-island-sketchybar --trigger dynamic_island_queue INFO="music" ISLAND_ARGS="$TITLE|$ARTIST|$STATE" 7 | -------------------------------------------------------------------------------- /scripts/islands/music/music_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | INFO_MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_MUSIC_INFO_EXPAND_HEIGHT + ($P_DYNAMIC_ISLAND_SQUISH_AMOUNT) / 2)) 6 | INFO_EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_MUSIC_INFO_MAX_EXPAND_WIDTH)) 7 | 8 | # $1 - override 9 | args=$* 10 | IFS='|' 11 | read -ra strarr <<<"$args" 12 | unset IFS 13 | 14 | # $1 - override 15 | # $2 - artist 16 | # $3 - title 17 | override="${strarr[0]}" 18 | # fetch music info 19 | ARTIST="${strarr[1]}" 20 | TITLE="${strarr[2]}" 21 | STATE="${strarr[3]}" 22 | 23 | PREVIOUS_ISLAND_CACHE="$DYNAMIC_ISLAND_DIR/scripts/islands/previous_island" 24 | 25 | if [[ $STATE == "playing" ]]; then 26 | if ! grep -Fxq "music" "$PREVIOUS_ISLAND_CACHE"; then 27 | echo "music" >> "$PREVIOUS_ISLAND_CACHE" 28 | fi 29 | 30 | if grep -Fxq "paused" "$PREVIOUS_ISLAND_CACHE"; then 31 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/music/pause_island.sh" "$override|1" 32 | exit 33 | fi 34 | else 35 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/music/pause_island.sh" "$override|0" 36 | exit 37 | fi 38 | 39 | if [[ ${#TITLE} -gt 25 ]]; then 40 | TITLE=$(printf "%s..." "$(echo "$TITLE" | cut -c 1-25)") 41 | fi 42 | 43 | if [[ ${#ARTIST} -gt 25 ]]; then 44 | ARTIST=$(printf "%s..." "$(echo "$ARTIST" | cut -c 1-25)") 45 | fi 46 | 47 | if [[ $override == "0" ]]; then 48 | dynamic-island-sketchybar --set island.music_artwork drawing=on \ 49 | --set island.music_title drawing=on \ 50 | --set island.music_artist drawing=on \ 51 | --set island.music_title label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 52 | --set island.music_artist label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 53 | --set island.music_artwork background.image.drawing=on \ 54 | --set island "${island[@]}" 55 | fi 56 | 57 | dynamic-island-sketchybar --set island.music_artist label="$ARTIST" \ 58 | --set island.music_title label="$TITLE" 59 | 60 | if [[ $override == "0" ]]; then 61 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 62 | 63 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$(($INFO_EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$INFO_EXPAND_SIZE" \ 64 | --animate tanh 10 --bar height="$INFO_MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_MUSIC_INFO_EXPAND_HEIGHT" \ 65 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_MUSIC_INFO_CORNER_RAD" 66 | else 67 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$(($INFO_EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$INFO_EXPAND_SIZE" \ 68 | --animate tanh 10 --bar height="$INFO_MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_MUSIC_INFO_EXPAND_HEIGHT" \ 69 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_MUSIC_INFO_CORNER_RAD" 70 | fi 71 | 72 | sleep 0.15 73 | dynamic-island-sketchybar --animate tanh 15 --set island.music_title label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 74 | --animate tanh 15 --set island.music_artist label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 75 | --animate tanh 15 --set island.music_artwork background.image.drawing=on 76 | 77 | sleep 1.7 78 | 79 | dynamic-island-sketchybar --animate tanh 15 --set island.music_title label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 80 | --animate tanh 15 --set island.music_artist label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 81 | --animate tanh 15 --set island.music_artwork background.image.drawing=off 82 | 83 | sleep 0.2 84 | 85 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 86 | 87 | sleep 0.4 88 | 89 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/music/reset.sh" 90 | -------------------------------------------------------------------------------- /scripts/islands/music/pause_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | PREVIOUS_ISLAND_CACHE="$DYNAMIC_ISLAND_DIR/scripts/islands/previous_island" 6 | 7 | RESUME_MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_MUSIC_RESUME_EXPAND_HEIGHT + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 8 | EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_MUSIC_RESUME_MAX_EXPAND_WIDTH)) 9 | 10 | args=$* 11 | IFS='|' 12 | read -ra strarr <<<"$args" 13 | unset IFS 14 | 15 | override="${strarr[0]}" 16 | pauseStatus="${strarr[1]}" 17 | 18 | 19 | if [[ $pauseStatus == "0" ]]; then 20 | echo "paused" > "$PREVIOUS_ISLAND_CACHE" 21 | else 22 | echo "music" > "$PREVIOUS_ISLAND_CACHE" 23 | fi 24 | 25 | # enable 26 | dynamic-island-sketchybar --set island.resume_text drawing=on 27 | 28 | if [[ $pauseStatus == "0" ]]; then 29 | # paused 30 | dynamic-island-sketchybar --set island.resume_text label="Paused" 31 | else 32 | # resume 33 | dynamic-island-sketchybar --set island.resume_text label="Resumed" 34 | fi 35 | 36 | if [[ $override == "0" ]]; then 37 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 38 | 39 | # animate 40 | dynamic-island-sketchybar --animate tanh 8 --bar margin=$target_width margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 41 | --animate tanh 10 --bar height=$RESUME_MAX_EXPAND_HEIGHT height="$P_DYNAMIC_ISLAND_MUSIC_RESUME_EXPAND_HEIGHT" \ 42 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_MUSIC_RESUME_CORNER_RAD" 43 | 44 | sleep 0.45 45 | dynamic-island-sketchybar --animate sin 10 --set island.resume_text label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 46 | else 47 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 48 | --animate tanh 10 --bar height=$RESUME_MAX_EXPAND_HEIGHT height="$P_DYNAMIC_ISLAND_MUSIC_RESUME_EXPAND_HEIGHT" \ 49 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_MUSIC_RESUME_CORNER_RAD" 50 | dynamic-island-sketchybar --animate sin 10 --set island.resume_text label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 51 | fi 52 | 53 | sleep 0.8 54 | 55 | dynamic-island-sketchybar --animate tanh 10 --set island.resume_text label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 56 | 57 | sleep 0.1 58 | 59 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 60 | sleep 0.7 61 | 62 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/music/reset-resume.sh" 63 | -------------------------------------------------------------------------------- /scripts/islands/music/reset-resume.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.resume_text drawing=off 3 | sleep 0.1 4 | 5 | # call end event 6 | dynamic-island-sketchybar --trigger dynamic_island_request 7 | -------------------------------------------------------------------------------- /scripts/islands/music/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.music_title drawing=off \ 3 | --set island.music_artist drawing=off \ 4 | --set island.music_artwork drawing=off 5 | 6 | sleep 0.1 7 | 8 | # call end event 9 | dynamic-island-sketchybar --trigger dynamic_island_request 10 | -------------------------------------------------------------------------------- /scripts/islands/notification/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | title=( 4 | width=0 5 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 6 | label.padding_left=0 7 | label.padding_right=0 8 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:16.0" 9 | label.y_offset=-6 10 | background.height=0 11 | background.padding_left=12 12 | background.padding_right=0 13 | drawing=off 14 | ) 15 | 16 | subtitle=( 17 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 18 | label.padding_left=0 19 | label.padding_right=0 20 | background.height=0 21 | background.padding_left=0 22 | background.padding_right=0 23 | width=0 24 | label.font="$P_DYNAMIC_ISLAND_FONT:Italic:12.0" 25 | label.y_offset=-24 26 | drawing=off 27 | ) 28 | 29 | body=( 30 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 31 | label.padding_left=0 32 | label.padding_right=0 33 | background.padding_left=0 34 | background.height=0 35 | background.padding_right=0 36 | label.font="$P_DYNAMIC_ISLAND_FONT:Semibold:14.0" 37 | label.y_offset=-43 38 | label.width="$P_DYNAMIC_ISLAND_NOTIFICATION_MAX_ALLOWED_BODY" 39 | width=0 40 | drawing=off 41 | ) 42 | 43 | logo=( 44 | background.color="$P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN" 45 | background.padding_left=20 46 | background.padding_right=12 47 | background.image.scale=0.8 48 | background.height=0 49 | y_offset=-10 50 | width=0 51 | drawing=off 52 | ) 53 | 54 | dynamic-island-sketchybar --add item island.notification_title popup.island \ 55 | --set island.notification_title "${title[@]}" \ 56 | --add item island.notification_subtitle popup.island \ 57 | --set island.notification_subtitle "${subtitle[@]}" \ 58 | --add item island.notification_body popup.island \ 59 | --set island.notification_body "${body[@]}" \ 60 | --add item island.notification_logo popup.island \ 61 | --set island.notification_logo "${logo[@]}" 62 | -------------------------------------------------------------------------------- /scripts/islands/notification/notification_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_NOTIFICATION_EXPAND_HEIGHT + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 6 | EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_NOTIFICATION_MAX_EXPAND_WIDTH)) 7 | 8 | args=$* 9 | IFS='|' 10 | read -ra strarr <<<"$args" 11 | unset IFS 12 | 13 | # 1 - override 14 | # 2 - title 15 | # 3 - subtitle 16 | # 4 - message - message1 17 | # 5 - app bundle identifier 18 | override="${strarr[0]}" 19 | title="${strarr[1]}" 20 | subtitle="${strarr[2]}" 21 | message="${strarr[3]}" 22 | appId="${strarr[4]%% *}" 23 | 24 | logo=( 25 | drawing=on 26 | background.color="$P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN" 27 | background.image="app.$appId" 28 | width=50 29 | ) 30 | 31 | # Enable 32 | dynamic-island-sketchybar --set island.notification_title drawing=on \ 33 | label="$title" \ 34 | --set island.notification_subtitle drawing=on \ 35 | label="$subtitle" \ 36 | --set island.notification_body drawing=on \ 37 | label="$message" \ 38 | --set island.notification_logo "${logo[@]}" \ 39 | 40 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 41 | 42 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 43 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_NOTIFICATION_EXPAND_HEIGHT" \ 44 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_NOTIFICATION_CORNER_RAD" 45 | 46 | sleep 0.45 47 | dynamic-island-sketchybar --animate sin 20 --set island.notification_title label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 48 | --animate sin 20 --set island.notification_subtitle label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 49 | --animate sin 20 --set island.notification_body label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 50 | --animate sin 20 --set island.notification_logo background.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 51 | 52 | sleep 2.25 53 | 54 | dynamic-island-sketchybar --animate tanh 20 --set island.notification_title label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 55 | --animate tanh 20 --set island.notification_subtitle label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 56 | --animate tanh 20 --set island.notification_body label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 57 | --animate tanh 20 --set island.notification_logo background.color="$P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN" 58 | 59 | sleep 0.15 60 | 61 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 62 | 63 | sleep 0.7 64 | 65 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/notification/reset.sh" 66 | -------------------------------------------------------------------------------- /scripts/islands/notification/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.notification_title drawing=off \ 3 | --set island.notification_subtitle drawing=off \ 4 | --set island.notification_body drawing=off \ 5 | --set island.notification_logo drawing=off \ 6 | 7 | sleep 0.1 8 | 9 | # call end event 10 | dynamic-island-sketchybar --trigger dynamic_island_request 11 | -------------------------------------------------------------------------------- /scripts/islands/power/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/bash 2 | 3 | power_text=( 4 | width=0 5 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 6 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:12.0" 7 | label.y_offset=-5 8 | label.align=right 9 | padding_left=0 10 | padding_right=10 11 | drawing=off 12 | ) 13 | 14 | power_icon=( 15 | label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 16 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:12.0" 17 | y_offset=-5 18 | padding_right=10 19 | drawing=off 20 | ) 21 | 22 | dynamic-island-sketchybar --add item island.power_text right \ 23 | --set island.power_text "${power_text[@]}" \ 24 | --add item island.power_icon left \ 25 | --set island.power_icon "${power_icon[@]}" 26 | -------------------------------------------------------------------------------- /scripts/islands/power/handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --trigger dynamic_island_queue INFO="power" ISLAND_ARGS="$INFO" 3 | -------------------------------------------------------------------------------- /scripts/islands/power/power_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_BATTERY_EXPAND_HEIGHT + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 6 | EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_BATTERY_MAX_EXPAND_WIDTH)) 7 | 8 | args=$* 9 | IFS='|' 10 | read -ra strarr <<<"$args" 11 | unset IFS 12 | 13 | # $1 - override 14 | # $2 - connection type 15 | override="${strarr[0]}" 16 | power_source="${strarr[1]}" 17 | icon=$P_DYNAMIC_ISLAND_ICON_BATTERY_ONBATTERY 18 | 19 | if [ "$power_source" == "AC" ]; then 20 | icon=$P_DYNAMIC_ISLAND_ICON_BATTERY_CONNECTEDAC 21 | fi 22 | 23 | if [[ $override == "0" ]]; then 24 | dynamic-island-sketchybar --set island.power_text drawing=on \ 25 | --set island.power_icon drawing=on 26 | fi 27 | 28 | dynamic-island-sketchybar --set island.power_icon label="$icon" \ 29 | --set island.power_text label="$power_source" 30 | 31 | if [[ $override == "0" ]]; then 32 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 33 | 34 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 35 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_BATTERY_EXPAND_HEIGHT" \ 36 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_BATTERY_CORNER_RAD" 37 | else 38 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 39 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_BATTERY_EXPAND_HEIGHT" \ 40 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_BATTERY_CORNER_RAD" 41 | fi 42 | 43 | sleep 0.1 44 | 45 | dynamic-island-sketchybar --animate sin 15 --set island.power_text label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 46 | --animate sin 15 --set island.power_icon label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 47 | 48 | sleep 0.8 49 | 50 | dynamic-island-sketchybar --animate tanh 15 --set island.power_text label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 51 | --animate tanh 15 --set island.power_icon label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 52 | 53 | sleep 0.1 54 | 55 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 56 | sleep 0.4 57 | 58 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/power/reset.sh" 59 | -------------------------------------------------------------------------------- /scripts/islands/power/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.power_text drawing=off \ 3 | --set island.power_icon drawing=off \ 4 | 5 | sleep 0.1 6 | 7 | # call end event 8 | dynamic-island-sketchybar --trigger dynamic_island_request 9 | -------------------------------------------------------------------------------- /scripts/islands/restore.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/bash 2 | PREVIOUS_ISLAND_CACHE="$DYNAMIC_ISLAND_DIR/scripts/islands/previous_island" 3 | 4 | dynamic-island-sketchybar --animate tanh 10 --bar height="$P_DYNAMIC_ISLAND_DEFAULT_HEIGHT" \ 5 | --animate sin 10 --bar corner_radius="$P_DYNAMIC_ISLAND_CORNER_RADIUS" 6 | 7 | TARGET_WIDTH="$P_DYNAMIC_ISLAND_DEFAULT_WIDTH" 8 | 9 | while IFS= read -r line 10 | do 11 | if [[ $line == "music" ]]; then 12 | if [[ $TARGET_WIDTH -lt $P_DYNAMIC_ISLAND_MUSIC_IDLE_EXPAND_WIDTH ]]; then 13 | TARGET_WIDTH="$P_DYNAMIC_ISLAND_MUSIC_IDLE_EXPAND_WIDTH" 14 | fi 15 | fi 16 | done < "$PREVIOUS_ISLAND_CACHE" 17 | 18 | dynamic-island-sketchybar --animate tanh 10 --bar margin=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $TARGET_WIDTH + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) margin=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $TARGET_WIDTH)) 19 | 20 | sleep 0.2 21 | 22 | # Restore elements 23 | while IFS= read -r line 24 | do 25 | echo "$line" 26 | if [[ $line == "music" ]]; then 27 | dynamic-island-sketchybar --set island.music_visualizer drawing=on \ 28 | --set island.small_artwork drawing=on 29 | 30 | dynamic-island-sketchybar --animate tanh 10 --set island.music_visualizer label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 31 | --animate tanh 10 --set island.small_artwork background.image.scale=1 32 | fi 33 | done < "$PREVIOUS_ISLAND_CACHE" 34 | -------------------------------------------------------------------------------- /scripts/islands/volume/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | volume_icon=( 4 | icon.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 5 | icon.font="$P_DYNAMIC_ISLAND_FONT:Bold:14.0" 6 | icon.y_offset=2 7 | padding_left=10 8 | padding_right=0 9 | width=0 10 | drawing=off 11 | ) 12 | 13 | volume_bar=( 14 | background.height=2 15 | background.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 16 | background.border_color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 17 | background.y_offset=0 18 | background.shadow.drawing=off 19 | drawing=off 20 | y_offset=-19 21 | padding_left=10 22 | ) 23 | 24 | dynamic-island-sketchybar --add item island.volume_icon left \ 25 | --set island.volume_icon "${volume_icon[@]}" \ 26 | --add item island.volume_bar left \ 27 | --set island.volume_bar "${volume_bar[@]}" 28 | -------------------------------------------------------------------------------- /scripts/islands/volume/handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | echo "volume" 3 | echo "$INFO" 4 | 5 | dynamic-island-sketchybar --trigger dynamic_island_queue INFO="volume" ISLAND_ARGS="$INFO" 6 | -------------------------------------------------------------------------------- /scripts/islands/volume/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.volume_icon drawing=off \ 3 | --set island.volume_bar drawing=off \ 4 | 5 | sleep 0.1 6 | 7 | # call end event 8 | dynamic-island-sketchybar --trigger dynamic_island_request 9 | -------------------------------------------------------------------------------- /scripts/islands/volume/volume_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_VOLUME_EXPAND_HEIGHT + ($P_DYNAMIC_ISLAND_SQUISH_AMOUNT / 2))) 6 | EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_VOLUME_MAX_EXPAND_WIDTH)) 7 | 8 | args=$* 9 | IFS='|' 10 | read -ra strarr <<<"$args" 11 | unset IFS 12 | 13 | # $1 - override 14 | # $2 - volume 15 | override="${strarr[0]}" 16 | volume="${strarr[1]}" 17 | 18 | # calculate volume logo 19 | case $volume in 20 | 100) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MAX ;; 21 | 9[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MAX ;; 22 | 8[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MAX ;; 23 | 7[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MAX ;; 24 | 6[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MED ;; 25 | 5[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MED ;; 26 | 4[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MED ;; 27 | 3[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_LOW ;; 28 | 2[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_LOW ;; 29 | 1[0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_LOW ;; 30 | [0-9]) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MUTED ;; 31 | *) ICON=$P_DYNAMIC_ISLAND_ICON_VOLUME_MUTED ;; 32 | esac 33 | 34 | if [[ $override == "0" ]]; then 35 | # enable 36 | dynamic-island-sketchybar --set island.volume_icon drawing=on \ 37 | icon="$ICON" \ 38 | --set island.volume_bar drawing=on 39 | fi 40 | 41 | if [[ $override == "0" ]]; then 42 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 43 | 44 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 45 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_VOLUME_CORNER_RAD" \ 46 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_VOLUME_EXPAND_HEIGHT" 47 | else 48 | dynamic-island-sketchybar --animate tanh 10 --bar margin="$(($EXPAND_SIZE + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 49 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_VOLUME_CORNER_RAD" \ 50 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_VOLUME_EXPAND_HEIGHT" 51 | fi 52 | 53 | sleep 0.1 54 | 55 | # subtract 20, because we're using padding value of 10. 56 | barWidth=$(bc -l <<<"$volume/100*$(($P_DYNAMIC_ISLAND_VOLUME_MAX_EXPAND_WIDTH * 2 - 20))") 57 | barWidth=$(printf "%.0f" "$barWidth") 58 | dynamic-island-sketchybar --animate tanh 15 --set island.volume_bar width="$barWidth" 59 | 60 | dynamic-island-sketchybar --animate sin 10 --set island.volume_bar background.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 61 | --animate sin 10 --set island.volume_bar background.border_color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 62 | --animate sin 10 --set island.volume_icon icon.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 63 | 64 | sleep 0.8 65 | 66 | dynamic-island-sketchybar --animate tanh 15 --set island.volume_icon icon.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 67 | --animate tanh 15 --set island.volume_bar background.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 68 | 69 | sleep 0.1 70 | 71 | dynamic-island-sketchybar --animate tanh 5 --set island.volume_bar width=0 72 | 73 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 74 | sleep 0.4 75 | 76 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/volume/reset.sh" 77 | -------------------------------------------------------------------------------- /scripts/islands/wifi/creator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/sh 2 | dynamic-island-sketchybar --add item island.wifi_ssid right \ 3 | --set island.wifi_ssid width=0 \ 4 | label.color=$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT \ 5 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:12.0" \ 6 | label.y_offset=-5 \ 7 | label.align=right \ 8 | padding_left=0 \ 9 | padding_right=10 \ 10 | drawing=off \ 11 | --add item island.wifi_icon left \ 12 | --set island.wifi_icon label.color=$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT \ 13 | label.font="$P_DYNAMIC_ISLAND_FONT:Bold:12.0" \ 14 | y_offset=-5 \ 15 | padding_right=10 \ 16 | drawing=off 17 | -------------------------------------------------------------------------------- /scripts/islands/wifi/handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | TITLE=$(jq -r '.title' <<< "$INFO") 3 | ARTIST=$(jq -r '.artist' <<< "$INFO") 4 | STATE=$(jq -r '.state' <<< "$INFO") 5 | 6 | dynamic-island-sketchybar --trigger dynamic_island_queue INFO="music" ISLAND_ARGS="$TITLE|$ARTIST|$STATE" 7 | -------------------------------------------------------------------------------- /scripts/islands/wifi/reset.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | dynamic-island-sketchybar --set island.wifi_icon drawing=off \ 3 | --set island.wifi_ssid drawing=off \ 4 | 5 | sleep 0.1 6 | 7 | # call end event 8 | dynamic-island-sketchybar --trigger dynamic_island_request 9 | -------------------------------------------------------------------------------- /scripts/islands/wifi/wifi_island.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source "$HOME/.config/dynamic-island-sketchybar/userconfig.sh" 3 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/clear.sh" 4 | 5 | MAX_EXPAND_HEIGHT=$(($P_DYNAMIC_ISLAND_WIFI_EXPAND_HEIGHT + $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 6 | EXPAND_SIZE=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_WIFI_MAX_EXPAND_WIDTH)) 7 | 8 | args=$* 9 | IFS='|' 10 | read -ra strarr <<<"$args" 11 | unset IFS 12 | 13 | # $1 - override 14 | # $2 - ssid 15 | override="${strarr[0]}" 16 | ssid="${strarr[1]}" 17 | icon=$P_DYNAMIC_ISLAND_ICON_WIFI_CONNECTED 18 | 19 | if [ -z "$ssid" ]; then 20 | icon=$P_DYNAMIC_ISLAND_ICON_WIFI_DISCONNECTED 21 | ssid="Disconnected" 22 | fi 23 | 24 | if [[ $override == "0" ]]; then 25 | dynamic-island-sketchybar --set island.wifi_ssid drawing=on \ 26 | --set island.wifi_icon drawing=on 27 | fi 28 | 29 | dynamic-island-sketchybar --set island.wifi_icon label="$icon" \ 30 | --set island.wifi_ssid label="$ssid" 31 | 32 | if [[ $override == "0" ]]; then 33 | target_width=$(($P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION / 2 - $P_DYNAMIC_ISLAND_DEFAULT_WIDTH - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT)) 34 | 35 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$target_width" margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 36 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_WIFI_EXPAND_HEIGHT" \ 37 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_WIFI_CORNER_RAD" 38 | else 39 | dynamic-island-sketchybar --animate tanh 8 --bar margin="$(($EXPAND_SIZE - $P_DYNAMIC_ISLAND_SQUISH_AMOUNT))" margin="$EXPAND_SIZE" \ 40 | --animate tanh 10 --bar height="$MAX_EXPAND_HEIGHT" height="$P_DYNAMIC_ISLAND_WIFI_EXPAND_HEIGHT" \ 41 | --animate tanh 10 --bar corner_radius="$P_DYNAMIC_ISLAND_WIFI_CORNER_RAD" 42 | fi 43 | 44 | sleep 0.1 45 | 46 | dynamic-island-sketchybar --animate sin 15 --set island.wifi_ssid label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" \ 47 | --animate sin 15 --set island.wifi_icon label.color="$P_DYNAMIC_ISLAND_COLOR_WHITE" 48 | 49 | sleep 0.8 50 | 51 | dynamic-island-sketchybar --animate tanh 15 --set island.wifi_ssid label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" \ 52 | --animate tanh 15 --set island.wifi_icon label.color="$P_DYNAMIC_ISLAND_COLOR_TRANSPARENT" 53 | 54 | sleep 0.1 55 | 56 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/restore.sh" 57 | sleep 0.4 58 | 59 | source "$DYNAMIC_ISLAND_DIR/scripts/islands/wifi/reset.sh" 60 | -------------------------------------------------------------------------------- /sketchybarrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | export DYNAMIC_ISLAND_DIR="/opt/homebrew/etc/dynamic-island-sketchybar" 4 | 5 | source "$DYNAMIC_ISLAND_DIR/item.sh" # Loads Dynamic-Island item 6 | 7 | dynamic-island-sketchybar --update 8 | -------------------------------------------------------------------------------- /userconfigs/mbp2021_14.sh: -------------------------------------------------------------------------------- 1 | #### DYNAMIC ISLAND USER CONFIG - MACBOOK PRO 2021 - 14 INCH ##### 2 | 3 | ## These are the default values, you can choose to only include modified options in a clean file 4 | 5 | # 6 | ### Main config 7 | # 8 | 9 | # Which display should the dynamic island be available? 10 | # Available options: all, main, id of display (e.g. 1, 2, 3) 11 | P_DYNAMIC_ISLAND_DISPLAY=main 12 | 13 | # Needs to have Regular, Bold, Semibold, Heavy and Black variants 14 | # Font icons may not load properly if not SF Pro 15 | P_DYNAMIC_ISLAND_FONT="SF Pro" 16 | 17 | # Enable/Disable Islands 18 | P_DYNAMIC_ISLAND_MUSIC_ENABLED=1 19 | P_DYNAMIC_ISLAND_APPSWITCH_ENABLED=1 20 | export P_DYNAMIC_ISLAND_NOTIFICATION_ENABLED=0 21 | P_DYNAMIC_ISLAND_VOLUME_ENABLED=1 22 | P_DYNAMIC_ISLAND_BRIGHTNESS_ENABLED=1 23 | P_DYNAMIC_ISLAND_WIFI_ENABLED=1 24 | P_DYNAMIC_ISLAND_POWER_ENABLED=1 25 | 26 | # Notch Size 27 | P_DYNAMIC_ISLAND_DEFAULT_HEIGHT=44 28 | P_DYNAMIC_ISLAND_DEFAULT_WIDTH=100 29 | P_DYNAMIC_ISLAND_CORNER_RADIUS=10 30 | 31 | # in case of built-in display, it must be divded by 2, e.g.: MBP 14 has 3024 resolution, so 3024/2=1512 32 | P_DYNAMIC_ISLAND_MONITOR_HORIZONTAL_RESOLUTION=1512 33 | 34 | # Animation Settings 35 | P_DYNAMIC_ISLAND_SQUISH_AMOUNT=6 36 | 37 | 38 | # 39 | ## App Switch Island config 40 | # 41 | P_DYNAMIC_ISLAND_APPSWITCH_MAX_EXPAND_WIDTH=110 # Max size per character of app name 42 | P_DYNAMIC_ISLAND_APPSWITCH_EXPAND_HEIGHT=56 43 | P_DYNAMIC_ISLAND_APPSWITCH_CORNER_RAD=15 # Corner Radius 44 | P_DYNAMIC_ISLAND_APPSWITCH_ICON_SIZE=1 45 | 46 | 47 | # 48 | ## Volume Island config 49 | # 50 | P_DYNAMIC_ISLAND_VOLUME_MAX_EXPAND_WIDTH=130 # Max size when expanded 51 | P_DYNAMIC_ISLAND_VOLUME_EXPAND_HEIGHT=65 52 | P_DYNAMIC_ISLAND_VOLUME_CORNER_RAD=12 # Corner Radius 53 | P_DYNAMIC_ISLAND_VOLUME_NORMAL_ICON_COLOR=0xffffffff 54 | P_DYNAMIC_ISLAND_ICON_VOLUME_MAX=􀊩 55 | P_DYNAMIC_ISLAND_ICON_VOLUME_MED=􀊧 56 | P_DYNAMIC_ISLAND_ICON_VOLUME_LOW=􀊥 57 | P_DYNAMIC_ISLAND_ICON_VOLUME_MUTED=􀊡 58 | 59 | # 60 | ## Brightness Island config 61 | # 62 | P_DYNAMIC_ISLAND_BRIGHTNESS_MAX_EXPAND_WIDTH=130 # Max size when expanded 63 | P_DYNAMIC_ISLAND_BRIGHTNESS_EXPAND_HEIGHT=65 64 | P_DYNAMIC_ISLAND_BRIGHTNESS_CORNER_RAD=12 # Corner Radius 65 | P_DYNAMIC_ISLAND_BRIGHTNESS_NORMAL_ICON_COLOR=0xffffffff 66 | P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_LOW=􀆫 67 | P_DYNAMIC_ISLAND_ICON_BRIGHTNESS_HIGH=􀆭 68 | 69 | 70 | # 71 | ## Music Island config 72 | # 73 | # Music Info 74 | P_DYNAMIC_ISLAND_MUSIC_SOURCE="Music" # AVAILABLE OPTIONS (case sensitive): Music (apple music), Spotify 75 | P_DYNAMIC_ISLAND_MUSIC_INFO_MAX_EXPAND_WIDTH=170 # Max size when expanded# 76 | P_DYNAMIC_ISLAND_MUSIC_INFO_EXPAND_HEIGHT=100 77 | P_DYNAMIC_ISLAND_MUSIC_INFO_CORNER_RAD=19 # Corner Radius 78 | 79 | # Music Idle Info 80 | P_DYNAMIC_ISLAND_MUSIC_IDLE_EXPAND_WIDTH=160 81 | 82 | # Resume Info 83 | P_DYNAMIC_ISLAND_MUSIC_RESUME_MAX_EXPAND_WIDTH=155 84 | P_DYNAMIC_ISLAND_MUSIC_RESUME_EXPAND_HEIGHT=56 85 | P_DYNAMIC_ISLAND_MUSIC_RESUME_CORNER_RAD=15 # Corner Radius 86 | 87 | # 88 | ## WIFI Island config 89 | # 90 | P_DYNAMIC_ISLAND_WIFI_MAX_EXPAND_WIDTH=190 # Max size when expanded 91 | P_DYNAMIC_ISLAND_WIFI_EXPAND_HEIGHT=56 92 | P_DYNAMIC_ISLAND_WIFI_CORNER_RAD=15 # Corner Radius 93 | P_DYNAMIC_ISLAND_ICON_WIFI_CONNECTED=􀙇 94 | P_DYNAMIC_ISLAND_ICON_WIFI_DISCONNECTED=􀙈 95 | 96 | # 97 | ## Battery Island config 98 | # 99 | P_DYNAMIC_ISLAND_BATTERY_MAX_EXPAND_WIDTH=190 # Max size when expanded 100 | P_DYNAMIC_ISLAND_BATTERY_EXPAND_HEIGHT=56 101 | P_DYNAMIC_ISLAND_BATTERY_CORNER_RAD=15 # Corner Radius 102 | P_DYNAMIC_ISLAND_ICON_BATTERY_CONNECTEDAC=􀢋 103 | P_DYNAMIC_ISLAND_ICON_BATTERY_ONBATTERY=􀺸 104 | 105 | 106 | # 107 | ## Notification Island Config 108 | # 109 | P_DYNAMIC_ISLAND_NOTIFICATION_MAX_EXPAND_WIDTH=180 # Max size when expanded 110 | P_DYNAMIC_ISLAND_NOTIFICATION_EXPAND_HEIGHT=90 111 | P_DYNAMIC_ISLAND_NOTIFICATION_CORNER_RAD=42 # Corner Radius 112 | P_DYNAMIC_ISLAND_NOTIFICATION_MAX_ALLOWED_BODY=250 # Max allowed body for notification message 113 | 114 | ############# THESE VALUES SHOULDN'T BE UNTOUCHED ############# 115 | 116 | # 117 | ## Colors 118 | # 119 | P_DYNAMIC_ISLAND_COLOR_WHITE=0xffffffff 120 | P_DYNAMIC_ISLAND_COLOR_BLACK=0xff000000 121 | P_DYNAMIC_ISLAND_COLOR_TRANSPARENT=0x00000000 122 | P_DYNAMIC_ISLAND_COLOR_ICON_HIDDEN=$P_DYNAMIC_ISLAND_COLOR_BLACK 123 | --------------------------------------------------------------------------------