You've already forked hotpocket
BTHLABS-58: Share Extension in Apple Apps
This commit is contained in:
@@ -7,6 +7,10 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class HPAuthFlow;
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
|
||||
@property (strong, nonnull) HPAuthFlow *authFlow;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,14 +7,32 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "HPAuthFlow.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
// Override point for customization after application launch.
|
||||
-(void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
self.authFlow = [[HPAuthFlow alloc] init];
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
|
||||
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls {
|
||||
HPAuthParams *receivedAuthParams = nil;
|
||||
for (NSURL *url in urls) {
|
||||
receivedAuthParams = [self.authFlow handlePostAuthenticateURL:url];
|
||||
|
||||
if (receivedAuthParams != nil) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (receivedAuthParams != nil) {
|
||||
[self.authFlow handleAuthParams:receivedAuthParams];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AuthorizationProgressViewController.h
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 20/09/2025.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AuthorizationProgressViewController : NSViewController
|
||||
|
||||
@property IBOutlet NSProgressIndicator *progressIndicator;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// AuthorizationProgressViewController.m
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 20/09/2025.
|
||||
//
|
||||
|
||||
#import "AuthorizationProgressViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "AuthorizationViewController.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "MainViewController.h"
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@interface AuthorizationProgressViewController (AuthorizationProgressViewControllerPrivate)
|
||||
|
||||
#pragma mark - Private interface
|
||||
|
||||
@end
|
||||
|
||||
@implementation AuthorizationProgressViewController
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
-(void)viewWillAppear {
|
||||
AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAuthFlowDidFinish:) name:@"AuthFlowDidFinish" object:appDelegate.authFlow];
|
||||
|
||||
[self.progressIndicator startAnimation:self];
|
||||
}
|
||||
|
||||
-(void)viewDidDisappear {
|
||||
[self.progressIndicator stopAnimation:self];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Notification handlers
|
||||
|
||||
-(void)onAuthFlowDidFinish:(NSNotification *)notification {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
HPCredentials *credentials = [[HPCredentialsHelper sharedHelper] getCredentials];
|
||||
|
||||
[[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest];
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
|
||||
if (credentials.usable == NO) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.alertStyle = NSAlertStyleCritical;
|
||||
alert.messageText = NSLocalizedString(@"Oops!", @"Oops!");
|
||||
alert.informativeText = NSLocalizedString(@"HotPocket couldn't complete this operation.", @"HotPocket couldn't complete this operation.");
|
||||
[alert runModal];
|
||||
|
||||
AuthorizationViewController *authorizationViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationViewController"];
|
||||
[self presentViewController:authorizationViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
} else {
|
||||
MainViewController *mainViewController = [self.storyboard instantiateControllerWithIdentifier:@"MainViewController"];
|
||||
[self presentViewController:mainViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
21
services/apple/macOS (App)/AuthorizationViewController.h
Normal file
21
services/apple/macOS (App)/AuthorizationViewController.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// AuthorizationViewController.h
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 20/09/2025.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AuthorizationViewController : NSViewController
|
||||
|
||||
@property (nullable) NSString *baseURL;
|
||||
@property (nullable) NSString *authorizationSessionToken;
|
||||
|
||||
-(IBAction)doStartAuthorizationFlow:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
49
services/apple/macOS (App)/AuthorizationViewController.m
Normal file
49
services/apple/macOS (App)/AuthorizationViewController.m
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// AuthorizationViewController.m
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 20/09/2025.
|
||||
//
|
||||
|
||||
#import "AuthorizationViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "HPAuthFlow.h"
|
||||
#import "AuthorizationProgressViewController.h"
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@interface AuthorizationViewController (AuthorizationViewControllerPrivate)
|
||||
|
||||
#pragma mark - Private interface
|
||||
|
||||
@end
|
||||
|
||||
@implementation AuthorizationViewController
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.baseURL = nil;
|
||||
self.authorizationSessionToken = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
-(IBAction)doStartAuthorizationFlow:(id)sender {
|
||||
AppDelegate *appDeleate = [[NSApplication sharedApplication] delegate];
|
||||
appDeleate.authFlow.baseURL = [NSURL URLWithString:self.baseURL];
|
||||
|
||||
NSURL *authURL = [appDeleate.authFlow start];
|
||||
if (authURL == nil) {
|
||||
NSBeep();
|
||||
return;
|
||||
}
|
||||
|
||||
AuthorizationProgressViewController *authProgressViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationProgressViewController"];
|
||||
[self presentViewController:authProgressViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
|
||||
[[NSWorkspace sharedWorkspace] openURL:authURL];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23727"/>
|
||||
<plugIn identifier="com.apple.WebKit2IBPlugin" version="23727"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24127"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@@ -77,7 +77,7 @@
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController showSeguePresentationStyle="single" id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||
<window key="window" title="HotPocket" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" animationBehavior="default" id="IQv-IB-iLA">
|
||||
<window key="window" title="HotPocket" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" animationBehavior="default" toolbarStyle="expanded" id="IQv-IB-iLA">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenNone="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="425" height="325"/>
|
||||
@@ -87,38 +87,216 @@
|
||||
</connections>
|
||||
</window>
|
||||
<connections>
|
||||
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
|
||||
<segue destination="r5D-xE-cNT" kind="relationship" relationship="window.shadowedContentViewController" id="j8b-cd-GSP"/>
|
||||
</connections>
|
||||
</windowController>
|
||||
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="250"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<!--Authorization View Controller-->
|
||||
<scene sceneID="hIz-AP-VOD">
|
||||
<objects>
|
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController">
|
||||
<view key="view" appearanceType="darkAqua" id="m2S-Jp-Qdl">
|
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
<viewController storyboardIdentifier="AuthorizationViewController" id="XfG-lQ-9wD" customClass="AuthorizationViewController" sceneMemberID="viewController">
|
||||
<view key="view" id="m2S-Jp-Qdl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<wkWebView wantsLayer="YES" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eOr-cG-IQY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<wkWebViewConfiguration key="configuration">
|
||||
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
|
||||
<wkPreferences key="preferences"/>
|
||||
</wkWebViewConfiguration>
|
||||
</wkWebView>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7sM-F3-Zzf">
|
||||
<rect key="frame" x="18" y="153" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="HotPocket Instance URL" id="XwM-DV-kei">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ygC-xe-m6y">
|
||||
<rect key="frame" x="20" y="124" width="385" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="rHK-hP-yWO">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="XfG-lQ-9wD" name="value" keyPath="self.baseURL" id="OhE-52-yPd">
|
||||
<dictionary key="options">
|
||||
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DIc-8O-uoQ">
|
||||
<rect key="frame" x="18" y="68" width="389" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="Enter the URL to your HotPocket instance, e.g. https://my.hotpocket.app" id="Y0q-a1-oBP">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PAH-U3-ltl">
|
||||
<rect key="frame" x="180" y="221" width="64" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon-mac-384" id="jnV-K2-7gf"/>
|
||||
</imageView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Zr-9i-XDS">
|
||||
<rect key="frame" x="13" y="33" width="89" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Continue" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="HBR-3P-qCC">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<color key="contentTintColor" name="AccentColor"/>
|
||||
<connections>
|
||||
<action selector="doStartAuthorizationFlow:" target="XfG-lQ-9wD" id="AOi-Wt-gmL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mQc-Ea-NNN">
|
||||
<rect key="frame" x="18" y="185" width="389" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="NTZ-zl-yhk">
|
||||
<font key="font" metaFont="system" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
</viewController>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="606" y="1067"/>
|
||||
</scene>
|
||||
<!--Authorization Progress View Controller-->
|
||||
<scene sceneID="HWJ-b5-BG6">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="AuthorizationProgressViewController" id="OX4-Oj-1cw" customClass="AuthorizationProgressViewController" sceneMemberID="viewController">
|
||||
<view key="view" id="qln-dC-eog">
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yRj-hC-QYS">
|
||||
<rect key="frame" x="18" y="185" width="389" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="F4l-2Z-D79">
|
||||
<font key="font" metaFont="system" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ca6-br-wxp">
|
||||
<rect key="frame" x="180" y="221" width="64" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon-mac-384" id="faZ-e6-z8R"/>
|
||||
</imageView>
|
||||
<progressIndicator fixedFrame="YES" maxValue="100" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="51a-ii-yug">
|
||||
<rect key="frame" x="196" y="113" width="32" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</progressIndicator>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g9a-gR-c7o">
|
||||
<rect key="frame" x="18" y="81" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Awaiting authorization response..." id="3oi-LK-vKv">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="webView" destination="eOr-cG-IQY" id="GFe-mU-dBY"/>
|
||||
<outlet property="progressIndicator" destination="51a-ii-yug" id="hWy-Hb-3pE"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
<customObject id="Dav-PG-FiQ" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="655"/>
|
||||
<point key="canvasLocation" x="605.5" y="654.5"/>
|
||||
</scene>
|
||||
<!--Main View Controller-->
|
||||
<scene sceneID="UJA-e4-0rA">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="MainViewController" id="r5D-xE-cNT" customClass="MainViewController" sceneMemberID="viewController">
|
||||
<view key="view" id="jVt-oL-KPZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ybL-DV-U73">
|
||||
<rect key="frame" x="180" y="221" width="64" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="icon-mac-384" id="fae-mz-0sj"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T7q-KB-3Ut">
|
||||
<rect key="frame" x="18" y="185" width="389" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="r5O-Sk-IdK">
|
||||
<font key="font" metaFont="system" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2h7-bN-dsa">
|
||||
<rect key="frame" x="18" y="121" width="389" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="HotPocket is configured and ready." id="5fh-mh-WR1">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uci-UC-wxo">
|
||||
<rect key="frame" x="18" y="97" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Instance URL" id="azk-ea-KeN">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LR4-eJ-jlA">
|
||||
<rect key="frame" x="13" y="30" width="80" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Log out" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="LDr-35-Wph">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<color key="contentTintColor" name="DangerColor"/>
|
||||
<connections>
|
||||
<action selector="doLogOut:" target="r5D-xE-cNT" id="BMt-Zp-8v5"/>
|
||||
<binding destination="r5D-xE-cNT" name="enabled" keyPath="self.logoutButtonEnabled" id="gTs-BO-USz"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8H3-oU-acU" customClass="LinkLabel">
|
||||
<rect key="frame" x="18" y="73" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" allowsEditingTextAttributes="YES" id="EoA-mM-phM">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="SecondaryColor"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="instanceURLLabel" destination="8H3-oU-acU" id="EuY-xr-zar"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="dlo-Mj-lGf" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="74.5" y="654.5"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="icon-mac-384" width="384" height="384"/>
|
||||
<namedColor name="AccentColor">
|
||||
<color red="0.10980392156862745" green="0.72941176470588232" blue="0.92941176470588238" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="DangerColor">
|
||||
<color red="0.93300002813339233" green="0.3919999897480011" blue="0.46299999952316284" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="SecondaryColor">
|
||||
<color red="0.0" green="0.50980392156862742" blue="0.8666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -4,9 +4,18 @@
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.pl.bthlabs.HotPocket</string>
|
||||
</array>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>keychain-access-groups</key>
|
||||
<array>
|
||||
<string>$(AppIdentifierPrefix)pl.bthlabs.HotPocketShared</string>
|
||||
<string>$(AppIdentifierPrefix)pl.bthlabs.HotPocket</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
32
services/apple/macOS (App)/Info.plist
Normal file
32
services/apple/macOS (App)/Info.plist
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>icon-mac-384</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>HotPocketDesktopMac</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>hotpocket-desktop</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>HPAuthFlowPostAuthenticateURLParts</key>
|
||||
<dict>
|
||||
<key>host</key>
|
||||
<string>post-authenticate</string>
|
||||
<key>scheme</key>
|
||||
<string>hotpocket-desktop</string>
|
||||
</dict>
|
||||
<key>HPAuthFlowSource</key>
|
||||
<string>HotPocketDesktop</string>
|
||||
<key>HPRPCClientOrigin</key>
|
||||
<string>hotpocket-desktop://HPRPCClient</string>
|
||||
</dict>
|
||||
</plist>
|
||||
16
services/apple/macOS (App)/LinkLabel.h
Normal file
16
services/apple/macOS (App)/LinkLabel.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// LinkLabel.h
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 24/09/2025.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface LinkLabel : NSTextField
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
24
services/apple/macOS (App)/LinkLabel.m
Normal file
24
services/apple/macOS (App)/LinkLabel.m
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// LinkLabel.m
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 24/09/2025.
|
||||
//
|
||||
|
||||
#import "LinkLabel.h"
|
||||
|
||||
@implementation LinkLabel
|
||||
|
||||
-(void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.allowsEditingTextAttributes = YES;
|
||||
self.textColor = [NSColor colorNamed:@"SecondaryColor"];
|
||||
self.selectable = YES;
|
||||
}
|
||||
|
||||
-(void)resetCursorRects {
|
||||
[super resetCursorRects];
|
||||
[self addCursorRect:self.bounds cursor:NSCursor.pointingHandCursor];
|
||||
}
|
||||
|
||||
@end
|
||||
22
services/apple/macOS (App)/MainViewController.h
Normal file
22
services/apple/macOS (App)/MainViewController.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// MainViewController.h
|
||||
// HotPocket (iOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 22/09/2025.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MainViewController : NSViewController
|
||||
|
||||
@property IBOutlet NSTextField *instanceURLLabel;
|
||||
|
||||
@property BOOL logoutButtonEnabled;
|
||||
|
||||
-(IBAction)doLogOut:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
65
services/apple/macOS (App)/MainViewController.m
Normal file
65
services/apple/macOS (App)/MainViewController.m
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// MainViewController.m
|
||||
// HotPocket (iOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 22/09/2025.
|
||||
//
|
||||
|
||||
#import "MainViewController.h"
|
||||
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "AuthorizationViewController.h"
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@interface MainViewController (MainViewControllerPrivate)
|
||||
|
||||
#pragma mark - Private interface
|
||||
|
||||
@end
|
||||
|
||||
@implementation MainViewController
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.logoutButtonEnabled = NO;
|
||||
}
|
||||
|
||||
-(void)viewDidAppear {
|
||||
HPCredentials *credentials = [[HPCredentialsHelper sharedHelper] getCredentials];
|
||||
|
||||
if (credentials.usable == NO) {
|
||||
AuthorizationViewController *authorizationViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationViewController"];
|
||||
[self presentViewController:authorizationViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
} else {
|
||||
self.logoutButtonEnabled = YES;
|
||||
}
|
||||
|
||||
NSString *instanceURLText = @"";
|
||||
if (credentials.baseURL != nil) {
|
||||
instanceURLText = credentials.baseURL;
|
||||
}
|
||||
|
||||
NSMutableAttributedString *instanceURLValue = [[NSMutableAttributedString alloc] initWithString:instanceURLText];
|
||||
if (credentials.baseURL != nil) {
|
||||
[instanceURLValue addAttribute:NSLinkAttributeName
|
||||
value:credentials.baseURL
|
||||
range:NSMakeRange(0, instanceURLValue.length)];
|
||||
}
|
||||
[instanceURLValue addAttribute:NSUnderlineStyleAttributeName
|
||||
value:[NSNumber numberWithInteger:NSUnderlineStyleSingle]
|
||||
range:NSMakeRange(0, instanceURLValue.length)];
|
||||
|
||||
self.instanceURLLabel.attributedStringValue = instanceURLValue;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
-(IBAction)doLogOut:(id)sender {
|
||||
[[HPCredentialsHelper sharedHelper] clearCredentials];
|
||||
AuthorizationViewController *authorizationViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationViewController"];
|
||||
[self presentViewController:authorizationViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
}
|
||||
|
||||
@end
|
||||
16
services/apple/macOS (App)/ReplaceAnimator.h
Normal file
16
services/apple/macOS (App)/ReplaceAnimator.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// ReplaceAnimator.h
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 20/09/2025.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ReplaceAnimator : NSObject<NSViewControllerPresentationAnimator>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
29
services/apple/macOS (App)/ReplaceAnimator.m
Normal file
29
services/apple/macOS (App)/ReplaceAnimator.m
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// ReplaceAnimator.m
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 20/09/2025.
|
||||
//
|
||||
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@implementation ReplaceAnimator
|
||||
|
||||
-(void)animatePresentationOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController {
|
||||
NSView *container = fromViewController.view.superview;
|
||||
if (container == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[fromViewController.view removeFromSuperview];
|
||||
|
||||
[container addSubview:viewController.view];
|
||||
viewController.view.frame = NSMakeRect(0, 0, viewController.view.frame.size.width, viewController.view.frame.size.height);
|
||||
viewController.view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
}
|
||||
|
||||
-(void)animateDismissalOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController {
|
||||
[viewController.view removeFromSuperview];
|
||||
}
|
||||
|
||||
@end
|
||||
19
services/apple/macOS (App)/WindowContentView.h
Normal file
19
services/apple/macOS (App)/WindowContentView.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// WindowContentView.h
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 30/09/2025.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface WindowContentView : NSView
|
||||
|
||||
@property (strong) NSColor *darkBackgroundColor;
|
||||
@property (strong) NSColor *lightBackgroundColor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
42
services/apple/macOS (App)/WindowContentView.m
Normal file
42
services/apple/macOS (App)/WindowContentView.m
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// WindowContentView.m
|
||||
// HotPocket (macOS)
|
||||
//
|
||||
// Created by Tomek Wójcik on 30/09/2025.
|
||||
//
|
||||
|
||||
#import "WindowContentView.h"
|
||||
|
||||
@implementation WindowContentView
|
||||
|
||||
-(void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.darkBackgroundColor = [NSColor colorNamed:@"BackgroundColor"];
|
||||
self.lightBackgroundColor = [NSColor windowBackgroundColor];
|
||||
}
|
||||
|
||||
-(BOOL)isOpaque {
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)drawRect:(NSRect)dirtyRect {
|
||||
[super drawRect:dirtyRect];
|
||||
|
||||
NSAppearance *appearance = self.effectiveAppearance;
|
||||
NSAppearanceName bestMatch = [appearance bestMatchFromAppearancesWithNames:@[
|
||||
NSAppearanceNameAqua,
|
||||
NSAppearanceNameDarkAqua
|
||||
]];
|
||||
|
||||
NSColor *backgroundColor = self.lightBackgroundColor;
|
||||
if ([bestMatch isEqualToString:NSAppearanceNameDarkAqua] == YES) {
|
||||
backgroundColor = self.darkBackgroundColor;
|
||||
}
|
||||
|
||||
if (backgroundColor) {
|
||||
[backgroundColor setFill];
|
||||
NSRectFill(dirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user