Skip to content
This repository has been archived by the owner on Jan 17, 2019. It is now read-only.

Add tvOS support #263

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HubFramework.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Pod::Spec.new do |s|
DESC

s.ios.deployment_target = "8.0"
s.tvos.deployment_target = "9.0"

s.homepage = "https://github.com/spotify/HubFramework"
s.social_media_url = "https://twitter.com/spotifyeng"
Expand Down
853 changes: 812 additions & 41 deletions HubFramework.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "344C5E3C1E09CF9A00597B61"
BuildableName = "HubFramework.framework"
BlueprintName = "HubFramework-tvOS"
ReferencedContainer = "container:HubFramework.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "345AFDD31E10797B00807DCC"
BuildableName = "HubFrameworkTests-tvOS.xctest"
BlueprintName = "HubFrameworkTests-tvOS"
ReferencedContainer = "container:HubFramework.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "344C5E3C1E09CF9A00597B61"
BuildableName = "HubFramework.framework"
BlueprintName = "HubFramework-tvOS"
ReferencedContainer = "container:HubFramework.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "344C5E3C1E09CF9A00597B61"
BuildableName = "HubFramework.framework"
BlueprintName = "HubFramework-tvOS"
ReferencedContainer = "container:HubFramework.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "344C5E3C1E09CF9A00597B61"
BuildableName = "HubFramework.framework"
BlueprintName = "HubFramework-tvOS"
ReferencedContainer = "container:HubFramework.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
2 changes: 1 addition & 1 deletion demo/tests/PaginationUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class PaginationUITests: UITestCase {
numberOfSwipes += 1

if numberOfSwipes > 20 {
XCTFail("Should not have taken over 20 swipes to load paginated content")
XCTFail("It took \(numberOfSwipes) to load paginated content. Test assumed it should not have taken over 20 swipes.")
break
}
}
Expand Down
2 changes: 1 addition & 1 deletion include/HubFramework/HUBActionTrigger.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#import <Foundation/Foundation.h>

