mirror of
https://github.com/tappollo/IGListKit.git
synced 2026-04-28 20:05:01 +08:00
macOS example app
Summary: Related issue: #333 I've made a very simple macOS example app. It's just a list of names which can be searched, shuffled or deleted. I think this is a good starting point for anyone who wants to use this on macOS projects :)  Closes https://github.com/Instagram/IGListKit/pull/337 Reviewed By: rnystrom Differential Revision: D4345236 Pulled By: jessesquires fbshipit-source-id: ce75372263d3f451e34f2c816c14ab6bc82116a7
This commit is contained in:
committed by
Facebook Github Bot
parent
1765d68406
commit
47fbb72fa6
@@ -8,9 +8,14 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
888609091DEF38A00019A4A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 888609081DEF38A00019A4A5 /* AppDelegate.swift */; };
|
||||
8886090B1DEF38A00019A4A5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8886090A1DEF38A00019A4A5 /* ViewController.swift */; };
|
||||
8886090B1DEF38A00019A4A5 /* UsersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8886090A1DEF38A00019A4A5 /* UsersViewController.swift */; };
|
||||
8886090D1DEF38A00019A4A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8886090C1DEF38A00019A4A5 /* Assets.xcassets */; };
|
||||
888609101DEF38A00019A4A5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8886090E1DEF38A00019A4A5 /* Main.storyboard */; };
|
||||
DD9018681E0319E40003789D /* IndexSet+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9018671E0319E40003789D /* IndexSet+Extensions.swift */; };
|
||||
DD90186A1E031A3E0003789D /* Shuffle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9018691E031A3E0003789D /* Shuffle.swift */; };
|
||||
DDE3D8511E030AFA00F96BE4 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE3D8501E030AFA00F96BE4 /* User.swift */; };
|
||||
DDE3D8541E03117600F96BE4 /* users.json in Resources */ = {isa = PBXBuildFile; fileRef = DDE3D8531E03117600F96BE4 /* users.json */; };
|
||||
DDE3D8571E0311D000F96BE4 /* UsersProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE3D8561E0311D000F96BE4 /* UsersProvider.swift */; };
|
||||
E451550281456814F7F659DB /* Pods_IGListKitExamples.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63F1F74ED983018C5D607DDC /* Pods_IGListKitExamples.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -19,11 +24,16 @@
|
||||
63F1F74ED983018C5D607DDC /* Pods_IGListKitExamples.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IGListKitExamples.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
888609051DEF38A00019A4A5 /* IGListKitExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IGListKitExamples.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
888609081DEF38A00019A4A5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
8886090A1DEF38A00019A4A5 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
8886090A1DEF38A00019A4A5 /* UsersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersViewController.swift; sourceTree = "<group>"; };
|
||||
8886090C1DEF38A00019A4A5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
8886090F1DEF38A00019A4A5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
888609111DEF38A00019A4A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C80289D4560E0726CF3F86E0 /* Pods-IGListKitExamples.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IGListKitExamples.debug.xcconfig"; path = "Pods/Target Support Files/Pods-IGListKitExamples/Pods-IGListKitExamples.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
DD9018671E0319E40003789D /* IndexSet+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "IndexSet+Extensions.swift"; sourceTree = "<group>"; };
|
||||
DD9018691E031A3E0003789D /* Shuffle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shuffle.swift; sourceTree = "<group>"; };
|
||||
DDE3D8501E030AFA00F96BE4 /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
|
||||
DDE3D8531E03117600F96BE4 /* users.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = users.json; sourceTree = "<group>"; };
|
||||
DDE3D8561E0311D000F96BE4 /* UsersProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UsersProvider.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -60,10 +70,10 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
888609081DEF38A00019A4A5 /* AppDelegate.swift */,
|
||||
8886090A1DEF38A00019A4A5 /* ViewController.swift */,
|
||||
8886090C1DEF38A00019A4A5 /* Assets.xcassets */,
|
||||
8886090E1DEF38A00019A4A5 /* Main.storyboard */,
|
||||
888609111DEF38A00019A4A5 /* Info.plist */,
|
||||
DDE3D8551E0311AF00F96BE4 /* Helpers */,
|
||||
DDE3D84F1E030A9200F96BE4 /* Resources */,
|
||||
DDE3D84E1E030A8400F96BE4 /* ViewControllers */,
|
||||
DDE3D84D1E030A8000F96BE4 /* Models */,
|
||||
);
|
||||
path = IGListKitExamples;
|
||||
sourceTree = "<group>";
|
||||
@@ -85,6 +95,51 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDE3D84D1E030A8000F96BE4 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDE3D8501E030AFA00F96BE4 /* User.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDE3D84E1E030A8400F96BE4 /* ViewControllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8886090A1DEF38A00019A4A5 /* UsersViewController.swift */,
|
||||
);
|
||||
path = ViewControllers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDE3D84F1E030A9200F96BE4 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDE3D8521E03117600F96BE4 /* Data */,
|
||||
8886090C1DEF38A00019A4A5 /* Assets.xcassets */,
|
||||
8886090E1DEF38A00019A4A5 /* Main.storyboard */,
|
||||
888609111DEF38A00019A4A5 /* Info.plist */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDE3D8521E03117600F96BE4 /* Data */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDE3D8531E03117600F96BE4 /* users.json */,
|
||||
);
|
||||
path = Data;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DDE3D8551E0311AF00F96BE4 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDE3D8561E0311D000F96BE4 /* UsersProvider.swift */,
|
||||
DD9018671E0319E40003789D /* IndexSet+Extensions.swift */,
|
||||
DD9018691E031A3E0003789D /* Shuffle.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -147,6 +202,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DDE3D8541E03117600F96BE4 /* users.json in Resources */,
|
||||
8886090D1DEF38A00019A4A5 /* Assets.xcassets in Resources */,
|
||||
888609101DEF38A00019A4A5 /* Main.storyboard in Resources */,
|
||||
);
|
||||
@@ -207,8 +263,12 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8886090B1DEF38A00019A4A5 /* ViewController.swift in Sources */,
|
||||
8886090B1DEF38A00019A4A5 /* UsersViewController.swift in Sources */,
|
||||
DD90186A1E031A3E0003789D /* Shuffle.swift in Sources */,
|
||||
DD9018681E0319E40003789D /* IndexSet+Extensions.swift in Sources */,
|
||||
888609091DEF38A00019A4A5 /* AppDelegate.swift in Sources */,
|
||||
DDE3D8511E030AFA00F96BE4 /* User.swift in Sources */,
|
||||
DDE3D8571E0311D000F96BE4 /* UsersProvider.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11542"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
<capability name="system font weights other than Regular or Bold" minToolsVersion="7.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Application-->
|
||||
@@ -156,6 +157,9 @@
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
CA
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
|
||||
@@ -658,17 +662,61 @@
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="IGListKitExamples" customModuleProvider="target"/>
|
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="0.0"/>
|
||||
<point key="canvasLocation" x="69" y="-171"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||
<window key="window" title="IGListKit" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
|
||||
<window key="window" title="IGListKit" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="documentWindow" id="IQv-IB-iLA">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||
<rect key="contentRect" x="196" y="240" width="400" height="500"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<value key="minSize" type="size" width="400" height="500"/>
|
||||
<toolbar key="toolbar" implicitIdentifier="5933590F-D75C-4F85-9CF5-9F8C642BEB7E" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconOnly" sizeMode="regular" id="ZU8-VD-rkc">
|
||||
<allowedToolbarItems>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="Iaf-zP-0J1"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="xCW-4o-Rg4"/>
|
||||
<toolbarItem implicitItemIdentifier="81A74327-33AB-469A-B000-7B99E478615F" label="Shuffle" paletteLabel="Shuffle" id="PKy-2S-Bpd">
|
||||
<nil key="toolTip"/>
|
||||
<size key="minSize" width="70" height="28"/>
|
||||
<size key="maxSize" width="82" height="32"/>
|
||||
<button key="view" verticalHuggingPriority="750" id="c7Y-5Y-bmU">
|
||||
<rect key="frame" x="0.0" y="14" width="70" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Shuffle" bezelStyle="texturedRounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="y9Q-xC-51x">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="shuffle:" target="Oky-zY-oP4" id="oSh-Ax-eP3"/>
|
||||
</connections>
|
||||
</button>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="46F37D49-9E53-4757-B306-C940250B5F0B" label="Search" paletteLabel="Search" id="xRY-zQ-Z0U">
|
||||
<nil key="toolTip"/>
|
||||
<size key="minSize" width="96" height="22"/>
|
||||
<size key="maxSize" width="9999" height="22"/>
|
||||
<searchField key="view" wantsLayer="YES" verticalHuggingPriority="750" id="9XO-e1-iaw">
|
||||
<rect key="frame" x="0.0" y="14" width="96" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="N3l-Fs-c7b">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</searchFieldCell>
|
||||
<connections>
|
||||
<action selector="search:" target="Oky-zY-oP4" id="bkb-YO-y0f"/>
|
||||
</connections>
|
||||
</searchField>
|
||||
</toolbarItem>
|
||||
</allowedToolbarItems>
|
||||
<defaultToolbarItems>
|
||||
<toolbarItem reference="xRY-zQ-Z0U"/>
|
||||
<toolbarItem reference="xCW-4o-Rg4"/>
|
||||
<toolbarItem reference="PKy-2S-Bpd"/>
|
||||
</defaultToolbarItems>
|
||||
</toolbar>
|
||||
</window>
|
||||
<connections>
|
||||
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
|
||||
@@ -678,38 +726,97 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="250"/>
|
||||
</scene>
|
||||
<!--View Controller-->
|
||||
<!--Users View Controller-->
|
||||
<scene sceneID="hIz-AP-VOD">
|
||||
<objects>
|
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="IGListKitExamples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="XfG-lQ-9wD" customClass="UsersViewController" customModule="IGListKitExamples" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GGG-55-615">
|
||||
<rect key="frame" x="116" y="126" width="248" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="17" id="Slu-aL-75I"/>
|
||||
<constraint firstAttribute="width" constant="244" id="hxZ-bk-Qa7"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="IGListKit macOS example. Coming soon." id="Gdi-Am-29O">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="50" horizontalPageScroll="10" verticalLineScroll="50" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UBz-hI-v7L">
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="500"/>
|
||||
<clipView key="contentView" id="CKR-qX-FYp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="48" viewBased="YES" id="cZM-LD-xWe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="8" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableViewGridLines key="gridStyleMask" horizontal="YES"/>
|
||||
<color key="gridColor" red="0.97900184037837579" green="0.97900184037837579" blue="0.97900184037837579" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="392" minWidth="40" maxWidth="1000" id="4hL-ap-md6">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="zPV-DN-rja">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView identifier="cell" id="RNW-L9-uKs">
|
||||
<rect key="frame" x="4" y="1" width="392" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField identifier="cell" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="G7m-E1-erw">
|
||||
<rect key="frame" x="0.0" y="15" width="392" height="19"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="5li-Kx-w3N">
|
||||
<font key="font" metaFont="systemLight" size="16"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="G7m-E1-erw" firstAttribute="leading" secondItem="RNW-L9-uKs" secondAttribute="leading" constant="2" id="2Ty-cM-jDM"/>
|
||||
<constraint firstItem="G7m-E1-erw" firstAttribute="centerY" secondItem="RNW-L9-uKs" secondAttribute="centerY" id="OvZ-D7-X77"/>
|
||||
<constraint firstItem="G7m-E1-erw" firstAttribute="centerX" secondItem="RNW-L9-uKs" secondAttribute="centerX" id="dbG-bh-8jt"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="textField" destination="G7m-E1-erw" id="wk2-cP-5N8"/>
|
||||
</connections>
|
||||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="XfG-lQ-9wD" id="EAO-x6-iol"/>
|
||||
<outlet property="delegate" destination="XfG-lQ-9wD" id="vDv-jQ-1x9"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="Etj-vY-BHi">
|
||||
<rect key="frame" x="0.0" y="254" width="400" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="WKs-xk-GPd">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="GGG-55-615" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="118" id="f7P-UT-nA0"/>
|
||||
<constraint firstItem="GGG-55-615" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="127" id="lkn-x9-SgV"/>
|
||||
<constraint firstAttribute="bottom" secondItem="GGG-55-615" secondAttribute="bottom" constant="126" id="r0K-O8-16C"/>
|
||||
<constraint firstAttribute="trailing" secondItem="GGG-55-615" secondAttribute="trailing" constant="118" id="xFP-Dx-Ljf"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UBz-hI-v7L" secondAttribute="trailing" id="SuS-t1-8hF"/>
|
||||
<constraint firstItem="UBz-hI-v7L" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="Suz-Mg-sXx"/>
|
||||
<constraint firstAttribute="bottom" secondItem="UBz-hI-v7L" secondAttribute="bottom" id="dBT-so-LaR"/>
|
||||
<constraint firstItem="UBz-hI-v7L" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="lt2-xn-gAQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="tableView" destination="cZM-LD-xWe" id="fsK-gP-bU1"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="655"/>
|
||||
<point key="canvasLocation" x="75" y="923"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
||||
603
Examples/Examples-macOS/IGListKitExamples/Data/users.json
Normal file
603
Examples/Examples-macOS/IGListKitExamples/Data/users.json
Normal file
@@ -0,0 +1,603 @@
|
||||
[{
|
||||
"name": "AMELIA"
|
||||
},
|
||||
{
|
||||
"name": "OLIVIA"
|
||||
},
|
||||
{
|
||||
"name": "EMILY"
|
||||
},
|
||||
{
|
||||
"name": "AVA"
|
||||
},
|
||||
{
|
||||
"name": "ISLA"
|
||||
},
|
||||
{
|
||||
"name": "JESSICA"
|
||||
},
|
||||
{
|
||||
"name": "POPPY"
|
||||
},
|
||||
{
|
||||
"name": "ISABELLA"
|
||||
},
|
||||
{
|
||||
"name": "SOPHIE"
|
||||
},
|
||||
{
|
||||
"name": "MIA"
|
||||
},
|
||||
{
|
||||
"name": "RUBY"
|
||||
},
|
||||
{
|
||||
"name": "LILY"
|
||||
},
|
||||
{
|
||||
"name": "GRACE"
|
||||
},
|
||||
{
|
||||
"name": "EVIE"
|
||||
},
|
||||
{
|
||||
"name": "SOPHIA"
|
||||
},
|
||||
{
|
||||
"name": "ELLA"
|
||||
},
|
||||
{
|
||||
"name": "SCARLETT"
|
||||
},
|
||||
{
|
||||
"name": "CHLOE"
|
||||
},
|
||||
{
|
||||
"name": "ISABELLE"
|
||||
},
|
||||
{
|
||||
"name": "FREYA"
|
||||
},
|
||||
{
|
||||
"name": "CHARLOTTE"
|
||||
},
|
||||
{
|
||||
"name": "SIENNA"
|
||||
},
|
||||
{
|
||||
"name": "DAISY"
|
||||
},
|
||||
{
|
||||
"name": "PHOEBE"
|
||||
},
|
||||
{
|
||||
"name": "MILLIE"
|
||||
},
|
||||
{
|
||||
"name": "EVA"
|
||||
},
|
||||
{
|
||||
"name": "ALICE"
|
||||
},
|
||||
{
|
||||
"name": "LUCY"
|
||||
},
|
||||
{
|
||||
"name": "FLORENCE"
|
||||
},
|
||||
{
|
||||
"name": "SOFIA"
|
||||
},
|
||||
{
|
||||
"name": "LAYLA"
|
||||
},
|
||||
{
|
||||
"name": "LOLA"
|
||||
},
|
||||
{
|
||||
"name": "HOLLY"
|
||||
},
|
||||
{
|
||||
"name": "IMOGEN"
|
||||
},
|
||||
{
|
||||
"name": "MOLLY"
|
||||
},
|
||||
{
|
||||
"name": "MATILDA"
|
||||
},
|
||||
{
|
||||
"name": "LILLY"
|
||||
},
|
||||
{
|
||||
"name": "ROSIE"
|
||||
},
|
||||
{
|
||||
"name": "ELIZABETH"
|
||||
},
|
||||
{
|
||||
"name": "ERIN"
|
||||
},
|
||||
{
|
||||
"name": "MAISIE"
|
||||
},
|
||||
{
|
||||
"name": "LEXI"
|
||||
},
|
||||
{
|
||||
"name": "ELLIE"
|
||||
},
|
||||
{
|
||||
"name": "HANNAH"
|
||||
},
|
||||
{
|
||||
"name": "EVELYN"
|
||||
},
|
||||
{
|
||||
"name": "ABIGAIL"
|
||||
},
|
||||
{
|
||||
"name": "ELSIE"
|
||||
},
|
||||
{
|
||||
"name": "SUMMER"
|
||||
},
|
||||
{
|
||||
"name": "MEGAN"
|
||||
},
|
||||
{
|
||||
"name": "JASMINE"
|
||||
},
|
||||
{
|
||||
"name": "MAYA"
|
||||
},
|
||||
{
|
||||
"name": "AMELIE"
|
||||
},
|
||||
{
|
||||
"name": "LACEY"
|
||||
},
|
||||
{
|
||||
"name": "WILLOW"
|
||||
},
|
||||
{
|
||||
"name": "EMMA"
|
||||
},
|
||||
{
|
||||
"name": "BELLA"
|
||||
},
|
||||
{
|
||||
"name": "ELEANOR"
|
||||
},
|
||||
{
|
||||
"name": "ESME"
|
||||
},
|
||||
{
|
||||
"name": "ELIZA"
|
||||
},
|
||||
{
|
||||
"name": "GEORGIA"
|
||||
},
|
||||
{
|
||||
"name": "HARRIET"
|
||||
},
|
||||
{
|
||||
"name": "GRACIE"
|
||||
},
|
||||
{
|
||||
"name": "ANNABELLE"
|
||||
},
|
||||
{
|
||||
"name": "EMILIA"
|
||||
},
|
||||
{
|
||||
"name": "AMBER"
|
||||
},
|
||||
{
|
||||
"name": "IVY"
|
||||
},
|
||||
{
|
||||
"name": "BROOKE"
|
||||
},
|
||||
{
|
||||
"name": "ROSE"
|
||||
},
|
||||
{
|
||||
"name": "ANNA"
|
||||
},
|
||||
{
|
||||
"name": "ZARA"
|
||||
},
|
||||
{
|
||||
"name": "LEAH"
|
||||
},
|
||||
{
|
||||
"name": "MOLLIE"
|
||||
},
|
||||
{
|
||||
"name": "MARTHA"
|
||||
},
|
||||
{
|
||||
"name": "FAITH"
|
||||
},
|
||||
{
|
||||
"name": "HOLLIE"
|
||||
},
|
||||
{
|
||||
"name": "AMY"
|
||||
},
|
||||
{
|
||||
"name": "BETHANY"
|
||||
},
|
||||
{
|
||||
"name": "VIOLET"
|
||||
},
|
||||
{
|
||||
"name": "KATIE"
|
||||
},
|
||||
{
|
||||
"name": "MARYAM"
|
||||
},
|
||||
{
|
||||
"name": "FRANCESCA"
|
||||
},
|
||||
{
|
||||
"name": "JULIA"
|
||||
},
|
||||
{
|
||||
"name": "MARIA"
|
||||
},
|
||||
{
|
||||
"name": "DARCEY"
|
||||
},
|
||||
{
|
||||
"name": "ISABEL"
|
||||
},
|
||||
{
|
||||
"name": "TILLY"
|
||||
},
|
||||
{
|
||||
"name": "MADDISON"
|
||||
},
|
||||
{
|
||||
"name": "VICTORIA"
|
||||
},
|
||||
{
|
||||
"name": "ISOBEL"
|
||||
},
|
||||
{
|
||||
"name": "NIAMH"
|
||||
},
|
||||
{
|
||||
"name": "SKYE"
|
||||
},
|
||||
{
|
||||
"name": "MADISON"
|
||||
},
|
||||
{
|
||||
"name": "DARCY"
|
||||
},
|
||||
{
|
||||
"name": "AISHA"
|
||||
},
|
||||
{
|
||||
"name": "BEATRICE"
|
||||
},
|
||||
{
|
||||
"name": "SARAH"
|
||||
},
|
||||
{
|
||||
"name": "ZOE"
|
||||
},
|
||||
{
|
||||
"name": "PAIGE"
|
||||
},
|
||||
{
|
||||
"name": "HEIDI"
|
||||
},
|
||||
{
|
||||
"name": "LYDIA"
|
||||
},
|
||||
{
|
||||
"name": "SARA"
|
||||
},
|
||||
{
|
||||
"name": "OLIVER"
|
||||
},
|
||||
{
|
||||
"name": "JACK"
|
||||
},
|
||||
{
|
||||
"name": "HARRY"
|
||||
},
|
||||
{
|
||||
"name": "JACOB"
|
||||
},
|
||||
{
|
||||
"name": "CHARLIE"
|
||||
},
|
||||
{
|
||||
"name": "THOMAS"
|
||||
},
|
||||
{
|
||||
"name": "OSCAR"
|
||||
},
|
||||
{
|
||||
"name": "WILLIAM"
|
||||
},
|
||||
{
|
||||
"name": "JAMES"
|
||||
},
|
||||
{
|
||||
"name": "GEORGE"
|
||||
},
|
||||
{
|
||||
"name": "ALFIE"
|
||||
},
|
||||
{
|
||||
"name": "JOSHUA"
|
||||
},
|
||||
{
|
||||
"name": "NOAH"
|
||||
},
|
||||
{
|
||||
"name": "ETHAN"
|
||||
},
|
||||
{
|
||||
"name": "MUHAMMAD"
|
||||
},
|
||||
{
|
||||
"name": "ARCHIE"
|
||||
},
|
||||
{
|
||||
"name": "LEO"
|
||||
},
|
||||
{
|
||||
"name": "HENRY"
|
||||
},
|
||||
{
|
||||
"name": "JOSEPH"
|
||||
},
|
||||
{
|
||||
"name": "SAMUEL"
|
||||
},
|
||||
{
|
||||
"name": "RILEY"
|
||||
},
|
||||
{
|
||||
"name": "DANIEL"
|
||||
},
|
||||
{
|
||||
"name": "MOHAMMED"
|
||||
},
|
||||
{
|
||||
"name": "ALEXANDER"
|
||||
},
|
||||
{
|
||||
"name": "MAX"
|
||||
},
|
||||
{
|
||||
"name": "LUCAS"
|
||||
},
|
||||
{
|
||||
"name": "MASON"
|
||||
},
|
||||
{
|
||||
"name": "LOGAN"
|
||||
},
|
||||
{
|
||||
"name": "ISAAC"
|
||||
},
|
||||
{
|
||||
"name": "BENJAMIN"
|
||||
},
|
||||
{
|
||||
"name": "DYLAN"
|
||||
},
|
||||
{
|
||||
"name": "JAKE"
|
||||
},
|
||||
{
|
||||
"name": "EDWARD"
|
||||
},
|
||||
{
|
||||
"name": "FINLEY"
|
||||
},
|
||||
{
|
||||
"name": "FREDDIE"
|
||||
},
|
||||
{
|
||||
"name": "HARRISON"
|
||||
},
|
||||
{
|
||||
"name": "TYLER"
|
||||
},
|
||||
{
|
||||
"name": "SEBASTIAN"
|
||||
},
|
||||
{
|
||||
"name": "ZACHARY"
|
||||
},
|
||||
{
|
||||
"name": "ADAM"
|
||||
},
|
||||
{
|
||||
"name": "THEO"
|
||||
},
|
||||
{
|
||||
"name": "JAYDEN"
|
||||
},
|
||||
{
|
||||
"name": "ARTHUR"
|
||||
},
|
||||
{
|
||||
"name": "TOBY"
|
||||
},
|
||||
{
|
||||
"name": "LUKE"
|
||||
},
|
||||
{
|
||||
"name": "LEWIS"
|
||||
},
|
||||
{
|
||||
"name": "MATTHEW"
|
||||
},
|
||||
{
|
||||
"name": "HARVEY"
|
||||
},
|
||||
{
|
||||
"name": "HARLEY"
|
||||
},
|
||||
{
|
||||
"name": "DAVID"
|
||||
},
|
||||
{
|
||||
"name": "RYAN"
|
||||
},
|
||||
{
|
||||
"name": "TOMMY"
|
||||
},
|
||||
{
|
||||
"name": "MICHAEL"
|
||||
},
|
||||
{
|
||||
"name": "REUBEN"
|
||||
},
|
||||
{
|
||||
"name": "NATHAN"
|
||||
},
|
||||
{
|
||||
"name": "BLAKE"
|
||||
},
|
||||
{
|
||||
"name": "MOHAMMAD"
|
||||
},
|
||||
{
|
||||
"name": "JENSON"
|
||||
},
|
||||
{
|
||||
"name": "BOBBY"
|
||||
},
|
||||
{
|
||||
"name": "LUCA"
|
||||
},
|
||||
{
|
||||
"name": "CHARLES"
|
||||
},
|
||||
{
|
||||
"name": "FRANKIE"
|
||||
},
|
||||
{
|
||||
"name": "DEXTER"
|
||||
},
|
||||
{
|
||||
"name": "KAI"
|
||||
},
|
||||
{
|
||||
"name": "ALEX"
|
||||
},
|
||||
{
|
||||
"name": "CONNOR"
|
||||
},
|
||||
{
|
||||
"name": "LIAM"
|
||||
},
|
||||
{
|
||||
"name": "JAMIE"
|
||||
},
|
||||
{
|
||||
"name": "ELIJAH"
|
||||
},
|
||||
{
|
||||
"name": "STANLEY"
|
||||
},
|
||||
{
|
||||
"name": "LOUIE"
|
||||
},
|
||||
{
|
||||
"name": "JUDE"
|
||||
},
|
||||
{
|
||||
"name": "CALLUM"
|
||||
},
|
||||
{
|
||||
"name": "HUGO"
|
||||
},
|
||||
{
|
||||
"name": "LEON"
|
||||
},
|
||||
{
|
||||
"name": "ELLIOT"
|
||||
},
|
||||
{
|
||||
"name": "LOUIS"
|
||||
},
|
||||
{
|
||||
"name": "THEODORE"
|
||||
},
|
||||
{
|
||||
"name": "GABRIEL"
|
||||
},
|
||||
{
|
||||
"name": "OLLIE"
|
||||
},
|
||||
{
|
||||
"name": "AARON"
|
||||
},
|
||||
{
|
||||
"name": "FREDERICK"
|
||||
},
|
||||
{
|
||||
"name": "EVAN"
|
||||
},
|
||||
{
|
||||
"name": "ELLIOTT"
|
||||
},
|
||||
{
|
||||
"name": "OWEN"
|
||||
},
|
||||
{
|
||||
"name": "TEDDY"
|
||||
},
|
||||
{
|
||||
"name": "FINLAY"
|
||||
},
|
||||
{
|
||||
"name": "CALEB"
|
||||
},
|
||||
{
|
||||
"name": "IBRAHIM"
|
||||
},
|
||||
{
|
||||
"name": "RONNIE"
|
||||
},
|
||||
{
|
||||
"name": "FELIX"
|
||||
},
|
||||
{
|
||||
"name": "AIDEN"
|
||||
},
|
||||
{
|
||||
"name": "CAMERON"
|
||||
},
|
||||
{
|
||||
"name": "AUSTIN"
|
||||
},
|
||||
{
|
||||
"name": "KIAN"
|
||||
},
|
||||
{
|
||||
"name": "RORY"
|
||||
},
|
||||
{
|
||||
"name": "SETH"
|
||||
},
|
||||
{
|
||||
"name": "ROBERT"
|
||||
},
|
||||
{
|
||||
"name": "ALBERT"
|
||||
},
|
||||
{
|
||||
"name": "SONNY"
|
||||
}]
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
@@ -12,19 +12,12 @@
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Cocoa
|
||||
import IGListKit
|
||||
import Foundation
|
||||
|
||||
final class ViewController: NSViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
override var representedObject: Any? {
|
||||
didSet {
|
||||
// Update the view, if already loaded.
|
||||
}
|
||||
extension IndexSet {
|
||||
|
||||
static var zero: IndexSet {
|
||||
return NSIndexSet(index: 0) as IndexSet
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
extension MutableCollection where Indices.Iterator.Element == Index {
|
||||
|
||||
/// Shuffles the contents of this collection.
|
||||
mutating func shuffle() {
|
||||
let c = count
|
||||
guard c > 1 else { return }
|
||||
|
||||
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
|
||||
let d: IndexDistance = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
|
||||
guard d != 0 else { continue }
|
||||
|
||||
let i = index(firstUnshuffled, offsetBy: d)
|
||||
|
||||
swap(&self[firstUnshuffled], &self[i])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Sequence {
|
||||
|
||||
/// Returns an array with the contents of this sequence, shuffled.
|
||||
var shuffled: [Iterator.Element] {
|
||||
var result = Array(self)
|
||||
result.shuffle()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
final class UsersProvider {
|
||||
|
||||
enum UsersError: Error {
|
||||
case invalidData
|
||||
}
|
||||
|
||||
let users: [User]
|
||||
|
||||
init(with file: URL) throws {
|
||||
let data = try Data(contentsOf: file)
|
||||
let json = try JSONSerialization.jsonObject(with: data, options: [])
|
||||
|
||||
guard let dicts = json as? [[String: String]] else {
|
||||
throw UsersError.invalidData
|
||||
}
|
||||
|
||||
self.users = dicts.enumerated().flatMap { index, dict in
|
||||
guard let name = dict["name"] else { return nil }
|
||||
|
||||
return User(pk: index, name: name.capitalized)
|
||||
}.sorted(by: { $0.name < $1.name })
|
||||
}
|
||||
|
||||
}
|
||||
40
Examples/Examples-macOS/IGListKitExamples/Models/User.swift
Normal file
40
Examples/Examples-macOS/IGListKitExamples/Models/User.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import IGListKit
|
||||
|
||||
final class User: IGListDiffable {
|
||||
|
||||
let pk: Int
|
||||
let name: String
|
||||
|
||||
init(pk: Int, name: String) {
|
||||
self.pk = pk
|
||||
self.name = name
|
||||
}
|
||||
|
||||
//MARK: IGListDiffable
|
||||
|
||||
func diffIdentifier() -> NSObjectProtocol {
|
||||
return pk as NSObjectProtocol
|
||||
}
|
||||
|
||||
func isEqual(toDiffableObject object: IGListDiffable?) -> Bool {
|
||||
guard self !== object else { return true }
|
||||
guard let object = object as? User else { return false }
|
||||
return name == object.name
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import Cocoa
|
||||
import IGListKit
|
||||
|
||||
final class UsersViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var tableView: NSTableView!
|
||||
|
||||
//MARK: Data
|
||||
|
||||
var users = [User]() {
|
||||
didSet {
|
||||
computeFilteredUsers()
|
||||
}
|
||||
}
|
||||
|
||||
var searchTerm = "" {
|
||||
didSet {
|
||||
computeFilteredUsers()
|
||||
}
|
||||
}
|
||||
|
||||
private func computeFilteredUsers() {
|
||||
guard searchTerm.characters.count > 1 else {
|
||||
filteredUsers = users
|
||||
return
|
||||
}
|
||||
|
||||
filteredUsers = users.filter({ $0.name.localizedCaseInsensitiveContains(self.searchTerm) })
|
||||
}
|
||||
|
||||
fileprivate func delete(user: User) {
|
||||
guard let index = self.users.index(where: { $0.pk == user.pk }) else { return }
|
||||
|
||||
self.users.remove(at: index)
|
||||
}
|
||||
|
||||
//MARK: -
|
||||
//MARK: Diffing
|
||||
|
||||
var filteredUsers = [User]() {
|
||||
didSet {
|
||||
// get the difference between the old array of Users and the new array of Users
|
||||
let diff = IGListDiff(oldValue, filteredUsers, .equality)
|
||||
|
||||
// this difference is used here to update the table view, but it can be used
|
||||
// to update collection views and other similar interface elements
|
||||
// this code can also be added to an extension of NSTableView ;)
|
||||
tableView.beginUpdates()
|
||||
tableView.insertRows(at: diff.inserts, withAnimation: .slideDown)
|
||||
tableView.removeRows(at: diff.deletes, withAnimation: .slideUp)
|
||||
tableView.reloadData(forRowIndexes: diff.updates, columnIndexes: .zero)
|
||||
diff.moves.forEach { move in
|
||||
self.tableView.moveRow(at: move.from, to: move.to)
|
||||
}
|
||||
tableView.endUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -
|
||||
|
||||
private func loadSampleUsers() {
|
||||
guard let file = Bundle.main.url(forResource: "users", withExtension: "json") else { return }
|
||||
|
||||
do {
|
||||
self.users = try UsersProvider(with: file).users
|
||||
} catch {
|
||||
NSAlert(error: error).runModal()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Interface
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
loadSampleUsers()
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
|
||||
view.window?.titleVisibility = .hidden
|
||||
}
|
||||
|
||||
@IBAction func shuffle(_ sender: Any?) {
|
||||
users = users.shuffled
|
||||
}
|
||||
|
||||
@IBAction func search(_ sender: NSSearchField) {
|
||||
searchTerm = sender.stringValue
|
||||
}
|
||||
|
||||
@IBAction func delete(_ sender: Any?) {
|
||||
guard tableView.selectedRowIndexes.count > 0 else { return }
|
||||
|
||||
tableView.selectedRowIndexes.forEach({ self.delete(user: self.filteredUsers[$0]) })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UsersViewController: NSTableViewDataSource {
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return filteredUsers.count
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UsersViewController: NSTableViewDelegate {
|
||||
|
||||
private struct Storyboard {
|
||||
static let cellIdentifier = "cell"
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
guard let cell = tableView.make(withIdentifier: Storyboard.cellIdentifier, owner: tableView) as? NSTableCellView else {
|
||||
return nil
|
||||
}
|
||||
|
||||
cell.textField?.stringValue = filteredUsers[row].name
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge: NSTableRowActionEdge) -> [NSTableViewRowAction] {
|
||||
let delete = NSTableViewRowAction(style: .destructive, title: "Delete") { action, row in
|
||||
guard row < self.filteredUsers.count else { return }
|
||||
|
||||
self.delete(user: self.filteredUsers[row])
|
||||
}
|
||||
|
||||
return [delete]
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user