Skip to content

Commit

Permalink
[menu-bar] Add auto update support (#65)
Browse files Browse the repository at this point in the history
* [menu-bar] Add auto update support

* Add appcast file

* Update Settings window

* Add changelog entry
  • Loading branch information
gabrieldonadel committed Sep 19, 2023
1 parent 749f2e1 commit d69f197
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 52 deletions.
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

## 0.1.3 — 2023-09

### 🛠 Breaking changes

### 🎉 New features

- Add auto update support. ([#65](https://github.com/expo/orbit/pull/65) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- Improved performance when running `cli` commands. ([#61](https://github.com/expo/orbit/pull/61) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- Show dock icon while windows are opened. ([#50](https://github.com/expo/orbit/pull/50) by [@gabrieldonadel](https://github.com/gabrieldonadel))

Expand Down
40 changes: 40 additions & 0 deletions appcast.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>Orbit</title>
<link>https://raw.githubusercontent.com/expo/orbit/main/appcast.xml</link>
<description>Most recent changes with links to updates.</description>
<language>en</language>
<item>
<title>0.1.2</title>
<description>
<![CDATA[
<h3 id="newfeatures">🎉 New features</h3>
<ul>
<li>Added a context menu when right clicking on the menu bar icon. (<a href="https://github.com/expo/orbit/pull/36">#36</a> by <a href="https://github.com/gabrieldonadel">@gabrieldonadel</a>)</li>
</ul>
<h3 id="bugfixes">🐛 Bug fixes</h3>
<ul>
<li>Fixed listing devices on Intel machines. (<a href="https://github.com/expo/orbit/pull/39">#39</a> by <a href="https://github.com/gabrieldonadel">@gabrieldonadel</a>)</li>
</ul>
<h3 id="others">💡 Others</h3>
<ul>
<li>Refetch devices list after launching a simulator. (<a href="https://github.com/expo/orbit/pull/37">#37</a> by <a href="https://github.com/gabrieldonadel">@gabrieldonadel</a>)</li>
<li>Improve Popover height estimations. (<a href="https://github.com/expo/orbit/pull/38">#38</a> by <a href="https://github.com/gabrieldonadel">@gabrieldonadel</a>)</li>
<li>Add alert when trying to install build with no available device. (<a href="https://github.com/expo/orbit/pull/38">#38</a> by <a href="https://github.com/gabrieldonadel">@gabrieldonadel</a>)</li>
</ul>
]]>
</description>
<pubDate>2023-08-13</pubDate>
<releaseNotesLink>https://github.com/expo/orbit/releases/tag/expo-orbit-v0.1.2</releaseNotesLink>
<sparkle:minimumSystemVersion>10.15</sparkle:minimumSystemVersion>
<enclosure
url="https://github.com/expo/orbit/releases/download/expo-orbit-v0.1.2/expo-orbit.v0.1.2.zip"
sparkle:version="6"
sparkle:shortVersionString="0.1.2"
length="0"
type="application/octet-stream"
/>
</item>
</channel>
</rss>
2 changes: 2 additions & 0 deletions apps/menu-bar/macos/ExpoMenuBar-macOS/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,7 @@
<true/>
<key>NSSupportsSuddenTermination</key>
<true/>
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/expo/orbit/main/appcast.xml</string>
</dict>
</plist>
4 changes: 4 additions & 0 deletions apps/menu-bar/macos/ExpoMenuBar-macOS/SparkleModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#import <React/RCTBridgeModule.h>

@interface SparkleModule : NSObject <RCTBridgeModule>
@end
46 changes: 46 additions & 0 deletions apps/menu-bar/macos/ExpoMenuBar-macOS/SparkleModule.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#import "SparkleModule.h"
#import "AppDelegate.h"

#import <Sparkle/SPUStandardUpdaterController.h>
#import <Sparkle/SPUUpdater.h>

@implementation SparkleModule {
SPUStandardUpdaterController *updateController;
}

RCT_EXPORT_MODULE();

- (instancetype)init {
self = [super init];
if (self) {
updateController = [[SPUStandardUpdaterController alloc] initWithStartingUpdater:YES updaterDelegate:nil userDriverDelegate:nil];
}
return self;
}


+ (BOOL)requiresMainQueueSetup
{
return YES;
}


RCT_EXPORT_METHOD(checkForUpdates)
{
dispatch_async(dispatch_get_main_queue(), ^{
[[self->updateController updater] checkForUpdates];
});
}

RCT_EXPORT_METHOD(getAutomaticallyChecksForUpdates:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
resolve(@([[self->updateController updater] automaticallyChecksForUpdates]));
}

RCT_EXPORT_METHOD(setAutomaticallyChecksForUpdates:(BOOL)value)
{
[[self->updateController updater] setAutomaticallyChecksForUpdates:value];
}

@end
18 changes: 16 additions & 2 deletions apps/menu-bar/macos/ExpoMenuBar.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
C08E65342A5D04910079E3A9 /* WindowNavigator.m in Sources */ = {isa = PBXBuildFile; fileRef = C08E65332A5D04910079E3A9 /* WindowNavigator.m */; };
C0B36EA22A65E25A004F2D8C /* Checkbox.m in Sources */ = {isa = PBXBuildFile; fileRef = C0B36E9F2A65E25A004F2D8C /* Checkbox.m */; };
C0B36EA32A65E25A004F2D8C /* CheckboxManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C0B36EA12A65E25A004F2D8C /* CheckboxManager.m */; };
C0C820022AB8E5EE003D75AF /* SparkleModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C0C820012AB8E5EE003D75AF /* SparkleModule.m */; };
C0E7CF482A15378D00C59DE5 /* MenuBarModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C0E7CF472A15378D00C59DE5 /* MenuBarModule.m */; };
E1CB5365F6C6CCE90A6EF541 /* libPods-ExpoMenuBar-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C6FA792906717DFD0B3546C1 /* libPods-ExpoMenuBar-macOS.a */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -97,6 +98,8 @@
C0B36E9F2A65E25A004F2D8C /* Checkbox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Checkbox.m; sourceTree = "<group>"; };
C0B36EA02A65E25A004F2D8C /* CheckboxManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckboxManager.h; sourceTree = "<group>"; };
C0B36EA12A65E25A004F2D8C /* CheckboxManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckboxManager.m; sourceTree = "<group>"; };
C0C820012AB8E5EE003D75AF /* SparkleModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SparkleModule.m; sourceTree = "<group>"; };
C0C820032AB8E600003D75AF /* SparkleModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SparkleModule.h; sourceTree = "<group>"; };
C0E7CF462A15372D00C59DE5 /* MenuBarModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MenuBarModule.h; sourceTree = "<group>"; };
C0E7CF472A15378D00C59DE5 /* MenuBarModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MenuBarModule.m; sourceTree = "<group>"; };
C6FA792906717DFD0B3546C1 /* libPods-ExpoMenuBar-macOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ExpoMenuBar-macOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -191,6 +194,8 @@
C0271C572A602CDE0065AB11 /* ProgressIndicatorManager.m */,
C0271C592A602FEC0065AB11 /* ProgressIndicatorView.h */,
C0271C5A2A602FF60065AB11 /* ProgressIndicatorView.m */,
C0C820012AB8E5EE003D75AF /* SparkleModule.m */,
C0C820032AB8E600003D75AF /* SparkleModule.h */,
);
path = "ExpoMenuBar-macOS";
sourceTree = "<group>";
Expand Down Expand Up @@ -432,10 +437,12 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ExpoMenuBar-macOS/Pods-ExpoMenuBar-macOS-frameworks.sh",
"${PODS_ROOT}/Sparkle/Sparkle.framework",
"${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/macosx/hermes.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sparkle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -455,6 +462,7 @@
C0523ED02A55980D003371AF /* WindowWithDeallocCallback.m in Sources */,
C0271C582A602CDE0065AB11 /* ProgressIndicatorManager.m in Sources */,
C0B36EA32A65E25A004F2D8C /* CheckboxManager.m in Sources */,
C0C820022AB8E5EE003D75AF /* SparkleModule.m in Sources */,
C0E7CF482A15378D00C59DE5 /* MenuBarModule.m in Sources */,
C0271C5B2A602FF60065AB11 /* ProgressIndicatorView.m in Sources */,
C0523ECC2A550983003371AF /* WindowManager.m in Sources */,
Expand Down Expand Up @@ -504,7 +512,10 @@
INFOPLIST_KEY_CFBundleDisplayName = "Expo Orbit";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.15;
OTHER_CFLAGS = "$(inherited) ";
OTHER_CFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -532,7 +543,10 @@
INFOPLIST_KEY_CFBundleDisplayName = "Expo Orbit";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.15;
OTHER_CFLAGS = "$(inherited) ";
OTHER_CFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
1 change: 1 addition & 0 deletions apps/menu-bar/macos/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ target 'ExpoMenuBar-macOS' do
)

# Pods specifically for macOS target
pod 'Sparkle', '~> 2.5.0'
end

post_install do |installer|
Expand Down
6 changes: 5 additions & 1 deletion apps/menu-bar/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ PODS:
- RNSVG (13.9.0):
- React-Core
- SocketRocket (0.6.0)
- Sparkle (2.5.0)
- Yoga (1.14.0)

DEPENDENCIES:
Expand Down Expand Up @@ -413,13 +414,15 @@ DEPENDENCIES:
- "RNCAsyncStorage (from `../../../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../../../node_modules/@react-native-clipboard/clipboard`)"
- RNSVG (from `../../../node_modules/react-native-svg`)
- Sparkle (~> 2.5.0)
- Yoga (from `../../../node_modules/react-native-macos/ReactCommon/yoga`)

SPEC REPOS:
trunk:
- fmt
- libevent
- SocketRocket
- Sparkle

EXTERNAL SOURCES:
boost:
Expand Down Expand Up @@ -537,8 +540,9 @@ SPEC CHECKSUMS:
RNCClipboard: 3f0451a8100393908bea5c5c5b16f96d45f30bfc
RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Sparkle: 913cef92f73e08d0ae47a36ee20e523913e5f9e2
Yoga: 4e076ec2978a0800817878be120de7e97b79bcf3

PODFILE CHECKSUM: b107cc642a2952bfc0a576b4722750483387b7f7
PODFILE CHECKSUM: 86cfebf9b1835c1a1feb1306c01bea9e04d5758d

COCOAPODS: 1.12.1
45 changes: 16 additions & 29 deletions apps/menu-bar/src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useLayoutEffect, useRef, useState} from 'react';
import { useLayoutEffect, useRef, useState } from 'react';
import {
NativeSyntheticEvent,
Pressable,
Expand All @@ -8,14 +8,15 @@ import {
ViewProps,
} from 'react-native';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import {Text} from './Text';

import { Text } from './Text';
import { Row } from './View';

interface CheckboxChangeEventData extends TargetedEvent {
value: boolean;
}

interface CheckboxChangeEvent
extends NativeSyntheticEvent<CheckboxChangeEventData> {}
interface CheckboxChangeEvent extends NativeSyntheticEvent<CheckboxChangeEventData> {}

type NativeCheckboxProps = ViewProps & {
disabled?: boolean;
Expand All @@ -31,51 +32,37 @@ type CheckboxProps = NativeCheckboxProps & {
};

interface NativeCommands {
setValue: (
viewRef: React.ElementRef<typeof NativeCheckbox>,
value: boolean,
) => void;
setValue: (viewRef: React.ElementRef<typeof NativeCheckbox>, value: boolean) => void;
}

export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['setValue'],
});

const Checkbox = ({
onChange,
onValueChange,
label,
...props
}: CheckboxProps) => {
const [native, setNative] = useState<{value?: boolean}>({value: undefined});
const Checkbox = ({ onChange, onValueChange, label, ...props }: CheckboxProps) => {
const [native, setNative] = useState<{ value?: boolean }>({ value: undefined });

const nativeSwitchRef = useRef<React.ElementRef<
typeof NativeCheckbox
> | null>(null);
const nativeSwitchRef = useRef<React.ElementRef<typeof NativeCheckbox> | null>(null);

useLayoutEffect(() => {
// This is necessary in case native updates the switch and JS decides
// that the update should be ignored and we should stick with the value
// that we have in JS.
const jsValue = props.value === true;
const shouldUpdateNativeSwitch =
native.value != null && native.value !== jsValue;
if (
shouldUpdateNativeSwitch &&
nativeSwitchRef.current?.setNativeProps != null
) {
const shouldUpdateNativeSwitch = native.value != null && native.value !== jsValue;
if (shouldUpdateNativeSwitch && nativeSwitchRef.current?.setNativeProps != null) {
Commands.setValue(nativeSwitchRef.current, jsValue);
}
}, [props.value, native]);

const handleChange = (event: CheckboxChangeEvent) => {
onChange?.(event);
onValueChange?.(event.nativeEvent.value);
setNative({value: event.nativeEvent.value});
setNative({ value: event.nativeEvent.value });
};

return (
<>
<Row align="center" gap="1">
<NativeCheckbox
{...props}
style={[styles.checkbox, props.style]}
Expand All @@ -86,17 +73,17 @@ const Checkbox = ({
<Pressable
onPress={() => {
onValueChange?.(!props.value);
setNative({value: !props.value});
setNative({ value: !props.value });
}}>
<Text>{label}</Text>
</Pressable>
)}
</>
</Row>
);
};

export default Checkbox;

const styles = StyleSheet.create({
checkbox: {height: 18, width: 18},
checkbox: { height: 18, width: 18 },
});
15 changes: 15 additions & 0 deletions apps/menu-bar/src/modules/SparkleModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { NativeModule, NativeModules } from 'react-native';

type SparkleModuleType = NativeModule & {
checkForUpdates: () => void;
getAutomaticallyChecksForUpdates: () => Promise<boolean>;
setAutomaticallyChecksForUpdates: (value: boolean) => void;
};

const SparkleModule: SparkleModuleType = NativeModules.SparkleModule;

export default {
...SparkleModule,
checkForUpdates: () => SparkleModule.checkForUpdates(),
getAutomaticallyChecksForUpdates: () => SparkleModule.getAutomaticallyChecksForUpdates(),
};
Loading

0 comments on commit d69f197

Please sign in to comment.