1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-08 04:20:07 +02:00

New notice alert API

This commit is contained in:
2022-02-16 22:42:43 +01:00
parent bc0b50f5bf
commit 50f003a2bd
6 changed files with 245 additions and 37 deletions

View File

@ -28,6 +28,10 @@
C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */; }; C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */; };
C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; }; C4068CAA27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; };
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; }; C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */; };
C4080FF627BD8C6400BF2C6B /* Notice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* Notice.swift */; };
C4080FF727BD8C6400BF2C6B /* Notice.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF527BD8C6400BF2C6B /* Notice.swift */; };
C4080FFA27BD956700BF2C6B /* NoticeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* NoticeVC.swift */; };
C4080FFB27BD956700BF2C6B /* NoticeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4080FF927BD956700BF2C6B /* NoticeVC.swift */; };
C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; }; C40B24F127A3106D0018C7D2 /* ServicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E67279DE0540010F296 /* ServicesView.swift */; };
C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; }; C40B24F227A310770018C7D2 /* Events.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4EC1E72279DFCF40010F296 /* Events.swift */; };
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; }; C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; };
@ -215,6 +219,8 @@
C4068CA327B0780A00544CD5 /* CheckboxPreferenceView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CheckboxPreferenceView.xib; sourceTree = "<group>"; }; C4068CA327B0780A00544CD5 /* CheckboxPreferenceView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CheckboxPreferenceView.xib; sourceTree = "<group>"; };
C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectPreferenceView.swift; sourceTree = "<group>"; }; C4068CA627B07A1300544CD5 /* SelectPreferenceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectPreferenceView.swift; sourceTree = "<group>"; };
C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarIcons.swift; sourceTree = "<group>"; }; C4068CA927B0890D00544CD5 /* MenuBarIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarIcons.swift; sourceTree = "<group>"; };
C4080FF527BD8C6400BF2C6B /* Notice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notice.swift; sourceTree = "<group>"; };
C4080FF927BD956700BF2C6B /* NoticeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeVC.swift; sourceTree = "<group>"; };
C40C7F1D2772136000DDDCDC /* PhpEnv.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpEnv.swift; sourceTree = "<group>"; }; C40C7F1D2772136000DDDCDC /* PhpEnv.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpEnv.swift; sourceTree = "<group>"; };
C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActivePhpInstallation+Checks.swift"; sourceTree = "<group>"; }; C40C7F2727721FF600DDDCDC /* ActivePhpInstallation+Checks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActivePhpInstallation+Checks.swift"; sourceTree = "<group>"; };
C40C7F2F27722E8D00DDDCDC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; }; C40C7F2F27722E8D00DDDCDC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
@ -385,6 +391,15 @@
path = IAP; path = IAP;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
C4080FF827BD955900BF2C6B /* Notice */ = {
isa = PBXGroup;
children = (
C4080FF527BD8C6400BF2C6B /* Notice.swift */,
C4080FF927BD956700BF2C6B /* NoticeVC.swift */,
);
path = Notice;
sourceTree = "<group>";
};
C40C7F1C27720E1400DDDCDC /* Test Files */ = { C40C7F1C27720E1400DDDCDC /* Test Files */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -460,6 +475,7 @@
C41E181722CB61EB0072CF09 /* Domain */ = { C41E181722CB61EB0072CF09 /* Domain */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C4080FF827BD955900BF2C6B /* Notice */,
C4AF9F6B275445D300D44ED0 /* Integrations */, C4AF9F6B275445D300D44ED0 /* Integrations */,
C4B13B1D25C4915000548C3A /* App */, C4B13B1D25C4915000548C3A /* App */,
C4D9ADBD27761084007277F4 /* PHP */, C4D9ADBD27761084007277F4 /* PHP */,
@ -829,6 +845,7 @@
5420395926135DC100FB00FA /* PrefsVC.swift in Sources */, 5420395926135DC100FB00FA /* PrefsVC.swift in Sources */,
C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */, C43603A0275E67610028EFC6 /* AppDelegate+Notifications.swift in Sources */,
C4068CA727B07A1300544CD5 /* SelectPreferenceView.swift in Sources */, C4068CA727B07A1300544CD5 /* SelectPreferenceView.swift in Sources */,
C4080FF627BD8C6400BF2C6B /* Notice.swift in Sources */,
C49E171F27A5736E00787921 /* PMServicesView.swift in Sources */, C49E171F27A5736E00787921 /* PMServicesView.swift in Sources */,
C4EE55AD27708B9E001DF387 /* PMStatsView.swift in Sources */, C4EE55AD27708B9E001DF387 /* PMStatsView.swift in Sources */,
C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */, C4C8E818276F54D8003AC782 /* App+ConfigWatch.swift in Sources */,
@ -884,6 +901,7 @@
C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */, C48D0C9625CC80B100CC7490 /* HeaderView.swift in Sources */,
C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */, C4CE3BBA27B31F670086CA49 /* MainMenu+Composer.swift in Sources */,
C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */, C4D9ADC8277611A0007277F4 /* InternalSwitcher.swift in Sources */,
C4080FFA27BD956700BF2C6B /* NoticeVC.swift in Sources */,
C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */, C4B5635E276AB09000F12CCB /* VersionExtractor.swift in Sources */,
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */, C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */,
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */, C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
@ -912,6 +930,7 @@
C4F780C825D80B75000DBC97 /* DateExtension.swift in Sources */, C4F780C825D80B75000DBC97 /* DateExtension.swift in Sources */,
C493084B279F331F009C240B /* AddSiteVC.swift in Sources */, C493084B279F331F009C240B /* AddSiteVC.swift in Sources */,
C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */, C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */,
C4080FFB27BD956700BF2C6B /* NoticeVC.swift in Sources */,
C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */, C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */,
C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */, C4F780B125D80B4D000DBC97 /* PhpExtension.swift in Sources */,
C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */, C4068CA827B07A1300544CD5 /* SelectPreferenceView.swift in Sources */,
@ -947,6 +966,7 @@
C4CE3BBC27B324250086CA49 /* MainMenu+Composer.swift in Sources */, C4CE3BBC27B324250086CA49 /* MainMenu+Composer.swift in Sources */,
C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */, C40B24F427A310830018C7D2 /* StatusMenu.swift in Sources */,
C417DC75277614690015E6EE /* Helpers.swift in Sources */, C417DC75277614690015E6EE /* Helpers.swift in Sources */,
C4080FF727BD8C6400BF2C6B /* Notice.swift in Sources */,
C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */, C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */,
C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */, C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */, C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */,

View File

@ -116,6 +116,8 @@ class Actions {
Detects all currently available PHP versions, Detects all currently available PHP versions,
and unlinks each and every one of them. and unlinks each and every one of them.
This all happens in sequence, nothing runs in parallel.
After this, the brew services are also stopped, After this, the brew services are also stopped,
the latest PHP version is linked, and php + nginx are restarted. the latest PHP version is linked, and php + nginx are restarted.

View File

@ -88,6 +88,25 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
startup procedure. startup procedure.
*/ */
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
/*
let notice = Notice.make()
.withInformation(
title: "Oh no, your PHP is kaput?!",
subtitle: "Unfortunately, PHP Monitor has detected an issue. You can find more info below."
// description: "brew install php@8.0 has returned error code -35"
)
.withPrimary(text: "Retry")
.withSecondary(text: "Quit", action: { _ in
exit(1)
})
.withTertiary(text: "Copy to Clipboard", action: { _ in
// Do something here
})
print(notice.present() == .alertFirstButtonReturn)
*/
// Make sure notifications will work // Make sure notifications will work
setupNotifications() setupNotifications()
// Make sure the menu performs its initial checks // Make sure the menu performs its initial checks

View File

@ -467,10 +467,9 @@
<!--Window Controller--> <!--Window Controller-->
<scene sceneID="BD0-La-ygq"> <scene sceneID="BD0-La-ygq">
<objects> <objects>
<windowController id="nfT-AN-9ZW" sceneMemberID="viewController"> <windowController storyboardIdentifier="noticeWindow" id="nfT-AN-9ZW" sceneMemberID="viewController">
<window key="window" title="Notice" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" titleVisibility="hidden" id="AoF-SN-xB0"> <window key="window" title="Notice" separatorStyle="none" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" titlebarAppearsTransparent="YES" toolbarStyle="unified" titleVisibility="hidden" id="AoF-SN-xB0">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/> <windowStyleMask key="styleMask" titled="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="425" y="462" width="480" height="270"/> <rect key="contentRect" x="425" y="462" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/> <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<view key="contentView" id="Src-7L-4Z4"> <view key="contentView" id="Src-7L-4Z4">
@ -489,24 +488,22 @@
</objects> </objects>
<point key="canvasLocation" x="-575" y="1624"/> <point key="canvasLocation" x="-575" y="1624"/>
</scene> </scene>
<!--View Controller--> <!--NoticeVC-->
<scene sceneID="y9E-bB-wIG"> <scene sceneID="y9E-bB-wIG">
<objects> <objects>
<viewController storyboardIdentifier="noticeVC" id="hkw-9V-NxP" sceneMemberID="viewController"> <viewController storyboardIdentifier="noticeVC" id="hkw-9V-NxP" customClass="NoticeVC" customModule="PHP_Monitor" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="UPH-hV-Naz"> <view key="view" id="UPH-hV-Naz">
<rect key="frame" x="0.0" y="0.0" width="508" height="207"/> <rect key="frame" x="0.0" y="0.0" width="524" height="205"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<box boxType="custom" borderWidth="0.0" title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="6U0-c0-4UL"> <visualEffectView blendingMode="behindWindow" material="appearanceBased" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="JVG-5w-fPd">
<rect key="frame" x="0.0" y="0.0" width="508" height="207"/> <rect key="frame" x="0.0" y="0.0" width="524" height="205"/>
<view key="contentView" id="aM7-ch-j0D"> </visualEffectView>
<rect key="frame" x="0.0" y="0.0" width="508" height="207"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
<color key="fillColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
</box>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TCp-nS-HN2"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="TCp-nS-HN2">
<rect key="frame" x="13" y="13" width="99" height="32"/> <rect key="frame" x="13" y="13" width="99" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="QWZ-BA-0g9"/>
</constraints>
<buttonCell key="cell" type="push" title="Secondary" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="eCk-FC-9Zr"> <buttonCell key="cell" type="push" title="Secondary" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="eCk-FC-9Zr">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -514,9 +511,15 @@
Gw Gw
</string> </string>
</buttonCell> </buttonCell>
<connections>
<action selector="secondaryButtonAction:" target="hkw-9V-NxP" id="YJs-Hu-lFP"/>
</connections>
</button> </button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8zu-cF-KCX"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8zu-cF-KCX">
<rect key="frame" x="414" y="13" width="81" height="32"/> <rect key="frame" x="417" y="13" width="94" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="4Uf-fh-jWJ"/>
</constraints>
<buttonCell key="cell" type="push" title="Primary" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="F26-vf-hFH"> <buttonCell key="cell" type="push" title="Primary" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="F26-vf-hFH">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -524,28 +527,31 @@ Gw
DQ DQ
</string> </string>
</buttonCell> </buttonCell>
<connections>
<action selector="primaryButtonAction:" target="hkw-9V-NxP" id="W7d-3b-pZT"/>
</connections>
</button> </button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="U1c-qS-cIm"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="U1c-qS-cIm">
<rect key="frame" x="86" y="171" width="404" height="16"/> <rect key="frame" x="102" y="151" width="404" height="19"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="400" id="WgB-hj-d4P"/> <constraint firstAttribute="width" relation="lessThanOrEqual" constant="400" id="WgB-hj-d4P"/>
</constraints> </constraints>
<textFieldCell key="cell" lineBreakMode="clipping" title="This is the title of the notice window." id="bzW-MI-jXb"> <textFieldCell key="cell" selectable="YES" title="This is the title of the notice window." id="bzW-MI-jXb">
<font key="font" metaFont="systemBold"/> <font key="font" metaFont="systemBold" size="16"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="yI6-qf-htf"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="yI6-qf-htf">
<rect key="frame" x="86" y="147" width="404" height="16"/> <rect key="frame" x="102" y="127" width="404" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="This is a slightly more expanded explanation." id="rY3-Nd-Iit"> <textFieldCell key="cell" selectable="YES" title="This is a slightly more expanded explanation." id="rY3-Nd-Iit">
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0rX-Ss-3Xd"> <button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0rX-Ss-3Xd">
<rect key="frame" x="12" y="139" width="48" height="48"/> <rect key="frame" x="12" y="137" width="48" height="48"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="Uib-R1-GEx"> <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="Uib-R1-GEx">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -553,16 +559,16 @@ DQ
</buttonCell> </buttonCell>
</button> </button>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QkM-5D-ZEQ"> <imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QkM-5D-ZEQ">
<rect key="frame" x="17" y="136" width="54" height="54"/> <rect key="frame" x="20" y="106" width="64" height="64"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="48" id="VhJ-fI-IKC"/> <constraint firstAttribute="height" constant="64" id="VhJ-fI-IKC"/>
<constraint firstAttribute="width" constant="48" id="a2d-Gn-Oor"/> <constraint firstAttribute="width" constant="64" id="a2d-Gn-Oor"/>
</constraints> </constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" imageFrameStyle="grayBezel" id="7eT-Hw-EL9"/> <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="7eT-Hw-EL9"/>
</imageView> </imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hml-dl-Cah"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hml-dl-Cah">
<rect key="frame" x="86" y="90" width="404" height="42"/> <rect key="frame" x="102" y="70" width="404" height="42"/>
<textFieldCell key="cell" id="7iW-Lc-DqO"> <textFieldCell key="cell" selectable="YES" id="7iW-Lc-DqO">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
<string key="title">Sometimes you need a really long explanation and in that case you can get a really, really long description here, along with, for example, various steps you can take. This allows for a lot of text to be displayed, yay!</string> <string key="title">Sometimes you need a really long explanation and in that case you can get a really, really long description here, along with, for example, various steps you can take. This allows for a lot of text to be displayed, yay!</string>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
@ -570,38 +576,55 @@ DQ
</textFieldCell> </textFieldCell>
</textField> </textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="n5T-nn-k3j"> <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="n5T-nn-k3j">
<rect key="frame" x="110" y="13" width="81" height="32"/> <rect key="frame" x="110" y="13" width="94" height="32"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="JEC-0F-zaa"/>
</constraints>
<buttonCell key="cell" type="push" title="Tertiary" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mzA-Uu-gyf"> <buttonCell key="cell" type="push" title="Tertiary" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mzA-Uu-gyf">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
</buttonCell> </buttonCell>
<connections>
<action selector="tertiaryButtonAction:" target="hkw-9V-NxP" id="o1C-av-ifx"/>
</connections>
</button> </button>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="hml-dl-Cah" firstAttribute="leading" secondItem="yI6-qf-htf" secondAttribute="leading" id="1Lh-ve-rwK"/> <constraint firstItem="hml-dl-Cah" firstAttribute="leading" secondItem="yI6-qf-htf" secondAttribute="leading" id="1Lh-ve-rwK"/>
<constraint firstAttribute="trailing" secondItem="8zu-cF-KCX" secondAttribute="trailing" constant="20" symbolic="YES" id="1Wo-BO-MIr"/> <constraint firstAttribute="trailing" secondItem="8zu-cF-KCX" secondAttribute="trailing" constant="20" symbolic="YES" id="1Wo-BO-MIr"/>
<constraint firstItem="6U0-c0-4UL" firstAttribute="top" secondItem="UPH-hV-Naz" secondAttribute="top" id="2Kx-K5-QHR"/>
<constraint firstItem="U1c-qS-cIm" firstAttribute="leading" secondItem="QkM-5D-ZEQ" secondAttribute="trailing" constant="20" id="2xX-Ma-iQZ"/> <constraint firstItem="U1c-qS-cIm" firstAttribute="leading" secondItem="QkM-5D-ZEQ" secondAttribute="trailing" constant="20" id="2xX-Ma-iQZ"/>
<constraint firstAttribute="trailing" secondItem="U1c-qS-cIm" secondAttribute="trailing" constant="20" symbolic="YES" id="39u-Uk-TDI"/> <constraint firstAttribute="trailing" secondItem="U1c-qS-cIm" secondAttribute="trailing" constant="20" symbolic="YES" id="39u-Uk-TDI"/>
<constraint firstAttribute="bottom" secondItem="8zu-cF-KCX" secondAttribute="bottom" constant="20" symbolic="YES" id="9tE-WS-TgA"/> <constraint firstAttribute="bottom" secondItem="8zu-cF-KCX" secondAttribute="bottom" constant="20" symbolic="YES" id="9tE-WS-TgA"/>
<constraint firstItem="n5T-nn-k3j" firstAttribute="top" secondItem="TCp-nS-HN2" secondAttribute="top" id="BlS-Yb-ME8"/> <constraint firstItem="n5T-nn-k3j" firstAttribute="top" secondItem="TCp-nS-HN2" secondAttribute="top" id="BlS-Yb-ME8"/>
<constraint firstItem="JVG-5w-fPd" firstAttribute="top" secondItem="UPH-hV-Naz" secondAttribute="top" id="CE7-54-G09"/>
<constraint firstItem="hml-dl-Cah" firstAttribute="trailing" secondItem="yI6-qf-htf" secondAttribute="trailing" id="DBa-7d-sS3"/> <constraint firstItem="hml-dl-Cah" firstAttribute="trailing" secondItem="yI6-qf-htf" secondAttribute="trailing" id="DBa-7d-sS3"/>
<constraint firstItem="n5T-nn-k3j" firstAttribute="leading" secondItem="TCp-nS-HN2" secondAttribute="trailing" constant="12" symbolic="YES" id="H9Z-Cc-sZr"/> <constraint firstItem="n5T-nn-k3j" firstAttribute="leading" secondItem="TCp-nS-HN2" secondAttribute="trailing" constant="12" symbolic="YES" id="H9Z-Cc-sZr"/>
<constraint firstItem="yI6-qf-htf" firstAttribute="trailing" secondItem="U1c-qS-cIm" secondAttribute="trailing" id="NvJ-vf-wEl"/> <constraint firstItem="yI6-qf-htf" firstAttribute="trailing" secondItem="U1c-qS-cIm" secondAttribute="trailing" id="NvJ-vf-wEl"/>
<constraint firstItem="TCp-nS-HN2" firstAttribute="leading" secondItem="UPH-hV-Naz" secondAttribute="leading" constant="20" symbolic="YES" id="Oxa-b8-QSZ"/> <constraint firstItem="TCp-nS-HN2" firstAttribute="leading" secondItem="UPH-hV-Naz" secondAttribute="leading" constant="20" symbolic="YES" id="Oxa-b8-QSZ"/>
<constraint firstItem="hml-dl-Cah" firstAttribute="top" secondItem="yI6-qf-htf" secondAttribute="bottom" constant="15" id="Pmz-I9-2up"/> <constraint firstItem="hml-dl-Cah" firstAttribute="top" secondItem="yI6-qf-htf" secondAttribute="bottom" constant="15" id="Pmz-I9-2up"/>
<constraint firstItem="8zu-cF-KCX" firstAttribute="top" secondItem="hml-dl-Cah" secondAttribute="bottom" constant="50" id="Uah-cm-AeJ"/> <constraint firstItem="8zu-cF-KCX" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="n5T-nn-k3j" secondAttribute="trailing" constant="12" symbolic="YES" id="SrE-Z3-bDB"/>
<constraint firstAttribute="bottom" secondItem="6U0-c0-4UL" secondAttribute="bottom" id="Z9d-4l-X8c"/> <constraint firstItem="8zu-cF-KCX" firstAttribute="top" secondItem="hml-dl-Cah" secondAttribute="bottom" constant="30" id="Uah-cm-AeJ"/>
<constraint firstItem="U1c-qS-cIm" firstAttribute="top" secondItem="UPH-hV-Naz" secondAttribute="top" constant="20" symbolic="YES" id="b8P-f5-G6s"/> <constraint firstItem="U1c-qS-cIm" firstAttribute="top" secondItem="UPH-hV-Naz" secondAttribute="top" constant="35" id="Uqt-sc-vxn"/>
<constraint firstItem="QkM-5D-ZEQ" firstAttribute="top" secondItem="U1c-qS-cIm" secondAttribute="top" id="WAj-rw-srg"/>
<constraint firstItem="yI6-qf-htf" firstAttribute="leading" secondItem="U1c-qS-cIm" secondAttribute="leading" id="bng-pH-jSG"/> <constraint firstItem="yI6-qf-htf" firstAttribute="leading" secondItem="U1c-qS-cIm" secondAttribute="leading" id="bng-pH-jSG"/>
<constraint firstAttribute="trailing" secondItem="JVG-5w-fPd" secondAttribute="trailing" id="dRt-Pq-6n0"/>
<constraint firstItem="JVG-5w-fPd" firstAttribute="leading" secondItem="UPH-hV-Naz" secondAttribute="leading" id="ejC-of-zjN"/>
<constraint firstAttribute="bottom" secondItem="JVG-5w-fPd" secondAttribute="bottom" id="hGp-DD-cKr"/>
<constraint firstItem="QkM-5D-ZEQ" firstAttribute="leading" secondItem="UPH-hV-Naz" secondAttribute="leading" constant="20" symbolic="YES" id="jG8-dt-l4x"/> <constraint firstItem="QkM-5D-ZEQ" firstAttribute="leading" secondItem="UPH-hV-Naz" secondAttribute="leading" constant="20" symbolic="YES" id="jG8-dt-l4x"/>
<constraint firstAttribute="trailing" secondItem="6U0-c0-4UL" secondAttribute="trailing" id="khc-R8-fWk"/>
<constraint firstItem="yI6-qf-htf" firstAttribute="top" secondItem="U1c-qS-cIm" secondAttribute="bottom" constant="8" symbolic="YES" id="kqR-yg-zdG"/> <constraint firstItem="yI6-qf-htf" firstAttribute="top" secondItem="U1c-qS-cIm" secondAttribute="bottom" constant="8" symbolic="YES" id="kqR-yg-zdG"/>
<constraint firstItem="6U0-c0-4UL" firstAttribute="leading" secondItem="UPH-hV-Naz" secondAttribute="leading" id="qiT-SB-MSz"/>
<constraint firstItem="QkM-5D-ZEQ" firstAttribute="top" secondItem="UPH-hV-Naz" secondAttribute="top" constant="20" symbolic="YES" id="rVw-A2-0JC"/>
<constraint firstAttribute="bottom" secondItem="TCp-nS-HN2" secondAttribute="bottom" constant="20" symbolic="YES" id="sm1-Qr-6iV"/> <constraint firstAttribute="bottom" secondItem="TCp-nS-HN2" secondAttribute="bottom" constant="20" symbolic="YES" id="sm1-Qr-6iV"/>
</constraints> </constraints>
</view> </view>
<connections>
<outlet property="buttonPrimary" destination="8zu-cF-KCX" id="MT5-Px-K97"/>
<outlet property="buttonSecondary" destination="TCp-nS-HN2" id="nPn-OX-Z4m"/>
<outlet property="buttonTertiary" destination="n5T-nn-k3j" id="UnB-8x-s3D"/>
<outlet property="imageView" destination="QkM-5D-ZEQ" id="zsW-l7-eH0"/>
<outlet property="labelDescription" destination="hml-dl-Cah" id="ehw-zs-EPc"/>
<outlet property="labelSubtitle" destination="yI6-qf-htf" id="m7A-bX-HE8"/>
<outlet property="labelTitle" destination="U1c-qS-cIm" id="oM3-kl-PL8"/>
<outlet property="primaryButtonTopMargin" destination="Uah-cm-AeJ" id="bQ0-Us-LKh"/>
</connections>
</viewController> </viewController>
<customObject id="5Ts-EZ-bJh" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/> <customObject id="5Ts-EZ-bJh" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects> </objects>

View File

@ -0,0 +1,81 @@
//
// Notice.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 16/02/2022.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
class Notice {
var windowController: NSWindowController!
var noticeVC: NoticeVC {
return self.windowController.contentViewController as! NoticeVC
}
public static func make() -> Notice {
let storyboard = NSStoryboard(name: "Main" , bundle : nil)
let notice = Notice()
notice.windowController = storyboard.instantiateController(
withIdentifier: "noticeWindow"
) as? NSWindowController
return notice
}
public func withPrimary(
text: String,
action: @escaping (NoticeVC) -> Void = {
vc in vc.close(with: .alertFirstButtonReturn)
}
) -> Self {
self.noticeVC.buttonPrimary.title = text
self.noticeVC.actionPrimary = action
return self
}
public func withSecondary(
text: String,
action: ((NoticeVC) -> Void)? = nil
) -> Self {
self.noticeVC.buttonSecondary.title = text
self.noticeVC.actionSecondary = action
return self
}
public func withTertiary(
text: String,
action: ((NoticeVC) -> Void)? = nil
) -> Self {
self.noticeVC.buttonTertiary.title = text
self.noticeVC.actionTertiary = action
return self
}
public func withInformation(
title: String,
subtitle: String,
description: String = ""
) -> Self {
self.noticeVC.labelTitle.stringValue = title
self.noticeVC.labelSubtitle.stringValue = subtitle
self.noticeVC.labelDescription.stringValue = description
// If the description is missing, handle the excess space and change the top margin
if (description == "") {
self.noticeVC.labelDescription.isHidden = true
self.noticeVC.primaryButtonTopMargin.constant = 0
}
return self
}
public func present() -> NSApplication.ModalResponse {
NSApp.activate(ignoringOtherApps: true)
windowController.window?.makeKeyAndOrderFront(nil)
return NSApplication.shared.runModal(for: windowController.window!)
}
}

View File

@ -0,0 +1,63 @@
//
// NoticeVC.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 16/02/2022.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import Foundation
import Cocoa
class NoticeVC: NSViewController {
@IBOutlet weak var labelTitle: NSTextField!
@IBOutlet weak var labelSubtitle: NSTextField!
@IBOutlet weak var labelDescription: NSTextField!
@IBOutlet weak var buttonPrimary: NSButton!
@IBOutlet weak var buttonSecondary: NSButton!
@IBOutlet weak var buttonTertiary: NSButton!
var actionPrimary: (NoticeVC) -> Void = { _ in }
var actionSecondary: ((NoticeVC) -> Void)?
var actionTertiary: ((NoticeVC) -> Void)?
@IBOutlet weak var imageView: NSImageView!
@IBOutlet weak var primaryButtonTopMargin: NSLayoutConstraint!
override func viewWillAppear() {
imageView.image = NSApp.applicationIconImage
if actionSecondary == nil {
buttonSecondary.isHidden = true
}
if actionTertiary == nil {
buttonTertiary.isHidden = true
}
}
@IBAction func primaryButtonAction(_ sender: Any) {
self.actionPrimary(self)
}
@IBAction func secondaryButtonAction(_ sender: Any) {
if self.actionSecondary != nil {
self.actionSecondary!(self)
} else {
self.close(with: .alertSecondButtonReturn)
}
}
@IBAction func tertiaryButtonAction(_ sender: Any) {
if self.actionSecondary != nil {
self.actionTertiary!(self)
}
}
public func close(with code: NSApplication.ModalResponse) {
self.view.window?.close()
NSApplication.shared.stopModal(withCode: code)
}
}