/// Enum describing various reasons that can cause an action to be triggered
typedef NS_ENUM(NSUInteger, HUBActionTrigger) {
typedef NS_ENUM(NSInteger, HUBActionTrigger) {
/// The action was triggered by that a component was selected
HUBActionTriggerSelection,
/// The action was triggered manually by a component
Expand Down
2 changes: 2 additions & 0 deletions include/HubFramework/HUBComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ NS_ASSUME_NONNULL_BEGIN
*
* `HUBComponentWithSelectionState`: For responding to highlight & selection events in a component.
*
* `HUBComponentWithFocusState`: For responding to focus events in a component (tvOS only).
*
* `HUBComponentContentOffsetObserver`: For components that react to the view's content offset.
*
* `HUBComponentViewObserver`: For components that observe their view for various events.
Expand Down
2 changes: 1 addition & 1 deletion include/HubFramework/HUBComponentLayoutManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
* A content edge is where the rendering of content "stops", such as at the screen edge or when
* an area covered by a navigation bar begins. Content edges have a 1:1 mapping to content insets.
*/
typedef NS_ENUM(NSUInteger, HUBComponentLayoutContentEdge) {
typedef NS_ENUM(NSInteger, HUBComponentLayoutContentEdge) {
/// The top content edge, usually where a navigation bar begins
HUBComponentLayoutContentEdgeTop,
/// The right content edge, usually at the screen edge
Expand Down
2 changes: 1 addition & 1 deletion include/HubFramework/HUBComponentType.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#import <Foundation/Foundation.h>

/// Enum describing various types of components used in the Hub Framework
typedef NS_ENUM(NSUInteger, HUBComponentType) {
typedef NS_ENUM(NSInteger, HUBComponentType) {
/// Type of components used in the header of a view
HUBComponentTypeHeader,
/// Type of components used in the body of a view
Expand Down
50 changes: 50 additions & 0 deletions include/HubFramework/HUBComponentWithFocusState.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2016 Spotify AB.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

#import "HUBComponent.h"

/// Enum defining various focus states that a component can be in
typedef NS_ENUM(NSInteger, HUBComponentFocusState) {
/// The component is not in focus
HUBComponentFocusStateNone,
/// The component is in focus, either programmatically or by the user
HUBComponentFocusStateInFocus
};

/**
* Extended Hub component protocol that adds the ability to respond to focus events (tvOS only).
*
* Use this protocol if your component adjusts its appearance when the user focuses on it.
*
* For more information, see `HUBComponent` and `HUBComponentFocusState`.
*/
@protocol HUBComponentWithFocusState <HUBComponent>

/**
* Update the components view for a certain focus state
*
* @param focusState The new focus state that the component's view should be updated for
*
* The Hub Framework automatically sends this message to a component when the user focuses on it.
*/
- (void)updateViewForFocusState:(HUBComponentFocusState)focusState NS_SWIFT_NAME(updateViewForFocusState(_:));

@end
2 changes: 1 addition & 1 deletion include/HubFramework/HUBComponentWithSelectionState.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#import "HUBComponent.h"

/// Enum defining various selection states that a component can be in
typedef NS_ENUM(NSUInteger, HUBComponentSelectionState) {
typedef NS_ENUM(NSInteger, HUBComponentSelectionState) {
/// The component is neither selected or highlighted
HUBComponentSelectionStateNone,
/// The component is currently highlighted through a user interaction
Expand Down
2 changes: 1 addition & 1 deletion include/HubFramework/HUBConnectivityState.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#import <Foundation/Foundation.h>

/// Enum describing various connectivity states that an application can be in
typedef NS_ENUM(NSUInteger, HUBConnectivityState) {
typedef NS_ENUM(NSInteger, HUBConnectivityState) {
/// The application is currently online and connected to the Internet
HUBConnectivityStateOnline,
/// The application is currently offline and not connected to the Internet
Expand Down
1 change: 1 addition & 0 deletions include/HubFramework/HubFramework.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
#import "HUBComponentWithScrolling.h"
#import "HUBComponentWithImageHandling.h"
#import "HUBComponentWithRestorableUIState.h"
#import "HUBComponentWithFocusState.h"
#import "HUBComponentWithSelectionState.h"
#import "HUBComponentContentOffsetObserver.h"
#import "HUBComponentViewObserver.h"
Expand Down
19 changes: 19 additions & 0 deletions sources/HUBComponentGestureRecognizer.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,25 @@ - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
self.state = UIGestureRecognizerStateCancelled;
}

#if TARGET_OS_TV

- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
self.state = UIGestureRecognizerStateBegan;
}

- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
self.state = UIGestureRecognizerStateEnded;
}

- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
{
self.state = UIGestureRecognizerStateCancelled;
}

#endif

@end

NS_ASSUME_NONNULL_END
2 changes: 2 additions & 0 deletions sources/HUBComponentWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#import "HUBComponentActionObserver.h"
#import "HUBComponentWithRestorableUIState.h"
#import "HUBComponentWithSelectionState.h"
#import "HUBComponentWithFocusState.h"
#import "HUBComponentWithScrolling.h"
#import "HUBHeaderMacros.h"

Expand Down Expand Up @@ -137,6 +138,7 @@ willUpdateSelectionState:(HUBComponentSelectionState)selectionState;
HUBComponentContentOffsetObserver,
HUBComponentActionObserver,
HUBComponentWithSelectionState,
HUBComponentWithFocusState,
HUBComponentWithScrolling
>

Expand Down
7 changes: 7 additions & 0 deletions sources/HUBComponentWrapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,13 @@ - (void)updateViewForSelectionState:(HUBComponentSelectionState)selectionState n
}
}

- (void)updateViewForFocusState:(HUBComponentFocusState)focusState
{
if ([self.component conformsToProtocol:@protocol(HUBComponentWithFocusState)]) {
[(id<HUBComponentWithFocusState>)self.component updateViewForFocusState:focusState];
}
}

- (CGRect)calculateViewFrameInWindow
{
UIView * const view = HUBComponentLoadViewIfNeeded(self);
Expand Down
2 changes: 1 addition & 1 deletion sources/HUBDefaultConnectivityStateResolver.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ - (void)dealloc
- (HUBConnectivityState)resolveConnectivityState
{
if (self.connectivityState != nil) {
return [self.connectivityState unsignedIntegerValue];
return [self.connectivityState integerValue];
}

SCNetworkReachabilityFlags reachabilityFlags;
Expand Down
17 changes: 14 additions & 3 deletions sources/HUBUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ static inline NSDictionary<NSString *, id> * _Nullable HUBMergeDictionaries(NSDi
*/
static inline NSArray<NSString *> *HUBNavigationItemPropertyNames()
{
#if TARGET_OS_TV
return @[
HUBKeyPath((UINavigationItem *)nil, title),
HUBKeyPath((UINavigationItem *)nil, titleView),
HUBKeyPath((UINavigationItem *)nil, leftBarButtonItems),
HUBKeyPath((UINavigationItem *)nil, rightBarButtonItems),
];
#else
return @[
HUBKeyPath((UINavigationItem *)nil, title),
HUBKeyPath((UINavigationItem *)nil, titleView),
Expand All @@ -164,6 +172,7 @@ static inline NSArray<NSString *> *HUBNavigationItemPropertyNames()
HUBKeyPath((UINavigationItem *)nil, rightBarButtonItems),
HUBKeyPath((UINavigationItem *)nil, leftItemsSupplementBackButton)
];
#endif
}

/**
Expand Down Expand Up @@ -199,20 +208,22 @@ static inline BOOL HUBNavigationItemEqualToNavigationItem(UINavigationItem *navi
*/
static inline UINavigationItem *HUBCopyNavigationItemProperties(UINavigationItem *navigationItemA, UINavigationItem * _Nullable navigationItemB)
{
#if !TARGET_OS_TV
NSSet<NSString *> * const boolPropertyNames = [NSSet setWithObjects:HUBKeyPath(navigationItemA, hidesBackButton),
HUBKeyPath(navigationItemA, leftItemsSupplementBackButton),
nil];

#endif
for (NSString * const propertyName in HUBNavigationItemPropertyNames()) {
id const value = [navigationItemB valueForKey:propertyName];


#if !TARGET_OS_TV
if (value == nil) {
if ([boolPropertyNames containsObject:propertyName]) {
navigationItemA.hidesBackButton = NO;
continue;
}
}

#endif
[navigationItemA setValue:value forKey:propertyName];
}

Expand Down
Loading