";
145 | };
146 | /* End PBXGroup section */
147 |
148 | /* Begin PBXNativeTarget section */
149 | 2356DBC526A50AB100A39A25 /* DSFDockTile Plugin Demo */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = 2356DBD426A50AB200A39A25 /* Build configuration list for PBXNativeTarget "DSFDockTile Plugin Demo" */;
152 | buildPhases = (
153 | 2356DBC226A50AB100A39A25 /* Sources */,
154 | 2356DBC326A50AB100A39A25 /* Frameworks */,
155 | 2356DBC426A50AB100A39A25 /* Resources */,
156 | 2356DBE426A50B5D00A39A25 /* Embed PlugIns */,
157 | );
158 | buildRules = (
159 | );
160 | dependencies = (
161 | 2356DBE326A50B5D00A39A25 /* PBXTargetDependency */,
162 | );
163 | name = "DSFDockTile Plugin Demo";
164 | packageProductDependencies = (
165 | );
166 | productName = "DSFDockTile Plugin Demo";
167 | productReference = 2356DBC626A50AB100A39A25 /* DSFDockTile Plugin Demo.app */;
168 | productType = "com.apple.product-type.application";
169 | };
170 | 2356DBDA26A50B0100A39A25 /* DSFDockTilePlugin */ = {
171 | isa = PBXNativeTarget;
172 | buildConfigurationList = 2356DBDC26A50B0100A39A25 /* Build configuration list for PBXNativeTarget "DSFDockTilePlugin" */;
173 | buildPhases = (
174 | 2356DBD726A50B0100A39A25 /* Sources */,
175 | 2356DBD826A50B0100A39A25 /* Frameworks */,
176 | 2356DBD926A50B0100A39A25 /* Resources */,
177 | );
178 | buildRules = (
179 | );
180 | dependencies = (
181 | );
182 | name = DSFDockTilePlugin;
183 | packageProductDependencies = (
184 | 2356DBF026A50C1300A39A25 /* DSFDockTile */,
185 | );
186 | productName = DSFDockTilePlugin;
187 | productReference = 2356DBDB26A50B0100A39A25 /* DSFDockTilePlugin.plugin */;
188 | productType = "com.apple.product-type.bundle";
189 | };
190 | /* End PBXNativeTarget section */
191 |
192 | /* Begin PBXProject section */
193 | 2356DBBE26A50AB100A39A25 /* Project object */ = {
194 | isa = PBXProject;
195 | attributes = {
196 | BuildIndependentTargetsInParallel = 1;
197 | LastSwiftUpdateCheck = 1300;
198 | LastUpgradeCheck = 1300;
199 | TargetAttributes = {
200 | 2356DBC526A50AB100A39A25 = {
201 | CreatedOnToolsVersion = 13.0;
202 | };
203 | 2356DBDA26A50B0100A39A25 = {
204 | CreatedOnToolsVersion = 13.0;
205 | };
206 | };
207 | };
208 | buildConfigurationList = 2356DBC126A50AB100A39A25 /* Build configuration list for PBXProject "DSFDockTile Plugin Demo" */;
209 | compatibilityVersion = "Xcode 13.0";
210 | developmentRegion = en;
211 | hasScannedForEncodings = 0;
212 | knownRegions = (
213 | en,
214 | Base,
215 | );
216 | mainGroup = 2356DBBD26A50AB100A39A25;
217 | packageReferences = (
218 | 2356DBEF26A50C1300A39A25 /* XCRemoteSwiftPackageReference "DSFDockTile" */,
219 | );
220 | productRefGroup = 2356DBC726A50AB100A39A25 /* Products */;
221 | projectDirPath = "";
222 | projectRoot = "";
223 | targets = (
224 | 2356DBC526A50AB100A39A25 /* DSFDockTile Plugin Demo */,
225 | 2356DBDA26A50B0100A39A25 /* DSFDockTilePlugin */,
226 | );
227 | };
228 | /* End PBXProject section */
229 |
230 | /* Begin PBXResourcesBuildPhase section */
231 | 2356DBC426A50AB100A39A25 /* Resources */ = {
232 | isa = PBXResourcesBuildPhase;
233 | buildActionMask = 2147483647;
234 | files = (
235 | 2356DBD126A50AB200A39A25 /* Preview Assets.xcassets in Resources */,
236 | 2356DBCE26A50AB200A39A25 /* Assets.xcassets in Resources */,
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | 2356DBD926A50B0100A39A25 /* Resources */ = {
241 | isa = PBXResourcesBuildPhase;
242 | buildActionMask = 2147483647;
243 | files = (
244 | 2356DC0926A51EB400A39A25 /* light.png in Resources */,
245 | 2356DC0726A51DAC00A39A25 /* dark.png in Resources */,
246 | );
247 | runOnlyForDeploymentPostprocessing = 0;
248 | };
249 | /* End PBXResourcesBuildPhase section */
250 |
251 | /* Begin PBXSourcesBuildPhase section */
252 | 2356DBC226A50AB100A39A25 /* Sources */ = {
253 | isa = PBXSourcesBuildPhase;
254 | buildActionMask = 2147483647;
255 | files = (
256 | 2356DBCC26A50AB100A39A25 /* ContentView.swift in Sources */,
257 | 23447D3926A52BDB0074ABF2 /* LightDarkImage.swift in Sources */,
258 | 2356DBCA26A50AB100A39A25 /* DSFDockTile_Plugin_DemoApp.swift in Sources */,
259 | );
260 | runOnlyForDeploymentPostprocessing = 0;
261 | };
262 | 2356DBD726A50B0100A39A25 /* Sources */ = {
263 | isa = PBXSourcesBuildPhase;
264 | buildActionMask = 2147483647;
265 | files = (
266 | 2356DBF426A50D3800A39A25 /* DockTilePlugin.swift in Sources */,
267 | );
268 | runOnlyForDeploymentPostprocessing = 0;
269 | };
270 | /* End PBXSourcesBuildPhase section */
271 |
272 | /* Begin PBXTargetDependency section */
273 | 2356DBE326A50B5D00A39A25 /* PBXTargetDependency */ = {
274 | isa = PBXTargetDependency;
275 | target = 2356DBDA26A50B0100A39A25 /* DSFDockTilePlugin */;
276 | targetProxy = 2356DBE226A50B5D00A39A25 /* PBXContainerItemProxy */;
277 | };
278 | /* End PBXTargetDependency section */
279 |
280 | /* Begin XCBuildConfiguration section */
281 | 2356DBD226A50AB200A39A25 /* Debug */ = {
282 | isa = XCBuildConfiguration;
283 | buildSettings = {
284 | ALWAYS_SEARCH_USER_PATHS = NO;
285 | CLANG_ANALYZER_NONNULL = YES;
286 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
287 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
288 | CLANG_CXX_LIBRARY = "libc++";
289 | CLANG_ENABLE_MODULES = YES;
290 | CLANG_ENABLE_OBJC_ARC = YES;
291 | CLANG_ENABLE_OBJC_WEAK = YES;
292 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
293 | CLANG_WARN_BOOL_CONVERSION = YES;
294 | CLANG_WARN_COMMA = YES;
295 | CLANG_WARN_CONSTANT_CONVERSION = YES;
296 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
297 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
298 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
299 | CLANG_WARN_EMPTY_BODY = YES;
300 | CLANG_WARN_ENUM_CONVERSION = YES;
301 | CLANG_WARN_INFINITE_RECURSION = YES;
302 | CLANG_WARN_INT_CONVERSION = YES;
303 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
304 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
307 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
308 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
309 | CLANG_WARN_STRICT_PROTOTYPES = YES;
310 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
311 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
312 | CLANG_WARN_UNREACHABLE_CODE = YES;
313 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
314 | COPY_PHASE_STRIP = NO;
315 | DEBUG_INFORMATION_FORMAT = dwarf;
316 | ENABLE_STRICT_OBJC_MSGSEND = YES;
317 | ENABLE_TESTABILITY = YES;
318 | GCC_C_LANGUAGE_STANDARD = gnu11;
319 | GCC_DYNAMIC_NO_PIC = NO;
320 | GCC_NO_COMMON_BLOCKS = YES;
321 | GCC_OPTIMIZATION_LEVEL = 0;
322 | GCC_PREPROCESSOR_DEFINITIONS = (
323 | "DEBUG=1",
324 | "$(inherited)",
325 | );
326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
328 | GCC_WARN_UNDECLARED_SELECTOR = YES;
329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
330 | GCC_WARN_UNUSED_FUNCTION = YES;
331 | GCC_WARN_UNUSED_VARIABLE = YES;
332 | MACOSX_DEPLOYMENT_TARGET = 11.4;
333 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
334 | MTL_FAST_MATH = YES;
335 | ONLY_ACTIVE_ARCH = YES;
336 | SDKROOT = macosx;
337 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
338 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
339 | };
340 | name = Debug;
341 | };
342 | 2356DBD326A50AB200A39A25 /* Release */ = {
343 | isa = XCBuildConfiguration;
344 | buildSettings = {
345 | ALWAYS_SEARCH_USER_PATHS = NO;
346 | CLANG_ANALYZER_NONNULL = YES;
347 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
348 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
349 | CLANG_CXX_LIBRARY = "libc++";
350 | CLANG_ENABLE_MODULES = YES;
351 | CLANG_ENABLE_OBJC_ARC = YES;
352 | CLANG_ENABLE_OBJC_WEAK = YES;
353 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
354 | CLANG_WARN_BOOL_CONVERSION = YES;
355 | CLANG_WARN_COMMA = YES;
356 | CLANG_WARN_CONSTANT_CONVERSION = YES;
357 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
358 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
359 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
360 | CLANG_WARN_EMPTY_BODY = YES;
361 | CLANG_WARN_ENUM_CONVERSION = YES;
362 | CLANG_WARN_INFINITE_RECURSION = YES;
363 | CLANG_WARN_INT_CONVERSION = YES;
364 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
365 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
366 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
367 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
368 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
369 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
370 | CLANG_WARN_STRICT_PROTOTYPES = YES;
371 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
372 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
373 | CLANG_WARN_UNREACHABLE_CODE = YES;
374 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
375 | COPY_PHASE_STRIP = NO;
376 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
377 | ENABLE_NS_ASSERTIONS = NO;
378 | ENABLE_STRICT_OBJC_MSGSEND = YES;
379 | GCC_C_LANGUAGE_STANDARD = gnu11;
380 | GCC_NO_COMMON_BLOCKS = YES;
381 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
382 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
383 | GCC_WARN_UNDECLARED_SELECTOR = YES;
384 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
385 | GCC_WARN_UNUSED_FUNCTION = YES;
386 | GCC_WARN_UNUSED_VARIABLE = YES;
387 | MACOSX_DEPLOYMENT_TARGET = 11.4;
388 | MTL_ENABLE_DEBUG_INFO = NO;
389 | MTL_FAST_MATH = YES;
390 | SDKROOT = macosx;
391 | SWIFT_COMPILATION_MODE = wholemodule;
392 | SWIFT_OPTIMIZATION_LEVEL = "-O";
393 | };
394 | name = Release;
395 | };
396 | 2356DBD526A50AB200A39A25 /* Debug */ = {
397 | isa = XCBuildConfiguration;
398 | buildSettings = {
399 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
401 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
402 | CODE_SIGN_STYLE = Automatic;
403 | COMBINE_HIDPI_IMAGES = YES;
404 | CURRENT_PROJECT_VERSION = 1;
405 | DEVELOPMENT_ASSET_PATHS = "\"DSFDockTile Plugin Demo/Preview Content\"";
406 | ENABLE_APP_SANDBOX = YES;
407 | ENABLE_PREVIEWS = YES;
408 | ENABLE_USER_SELECTED_FILES = readonly;
409 | GENERATE_INFOPLIST_FILE = YES;
410 | INFOPLIST_FILE = "DSFDockTile-Plugin-Demo-Info.plist";
411 | INFOPLIST_KEY_CFBundleExecutable = "DSFDockTile Plugin Demo";
412 | INFOPLIST_KEY_CFBundleName = "DSFDockTile Plugin Demo";
413 | INFOPLIST_KEY_CFBundleVersion = 1;
414 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
415 | LD_RUNPATH_SEARCH_PATHS = (
416 | "$(inherited)",
417 | "@executable_path/../Frameworks",
418 | );
419 | MACOSX_DEPLOYMENT_TARGET = 11.0;
420 | MARKETING_VERSION = 1.0;
421 | PRODUCT_BUNDLE_IDENTIFIER = "com.dagronf.dsfdocktile.plugin-demo.app";
422 | PRODUCT_NAME = "$(TARGET_NAME)";
423 | SWIFT_EMIT_LOC_STRINGS = YES;
424 | SWIFT_VERSION = 5.0;
425 | };
426 | name = Debug;
427 | };
428 | 2356DBD626A50AB200A39A25 /* Release */ = {
429 | isa = XCBuildConfiguration;
430 | buildSettings = {
431 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
432 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
433 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
434 | CODE_SIGN_STYLE = Automatic;
435 | COMBINE_HIDPI_IMAGES = YES;
436 | CURRENT_PROJECT_VERSION = 1;
437 | DEVELOPMENT_ASSET_PATHS = "\"DSFDockTile Plugin Demo/Preview Content\"";
438 | ENABLE_APP_SANDBOX = YES;
439 | ENABLE_PREVIEWS = YES;
440 | ENABLE_USER_SELECTED_FILES = readonly;
441 | GENERATE_INFOPLIST_FILE = YES;
442 | INFOPLIST_FILE = "DSFDockTile-Plugin-Demo-Info.plist";
443 | INFOPLIST_KEY_CFBundleExecutable = "DSFDockTile Plugin Demo";
444 | INFOPLIST_KEY_CFBundleName = "DSFDockTile Plugin Demo";
445 | INFOPLIST_KEY_CFBundleVersion = 1;
446 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
447 | LD_RUNPATH_SEARCH_PATHS = (
448 | "$(inherited)",
449 | "@executable_path/../Frameworks",
450 | );
451 | MACOSX_DEPLOYMENT_TARGET = 11.0;
452 | MARKETING_VERSION = 1.0;
453 | PRODUCT_BUNDLE_IDENTIFIER = "com.dagronf.dsfdocktile.plugin-demo.app";
454 | PRODUCT_NAME = "$(TARGET_NAME)";
455 | SWIFT_EMIT_LOC_STRINGS = YES;
456 | SWIFT_VERSION = 5.0;
457 | };
458 | name = Release;
459 | };
460 | 2356DBDD26A50B0100A39A25 /* Debug */ = {
461 | isa = XCBuildConfiguration;
462 | buildSettings = {
463 | CODE_SIGN_STYLE = Automatic;
464 | COMBINE_HIDPI_IMAGES = YES;
465 | CURRENT_PROJECT_VERSION = 1;
466 | EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
467 | GENERATE_INFOPLIST_FILE = YES;
468 | INFOPLIST_FILE = "DSFDockTilePlugin-Info.plist";
469 | INFOPLIST_KEY_CFBundleExecutable = DSFDockTilePlugin;
470 | INFOPLIST_KEY_CFBundleName = DSFDockTilePlugin;
471 | INFOPLIST_KEY_CFBundleVersion = 1;
472 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
473 | INFOPLIST_KEY_NSPrincipalClass = "";
474 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
475 | MACOSX_DEPLOYMENT_TARGET = 11.0;
476 | MARKETING_VERSION = 1.0;
477 | PRODUCT_BUNDLE_IDENTIFIER = "com.dagronf.dsfdocktile.plugin-demo.plugin.DSFDockTilePlugin";
478 | PRODUCT_NAME = "$(TARGET_NAME)";
479 | SKIP_INSTALL = YES;
480 | SWIFT_EMIT_LOC_STRINGS = YES;
481 | SWIFT_VERSION = 5.0;
482 | WRAPPER_EXTENSION = plugin;
483 | };
484 | name = Debug;
485 | };
486 | 2356DBDE26A50B0100A39A25 /* Release */ = {
487 | isa = XCBuildConfiguration;
488 | buildSettings = {
489 | CODE_SIGN_STYLE = Automatic;
490 | COMBINE_HIDPI_IMAGES = YES;
491 | CURRENT_PROJECT_VERSION = 1;
492 | EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
493 | GENERATE_INFOPLIST_FILE = YES;
494 | INFOPLIST_FILE = "DSFDockTilePlugin-Info.plist";
495 | INFOPLIST_KEY_CFBundleExecutable = DSFDockTilePlugin;
496 | INFOPLIST_KEY_CFBundleName = DSFDockTilePlugin;
497 | INFOPLIST_KEY_CFBundleVersion = 1;
498 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
499 | INFOPLIST_KEY_NSPrincipalClass = "";
500 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
501 | MACOSX_DEPLOYMENT_TARGET = 11.0;
502 | MARKETING_VERSION = 1.0;
503 | PRODUCT_BUNDLE_IDENTIFIER = "com.dagronf.dsfdocktile.plugin-demo.plugin.DSFDockTilePlugin";
504 | PRODUCT_NAME = "$(TARGET_NAME)";
505 | SKIP_INSTALL = YES;
506 | SWIFT_EMIT_LOC_STRINGS = YES;
507 | SWIFT_VERSION = 5.0;
508 | WRAPPER_EXTENSION = plugin;
509 | };
510 | name = Release;
511 | };
512 | /* End XCBuildConfiguration section */
513 |
514 | /* Begin XCConfigurationList section */
515 | 2356DBC126A50AB100A39A25 /* Build configuration list for PBXProject "DSFDockTile Plugin Demo" */ = {
516 | isa = XCConfigurationList;
517 | buildConfigurations = (
518 | 2356DBD226A50AB200A39A25 /* Debug */,
519 | 2356DBD326A50AB200A39A25 /* Release */,
520 | );
521 | defaultConfigurationIsVisible = 0;
522 | defaultConfigurationName = Release;
523 | };
524 | 2356DBD426A50AB200A39A25 /* Build configuration list for PBXNativeTarget "DSFDockTile Plugin Demo" */ = {
525 | isa = XCConfigurationList;
526 | buildConfigurations = (
527 | 2356DBD526A50AB200A39A25 /* Debug */,
528 | 2356DBD626A50AB200A39A25 /* Release */,
529 | );
530 | defaultConfigurationIsVisible = 0;
531 | defaultConfigurationName = Release;
532 | };
533 | 2356DBDC26A50B0100A39A25 /* Build configuration list for PBXNativeTarget "DSFDockTilePlugin" */ = {
534 | isa = XCConfigurationList;
535 | buildConfigurations = (
536 | 2356DBDD26A50B0100A39A25 /* Debug */,
537 | 2356DBDE26A50B0100A39A25 /* Release */,
538 | );
539 | defaultConfigurationIsVisible = 0;
540 | defaultConfigurationName = Release;
541 | };
542 | /* End XCConfigurationList section */
543 |
544 | /* Begin XCRemoteSwiftPackageReference section */
545 | 2356DBEF26A50C1300A39A25 /* XCRemoteSwiftPackageReference "DSFDockTile" */ = {
546 | isa = XCRemoteSwiftPackageReference;
547 | repositoryURL = "https://github.com/dagronf/DSFDockTile";
548 | requirement = {
549 | kind = upToNextMajorVersion;
550 | minimumVersion = 0.5.2;
551 | };
552 | };
553 | /* End XCRemoteSwiftPackageReference section */
554 |
555 | /* Begin XCSwiftPackageProductDependency section */
556 | 2356DBF026A50C1300A39A25 /* DSFDockTile */ = {
557 | isa = XCSwiftPackageProductDependency;
558 | package = 2356DBEF26A50C1300A39A25 /* XCRemoteSwiftPackageReference "DSFDockTile" */;
559 | productName = DSFDockTile;
560 | };
561 | /* End XCSwiftPackageProductDependency section */
562 | };
563 | rootObject = 2356DBBE26A50AB100A39A25 /* Project object */;
564 | }
565 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "DSFDockTile",
6 | "repositoryURL": "https://github.com/dagronf/DSFDockTile",
7 | "state": {
8 | "branch": null,
9 | "revision": "bb18b82cd3d64206eb322bd297f794b0a36dbf4d",
10 | "version": "0.5.2"
11 | }
12 | },
13 | {
14 | "package": "DSFImageFlipbook",
15 | "repositoryURL": "https://github.com/dagronf/DSFImageFlipbook",
16 | "state": {
17 | "branch": null,
18 | "revision": "8b6e1e7f862c1d39ce34c59705f9fa731d9fd539",
19 | "version": "1.0.1"
20 | }
21 | }
22 | ]
23 | },
24 | "version": 1
25 | }
26 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/dark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "dark.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "dark@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/dark.imageset/dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/dark.imageset/dark.png
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/dark.imageset/dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/dark.imageset/dark@2x.png
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/light.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "light.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "light@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/light.imageset/light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/light.imageset/light.png
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/light.imageset/light@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Assets.xcassets/light.imageset/light@2x.png
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // DSFDockTile Plugin Demo
4 | //
5 | // Created by Darren Ford on 19/7/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 |
12 | @Environment(\.colorScheme) var scheme
13 |
14 | var body: some View {
15 | VStack(spacing: 16) {
16 | LightDarkImage()
17 | .frame(width: 196, height: 196)
18 |
19 | Text("NSDockTile Plugin Demo").font(.title)
20 | .frame(alignment: .center)
21 |
22 | VStack(alignment: .leading) {
23 | Text("This demo uses a NSDockTile plugin to display its dock content")
24 | Text("Change the appearance to/from dark mode to see the dock icon change")
25 | Text("Note this change occurs even if the app isn't running (but it has been added to the dock)")
26 | }
27 | }
28 | .padding()
29 | .frame(maxWidth: .infinity, maxHeight: .infinity)
30 | }
31 | }
32 |
33 | struct ContentView_Previews: PreviewProvider {
34 | static var previews: some View {
35 | ContentView()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/DSFDockTile_Plugin_DemoApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile_Plugin_DemoApp.swift
3 | // DSFDockTile Plugin Demo
4 | //
5 | // Created by Darren Ford on 19/7/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct DSFDockTile_Plugin_DemoApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | .onReceive(NotificationCenter.default.publisher(for: NSApplication.willUpdateNotification), perform: { _ in
16 | hideZoomButton()
17 | })
18 | .navigationTitle("NSDockTilePlugin Demo")
19 | }
20 | }
21 |
22 |
23 | func hideZoomButton() {
24 | if let window = NSApplication.shared.windows.filter({ $0.title == "NSDockTilePlugin Demo" }).first {
25 | window.standardWindowButton(NSWindow.ButtonType.zoomButton)!.isHidden = true
26 | window.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)!.isHidden = true
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/LightDarkImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightDarkImage.swift
3 | // DSFDockTile Plugin Demo
4 | //
5 | // Created by Darren Ford on 19/7/21.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct LightDarkImage: View {
11 | @Environment(\.colorScheme) var scheme
12 | var body: some View {
13 | Group {
14 | if scheme == .light {
15 | Image("light").resizable()
16 | }
17 | else {
18 | Image("dark").resizable()
19 | }
20 | }
21 | .padding(0)
22 | }
23 | }
24 |
25 | struct LightDarkImage_Previews: PreviewProvider {
26 | static var previews: some View {
27 | HStack {
28 | LightDarkImage()//.previewLayout(.fixed(width: 196, height: 196))
29 | .environment(\.colorScheme, .light)
30 | LightDarkImage()//.previewLayout(.fixed(width: 196, height: 196))
31 | .environment(\.colorScheme, .dark)
32 | }
33 | .frame(width: 196 * 2, height: 196)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin Demo/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin/DockTilePlugin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DockTilePlugin.swift
3 | // DockTilePluginTest
4 | //
5 | // Created by Darren Ford on 25/3/21.
6 | //
7 |
8 | import AppKit
9 | import Combine
10 | import os
11 |
12 | import DSFDockTile
13 |
14 | class DockTilePlugin: NSObject, NSDockTilePlugIn {
15 |
16 | // MARK: - Bundle loading
17 |
18 | private static func LoadImage(named name: String) -> NSImage {
19 | let bundle = Bundle(for: DockTilePlugin.self)
20 | let path = bundle.path(forResource: name, ofType: "png")!
21 | return NSImage(byReferencingFile: path)!
22 | }
23 |
24 | // MARK: - Images
25 |
26 | private lazy var lightImage: NSImage = {
27 | return Self.LoadImage(named: "light")
28 | }()
29 |
30 | private lazy var darkImage: NSImage = {
31 | return Self.LoadImage(named: "dark")
32 | }()
33 |
34 | // MARK: - Dock icon
35 | private var appIcon: DSFDockTile.Image? = nil
36 |
37 | weak var dockTile: NSDockTile? = nil {
38 | didSet {
39 | if let d = self.dockTile {
40 | appIcon = DSFDockTile.Image(dockTile: d)
41 | }
42 | else {
43 | appIcon = nil
44 | }
45 | }
46 | }
47 |
48 | // MARK: - Combine
49 |
50 | // publisher cancellable for theme changes
51 | private var cancellable: AnyCancellable? = nil
52 |
53 | // MARK: - Plugin callbacks
54 |
55 | /// Invoked when the plug-in is first loaded and when the application is removed from the Dock.
56 | func setDockTile(_ dockTile: NSDockTile?) {
57 | guard let dockTile = dockTile else { return }
58 | self.dockTile = dockTile
59 |
60 | self.updateDockTile()
61 |
62 | self.cancellable = NSApp.publisher(for: \.effectiveAppearance)
63 | .removeDuplicates()
64 | .sink { [weak self] appearance in
65 | self?.updateDockTile(appearance: appearance)
66 | }
67 | }
68 | }
69 |
70 | extension DockTilePlugin {
71 | private func updateDockTile(appearance: NSAppearance = NSApp.effectiveAppearance) {
72 | let isLight = appearance.bestMatch(from: [.aqua, .darkAqua]) == .aqua
73 | if isLight {
74 | appIcon?.display(self.lightImage)
75 | }
76 | else {
77 | appIcon?.display(self.darkImage)
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin/resources/dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin/resources/dark.png
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin/resources/light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/DSFDockTile Plugin Demo/DSFDockTile Plugin/resources/light.png
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTile-Plugin-Demo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleInfoDictionaryVersion
6 | 6.0
7 | NSDockTilePlugIn
8 | DSFDockTilePlugin.plugin
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demos/DSFDockTile Plugin Demo/DSFDockTilePlugin-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleInfoDictionaryVersion
6 | 6.0
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/apple-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "iu.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/apple-icon.imageset/iu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/SwiftUI docktile demo/Assets.xcassets/apple-icon.imageset/iu.png
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/marble.dataset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "data" : [
3 | {
4 | "filename" : "marble.gif",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Assets.xcassets/marble.dataset/marble.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagronf/DSFDockTile/74fe5412bf42d9bfd461598178fe2902b32edf99/Demos/SwiftUI docktile demo/Assets.xcassets/marble.dataset/marble.gif
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // SwiftUI docktile demo
4 | //
5 | // Created by Darren Ford on 22/3/2022.
6 | //
7 |
8 | import SwiftUI
9 | import Combine
10 | import DSFDockTile
11 |
12 |
13 | struct ContentView: View {
14 |
15 | @Binding var isAnimating: Bool
16 |
17 | var body: some View {
18 | VStack(alignment: .leading, spacing: 8) {
19 | Text("Example SwiftUI DockTile View demo.").font(.title)
20 | Text("Try minimising this window to see a window docktile updating.")
21 | Toggle("Animate window dock tile", isOn: $isAnimating)
22 | }
23 | .padding()
24 | }
25 | }
26 |
27 | struct ContentView_Previews: PreviewProvider {
28 | static var previews: some View {
29 | ContentView(isAnimating: .constant(false))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/DockTileContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DockTileContentView.swift
3 | // SwiftUI docktile demo
4 | //
5 | // Created by Darren Ford on 22/3/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | // The content to display in the dock tile
11 | struct DockTileContentView: View {
12 | let percent: Int
13 | var body: some View {
14 | ZStack {
15 | Image("apple-icon")
16 | .resizable()
17 | .scaledToFit()
18 | VStack {
19 | Spacer()
20 | Text("\(percent)%")
21 | .foregroundColor(.white).bold()
22 | .font(Font.system(size: 30))
23 | .shadow(color: .black, radius: 1, x: 1, y: -2)
24 | .frame(maxWidth: .infinity)
25 | .background {
26 | RoundedRectangle(cornerRadius: 16)
27 | .fill(Color.blue.opacity(0.6))
28 | }
29 | .padding(4)
30 | }
31 | }
32 | }
33 | }
34 |
35 | struct DockTileContentView_Previews: PreviewProvider {
36 | static var previews: some View {
37 | DockTileContentView(percent: 12)
38 | .frame(width: 128, height: 128)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/SwiftUI_docktile_demo.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demos/SwiftUI docktile demo/SwiftUI_docktile_demoApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUI_docktile_demoApp.swift
3 | // SwiftUI docktile demo
4 | //
5 | // Created by Darren Ford on 22/3/2022.
6 | //
7 |
8 | import DSFDockTile
9 | import SwiftUI
10 |
11 | let animatedDockTile: DSFDockTile.Animated = {
12 | let da = NSDataAsset(name: NSDataAsset.Name("marble"))!.data
13 | return DSFDockTile.Animated(animatedImageData: da)!
14 | }()
15 |
16 | @main
17 | struct SwiftUI_docktile_demoApp: App {
18 | let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
19 | @State var count = 0
20 |
21 | @State var animating: Bool = false
22 |
23 | var body: some Scene {
24 | WindowGroup {
25 | VStack {
26 | ContentView(isAnimating: $animating)
27 | .onReceive(timer) { input in
28 | count += 1
29 | }
30 | // The docktile for the application
31 | DockTile(
32 | label: "\(count)",
33 | content: DockTileContentView(percent: count % 100)
34 | )
35 |
36 | // The docktile for the _window_ containing this view
37 | DockTile(
38 | .window,
39 | animation: animatedDockTile,
40 | isAnimating: animating)
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Darren Ford
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 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "DSFImageFlipbook",
6 | "repositoryURL": "https://github.com/dagronf/DSFImageFlipbook",
7 | "state": {
8 | "branch": null,
9 | "revision": "8b6e1e7f862c1d39ce34c59705f9fa731d9fd539",
10 | "version": "1.0.1"
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.4
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "DSFDockTile",
7 | platforms: [
8 | .macOS(.v10_13),
9 | ],
10 | products: [
11 | .library(
12 | name: "DSFDockTile",
13 | targets: ["DSFDockTile"]),
14 | ],
15 | dependencies: [
16 | .package(name: "DSFImageFlipbook", url: "https://github.com/dagronf/DSFImageFlipbook", from: Version(1, 0, 0))
17 | ],
18 | targets: [
19 | .target(
20 | name: "DSFDockTile",
21 | dependencies: ["DSFImageFlipbook"],
22 | resources: [
23 | .copy("PrivacyInfo.xcprivacy"),
24 | ]
25 | ),
26 | .testTarget(
27 | name: "DSFDockTileTests",
28 | dependencies: ["DSFDockTile"]),
29 | ]
30 | )
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DSFDockTile
2 |
3 | Easily display images, animations, badges and alerts to your macOS application's dock icon.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 
16 |
17 | ## Why?
18 |
19 | I was inspired by [Neil Sardesai](https://twitter.com/neilsardesai) after he posted [this on Twitter](https://twitter.com/neilsardesai/status/1362179114204073984?s=20). And this marvellous follow-up tweet by [Norbert M. Doerner](https://twitter.com/cdfinder/status/1365201157854015488?s=20).
20 |
21 | While the NSDockTile API isn't overly complex, I wanted something that made it easy to change the dock image, and even add basic animations from GIF images etc.
22 |
23 | ## Features
24 |
25 | * Set the badge label
26 | * Display an image
27 | * Display an animated image
28 | * Display the content of an NSView
29 | * Bounce the docktile
30 |
31 | By default a `DSFDockTile` instance operates on the Application's docktile. You can provide your own `NSDockTile` for any window (by calling `window.dockTile`) via the `init` functions on the badge generators.
32 |
33 | ## DockTile plugins
34 |
35 | Did you know that your application can show a custom DockTile image even when it's not running? Apple provides an `NSDockTilePlugin` prodocol that allows you to do exactly that. Want to provide different application icons for dark and light modes? `NSDockTilePlugin` allows you to! Want to tweak the dock icon when your application isn't running, but needs attention? `NSDockTilePlugin`!
36 |
37 | There is a demo application in the `Demos` folder called **'DSFDockTile Plugin Demo'** (macOS 11+) that demonstrates using `NSDockTilePlugin` and `DSFDockIcon` in SwiftUI.
38 |
39 | ## Integration
40 |
41 | ### Swift package manager
42 |
43 | Add `https://github.com/dagronf/DSFDockTile` to your project.
44 |
45 | If you don't want to include the `DSFImageFlipbook` package, copy all the files in the `Sources/` folder **EXCEPT** for `DSFDockTile+Animation.swift`.
46 |
47 | ### Demo
48 |
49 | There is a demo macOS application available in the `Demos` subfolder.
50 |
51 | ## Badge Label
52 |
53 | It's very easy to add a badge label to a docktile.
54 |
55 | ```swift
56 | // Set the label on the docktile to 1234
57 | DSFDockTile.badgeLabel = "1234"
58 |
59 | // Remove the badge label from the docktile
60 | DSFDockTile.badgeLabel = nil
61 | ```
62 |
63 | ## DockTile Generators
64 |
65 | ### AppIcon
66 |
67 | Set the docktile to the application's icon.
68 |
69 | ```swift
70 | // Set the dock icon to the application icon
71 | DSFDockTile.AppIcon.display()
72 | ```
73 |
74 | ### Constant Image
75 |
76 | This is a `DSFDockTile` object that displays a single image. Useful for if you have a set of images to display in the docktile that do not change and you want to the constantness.
77 |
78 | ```swift
79 | static let LockedImage = NSImage(named: NSImage.Name("padlock-locked"))!
80 | static let UnlockedImage = NSImage(named: NSImage.Name("padlock-unlocked"))!
81 |
82 | let LockedDockTileImage = DSFDockTile.ConstantImage(LockedImage)
83 | let UnlockedDockTileImage = DSFDockTile.ConstantImage(UnlockedImage)
84 | ...
85 |
86 | if application.isEditable {
87 | UnlockedDockTileImage.display()
88 | }
89 | else {
90 | LockedDockTileImage.display()
91 | }
92 | ```
93 |
94 | ### Image
95 |
96 | This is a `DSFDockTile` object that can display images.
97 |
98 | ```swift
99 | static let LockedImage = NSImage(named: NSImage.Name("padlock-locked"))!
100 | static let UnlockedImage = NSImage(named: NSImage.Name("padlock-unlocked"))!
101 |
102 | let stateDockTile = DSFDockTile.Image()
103 |
104 | ...
105 |
106 | func viewDidLoad() {
107 | let image = application.isEditable ? UnlockedImage : LockedImage
108 | stateDockTile.display(image)
109 | }
110 | ```
111 |
112 | ### View
113 |
114 | This is a `DSFDockTile` object that can display the content of a view managed by a view controller
115 |
116 | Due to NSDockTile restrictions, the view is not drawn live into the dock as the view is updated. You must call `display()` to update the dock tile with the view's current content whenever a change occurs in the view.
117 |
118 | ```swift
119 | /// The view controller to display on the docktile
120 | let dockViewController = DockViewController()
121 |
122 | /// The docktile instance handling the docktile
123 | lazy var updateDockTile: DSFDockTile.View = {
124 | dockViewController.loadView()
125 | return DSFDockTile.View(dockViewController)
126 | }()
127 | ...
128 | func doUpdate() {
129 | // Change the color of the item in the
130 | self.dockViewController.foregroundColor = .systemYellow
131 |
132 | // NSDockTile does not update automatically so need to tell it when changes are made
133 | self.updateDockTile.display()
134 | }
135 | ```
136 |
137 | ### Animation
138 |
139 | This is a docktile that can display an animation. It uses `DSFImageFlipbook` under the seams to handle the animation itself.
140 |
141 | ```swift
142 | let animatedDockTile: DSFDockTile.Animated = {
143 | let fb = DSFImageFlipbook()
144 | let da = NSDataAsset(name: NSDataAsset.Name("animated-gif"))!
145 | _ = fb.loadFrames(from: da.data)
146 | return DSFDockTile.Animated(fb)
147 | }()
148 |
149 | ...
150 |
151 | @IBAction func startAnimating(_ sender: Any) {
152 | animatedDockTile.startAnimating()
153 | }
154 |
155 | @IBAction func stopAnimating(_ sender: Any) {
156 | animatedDockTile.stopAnimating()
157 | }
158 | ```
159 |
160 | ## SwiftUI
161 |
162 | The `DockTile` view is used to manipulate the docktile for
163 |
164 | * The application (`.application`)
165 | * The window containing the `DockTile` View (`.window`)
166 |
167 | You can set which docktile you want to update in the initializer of the `DockTile` View
168 |
169 | ### Updating the badge
170 |
171 | To set a badge using SwiftUI, use the `DockTile` view and provide a label for the badge
172 |
173 | ```swift
174 | @State var badgeLabel: String = ""
175 | var body: some Scene {
176 | WindowGroup {
177 | ZStack {
178 | ContentView()
179 | DockTile(label: badgeLabel)
180 | }
181 | }
182 | }
183 | ```
184 |
185 | ### Updating the content
186 |
187 | To set the content of a dock tile, provide a view to the initializer. Set to `nil` to return the docktile to its default.
188 |
189 | ```swift
190 | @State var dockText: String = ""
191 | var body: some Scene {
192 | WindowGroup {
193 | ZStack {
194 | ContentView()
195 | DockTile(
196 | .window,
197 | label: "3",
198 | content: ZStack {
199 | Color.white
200 | Text(dockText)
201 | }
202 | )
203 | }
204 | }
205 | }
206 | ```
207 |
208 | Remember that the DockTile API does not provide live docktile updating, and will require you to update the view for each
209 | visual change you want to make
210 |
211 | ## Attention Concepts
212 |
213 | You can request user information via the DockTile of an application if your application is not the front-most application.
214 |
215 | See [Apple's Documentation](https://developer.apple.com/documentation/appkit/nsapplication/1428358-requestuserattention) for more details.
216 |
217 | ### requestInformationalAttention()
218 |
219 | Request that the docktile 'bounce' to inform the user of something informational. The function returns an object which you can use to cancel the attention request.
220 |
221 | ```swift
222 | let cancellable = DSFDockTile.requestInformationalAttention()
223 | ```
224 |
225 | The `cancellable` can be used to cancel the information request.
226 |
227 | See [Apple's Documentation](https://developer.apple.com/documentation/appkit/nsapplication/requestuserattentiontype/criticalrequest)
228 |
229 | ### requestCriticalAttention()
230 |
231 | Request that the docktile 'bounce' to inform the user of something informational. The function returns an object which you can use to cancel the attention request.
232 |
233 | ```swift
234 | let cancellable = DSFDockTile.requestCriticalAttention()
235 | ```
236 |
237 | The `cancellable` can be used to cancel the critical request.
238 |
239 | See [Apple's Documentation](https://developer.apple.com/documentation/appkit/nsapplication/requestuserattentiontype/informationalrequest)
240 |
241 | ### Cancellation protocol (DSFDockTileUserAttentionCancellation)
242 |
243 | The user attention methods return an object that conforms to `DSFDockTileUserAttentionCancellation` that can be used to cancel an attention request.
244 |
245 | See [Apple's Documentation](https://developer.apple.com/documentation/appkit/nsapplication/1428683-canceluserattentionrequest)
246 |
247 | ## Thanks
248 |
249 | * [Neil Sardesai](https://twitter.com/neilsardesai)
250 | * [Norbert M. Doerner](https://twitter.com/cdfinder)
251 | * The images (light/dark) in the demo application are thanks to [brgfx on freepix](https://www.freepik.com/free-vector/opposite-adjectives-light-dark_1172843.htm)
252 | * Attribution - Background vector created by brgfx - www.freepik.com
253 |
254 | * Here is the project I used to understand how to use `NSDockTilePlugin` for my own project. [https://github.com/rrroyal/AutomaticDockTile](https://github.com/rrroyal/AutomaticDockTile)
255 |
256 | ## License
257 |
258 | MIT. Use it and abuse it for anything you want, just attribute my work. Let me know if you do use it somewhere, I'd love to hear about it!
259 |
260 | ```
261 | MIT License
262 |
263 | Copyright (c) 2022 Darren Ford
264 |
265 | Permission is hereby granted, free of charge, to any person obtaining a copy
266 | of this software and associated documentation files (the "Software"), to deal
267 | in the Software without restriction, including without limitation the rights
268 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
269 | copies of the Software, and to permit persons to whom the Software is
270 | furnished to do so, subject to the following conditions:
271 |
272 | The above copyright notice and this permission notice shall be included in all
273 | copies or substantial portions of the Software.
274 |
275 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
276 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
277 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
278 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
279 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
280 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
281 | SOFTWARE.
282 | ```
283 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+Animation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile+Animation.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 | import DSFImageFlipbook
30 |
31 | extension DSFDockTile {
32 |
33 | /// A docktile object that handles an animation
34 | public class Animated: Image {
35 |
36 | /// The flipbook used to handle the animation
37 | public let flipbook: DSFImageFlipbook
38 |
39 | // Flipbook animation settings
40 | fileprivate var stopAtEndOfCurrentLoop: Bool = false
41 |
42 | /// Is the animation currently playing?
43 | @inlinable public var isAnimating: Bool {
44 | return flipbook.isAnimating()
45 | }
46 |
47 | /// Create a DockTile object presenting an animation
48 | /// - Parameters:
49 | /// - flipbook: The flipbook containing the image to present
50 | /// - dockTile: The docktile to update
51 | public init(_ flipbook: DSFImageFlipbook,
52 | dockTile: NSDockTile? = NSApp?.dockTile) {
53 | self.flipbook = flipbook
54 | super.init(dockTile: dockTile)
55 | }
56 |
57 | /// Create a DockTile object presenting an animation from the raw data
58 | /// - Parameters:
59 | /// - flipbook: The image data for the animation (eg. a gif file)
60 | /// - dockTile: The docktile to update
61 | public init?(
62 | animatedImageData: Data,
63 | dockTile: NSDockTile? = NSApp?.dockTile)
64 | {
65 | let fb = DSFImageFlipbook()
66 | _ = fb.loadFrames(from: animatedImageData)
67 | guard fb.frameCount > 0 else {
68 | return nil
69 | }
70 | self.flipbook = fb
71 | super.init(dockTile: dockTile)
72 | }
73 |
74 | /// Display the first frame of the animation
75 | public override func display() {
76 | if let image = flipbook.frame(at: 0)?.image {
77 | self.display(image)
78 | }
79 | }
80 |
81 | /// Start the flipbook animation on the docktile
82 | /// - Parameter frame: The frame in the flipbook to start animating at
83 | /// - Parameter speed: The speed to animate the dock tile
84 | public func startAnimating(atFrame frame: Int = 0, speed: Double = 1) {
85 | self.stopAtEndOfCurrentLoop = false
86 | flipbook.start(
87 | startAtFrame: frame,
88 | speed: speed) { [weak self] frame, currentFrame, count, stop in
89 |
90 | guard let `self` = self else { return }
91 |
92 | self.display(frame.image)
93 |
94 | if self.stopAtEndOfCurrentLoop, currentFrame == (count - 1) {
95 | stop = true
96 | }
97 | }
98 | }
99 |
100 | /// Stop the current docktile animation
101 | /// - Parameter stopAtEndOfCurrentLoop: If true, stops the animation at the end of the current animation loop
102 | public func stopAnimating(stopAtEndOfCurrentLoop: Bool = false) {
103 | if flipbook.isAnimating() == false ||
104 | self.stopAtEndOfCurrentLoop
105 | {
106 | return
107 | }
108 |
109 | self.stopAtEndOfCurrentLoop = stopAtEndOfCurrentLoop
110 |
111 | if stopAtEndOfCurrentLoop == false {
112 | flipbook.stop(reason: .userStopped)
113 | }
114 | }
115 |
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+Attention.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile+Attention.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 |
30 | /// Protocol for cancelling a user attention request
31 | public protocol DSFDockTileUserAttentionCancellation {
32 | /// Cancels a previous user attention request.
33 | func cancel()
34 | }
35 |
36 | public extension DSFDockTile {
37 | /// User attention cancellation object
38 | struct UserAttention: DSFDockTileUserAttentionCancellation {
39 | public let identifier: Int
40 | @inlinable internal init(_ identifier: Int) {
41 | self.identifier = identifier
42 | }
43 |
44 | /// Cancels a previous user attention request.
45 | @inlinable public func cancel() {
46 | NSApp.cancelUserAttentionRequest(self.identifier)
47 | }
48 | }
49 |
50 | /// Starts a critical attention request
51 | /// - Returns: A cancel object
52 | ///
53 | /// A request is canceled automatically by user activation of the app.
54 | ///
55 | /// See:- [https://developer.apple.com/documentation/appkit/nsapplication/requestuserattentiontype/criticalrequest](https://developer.apple.com/documentation/appkit/nsapplication/requestuserattentiontype/criticalrequest)
56 | @discardableResult
57 | @inlinable static func requestCriticalAttention() -> DSFDockTileUserAttentionCancellation {
58 | return UserAttention(NSApp.requestUserAttention(.criticalRequest))
59 | }
60 |
61 | /// Starts an informational attention request
62 | /// - Returns: A cancel object
63 | ///
64 | /// See:- [https://developer.apple.com/documentation/appkit/nsapplication/requestuserattentiontype/informationalrequest](https://developer.apple.com/documentation/appkit/nsapplication/requestuserattentiontype/informationalrequest)
65 | @discardableResult
66 | @inlinable static func requestInformationalAttention() -> DSFDockTileUserAttentionCancellation {
67 | return UserAttention(NSApp.requestUserAttention(.informationalRequest))
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+ConstantImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile+ConstantImage.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 |
30 | extension DSFDockTile {
31 |
32 | /// A docktile object which displays a constant image
33 | public class ConstantImage: Core {
34 |
35 | // Image settings
36 | private let image: NSImage
37 |
38 | // A lazy imageview to use when displaying images
39 | private let _imageDisplayView: NSImageView = {
40 | let v = NSImageView()
41 | v.wantsLayer = true
42 | v.imageScaling = .scaleProportionallyUpOrDown
43 | return v
44 | }()
45 |
46 | /// Create an instance which displays an image as a docktile
47 | /// - Parameters:
48 | /// - image: The image to initially display when creating this instance
49 | /// - dockTile: The docktile to update. By default, updates the application docktile.
50 | public init(_ image: NSImage, dockTile: NSDockTile = NSApp.dockTile) {
51 | self.image = image
52 | super.init(dockTile: dockTile)
53 |
54 | // Set the image
55 | self._imageDisplayView.image = image
56 | }
57 |
58 | // Present the stored image
59 | public func display() {
60 | precondition(Thread.isMainThread)
61 |
62 | guard let tile = self.dockTile else {
63 | return
64 | }
65 |
66 | let imageView = self._imageDisplayView
67 |
68 | // If we aren't already being displayed, then make sure to update the content view
69 | if tile.contentView !== imageView {
70 | tile.contentView = imageView
71 | }
72 |
73 | // And update the docktile display
74 | tile.display()
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+Core.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile+Core.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 |
30 | extension DSFDockTile {
31 |
32 | /// Base type for a docktile. Can only be inherited from
33 | public class Core {
34 | // The docktile to update. By default, this is the App Icon
35 | public weak var dockTile: NSDockTile?
36 |
37 | /// Set the docktile badge label
38 | public var badgeLabel: String? {
39 | didSet {
40 | self.dockTile?.badgeLabel = self.badgeLabel
41 | }
42 | }
43 |
44 | internal init(dockTile: NSDockTile? = NSApp?.dockTile) {
45 | self.dockTile = dockTile
46 | }
47 | }
48 | }
49 |
50 | extension DSFDockTile {
51 | /// A docktile object that displays the default docktile content.
52 | public class AppIconType: Core {
53 |
54 | public override init(dockTile: NSDockTile? = NSApp?.dockTile) {
55 | super.init(dockTile: dockTile)
56 | }
57 |
58 | public func display() {
59 | if let tile = self.dockTile {
60 | tile.contentView = nil
61 | tile.display()
62 | }
63 | }
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+Image.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile+Image.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 |
30 | extension DSFDockTile {
31 |
32 | /// A docktile with an updatable image
33 | public class Image: Core {
34 |
35 | var image: NSImage?
36 |
37 | // A lazy imageview to use when displaying images
38 | private let _imageDisplayView: NSImageView = {
39 | let v = NSImageView()
40 | v.wantsLayer = true
41 | v.imageScaling = .scaleProportionallyUpOrDown
42 | return v
43 | }()
44 |
45 | /// Create an instance which displays an updatable image as a docktile
46 | /// - Parameters:
47 | /// - image: (optional) The image to initially display when creating this instance
48 | /// - dockTile: The docktile to update. By default, updates the application docktile.
49 | public init(_ image: NSImage? = nil, dockTile: NSDockTile? = NSApp?.dockTile) {
50 | self.image = image
51 | super.init(dockTile: dockTile)
52 | if let image = image {
53 | self.display(image)
54 | }
55 | }
56 |
57 | /// Set image as docktile
58 | /// - Parameter cgImage: The image to display in the docktile
59 | public func display(_ cgImage: CGImage) {
60 | let i = NSImage(cgImage: cgImage, size: .zero)
61 | self.image = i
62 | self.display(i)
63 | }
64 |
65 | public func display() {
66 | if let i = self.image {
67 | self.display(i)
68 | }
69 | }
70 |
71 | /// Set image as docktile
72 | /// - Parameter nsImage: The image to display in the docktile
73 | public func display(_ nsImage: NSImage) {
74 | self.image = nsImage
75 | precondition(Thread.isMainThread)
76 |
77 | guard let tile = self.dockTile else {
78 | return
79 | }
80 |
81 | let imageView = self._imageDisplayView
82 |
83 | // Update the image view with the new image
84 | imageView.image = nsImage
85 |
86 | // If we aren't already being displayed, then make sure to update the content view
87 | if tile.contentView !== imageView {
88 | tile.contentView = imageView
89 | }
90 |
91 | // And update the docktile display
92 | tile.display()
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+SwiftUI.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIView.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 22/3/2022.
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | #if canImport(SwiftUI)
29 |
30 | import SwiftUI
31 |
32 | /// The doctile to modify
33 | public enum DockTileLocation {
34 | /// The application's docktile
35 | case application
36 | /// The docktile for the window containing the `DockTile` view
37 | case window
38 | }
39 |
40 | /// A SwiftUI view for setting the content of a dock tile.
41 | ///
42 | /// To set the content of the dock tile, use the `DockView` view and provide the view content/label to the initializer.
43 | /// You can set the docktile content from anywhere in your code, but it would be prudent to centralise access to a single location.
44 | ///
45 | /// ```swift
46 | /// @State var dockText: String = ""
47 | /// var body: some Scene {
48 | /// WindowGroup {
49 | /// ZStack {
50 | /// ContentView()
51 | /// DockTile(
52 | /// .window,
53 | /// label: "3",
54 | /// content: ZStack {
55 | /// Color.white
56 | /// Text(dockText)
57 | /// }
58 | /// )
59 | /// }
60 | /// }
61 | /// }
62 | /// ```
63 | @available(macOS 10.15, *)
64 | public struct DockTile: NSViewRepresentable {
65 | private let location: DockTileLocation
66 | private let label: String
67 | private let content: AnyView?
68 | private let animation: DSFDockTile.Animated?
69 | private let isAnimating: Bool
70 |
71 | /// Create a docktile container
72 | /// - Parameters:
73 | /// - location: Which docktile to update (.application for the application docktile, .window for the docktile for the window containing the View)
74 | /// - label: The label to apply to the docktile
75 | public init(_ location: DockTileLocation = .application, label: String) {
76 | self.content = nil
77 | self.location = location
78 | self.label = label
79 | self.animation = nil
80 | self.isAnimating = false
81 | }
82 |
83 | /// Create a docktile container
84 | /// - Parameters:
85 | /// - location: Which docktile to update (.application for the application docktile, .window for the docktile for the window containing the View)
86 | /// - label: The label to apply to the docktile
87 | /// - content: The content View to display in the docktile, or nil to restore the default doctile view
88 | public init(_ which: DockTileLocation = .application, label: String = "", content: ViewContentType?) {
89 | self.content = AnyView(content)
90 | self.location = which
91 | self.label = label
92 | self.animation = nil
93 | self.isAnimating = false
94 | }
95 |
96 | public func makeNSView(context: Context) -> NSView {
97 | let c = NSView()
98 | c.translatesAutoresizingMaskIntoConstraints = false
99 | c.widthAnchor.constraint(equalToConstant: 0).isActive = true
100 | c.heightAnchor.constraint(equalToConstant: 0).isActive = true
101 | return c
102 | }
103 |
104 | public func updateNSView(_ nsView: NSView, context: Context) {
105 | let which = (location == .window) ? nsView.window?.dockTile : NSApp?.dockTile
106 |
107 | if let which = which {
108 | if let animation = animation {
109 | animation.dockTile = which
110 | if self.isAnimating {
111 | if animation.isAnimating == false {
112 | animation.startAnimating()
113 | }
114 | }
115 | else {
116 | animation.stopAnimating(stopAtEndOfCurrentLoop: true)
117 | }
118 | }
119 | else if let content = content {
120 | let dockViewController = NSHostingController(rootView: content)
121 | let dt = DSFDockTile.View(dockViewController, dockTile: which)
122 | dt.display()
123 | }
124 | else {
125 | which.contentView = nil
126 | }
127 | }
128 |
129 | which?.badgeLabel = self.label
130 | }
131 |
132 | public typealias NSViewType = NSView
133 | }
134 |
135 | // MARK: - Animation handling
136 |
137 | @available(macOS 10.15, *)
138 | extension DockTile {
139 | public init(
140 | _ location: DockTileLocation = .application,
141 | label: String = "",
142 | animation: DSFDockTile.Animated,
143 | isAnimating: Bool
144 | ) {
145 | self.animation = animation
146 | self.label = label
147 | self.content = nil
148 | self.location = location
149 | self.isAnimating = isAnimating
150 | }
151 | }
152 |
153 | #endif
154 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile+ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile+ViewController.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 |
30 | extension DSFDockTile {
31 |
32 | /// Display the content of a view as a dock tile
33 | public class View: Core {
34 |
35 | /// The view controller
36 | internal weak var viewController: NSViewController?
37 |
38 | /// Create an instance which uses a view as the content of a docktile
39 | /// - Parameters:
40 | /// - viewController: The viewController handling the view being displayed in the dock tile. This parameter is weakly held by this object, so it's important to make sure you hold onto this view controller outside the instance
41 | /// - dockTile: The docktile to update. By default, updates the application docktile.
42 | public init(_ viewController: NSViewController, dockTile: NSDockTile = NSApp.dockTile) {
43 | self.viewController = viewController
44 | super.init(dockTile: dockTile)
45 | }
46 |
47 | // Set view as docktile
48 | public func display() {
49 | precondition(Thread.isMainThread)
50 |
51 | guard let tile = self.dockTile,
52 | let vc = self.viewController else {
53 | return
54 | }
55 |
56 | // Make sure the docktile is showing our view
57 | if tile.contentView !== vc.view {
58 | tile.contentView = vc.view
59 | }
60 |
61 | // And update the docktile display
62 | tile.display()
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/DSFDockTile.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DSFDockTile.swift
3 | // DSFDockTile
4 | //
5 | // Created by Darren Ford on 17/7/21
6 | //
7 | // MIT License
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in all
17 | // copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | // SOFTWARE.
26 | //
27 |
28 | import AppKit
29 |
30 | public class DSFDockTile {
31 | /// A docktile that represents the current application's icon
32 | public static let AppIcon = DSFDockTile.AppIconType()
33 |
34 | /// Set the badge label to be displayed on the application's docktile
35 | public static var badgeLabel: String? {
36 | get {
37 | NSApp.dockTile.badgeLabel
38 | }
39 | set {
40 | NSApp.dockTile.badgeLabel = newValue
41 | }
42 | }
43 |
44 | /// Set the badge label to be displayed on a provided docktile
45 | @inlinable public static func setBadgeLabel(_ label: String?, dockTile: NSDockTile? = NSApp.dockTile) {
46 | dockTile?.badgeLabel = label
47 | }
48 |
49 | func reset() {
50 | NSApp.dockTile.contentView = nil
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/DSFDockTile/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyAccessedAPITypes
6 |
7 | NSPrivacyCollectedDataTypes
8 |
9 | NSPrivacyTracking
10 |
11 | NSPrivacyTrackingDomains
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Tests/DSFDockTileTests/DSFDockTileTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import DSFDockTile
3 |
4 | final class DSFDockTileTests: XCTestCase {
5 | // func testExample() throws {
6 | // // This is an example of a functional test case.
7 | // // Use XCTAssert and related functions to verify your tests produce the correct
8 | // // results.
9 | // XCTAssertEqual(DSFDockTile().text, "Hello, World!")
10 | // }
11 | }
12 |
--------------------------------------------------------------------------------