├── .gitignore ├── DefaultIcon-ios.png ├── DefaultIcon.png ├── LICENSE ├── README.md ├── app ├── alloy.jmk ├── alloy.js ├── assets │ ├── android │ │ ├── appicon.png │ │ └── images │ │ │ ├── launcher.png │ │ │ └── logo.png │ └── iphone │ │ ├── LaunchLogo@2x~ipad.png │ │ ├── LaunchLogo@2x~iphone.png │ │ ├── LaunchLogo@3x~iphone.png │ │ ├── LaunchLogo~ipad.png │ │ ├── LaunchLogo~iphone.png │ │ └── images │ │ ├── tabIcon.png │ │ ├── tabIcon@2x.png │ │ └── tabIcon@3x.png ├── config.json ├── controllers │ ├── android │ │ ├── keyboard.js │ │ ├── launcher.js │ │ ├── streetview.js │ │ ├── tableview.js │ │ ├── transitions.js │ │ ├── transitions_a.js │ │ └── transitions_b.js │ ├── console.js │ ├── index.js │ ├── ios │ │ ├── appshortcuts.js │ │ ├── keyboard.js │ │ ├── listview.js │ │ ├── livephoto.js │ │ ├── menupopup.js │ │ ├── popover.js │ │ ├── scrollview.js │ │ ├── touch.js │ │ └── watchos.js │ └── tab.js ├── lib │ └── log.js ├── platform │ ├── android │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ ├── appicon.png │ │ │ └── background.9.png │ │ │ ├── drawable-mdpi │ │ │ ├── appicon.png │ │ │ └── background.9.png │ │ │ ├── drawable-xhdpi │ │ │ ├── appicon.png │ │ │ └── background.9.png │ │ │ ├── drawable-xxhdpi │ │ │ ├── appicon.png │ │ │ └── background.9.png │ │ │ └── values │ │ │ └── custom_theme.xml │ └── ios │ │ └── _LaunchScreen.storyboard ├── styles │ ├── android │ │ ├── keyboard.tss │ │ ├── streetview.tss │ │ ├── transitions_a.tss │ │ └── transitions_b.tss │ ├── app.tss │ ├── console.tss │ ├── index.tss │ ├── ios │ │ ├── listview.tss │ │ ├── livephoto.tss │ │ ├── progressbar.tss │ │ ├── touch.tss │ │ └── window.tss │ └── tab.tss └── views │ ├── android │ ├── keyboard.xml │ ├── launcher.xml │ ├── streetview.xml │ ├── tableview.xml │ ├── transitions.xml │ ├── transitions_a.xml │ └── transitions_b.xml │ ├── console.xml │ ├── index.xml │ ├── ios │ ├── appshortcuts.xml │ ├── keyboard.xml │ ├── listview.xml │ ├── livephoto.xml │ ├── menupopup.xml │ ├── popover.xml │ ├── progressbar.xml │ ├── scrollview.xml │ ├── touch.xml │ ├── watchos.xml │ └── window.xml │ └── tab.xml ├── docs ├── android.md ├── assets │ ├── avd.png │ ├── image.png │ ├── insertion.png │ ├── ipadpro.png │ ├── launch-builtin.png │ ├── launch-custom.png │ ├── menupopup.png │ ├── module.png │ ├── screenshots.png │ ├── simpholders.png │ ├── splitview.png │ ├── streetview.png │ ├── tab.png │ └── transitions.png ├── ios.md ├── launchfiles.md ├── livephotos.md ├── streetview.md └── transitions.md ├── extensions └── Ti 5.2.0 │ ├── Ti 5.2.0 WatchKit App │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-24@2x.png │ │ │ ├── icon-27.5@2x.png │ │ │ ├── icon-29@2x.png │ │ │ ├── icon-29@3x.png │ │ │ ├── icon-40@2x.png │ │ │ ├── icon-44@2x.png │ │ │ ├── icon-86@2x.png │ │ │ └── icon-98@2x.png │ ├── Base.lproj │ │ └── Interface.storyboard │ └── Info.plist │ ├── Ti 5.2.0 WatchKit Extension │ ├── Assets.xcassets │ │ └── README__ignoredByTemplate__ │ ├── ExtensionDelegate.h │ ├── ExtensionDelegate.m │ ├── Info.plist │ ├── InterfaceController.h │ ├── InterfaceController.m │ ├── NotificationController.h │ ├── NotificationController.m │ └── PushNotificationPayload.apns │ └── Ti 5.2.0.xcodeproj │ └── project.pbxproj ├── platform └── ios │ └── _LaunchScreen.storyboard ├── plugins ├── ti.alloy │ ├── hooks │ │ ├── alloy.js │ │ └── deepclean.js │ └── plugin.py └── ti.version │ └── 1.0 │ └── hooks │ └── version.js └── tiapp.xml /.gitignore: -------------------------------------------------------------------------------- 1 | _assets 2 | .DS_Store 3 | Resources 4 | build.log 5 | build 6 | npm-debug.log 7 | tmp 8 | .map 9 | .project 10 | .settings 11 | Thumbs.db 12 | extensions/Ti 5.2.0/Ti 5.2.0.xcodeproj/xcuserdata 13 | extensions/Ti 5.2.0/Ti 5.2.0.xcodeproj/project.xcworkspace 14 | NOTES.md 15 | /platform 16 | /i18n 17 | -------------------------------------------------------------------------------- /DefaultIcon-ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/DefaultIcon-ios.png -------------------------------------------------------------------------------- /DefaultIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/DefaultIcon.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Appcelerator, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | (or the full text of the license is below) 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | 18 | 19 | Apache License 20 | Version 2.0, January 2004 21 | http://www.apache.org/licenses/ 22 | 23 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 24 | 25 | 1. Definitions. 26 | 27 | "License" shall mean the terms and conditions for use, reproduction, 28 | and distribution as defined by Sections 1 through 9 of this document. 29 | 30 | "Licensor" shall mean the copyright owner or entity authorized by 31 | the copyright owner that is granting the License. 32 | 33 | "Legal Entity" shall mean the union of the acting entity and all 34 | other entities that control, are controlled by, or are under common 35 | control with that entity. For the purposes of this definition, 36 | "control" means (i) the power, direct or indirect, to cause the 37 | direction or management of such entity, whether by contract or 38 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 39 | outstanding shares, or (iii) beneficial ownership of such entity. 40 | 41 | "You" (or "Your") shall mean an individual or Legal Entity 42 | exercising permissions granted by this License. 43 | 44 | "Source" form shall mean the preferred form for making modifications, 45 | including but not limited to software source code, documentation 46 | source, and configuration files. 47 | 48 | "Object" form shall mean any form resulting from mechanical 49 | transformation or translation of a Source form, including but 50 | not limited to compiled object code, generated documentation, 51 | and conversions to other media types. 52 | 53 | "Work" shall mean the work of authorship, whether in Source or 54 | Object form, made available under the License, as indicated by a 55 | copyright notice that is included in or attached to the work 56 | (an example is provided in the Appendix below). 57 | 58 | "Derivative Works" shall mean any work, whether in Source or Object 59 | form, that is based on (or derived from) the Work and for which the 60 | editorial revisions, annotations, elaborations, or other modifications 61 | represent, as a whole, an original work of authorship. For the purposes 62 | of this License, Derivative Works shall not include works that remain 63 | separable from, or merely link (or bind by name) to the interfaces of, 64 | the Work and Derivative Works thereof. 65 | 66 | "Contribution" shall mean any work of authorship, including 67 | the original version of the Work and any modifications or additions 68 | to that Work or Derivative Works thereof, that is intentionally 69 | submitted to Licensor for inclusion in the Work by the copyright owner 70 | or by an individual or Legal Entity authorized to submit on behalf of 71 | the copyright owner. For the purposes of this definition, "submitted" 72 | means any form of electronic, verbal, or written communication sent 73 | to the Licensor or its representatives, including but not limited to 74 | communication on electronic mailing lists, source code control systems, 75 | and issue tracking systems that are managed by, or on behalf of, the 76 | Licensor for the purpose of discussing and improving the Work, but 77 | excluding communication that is conspicuously marked or otherwise 78 | designated in writing by the copyright owner as "Not a Contribution." 79 | 80 | "Contributor" shall mean Licensor and any individual or Legal Entity 81 | on behalf of whom a Contribution has been received by Licensor and 82 | subsequently incorporated within the Work. 83 | 84 | 2. Grant of Copyright License. Subject to the terms and conditions of 85 | this License, each Contributor hereby grants to You a perpetual, 86 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 87 | copyright license to reproduce, prepare Derivative Works of, 88 | publicly display, publicly perform, sublicense, and distribute the 89 | Work and such Derivative Works in Source or Object form. 90 | 91 | 3. Grant of Patent License. Subject to the terms and conditions of 92 | this License, each Contributor hereby grants to You a perpetual, 93 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 94 | (except as stated in this section) patent license to make, have made, 95 | use, offer to sell, sell, import, and otherwise transfer the Work, 96 | where such license applies only to those patent claims licensable 97 | by such Contributor that are necessarily infringed by their 98 | Contribution(s) alone or by combination of their Contribution(s) 99 | with the Work to which such Contribution(s) was submitted. If You 100 | institute patent litigation against any entity (including a 101 | cross-claim or counterclaim in a lawsuit) alleging that the Work 102 | or a Contribution incorporated within the Work constitutes direct 103 | or contributory patent infringement, then any patent licenses 104 | granted to You under this License for that Work shall terminate 105 | as of the date such litigation is filed. 106 | 107 | 4. Redistribution. You may reproduce and distribute copies of the 108 | Work or Derivative Works thereof in any medium, with or without 109 | modifications, and in Source or Object form, provided that You 110 | meet the following conditions: 111 | 112 | (a) You must give any other recipients of the Work or 113 | Derivative Works a copy of this License; and 114 | 115 | (b) You must cause any modified files to carry prominent notices 116 | stating that You changed the files; and 117 | 118 | (c) You must retain, in the Source form of any Derivative Works 119 | that You distribute, all copyright, patent, trademark, and 120 | attribution notices from the Source form of the Work, 121 | excluding those notices that do not pertain to any part of 122 | the Derivative Works; and 123 | 124 | (d) If the Work includes a "NOTICE" text file as part of its 125 | distribution, then any Derivative Works that You distribute must 126 | include a readable copy of the attribution notices contained 127 | within such NOTICE file, excluding those notices that do not 128 | pertain to any part of the Derivative Works, in at least one 129 | of the following places: within a NOTICE text file distributed 130 | as part of the Derivative Works; within the Source form or 131 | documentation, if provided along with the Derivative Works; or, 132 | within a display generated by the Derivative Works, if and 133 | wherever such third-party notices normally appear. The contents 134 | of the NOTICE file are for informational purposes only and 135 | do not modify the License. You may add Your own attribution 136 | notices within Derivative Works that You distribute, alongside 137 | or as an addendum to the NOTICE text from the Work, provided 138 | that such additional attribution notices cannot be construed 139 | as modifying the License. 140 | 141 | You may add Your own copyright statement to Your modifications and 142 | may provide additional or different license terms and conditions 143 | for use, reproduction, or distribution of Your modifications, or 144 | for any such Derivative Works as a whole, provided Your use, 145 | reproduction, and distribution of the Work otherwise complies with 146 | the conditions stated in this License. 147 | 148 | 5. Submission of Contributions. Unless You explicitly state otherwise, 149 | any Contribution intentionally submitted for inclusion in the Work 150 | by You to the Licensor shall be under the terms and conditions of 151 | this License, without any additional terms or conditions. 152 | Notwithstanding the above, nothing herein shall supersede or modify 153 | the terms of any separate license agreement you may have executed 154 | with Licensor regarding such Contributions. 155 | 156 | 6. Trademarks. This License does not grant permission to use the trade 157 | names, trademarks, service marks, or product names of the Licensor, 158 | except as required for reasonable and customary use in describing the 159 | origin of the Work and reproducing the content of the NOTICE file. 160 | 161 | 7. Disclaimer of Warranty. Unless required by applicable law or 162 | agreed to in writing, Licensor provides the Work (and each 163 | Contributor provides its Contributions) on an "AS IS" BASIS, 164 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 165 | implied, including, without limitation, any warranties or conditions 166 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 167 | PARTICULAR PURPOSE. You are solely responsible for determining the 168 | appropriateness of using or redistributing the Work and assume any 169 | risks associated with Your exercise of permissions under this License. 170 | 171 | 8. Limitation of Liability. In no event and under no legal theory, 172 | whether in tort (including negligence), contract, or otherwise, 173 | unless required by applicable law (such as deliberate and grossly 174 | negligent acts) or agreed to in writing, shall any Contributor be 175 | liable to You for damages, including any direct, indirect, special, 176 | incidental, or consequential damages of any character arising as a 177 | result of this License or out of the use or inability to use the 178 | Work (including but not limited to damages for loss of goodwill, 179 | work stoppage, computer failure or malfunction, or any and all 180 | other commercial damages or losses), even if such Contributor 181 | has been advised of the possibility of such damages. 182 | 183 | 9. Accepting Warranty or Additional Liability. While redistributing 184 | the Work or Derivative Works thereof, You may choose to offer, 185 | and charge a fee for, acceptance of support, warranty, indemnity, 186 | or other liability obligations and/or rights consistent with this 187 | License. However, in accepting such obligations, You may act only 188 | on Your own behalf and on Your sole responsibility, not on behalf 189 | of any other Contributor, and only if You agree to indemnify, 190 | defend, and hold each Contributor harmless for any liability 191 | incurred by, or claims asserted against, such Contributor by reason 192 | of your accepting any such warranty or additional liability. 193 | 194 | END OF TERMS AND CONDITIONS 195 | 196 | APPENDIX: How to apply the Apache License to your work. 197 | 198 | To apply the Apache License to your work, attach the following 199 | boilerplate notice, with the fields enclosed by brackets "[]" 200 | replaced with your own identifying information. (Don't include 201 | the brackets!) The text should be enclosed in the appropriate 202 | comment syntax for the file format. We also recommend that a 203 | file or class name and description of purpose be included on the 204 | same "printed page" as the copyright notice for easier 205 | identification within third-party archives. 206 | 207 | Copyright [yyyy] [name of copyright owner] 208 | 209 | Licensed under the Apache License, Version 2.0 (the "License"); 210 | you may not use this file except in compliance with the License. 211 | You may obtain a copy of the License at 212 | 213 | http://www.apache.org/licenses/LICENSE-2.0 214 | 215 | Unless required by applicable law or agreed to in writing, software 216 | distributed under the License is distributed on an "AS IS" BASIS, 217 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 218 | See the License for the specific language governing permissions and 219 | limitations under the License. 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0 Sample App 2 | 3 | > **NOTE:** This Sample App requires Titanium >=5.2.2<5.3 and Alloy >=1.8.5 (part of AppC CLI >=5.2.2). It supports Android 4.x and iOS 9.x. Some examples might be restricted to specific platforms or devices. 4 | 5 | ![screenshots](docs/assets/screenshots.png) 6 | 7 | For more information on Titanium 5.2.0 see the [official announcement](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/), which also links the release notes and full list of closed tickets. 8 | 9 | ## Walkthroughs 10 | 11 | The examples and code itself should be fairly self explanatory, but we've published detailed walkthroughs on some of the main features: 12 | 13 | * [Launch Files, iPad Pro, Slide Over and Split View](docs/launchfiles.md) 14 | * [Live Photos](docs/livephotos.md) 15 | * [Google Street View Panorama](docs/streetview.md) 16 | * [Android Activity & Shared Element Transitions](docs/transitions.md) 17 | * [Wrap-up for iOS](docs/ios.md) 18 | * [Wrap-up for Android](docs/android.md) 19 | 20 | ## Running the Sample 21 | 22 | ### Via Appcelerator Studio 23 | 24 | 1. Import it via *Dashboard* if available. 25 | 2. Or import it via *File > Import... > Git > Git Repository as New Project* with *URI*: 26 | 27 | https://github.com/appcelerator-developer-relations/appc-sample-ti520 28 | 29 | 3. Select a Simulator or Device to build to via *Run > Run As*. 30 | 31 | ### Via CLI 32 | 33 | 1. Clone the repository: 34 | 35 | git clone https://github.com/appcelerator-developer-relations/appc-sample-ti520 36 | 37 | 2. To run it with `appc run` first import it to the platform: 38 | 39 | appc new --import --no-services 40 | 41 | 3. Build to Simulator or Device: 42 | 43 | [appc run | ti build] -p ios [-T device] 44 | -------------------------------------------------------------------------------- /app/alloy.jmk: -------------------------------------------------------------------------------- 1 | task('pre:load', function(event, logger) { 2 | 3 | if (event.minVersion) { 4 | var pkg = require(require('path').join(process.mainModule.filename, '..', '..', 'package.json')); 5 | 6 | if (versionStringToInt(pkg.version) < versionStringToInt(event.minVersion)) { 7 | logger.error('This app requires Alloy ' + event.minVersion + ' or later instead of ' + pkg.version); 8 | process.exit(1); 9 | } 10 | } 11 | }); 12 | 13 | function versionStringToInt(versionStr) { 14 | return versionStr.split(/[^0-9]+/).reverse().reduce(function(previousValue, currentValue, currentIndex) { 15 | return previousValue + Math.pow(100, currentIndex) * parseInt(currentValue, 10); 16 | }, 0); 17 | } 18 | -------------------------------------------------------------------------------- /app/alloy.js: -------------------------------------------------------------------------------- 1 | /* global Alloy, ENV_PROD */ 2 | 3 | var log = require('log'); 4 | 5 | // The contents of this file will be executed before any of 6 | // your view controllers are ever executed, including the index. 7 | // You have access to all functionality on the `Alloy` namespace. 8 | // 9 | // This is a great place to do any initialization for your app 10 | // or create any global variables/functions that you'd like to 11 | // make available throughout your app. You can easily make things 12 | // accessible globally by attaching them to the `Alloy.Globals` 13 | // object. For example: 14 | // 15 | // Alloy.Globals.someGlobalFunction = function(){}; 16 | 17 | /** 18 | * It's a best practice to your code in alloy.js in a self-executing function 19 | * since any variable declared here will be in global scope and never garbage 20 | * collected. Use this or global to explicitly define a global, but rather 21 | * use Alloy.Globals or a CommonJS module you require where needed. 22 | */ 23 | (function(global) { 24 | 25 | // This variable would have been global without the above SEF 26 | var versions = Ti.version.split('.'); 27 | 28 | // Used in the index view and controller to check if the appw as build with Ti 5.2 or later 29 | Alloy.Globals.isSupported = (parseInt(versions[0], 10) >= 5 && parseInt(versions[1], 10) >= 2); 30 | 31 | // Used in index.tss to set flags for supported examples 32 | Alloy.Globals.isForceTouchSupported = (OS_IOS && Ti.UI.iOS.forceTouchSupported); 33 | Alloy.Globals.isWatchSupported = (OS_IOS && Ti.WatchSession.isSupported); 34 | 35 | if (OS_IOS) { 36 | initAppshortcuts(); 37 | } 38 | 39 | })(this); 40 | 41 | // Set in controllers/appshortcuts.js 42 | function initAppshortcuts() { 43 | 44 | // Fired when the shortcut is used 45 | Ti.App.iOS.addEventListener('shortcutitemclick', function onShortcutitemclick(e) { 46 | log.args('Ti.App.iOS:shortcutitemclick', e); 47 | 48 | alert('Hi ' + e.userInfo.person.fullName); 49 | }); 50 | } 51 | -------------------------------------------------------------------------------- /app/assets/android/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/android/appicon.png -------------------------------------------------------------------------------- /app/assets/android/images/launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/android/images/launcher.png -------------------------------------------------------------------------------- /app/assets/android/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/android/images/logo.png -------------------------------------------------------------------------------- /app/assets/iphone/LaunchLogo@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/LaunchLogo@2x~ipad.png -------------------------------------------------------------------------------- /app/assets/iphone/LaunchLogo@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/LaunchLogo@2x~iphone.png -------------------------------------------------------------------------------- /app/assets/iphone/LaunchLogo@3x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/LaunchLogo@3x~iphone.png -------------------------------------------------------------------------------- /app/assets/iphone/LaunchLogo~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/LaunchLogo~ipad.png -------------------------------------------------------------------------------- /app/assets/iphone/LaunchLogo~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/LaunchLogo~iphone.png -------------------------------------------------------------------------------- /app/assets/iphone/images/tabIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/images/tabIcon.png -------------------------------------------------------------------------------- /app/assets/iphone/images/tabIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/images/tabIcon@2x.png -------------------------------------------------------------------------------- /app/assets/iphone/images/tabIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/assets/iphone/images/tabIcon@3x.png -------------------------------------------------------------------------------- /app/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "brandPrimary": "#CD1625", 4 | "brandSecondary": "#484950", 5 | "brandSuccess": "#5cb85c", 6 | "minVersion": "1.8.5" 7 | }, 8 | "env:development": {}, 9 | "env:test": {}, 10 | "env:production": {}, 11 | "os:android": {}, 12 | "os:blackberry": {}, 13 | "os:ios": {}, 14 | "os:mobileweb": {}, 15 | "os:windows": {}, 16 | "dependencies": {} 17 | } 18 | -------------------------------------------------------------------------------- /app/controllers/android/keyboard.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function closeWindow() { 4 | $.win.close(); 5 | } 6 | 7 | function setInputType() { 8 | var names = []; 9 | var inputType = []; 10 | 11 | if ($.number.value) { 12 | names.push('Ti.UI.INPUT_TYPE_CLASS_NUMBER'); 13 | inputType.push(Ti.UI.INPUT_TYPE_CLASS_NUMBER); 14 | } 15 | 16 | if ($.text.value) { 17 | names.push('Ti.UI.INPUT_TYPE_CLASS_TEXT'); 18 | inputType.push(Ti.UI.INPUT_TYPE_CLASS_TEXT); 19 | } 20 | 21 | log.args('Ti.UI.TextField.inputType', names); 22 | 23 | $.textField.inputType = inputType; 24 | $.textField.blur(); 25 | } 26 | -------------------------------------------------------------------------------- /app/controllers/android/launcher.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | /** 4 | * I wrap code that executes on creation in a self-executing function just to 5 | * keep it organised, not to protect global scope like it would in alloy.js 6 | */ 7 | (function constructor() { 8 | 9 | // If the app was launched with the shortcut it would have this extra metadata 10 | $.feedback.text = Ti.App.Android.launchIntent.hasExtra('sample') ? 'Yes' : 'No'; 11 | 12 | })(); 13 | 14 | function closeWindow() { 15 | $.win.close(); 16 | } 17 | 18 | function installShortcut(e) { 19 | 20 | // Copy the intent used to launch the app 21 | var intentForShortcut = Ti.App.Android.launchIntent; 22 | 23 | // Re-set the action to have the intent be the app entry point 24 | intentForShortcut.action = Ti.Android.ACTION_MAIN; 25 | intentForShortcut.addFlags(Ti.Android.FLAG_ACTIVITY_SINGLE_TOP); 26 | 27 | // Add custom metadata to read when the app is launched from the shortcut. 28 | // See index.js to see how we use this to directly open the launcher sample. 29 | intentForShortcut.putExtra('sample', 'launcher'); 30 | 31 | // Create an intent to install the shortcut 32 | var intentToInstallShortcut = Ti.Android.createIntent({ 33 | action: 'com.android.launcher.action.INSTALL_SHORTCUT', 34 | }); 35 | 36 | // NEW: Link the actual intent for the shortcut 37 | intentToInstallShortcut.putExtra(Ti.Android.EXTRA_SHORTCUT_INTENT, intentForShortcut); 38 | 39 | // Title for the shortcut 40 | intentToInstallShortcut.putExtra(Ti.Android.EXTRA_SHORTCUT_NAME, 'Launch Sample'); 41 | 42 | // NEW: Icon for the shortcut 43 | var icon = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'images', 'launcher.png').read(); 44 | intentToInstallShortcut.putExtra(Ti.Android.EXTRA_SHORTCUT_ICON, icon); 45 | 46 | // Broadcast the intent 47 | Ti.Android.currentActivity.sendBroadcast(intentToInstallShortcut); 48 | 49 | if (Ti.App.Properties.getBool('installedShortcut', false)) { 50 | alert('You already installed the shortcut before. You might now have an additional one if, unless you have removed the previous one(s).'); 51 | } else { 52 | alert('The shortcut has been installed. Force quit the app (3rd button in the system navigation bar, then swipe to close) to try it.'); 53 | } 54 | 55 | Ti.App.Properties.setBool('installedShortcut', true); 56 | } 57 | -------------------------------------------------------------------------------- /app/controllers/android/streetview.js: -------------------------------------------------------------------------------- 1 | function closeWindow() { 2 | $.win.close(); 3 | } 4 | 5 | function toggle(e) { 6 | var property = e.source.title; 7 | var value = !(e.source.backgroundColor === Alloy.CFG.brandSuccess); 8 | 9 | $.streetView[property] = value; 10 | 11 | // Change color depending on state 12 | e.source.backgroundColor = value ? Alloy.CFG.brandSuccess : Alloy.CFG.brandSecondary; 13 | } 14 | -------------------------------------------------------------------------------- /app/controllers/android/tableview.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function closeWindow() { 4 | $.win.close(); 5 | } 6 | 7 | function toggleSeparatorStyle(e) { 8 | 9 | if ($.tableView.separatorStyle === Ti.UI.TABLE_VIEW_SEPARATOR_STYLE_NONE) { 10 | log.args('Ti.UI.TableView.separatorStyle', 'Ti.UI.TABLE_VIEW_SEPARATOR_STYLE_SINGLE_LINE'); 11 | $.tableView.separatorStyle = Ti.UI.TABLE_VIEW_SEPARATOR_STYLE_SINGLE_LINE; 12 | } else { 13 | log.args('Ti.UI.TableView.separatorStyle', 'Ti.UI.TABLE_VIEW_SEPARATOR_STYLE_NONE'); 14 | $.tableView.separatorStyle = Ti.UI.TABLE_VIEW_SEPARATOR_STYLE_NONE; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/controllers/android/transitions.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function closeWindow() { 4 | $.win.close(); 5 | } 6 | 7 | function openWindowA() { 8 | 9 | // For each setting 10 | ['activityExitTransition', 'activityReenterTransition', 'activitySharedElementExitTransition', 'activitySharedElementReenterTransition'].forEach(function(prop) { 11 | var constant = $[prop].getSelectedRow(0).title; 12 | 13 | if (constant.indexOf('TRANSITION_') === -1) { 14 | log.args('Ti.UI.Window.' + prop, constant); 15 | 16 | // We set a global that will be used for the creation-only property in transitions_a.tss 17 | Alloy.Globals[prop] = undefined; 18 | 19 | } else { 20 | log.args('Ti.UI.Window.' + prop, 'Ti.UI.Android.' + constant); 21 | Alloy.Globals[prop] = Ti.UI.Android[constant]; 22 | } 23 | 24 | }); 25 | 26 | // Open Window A 27 | Alloy.createController('transitions_a').getView().open(); 28 | } 29 | -------------------------------------------------------------------------------- /app/controllers/android/transitions_a.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function closeWindow() { 4 | $.win.close(); 5 | } 6 | 7 | function openWindowB() { 8 | 9 | // For each setting 10 | ['activityEnterTransition', 'activityReturnTransition', 'activitySharedElementEnterTransition', 'activitySharedElementReturnTransition'].forEach(function(prop) { 11 | var constant = $[prop].getSelectedRow(0).title; 12 | 13 | if (constant.indexOf('TRANSITION_') === -1) { 14 | log.args('Ti.UI.Window.' + prop, constant); 15 | 16 | // We set a global that will be used for the creation-only property in transitions_a.tss 17 | Alloy.Globals[prop] = undefined; 18 | 19 | } else { 20 | log.args('Ti.UI.Window.' + prop, 'Ti.UI.Android.' + constant); 21 | Alloy.Globals[prop] = Ti.UI.Android[constant]; 22 | } 23 | 24 | }); 25 | 26 | // Get Window B 27 | var win = Alloy.createController('transitions_b').getView(); 28 | 29 | // Link shared elements using the transitionName also set in both XML files 30 | win.addSharedElement($.logo, 'logo'); 31 | win.addSharedElement($.text, 'text'); 32 | 33 | // Open the Window 34 | win.open(); 35 | } 36 | -------------------------------------------------------------------------------- /app/controllers/android/transitions_b.js: -------------------------------------------------------------------------------- 1 | function closeWindow() { 2 | $.win.close(); 3 | } 4 | -------------------------------------------------------------------------------- /app/controllers/console.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | /** 4 | * I wrap code that executes on creation in a self-executing function just to 5 | * keep it organised, not to protect global scope like it would in alloy.js 6 | */ 7 | (function constructor(args) { 8 | 9 | // Show logs from before this controller was created 10 | showLogs(); 11 | 12 | // Listen to changes to the logs 13 | log.on('change', showLogs); 14 | 15 | })(arguments[0] || {}); 16 | 17 | function showLogs() { 18 | $.log.text = log.history; 19 | 20 | $.scrollView.scrollToBottom(); 21 | } 22 | 23 | function clearLogs() { 24 | 25 | // Clear the public property holding the log history 26 | log.history = ''; 27 | 28 | showLogs(); 29 | } 30 | -------------------------------------------------------------------------------- /app/controllers/index.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | var activity; 4 | 5 | /** 6 | * I wrap code that executes on creation in a self-executing function just to 7 | * keep it organised, not to protect global scope like it would in alloy.js 8 | */ 9 | (function constructor(args) { 10 | 11 | if (Alloy.Globals.isSupported) { 12 | 13 | if (OS_IOS) { 14 | initActivity(); 15 | 16 | if (Alloy.isTablet) { 17 | initMultitasking(); 18 | } 19 | } 20 | 21 | if (OS_ANDROID) { 22 | initTabMenus(); 23 | initShortcut(); 24 | } 25 | } 26 | 27 | // Wait a bit to make it easier to see fullscreen and storyboard changes 28 | setTimeout(function() { 29 | 30 | // Opens either the TabGroup or "Not Supported" Window depending on 31 | // the Alloy.Globals.isSupported flag used in index.xml 32 | $.index.open(); 33 | 34 | }, 2000); 35 | 36 | })(arguments[0] || {}); 37 | 38 | function onListViewItemclick(e) { 39 | var item = e.section.getItemAt(e.itemIndex); 40 | 41 | // We use classes in index.xml with conditional TSS in index.tss to set this flag 42 | if (item.properties.unsupported) { 43 | return alert('Your device does not meet the requirements for this example.'); 44 | } 45 | 46 | var controllerName = e.itemId; 47 | 48 | // Special case. We want to list the Tab sample but it should select the middle tab. 49 | if (controllerName === 'tab') { 50 | $.index.tabs[1].active = true; 51 | return; 52 | } 53 | 54 | openSample(controllerName); 55 | } 56 | 57 | function openSample(controllerName) { 58 | var controller = Alloy.createController(controllerName); 59 | 60 | $.samplesTab.open(controller.getView()); 61 | } 62 | 63 | // iOS: Show how the usage of needsSave has changed 64 | function initActivity() { 65 | 66 | activity = Ti.App.iOS.createUserActivity({ 67 | activityType: 'com.appcelerator.sample.ti520.tab', 68 | title: Ti.App.name, 69 | userInfo: { 70 | activeTabIndex: 0 71 | } 72 | }); 73 | 74 | if (activity.isSupported()) { 75 | activity.becomeCurrent(); 76 | 77 | Ti.App.iOS.addEventListener('continueactivity', function(e) { 78 | log.args('Ti.App.iOS:continueactivity', e); 79 | 80 | // Activate the tab active on the other device 81 | if (e.activityType === 'com.appcelerator.sample.ti520.tab') { 82 | $.index.tabs[e.userInfo.activeTabIndex].active = true; 83 | } 84 | 85 | }); 86 | 87 | // When a tab receives focus 88 | $.index.addEventListener('focus', function(e) { 89 | var userInfo = { 90 | activeTabIndex: e.index 91 | }; 92 | 93 | log.args('Ti.App.iOS.UserActivity.userInfo', userInfo); 94 | 95 | // Update the userInfo here, where before we would need to wait for 96 | // the useractivitywillsave event 97 | activity.userInfo = userInfo; 98 | 99 | // Inform iOS the activity has changed 100 | activity.needsSave = true; 101 | }); 102 | } 103 | } 104 | 105 | // iPad: Logs the TabGroup dimensions each time we switch fullscreen, Slide Over or Split View mode 106 | function initMultitasking() { 107 | 108 | function logDimensions(e) { 109 | log.args('Ti.App:' + e.type + ' was fired and our dimensions are:', { 110 | 'Ti.Platform.displayCaps.platformWidth': Ti.Platform.displayCaps.platformWidth, 111 | 'Ti.Platform.displayCaps.platformHeight': Ti.Platform.displayCaps.platformHeight, 112 | '$.index.size.width': $.index.size.width, 113 | '$.index.size.height': $.index.size.height 114 | }); 115 | } 116 | 117 | // This event fires when the app was still active in the background when it Slides Over another app 118 | Ti.App.addEventListener('resume', logDimensions); 119 | 120 | // Will (also) fires when: 121 | // 1) This app Slides Over another app 122 | // 2) This app goes from Slide Over to Split View 123 | // 3) This app goes from quarter to half Split View or visa versa 124 | // 4) The user dragged the Split View devider but released it to bounce back to existing mode 125 | // 5) This app goes from Split View to full view (by dragging the devider to the left edge) 126 | // 6) This app goes from Split View to Slide Over (by singletap on devider) 127 | // 7) Another app goes from Slide Over to Split View 128 | // 129 | // It does not fire when: 130 | // 1) Another app goes from Slit View to Slide Over (by singletap on devider) 131 | Ti.App.addEventListener('resumed', logDimensions); 132 | 133 | // 1) Another app starts to Slide Over 134 | // 2) Another app starts to go from right Split View to Slide Over (by singletap on devider) 135 | // 3) The user starts dragging the Split View devider 136 | Ti.App.addEventListener('pause', logDimensions); 137 | 138 | // This event fires when another app is dragged from quarter or half Split View to fullscreen 139 | Ti.App.addEventListener('paused', logDimensions); 140 | } 141 | 142 | // Android: Hack to delegate the creation of the TabGroup's menu to the active tab 143 | function initTabMenus() { 144 | 145 | $.index.addEventListener('open', function(e) { 146 | 147 | $.index.activity.addEventListener('newintent', function(e) { 148 | console.log('newintent from index.js added to tabgroup activity ' + JSON.stringify(e)); 149 | }); 150 | 151 | $.index.activity.onCreateOptionsMenu = function(e) { 152 | 153 | // Delegate the creation of the menu to the active tab 154 | if ($.index.activeTab.window.activity.onCreateOptionsMenu) { 155 | $.index.activeTab.window.activity.onCreateOptionsMenu(e); 156 | } 157 | }; 158 | 159 | }); 160 | 161 | // When a tab receives focus 162 | $.index.addEventListener('focus', function(e) { 163 | 164 | // Force the TabGroup's menu to be regenerated 165 | $.index.activity.invalidateOptionsMenu(); 166 | }); 167 | 168 | } 169 | 170 | // Android: Launch the app via an additional shortcut to a sample (see launcher.js) 171 | function initShortcut() { 172 | var sample = Ti.App.Android.launchIntent.getStringExtra('sample'); 173 | 174 | // If we were launched using a shortcut to a specific sample 175 | if (sample) { 176 | 177 | // Wait for the TabGroup to be open 178 | $.index.addEventListener('open', function(e) { 179 | openSample(sample); 180 | 181 | alert('You have used the additional launch shortcut.'); 182 | }); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /app/controllers/ios/appshortcuts.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function createShortcut(e) { 4 | 5 | if (Ti.Contacts.hasContactsPermissions()) { 6 | return _createShortcut(); 7 | } 8 | 9 | if (Ti.Contacts.contactsAuthorization === Ti.Contacts.AUTHORIZATION_RESTRICTED) { 10 | return alert('Access to contacts has been restricted'); 11 | } 12 | 13 | Ti.Contacts.requestContactsPermissions(function(e) { 14 | 15 | if (!e.success) { 16 | return alert(e.error || 'Error #' + code); 17 | } 18 | 19 | _createShortcut(); 20 | }); 21 | } 22 | 23 | function _createShortcut() { 24 | 25 | Ti.Contacts.showContacts({ 26 | 27 | // Called when the user has selected a contact person 28 | selectedPerson: function(e) { 29 | var appShortcuts = Ti.UI.iOS.createApplicationShortcuts(); 30 | 31 | // remove previous shortcut of this type, if any 32 | appShortcuts.removeDynamicShortcut('contact'); 33 | 34 | // add the new shortcut 35 | appShortcuts.addDynamicShortcut({ 36 | itemtype: 'contact', 37 | title: e.person.fullName, 38 | userInfo: { 39 | person: { 40 | fullName: e.person.fullName 41 | } 42 | }, 43 | 44 | // use the contact person as the icon 45 | icon: e.person 46 | }); 47 | 48 | alert('Now move your app to the background and force touch the app icon to see the contact icon'); 49 | } 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /app/controllers/ios/keyboard.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function changeKeyboardType(e) { 4 | var keyboardType = 'KEYBOARD_TYPE_' + e.source.labels[e.index].title; 5 | log.args('keyboardType', 'Ti.UI.' + keyboardType); 6 | 7 | $.textField.keyboardType = Ti.UI[keyboardType]; 8 | $.textField.blur(); 9 | } 10 | 11 | function changeKeyboardAppearance(e) { 12 | var keyboardAppearance = 'KEYBOARD_APPEARANCE_' + e.source.labels[e.index].title; 13 | log.args('keyboardAppearance', 'Ti.UI.' + keyboardAppearance); 14 | 15 | // Notice that since 5.2 you should use keyboardAppearance instead of appearance 16 | $.textField.keyboardAppearance = Ti.UI[keyboardAppearance]; 17 | $.textField.blur(); 18 | } 19 | 20 | function changeReturnKeyType(e) { 21 | var returnKeyType = 'RETURNKEY_' + e.source.labels[e.index].title; 22 | log.args('returnKeyType', 'Ti.UI.' + returnKeyType); 23 | 24 | $.textField.returnKeyType = Ti.UI[returnKeyType]; 25 | $.textField.blur(); 26 | } 27 | -------------------------------------------------------------------------------- /app/controllers/ios/listview.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function enableEdit(e) { 4 | $.win.rightNavButton = $.doneBtn; 5 | 6 | $.listView.editing = true; 7 | } 8 | 9 | function disableEdit(e) { 10 | $.win.rightNavButton = $.editBtn; 11 | 12 | $.listView.editing = false; 13 | } 14 | 15 | function onDrag(e) { 16 | log.args('Ti.UI.ListView:' + e.type, e); 17 | } 18 | 19 | function onInsert(e) { 20 | log.args('Ti.UI.ListView:insert', e); 21 | 22 | var item = e.section.getItemAt(e.itemIndex); 23 | 24 | // We insert a new item AFTER (+1) the selected item 25 | e.section.insertItemsAt(e.itemIndex + 1, [{ 26 | properties: { 27 | canInsert: true, 28 | title: 'Inserted after ' + item.properties.title 29 | } 30 | }]); 31 | } 32 | -------------------------------------------------------------------------------- /app/controllers/ios/livephoto.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function openPhotoGallery() { 4 | 5 | Ti.Media.openPhotoGallery({ 6 | 7 | // You can not use LIVEPHOTO without also allowing PHOTO 8 | mediaTypes: [Ti.Media.MEDIA_TYPE_LIVEPHOTO, Ti.Media.MEDIA_TYPE_PHOTO], 9 | cancel: handleResponse, 10 | error: handleResponse, 11 | success: handleResponse 12 | }); 13 | } 14 | 15 | function handleResponse(e) { 16 | log.args('Ti.Media.openPhotoGallery', e); 17 | 18 | if (!e.success) { 19 | return alert(e.error || 'Error #' + e.code); 20 | } 21 | 22 | if (e.mediaType !== Ti.Media.MEDIA_TYPE_LIVEPHOTO) { 23 | return alert('This should never happen. We required a Live Photo but somehow you selected something else.'); 24 | } 25 | 26 | if (!e.livePhoto) { 27 | return alert('This should never happen. If mediaType says you selected a Live Photo it should be there.'); 28 | } 29 | 30 | $.livePhotoView.livePhoto = e.livePhoto; 31 | 32 | // Programmatically triggering playback isn't recommended in any other use case 33 | // then when the photo is loaded or slides in to the viewport. 34 | $.livePhotoView.startPlaybackWithStyle(Ti.UI.iOS.LIVEPHOTO_PLAYBACK_STYLE_HINT); 35 | } 36 | 37 | function onLivePhotoViewStartStop(e) { 38 | log.args('Ti.UI.iOS.LivePhotoView:' + e.type, e); 39 | } 40 | 41 | function startPlaybackWithStyle(e) { 42 | var playbackStyle = 'LIVEPHOTO_PLAYBACK_STYLE_' + e.source.labels[e.index].title; 43 | log.args('playbackStyle', 'Ti.UI.iOS.' + playbackStyle); 44 | 45 | $.livePhotoView.startPlaybackWithStyle(Ti.UI.iOS[playbackStyle]); 46 | } 47 | 48 | function stopPlayback() { 49 | $.livePhotoView.stopPlayback(); 50 | } 51 | -------------------------------------------------------------------------------- /app/controllers/ios/menupopup.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | var timeout; 4 | 5 | function showWithDefaults(e) { 6 | show({ 7 | view: e.source 8 | }); 9 | } 10 | 11 | function showWithAnimated(e) { 12 | show({ 13 | view: e.source, 14 | animated: (e.index === 0) 15 | }); 16 | } 17 | 18 | function showWithArrowDirection(e) { 19 | var arrowDirection = 'MENU_POPUP_ARROW_DIRECTION_' + e.source.labels[e.index].title; 20 | 21 | show({ 22 | view: e.source, 23 | arrowDirection: Ti.UI.iOS[arrowDirection] 24 | }); 25 | } 26 | 27 | function show(params) { 28 | 29 | // if we didn't do so already, clear the timeout to auto-hide 30 | clearTimeout(timeout); 31 | 32 | log.args('Ti.UI.iOS.MenuPopup.show()', stringifyArrowDirection(params)); 33 | 34 | $.menu.show(params); 35 | 36 | // To demonstrate isVisible and hide() we set a timeout 37 | timeout = setTimeout(function() { 38 | 39 | var isVisible = $.menu.isVisible(); 40 | log.args('Ti.UI.iOS.MenuPopup.isVisible()', isVisible); 41 | 42 | if (isVisible) { 43 | var hideParams = _.pick(params, 'animated'); 44 | log.args('Ti.UI.iOS.MenuPopup.hide()', hideParams); 45 | 46 | $.menu.hide(hideParams); 47 | } 48 | 49 | }, 1000); 50 | } 51 | 52 | function onMenuPopupClick(e) { 53 | log.args('Ti.UI.iOS.MenuPopup:click', e); 54 | } 55 | 56 | // Helper to display the constant name instead of its value 57 | function stringifyArrowDirection(params) { 58 | var clone = _.clone(params); 59 | 60 | if (clone.arrowDirection) { 61 | 62 | switch (clone.arrowDirection) { 63 | case Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_LEFT: 64 | clone.arrowDirection = 'Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_LEFT'; 65 | break; 66 | case Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_UP: 67 | clone.arrowDirection = 'Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_UP'; 68 | break; 69 | case Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_DOWN: 70 | clone.arrowDirection = 'Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_DOWN'; 71 | break; 72 | case Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_RIGHT: 73 | clone.arrowDirection = 'Ti.UI.iOS.MENU_POPUP_ARROW_DIRECTION_RIGHT'; 74 | break; 75 | } 76 | } 77 | 78 | return clone; 79 | } 80 | -------------------------------------------------------------------------------- /app/controllers/ios/popover.js: -------------------------------------------------------------------------------- 1 | function openPopover(e) { 2 | 3 | $.popover.backgroundColor = (e.index === 1) ? Alloy.CFG.brandPrimary : ''; 4 | 5 | $.popover.show({ 6 | view: e.source, 7 | rect: { 8 | 9 | // This will position the arrow on 1/4th or 3/4th of the ButtonBar width 10 | x: e.source.size.width * ((e.index === 1) ? 0.75 : 0.25), 11 | 12 | // This will position the arrow at the bottom of the ButtonBar 13 | y: e.source.size.height 14 | } 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /app/controllers/ios/scrollview.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function onScroll(e) { 4 | log.args('Ti.UI.ScrollView:scroll', e); 5 | } 6 | -------------------------------------------------------------------------------- /app/controllers/ios/touch.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | var EVENTS = ['touchstart', 'touchend', 'click', 'touchmove', 'dblclick', 'touchcancel']; 4 | var PROPS = ['x', 'y', 'force', 'maximumPossibleForce', 'timestamp', 'altitudeAngle']; 5 | 6 | /** 7 | * I wrap code that executes on creation in a self-executing function just to 8 | * keep it organised, not to protect global scope like it would in alloy.js 9 | */ 10 | 11 | (function constructor() { 12 | 13 | // For each event 14 | EVENTS.forEach(function(name) { 15 | 16 | $.touchArea.addEventListener(name, function(e) { 17 | 18 | if (e.maximumPossibleForce === undefined) { 19 | return alert('This should never happen. Force Touch is supported by maximumPossibleForce is undefined.'); 20 | } 21 | 22 | // Show property values 23 | $.feedback.text = 'type: ' + e.type + '\n' + PROPS.map(function(prop) { 24 | return prop + ': ' + e[prop]; 25 | }).join('\n'); 26 | 27 | // the harder you press, the less opaque the view becomes 28 | $.touchArea.opacity = 1 - (e.force / e.maximumPossibleForce); 29 | }); 30 | 31 | }); 32 | 33 | })(); 34 | -------------------------------------------------------------------------------- /app/controllers/ios/watchos.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | var PROPS = ['isSupported', 'isPaired', 'isReachable', 'isWatchAppInstalled']; 4 | 5 | /** 6 | * I wrap code that executes on creation in a self-executing function just to 7 | * keep it organised, not to protect global scope like it would in alloy.js 8 | */ 9 | (function constructor() { 10 | 11 | if (Ti.WatchSession.isSupported) { 12 | Ti.WatchSession.activateSession(); 13 | } 14 | 15 | // Show properties values 16 | $.feedback.text = PROPS.map(function(prop) { 17 | return 'Ti.WatchSession.' + prop + ':\n' + Ti.WatchSession[prop]; 18 | }).join('\n\n'); 19 | 20 | })(); 21 | -------------------------------------------------------------------------------- /app/controllers/tab.js: -------------------------------------------------------------------------------- 1 | var log = require('log'); 2 | 3 | function onTabSelection(e) { 4 | log.args('Ti.UI.Tab:' + e.type, e); 5 | } 6 | -------------------------------------------------------------------------------- /app/lib/log.js: -------------------------------------------------------------------------------- 1 | /* global ENV_PROD */ 2 | 3 | var moment = require('alloy/moment'); 4 | 5 | var Log = module.exports = _.extend({}, Backbone.Events); 6 | 7 | Log.history = ''; 8 | 9 | Log.args = function() { 10 | _log(arguments, { 11 | withoutApis: true 12 | }); 13 | }; 14 | 15 | Log.argsWithApis = function() { 16 | _log(arguments, { 17 | withoutApis: false 18 | }); 19 | }; 20 | 21 | function _log(args, opts) { 22 | args = Array.prototype.slice.call(args); 23 | opts = opts || {}; 24 | 25 | // Stringify non-strings 26 | args = args.map(function(arg) { 27 | 28 | if (typeof arg !== 'string') { 29 | arg = JSON.stringify(arg, opts.withoutApis ? function(key, val) { 30 | 31 | if (typeof val === 'object' && val !== null && val.apiName) { 32 | return '[' + val.apiName + ']' + (val.id ? ' #' + val.id : ''); 33 | } else { 34 | return val; 35 | } 36 | 37 | } : null, 2); 38 | } 39 | 40 | return arg; 41 | }); 42 | 43 | var message = args.join(' '); 44 | 45 | // Use error-level for production or they will not show in Xcode console 46 | console[ENV_PROD ? 'error' : 'info'](message); 47 | 48 | // Add the message to a global variable for controllers/console.js to use 49 | Log.history = (Log.history || '') + '[' + moment().format('HH:mm:ss.SS') + '] ' + message + '\n\n'; 50 | 51 | // Trigger an event for controllers/console.js to listen to and display the log 52 | Log.trigger('change'); 53 | } 54 | -------------------------------------------------------------------------------- /app/platform/android/res/drawable-hdpi/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-hdpi/appicon.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-hdpi/background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-hdpi/background.9.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-mdpi/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-mdpi/appicon.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-mdpi/background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-mdpi/background.9.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-xhdpi/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-xhdpi/appicon.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-xhdpi/background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-xhdpi/background.9.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-xxhdpi/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-xxhdpi/appicon.png -------------------------------------------------------------------------------- /app/platform/android/res/drawable-xxhdpi/background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/app/platform/android/res/drawable-xxhdpi/background.9.png -------------------------------------------------------------------------------- /app/platform/android/res/values/custom_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/platform/ios/_LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/styles/android/keyboard.tss: -------------------------------------------------------------------------------- 1 | 'Window': { 2 | 3 | // Hide the softkeyboard when the Window opens (and the field receives focus) 4 | windowSoftInputMode: Ti.UI.Android.SOFT_INPUT_STATE_HIDDEN 5 | } 6 | -------------------------------------------------------------------------------- /app/styles/android/streetview.tss: -------------------------------------------------------------------------------- 1 | '#streetView': { 2 | 3 | // We can set the position (but not the heading) 4 | position: { 5 | latitude: 37.3676332, 6 | longitude: -121.9139205 7 | } 8 | } 9 | 10 | '.buttons': { 11 | top: 0, 12 | right: 10, 13 | width: Ti.UI.SIZE, 14 | height: Ti.UI.SIZE, 15 | 16 | layout: 'vertical' 17 | } 18 | 19 | 'Button': { 20 | top: 10, 21 | right: 0, 22 | width: Ti.UI.SIZE, 23 | 24 | backgroundColor: Alloy.CFG.brandSuccess 25 | } 26 | -------------------------------------------------------------------------------- /app/styles/android/transitions_a.tss: -------------------------------------------------------------------------------- 1 | 'Window' : { 2 | 3 | // See the XML for the descriptions 4 | // These are creation-only so we use Alloy.Globals to make them configurable 5 | // FIXME: https://jira.appcelerator.org/browse/ALOY-1316 6 | /*activityExitTransition: Alloy.Globals.activityExitTransition,*/ 7 | /*activityReenterTransition: Alloy.Globals.activityReenterTransition,*/ 8 | 9 | activityExitTransition: Titanium.UI.Android.TRANSITION_NONE, 10 | activityReenterTransition: Titanium.UI.Android.TRANSITION_NONE, 11 | 12 | activitySharedElementExitTransition: Alloy.Globals.activitySharedElementExitTransition, 13 | activitySharedElementReenterTransition: Alloy.Globals.activitySharedElementReenterTransition 14 | } 15 | 16 | 'ImageView': { 17 | width: 50, 18 | backgroundColor: 'white' 19 | } 20 | -------------------------------------------------------------------------------- /app/styles/android/transitions_b.tss: -------------------------------------------------------------------------------- 1 | 'Window': { 2 | 3 | // See the XML for the descriptions 4 | // These are creation-only so we use Alloy.Globals to make them configurable 5 | // FIXME: https://jira.appcelerator.org/browse/ALOY-1316 6 | activityEnterTransition: Alloy.Globals.activityEnterTransition, 7 | activityReturnTransition: Alloy.Globals.activityReturnTransition, 8 | activitySharedElementEnterTransition: Alloy.Globals.activitySharedElementEnterTransition, 9 | activitySharedElementReturnTransition: Alloy.Globals.activitySharedElementReturnTransition 10 | } 11 | 12 | 'ImageView': { 13 | width: Ti.UI.FILL, 14 | backgroundColor: 'white' 15 | } 16 | -------------------------------------------------------------------------------- /app/styles/app.tss: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This is your global styles file. Selectors and rules you define 4 | here will be applied throughout your app. However, these rules 5 | have the lowest priority of any style settings. 6 | 7 | For more information, see the 'Style Priorities' section of 8 | http://docs.appcelerator.com/titanium/latest/#!/guide/Alloy_Styles_and_Themes 9 | 10 | For example, the following would apply to all labels, windows, 11 | and text fields (depending on platform) in your app unless you 12 | overrode the settings with other TSS, XML, or JS settings: 13 | 14 | */ 15 | 16 | 'TabGroup[platform=ios]': { 17 | 18 | // by setting both two white you get a brighter kind of white 19 | backgroundColor: 'green', 20 | tabsBackgroundColor: 'white', 21 | 22 | tabsTintColor: Alloy.CFG.brandPrimary 23 | } 24 | 25 | 'Tab[platform=ios]': { 26 | icon: '/images/tabIcon.png' 27 | } 28 | 29 | 'Window[platform=ios]': { 30 | 31 | // white background instead of default transparent or black 32 | backgroundColor: '#fff', 33 | 34 | // Style the TabGroup's navigation bar 35 | barColor: Alloy.CFG.brandPrimary, 36 | navTintColor: '#FFF', 37 | translucent: false, 38 | titleAttributes: { 39 | color: '#FFF' 40 | } 41 | } 42 | 43 | 'Button': { 44 | width: 280 45 | } 46 | 47 | 'ButtonBar': { 48 | width: 280 49 | } 50 | 51 | 'TabbedBar': { 52 | width: 280 53 | } 54 | 55 | 'TextField': { 56 | width: 280 57 | } 58 | 59 | 'ProgressBar': { 60 | width: 280 61 | } 62 | 63 | 'Picker': { 64 | width: 280 65 | } 66 | 67 | // Make Buttons stand out a bit more on iOS 68 | 'Button[platform=ios]': { 69 | borderWidth: 1, 70 | borderColor: '#0071ff', 71 | borderRadius: 4 72 | } 73 | 74 | // Make TextFields stand out a bit more on iOS 75 | 'TextField[platform=ios]': { 76 | height: 30, 77 | paddingLeft: 5, 78 | paddingRight: 5, 79 | borderWidth: 1, 80 | borderColor: '#0071ff', 81 | borderRadius: 4 82 | } 83 | 84 | // Make all ScrollViews scroll vertical 85 | 'ScrollView': { 86 | contentWidth: Ti.UI.FILL, 87 | contentHeight: Ti.UI.SIZE, 88 | 89 | scrollType: 'vertical' 90 | } 91 | 92 | 'MenuItem': { 93 | showAsAction: Ti.Android.SHOW_AS_ACTION_ALWAYS 94 | } 95 | 96 | // A vertical layout with padding 97 | '.vbox': { 98 | layout: 'vertical', 99 | top: 20, 100 | right: 20, 101 | bottom: 20, 102 | left: 20, 103 | 104 | // Because we use both top and bottom height would default to the parent height 105 | height: Ti.UI.SIZE 106 | } 107 | 108 | '.tpad-s': { 109 | top: 10 110 | } 111 | 112 | '.tpad': { 113 | top: 20 114 | } 115 | 116 | '.tpad-l': { 117 | top: 40 118 | } 119 | 120 | '.help': { 121 | color: '#999', 122 | font: { 123 | fontSize: 13 124 | }, 125 | textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER 126 | } 127 | -------------------------------------------------------------------------------- /app/styles/console.tss: -------------------------------------------------------------------------------- 1 | 'ScrollView': { 2 | contentWidth: Ti.UI.FILL, 3 | contentHeight: Ti.UI.SIZE 4 | } 5 | 6 | 'Label': { 7 | top: 10, 8 | right: 10, 9 | left: 10, 10 | 11 | width: Ti.UI.FILL, 12 | height: Ti.UI.SIZE, 13 | 14 | font: { 15 | fontFamily: 'monospace', 16 | fontSize: 13 17 | } 18 | } -------------------------------------------------------------------------------- /app/styles/index.tss: -------------------------------------------------------------------------------- 1 | 'ItemTemplate': { 2 | height: 50 3 | } 4 | 5 | '.item': { 6 | height: 25 7 | } 8 | 9 | '.item[platform=ios]': { 10 | left: 15 11 | } 12 | 13 | '.item[platform=android]': { 14 | left: 5 15 | } 16 | 17 | '.itemTitle': { 18 | top: 0 19 | } 20 | 21 | '.itemSubtitle': { 22 | top: 25, 23 | color: 'gray' 24 | } 25 | 26 | '.ios[platform=!ios]': { 27 | unsupported: true 28 | } 29 | 30 | '.tablet[formFactor=!tablet]': { 31 | unsupported: true 32 | } 33 | 34 | '.android[platform=!android]': { 35 | unsupported: true 36 | } 37 | 38 | '.forcetouch[if=!Alloy.Globals.isForceTouchSupported]': { 39 | unsupported: true 40 | } 41 | 42 | '.watch[if=!Alloy.Globals.isWatchSupported]': { 43 | unsupported: true 44 | } 45 | 46 | '.unsupported': { 47 | 48 | // Add some margin left and right 49 | left: 20, 50 | right: 20, 51 | 52 | textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER 53 | } 54 | -------------------------------------------------------------------------------- /app/styles/ios/listview.tss: -------------------------------------------------------------------------------- 1 | 'ItemTemplate': { 2 | height: Ti.UI.SIZE 3 | } 4 | 5 | '.listHelp': { 6 | top: 10, 7 | right: 10, 8 | bottom: 10, 9 | left: 15, 10 | 11 | height: Ti.UI.SIZE 12 | } 13 | -------------------------------------------------------------------------------- /app/styles/ios/livephoto.tss: -------------------------------------------------------------------------------- 1 | 'LivePhotoView': { 2 | width: 280, 3 | height: 280, 4 | backgroundColor: '#CCC' 5 | } 6 | -------------------------------------------------------------------------------- /app/styles/ios/progressbar.tss: -------------------------------------------------------------------------------- 1 | 'ProgressBar': { 2 | value: 0.33, 3 | 4 | color: 'blue', // message color 5 | tintColor: 'green', // completed part 6 | trackTintColor: 'red', // uncompleted part 7 | 8 | // FIXME: https://jira.appcelerator.org/browse/TIMOB-20404 9 | bottom: 20, 10 | height: Ti.UI.SIZE 11 | } 12 | -------------------------------------------------------------------------------- /app/styles/ios/touch.tss: -------------------------------------------------------------------------------- 1 | '#touchArea': { 2 | width: 280, 3 | height: 280, 4 | backgroundColor: '#000', 5 | opacity: 1 6 | } 7 | 8 | '#feedback': { 9 | width: 280, 10 | textAlign: Ti.UI.TEXT_ALIGNMENT_LEFT, 11 | } 12 | -------------------------------------------------------------------------------- /app/styles/ios/window.tss: -------------------------------------------------------------------------------- 1 | 'Window': { 2 | swipeToClose: false 3 | } 4 | -------------------------------------------------------------------------------- /app/styles/tab.tss: -------------------------------------------------------------------------------- 1 | 'Tab': { 2 | iconInsets: { 3 | top: 5 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/views/android/keyboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/views/android/launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/views/android/streetview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /app/views/android/transitions_a.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /app/views/android/transitions_b.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/views/console.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/views/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/views/ios/appshortcuts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/views/ios/keyboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/views/ios/listview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/views/ios/menupopup.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Option A 40 | Option B 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/views/ios/popover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | > 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/views/ios/progressbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | > 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/views/ios/scrollview.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/views/ios/touch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/views/ios/watchos.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/ios/window.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/views/tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | > 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/android.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0: Wrap-up for Android 2 | 3 | This is our final walkthrough on the [Sample App](http://github.com/appcelerator-developer-relations/appc-sample-ti520) for [Titanium 5.2.0](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/) as we wrap up with the remaining new features and changes for Android: 4 | 5 | [![video](http://img.youtube.com/vi/6UG8VwgoFOk/0.jpg)](https://www.youtube.com/watch?v=6UG8VwgoFOk) 6 | 7 | * [TextField inputType](#textfield-inputtype) 8 | * [Launcher Shortcuts](#launcher-shortcuts) 9 | * [TableView separatorStyle](#tableview-separatorstyle) 10 | * [Fullscreen Splash Image](#fullscreen-splash-image) 11 | * [Renamed APIs](#renamed-apis) 12 | 13 | ## Textfield inputType 14 | 15 | You could already set the [keyboardType](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.TextField-property-inputType) for a TextField, but even the [KEYBOARD\_TYPE\_NUMBER_PAD](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI-property-KEYBOARD_TYPE_NUMBER_PAD) still included other characters than just numbers and does not impose any limit on hardware keyboards. 16 | 17 | The new [inputType](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.TextField-property-inputType) allows you to the specifically allow only numbers or numbers and text. It will automatically override the right keyboardType for you. 18 | 19 | The sample [allows](../app/views/android/keyboard.xml) you to enable either or both input types to see the effect. 20 | 21 | ## Launcher Shortcuts 22 | 23 | [Ti.Android.Intent.putExra()](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Android.Intent-method-putExtra) now accepts an [intent](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Android-property-EXTRA_SHORTCUT_INTENT) or [icon](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Android-property-EXTRA_SHORTCUT_ICON). Among other possible use cases, this allows you to create an intent to install additional launch shortcuts for specific activities within your app, each with a unique icon, title and extras to identify the desired action. 24 | 25 | The sample demonstrates how to create this intent in the [launcher.js](../app/controllers/android/launcher.js) controller, while the [index.js](../app/controllers/index.js#L170) shows how to retrieve extras from the launch intent to take appropriate action. 26 | 27 | > **NOTE:** It's a [known issue](https://jira.appcelerator.org/browse/TIMOB-20459) that if the app is running in the background, there is no way to know which intent (e.g. a launch shortcut) caused it to resume. 28 | 29 | ## TableView separatorStyle 30 | 31 | [Ti.UI.TableView.separatorStyle](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.TableView-property-separatorStyle) was already supported for iOS and MobileWeb, but now you can hide the separator line on Android as well. 32 | 33 | Tap anywhere in the Sample's TableView to [toggle the style](../app/controllers/android/tableview.js). 34 | 35 | > **NOTE:** Support for ListView is [yet to be added](https://jira.appcelerator.org/browse/TIMOB-19141). 36 | 37 | ## Fullscreen Splash Image 38 | 39 | If you set the `` option in [tiapp.xml](../tiapp.xml#L14) to `true` this will now show the splash image fullscreen. The Android top status bar and bottom soft navigation bar will be hidden: 40 | 41 | [![video](http://img.youtube.com/vi/tF042Nl99UA/0.jpg)](https://www.youtube.com/watch?v=tF042Nl99UA) 42 | 43 | Be aware that this will also default your app to use the `Theme.AppCompat.NoTitleBar.Fullscreen` theme [introduced in 5.0](http://docs.appcelerator.com/platform/latest/#!/guide/Titanium_SDK_5.0.0_Release_Note-section-46239777_TitaniumSDK5.0.0ReleaseNote-TitaniumThemes). If you want a fullscreen splash image but still show the status bar and Action Bar in the app itself, you will have to manually set the theme. The sample app [uses a custom theme](../tiapp.xml#L98), but you can also use the default like this: 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ## Renamed APIs 52 | 53 | Finally, I'd like to remind you again of some properties and methods that we have deprecated and renamed to improve the consistency of our API. The old ones will be removed in Titanium 6.0. 54 | 55 | | Old | New | 56 | | --- | --- | 57 | | `Ti.UI.Tab.(blur/focus)` | `Ti.UI.Tab.(un)?selected` 58 | | `Ti.UI.TabGroup.(un)?selected` | `Ti.UI.TabGroup.(blur/focus)` 59 | | `Ti.UI.(TextArea/Field).appearance` | `Ti.UI.(TextArea/Field).keyboardAppearance` 60 | | `Ti.UI.KEYBOARD_*` | `Ti.UI.KEYBOARD_TYPE_*` and `Ti.UI.KEYBOARD_APPEARANCE_*` 61 | | `Ti.UI.KEYBOARD_APPEARANCE_ALERT` | `Ti.UI.KEYBOARD_APPEARANCE_DARK` 62 | | `Ti.Calendar.STATUS_CANCELLED` | `Ti.Calendar.STATUS_CANCELED` 63 | | `Ti.Calendar.eventsAuthorization` | `Ti.Calendar.calendarAuthorization` 64 | | `Ti.Calendar.CAMERA_AUTHORIZATION_NOT_DETERMINED` | `Ti.Calendar.CAMERA_AUTHORIZATION_UNKNOWN` 65 | | `Ti.Media.cameraAuthorizationStatus` | `Ti.Media.cameraAuthorization` 66 | 67 | Code Strong 🚀 68 | -------------------------------------------------------------------------------- /docs/assets/avd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/avd.png -------------------------------------------------------------------------------- /docs/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/image.png -------------------------------------------------------------------------------- /docs/assets/insertion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/insertion.png -------------------------------------------------------------------------------- /docs/assets/ipadpro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/ipadpro.png -------------------------------------------------------------------------------- /docs/assets/launch-builtin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/launch-builtin.png -------------------------------------------------------------------------------- /docs/assets/launch-custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/launch-custom.png -------------------------------------------------------------------------------- /docs/assets/menupopup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/menupopup.png -------------------------------------------------------------------------------- /docs/assets/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/module.png -------------------------------------------------------------------------------- /docs/assets/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/screenshots.png -------------------------------------------------------------------------------- /docs/assets/simpholders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/simpholders.png -------------------------------------------------------------------------------- /docs/assets/splitview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/splitview.png -------------------------------------------------------------------------------- /docs/assets/streetview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/streetview.png -------------------------------------------------------------------------------- /docs/assets/tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/tab.png -------------------------------------------------------------------------------- /docs/assets/transitions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/docs/assets/transitions.png -------------------------------------------------------------------------------- /docs/ios.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0: Wrap-up for iOS 2 | 3 | Let's wrap-up our tour through the [Sample App](http://github.com/appcelerator-developer-relations/appc-sample-ti520) for [Titanium 5.2.0](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/) before 5.2.1 arrives. I'll briefly introduce you to some of the remaining new features and changes. 4 | 5 | Let's start with iOS: 6 | 7 | [![video](http://img.youtube.com/vi/vGZ4su0TZts/0.jpg)](https://www.youtube.com/watch?v=vGZ4su0TZts) 8 | 9 | * [MenuPopup](#menupopup) 10 | * [3D Touch & Apple Pencil Events](#3d-touch--apple-pencil-events) 11 | * [WatchOS2 Swift Template](#watchos2-swift-template) 12 | * [ListView Insertion Control & Drag Events](#listview-insertion-control--drag-events) 13 | * [Tab Icon Insets](#tab-icon-insets) 14 | * [Updating User Activities](#updating-user-activities) 15 | * [Small but not forgotten](#small-but-not-forgotten) 16 | * [Renamed APIs](#renamed-apis) 17 | 18 | ## MenuPopup 19 | 20 | The last remaining new UI component added in this release is [Ti.UI.iOS.MenuPopup](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.MenuPopup) which implements [UIMenuController](https://developer.apple.com/library/prerelease/ios/documentation/iPhone/Reference/UIMenuController_Class/index.html). In TextFields and TextAreas these popup automatically with edit options like cut, copy, paste etc. Alloy support is [under way](https://jira.appcelerator.org/browse/ALOY-1357), so open the [menupopup.js](../app/controllers/ios/menupopup.js) controller to see how we instantiate and configure this menu to show with any view. 21 | 22 | ![MenuPopup](assets/menupopup.png) 23 | 24 | ## 3D Touch & Apple Pencil Events 25 | 26 | We've added new events to the [touch*](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.View-event-touchstart), `click` and `dblclick` events for use with 3D Touch and Apple Pencil. Playback the above video to see how the [touch.xml](../app/views/ios/touch.xml) view allows you to try them out with some nice visual feedback using `force` and `maximumPossibleForce`. 27 | 28 | ## WatchOS2 Swift Template 29 | 30 | When you add an WatchOS2 extension to your Titanium iOS app using `appc create` you will now get a [Swift template](../extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension). The Objective-C template is still available by using `appc create -t applewatch --template watchos2-objc`. We've also cleaned up the template to include nothing more than Xcode does, except for some [icons](../extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/) and an example of how to [initiate a Watch Connectivity Session](../extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/InterfaceController.m#L22-L29). 31 | 32 | The sample comes with the default WatchOS2 extension and the [watchos.js](../app/controllers/ios/watchos.js) controller lets you confirm the Watch Connectivity Session has been established. 33 | 34 | ## ListView Insertion Control & Drag Events 35 | 36 | As the video demonstrates, you can now enable the [Insertion control](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html) just like you could already enable the Deletion control. Identical to [delete](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.ListView-event-delete), you will need to listen to the ([undocumented](https://jira.appcelerator.org/browse/TIDOC-2481)) `insert` event to do the actual insert as demonstrated in the [listview.js](../app/controllers/ios/listview.js) controller. 37 | 38 | ![Insertion Control](assets/insertion.png) 39 | 40 | There's two more new events. Like TableView and ScrollView, ListView now also has `dragstart` and `dragend` events. The sample demonstrates both. 41 | 42 | ## Tab Icon Insets 43 | 44 | If you don't give your tab a title, the icon would still show at the same place to line up with other tabs that might still have a title. You can now [set insets](../app/styles/tab.tss) to shift the icon: 45 | 46 | ![Tab Icon Insets](assets/tab.png) 47 | 48 | ## Updating User Activities 49 | 50 | Finally, we need to talk about `Ti.App.iOS.UserActivity`. Originally we modelled this very close to the iOS API. To update an activity you would do set its `needsSave` property to `true` and then wait for the `useractivitywillsave` event to do the actual update. We've now simplified this. You'll make the changes right away and then set the `needsSave` property to inform iOS, as demonstrated in [index.js](../app/controllers/index.js#L63). 51 | 52 | ## Small but not forgotten 53 | But let's not forget that with Titanium 5.2.0 for iOS you can also: 54 | 55 | * [Set the color](../app/styles/ios/progressbar.tss#L6) of the uncompleted track of an `Ti.UI.ProgressBar`. 56 | * [Set the backgroundColor](../app/controllers/ios/popover.js#L3) of `Ti.UI.iPad.Popover` so that its arrow can match the backgroundColor of the ContentView. 57 | * [Prevent](../app/styles/ios/window.tss) a `Ti.UI.Window` inside a `Ti.UI.iOS.NavigationWindow` to be closed by swiping form the left edge of the screen. 58 | * [Use](../app/controllers/ios/appshortcuts.js#L45) a `Ti.Contacts.Person` for the icon of `Ti.UI.iOS.ApplicationShortcuts` to display their photo or initials. 59 | * [Listen to the scroll-event](../app/views/ios/scrollview.xml) of a `Ti.UI.ScrollView` to get the `contentSize`, just like with a TableView. 60 | * [Use two new keyboard-types](../app/views/ios/keyboard.xml) and a a new *Continue* return key type in TextFields and TextAreas. 61 | 62 | ## Renamed APIs 63 | 64 | We've also deprecated and renamed some APIs to improve the consistency of our APIs. The old will be removed in Titanium 6.0. 65 | 66 | | Old | New | 67 | | --- | --- | 68 | | `Ti.UI.Tab.(blur/focus)` | `Ti.UI.Tab.(un)?selected` 69 | | `Ti.UI.TabGroup.(un)?selected` | `Ti.UI.TabGroup.(blur/focus)` 70 | | `Ti.UI.(TextArea/Field).appearance` | `Ti.UI.(TextArea/Field).keyboardAppearance` 71 | | `Ti.UI.KEYBOARD_*` | `Ti.UI.KEYBOARD_TYPE_*` and `Ti.UI.KEYBOARD_APPEARANCE_*` 72 | | `Ti.UI.KEYBOARD_APPEARANCE_ALERT` | `Ti.UI.KEYBOARD_APPEARANCE_DARK` 73 | | `Ti.Calendar.STATUS_CANCELLED` | `Ti.Calendar.STATUS_CANCELED` 74 | | `Ti.Calendar.eventsAuthorization` | `Ti.Calendar.calendarAuthorization` 75 | | `Ti.Calendar.CAMERA_AUTHORIZATION_NOT_DETERMINED` | `Ti.Calendar.CAMERA_AUTHORIZATION_UNKNOWN` 76 | | `Ti.Media.cameraAuthorizationStatus` | `Ti.Media.cameraAuthorization` 77 | 78 | Code Strong 🚀 79 | -------------------------------------------------------------------------------- /docs/launchfiles.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0: Launch Files, iPad Pro, Slide Over and Split View 2 | 3 | With iOS 9 Apple introduced [Slide Over and Split View](https://developer.apple.com/library/prerelease/ios/documentation/WindowsViews/Conceptual/AdoptingMultitaskingOniPad/QuickStartForSlideOverAndSplitView.html) for multitasking on eligible iPad models. You can now enable these new features for your apps in [Titanium 5.2.0](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/). 4 | 5 | In this blog post I'll walk you through all of this using the new [Titanium 5.2.0 Sample App](http://github.com/appcelerator-developer-relations/appc-sample-ti520): 6 | 7 | [![Split View](assets/splitview.png)](https://github.com/appcelerator-developer-relations/appc-sample-ti520) 8 | 9 | ## Not a small thing 10 | 11 | Supporting these new features actually was quite an undertaking. We needed to refactor our custom layout engine to use [Auto Layout](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/index.html), which we did for Titanium 5.1.0 as an [opt-in](http://docs.appcelerator.com/platform/latest/#!/guide/Titanium_SDK_5.1.0_Release_Note-section-46239771_TitaniumSDK5.1.0ReleaseNote-AutoLayout). The other ingredient were [Launch Files](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/LaunchImages.html), now available in Titanium 5.2.0. This also gets us support for the [iPad Pro](http://www.apple.com/ipad-pro/), which no longer supports Launch Images. 12 | 13 | ## What are Launch Files? 14 | 15 | Until now, you used to create a bunch of `Default*.png` Launch Images. In iOS 8 Apple introduced [Launch Files](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/LaunchImages.html). These are the same XIB files or Storyboards that you'd normally build you UI with in Xcode. This means you can use any iOS UI component and only need one file to support all devices. When you app first runs, iOS takes a snapshot image of the launch file to use as launch image. A great way to slim down your IPA! 16 | 17 | ## iPad Pro requires Launch Files 18 | 19 | The iPad Pro no longer supports Launch Images. Without it, a (Titanium) iOS app will be stretched to fit the iPad Pro: 20 | 21 | ![iPad Pro with no Launch File](assets/ipadpro.png) 22 | 23 | The iPad Pro also requires a new 167px icon called `appicon-83.5@2x.png`. If you use [DefaultIcon[-ios].png](http://docs.appcelerator.com/platform/latest/#!/guide/Icons_and_Splash_Screens-section-29004897_IconsandSplashScreens-iOSgraphicassetrequirementsandoptions) it will be generated automatically since Titanium 5.1.2.GA. 24 | 25 | You can select the iPad Pro from the device list in Studio or use `-C ?` to select if from the CLI. 26 | 27 | ## Using Launch Files 28 | 29 | You have two ways to use Launch Files: by using our builtin Storyboard or your own. 30 | 31 | Both need to be enabled in the `` section of your [tiapp.xml](tiapp.xml#L28): 32 | 33 | true 34 | 35 | ## Option A: Use the builtin Storyboard 36 | 37 | The builtin Storyboard features a centered image on a solid background color. The sample uses the builtin storyboard with a [custom image](app/assets/iphone) on an [Appcelerator red Background Color](tiapp.xml#L31): 38 | 39 | ![Builtin Storyboard](assets/launch-builtin.png) 40 | 41 | ### Customising the Image 42 | 43 | By default we'll generate the image from `DefaultIcon[-ios].png`. To use a different image, add the following `LaunchLogo*.png` files to the [app/assets/iphone](app/assets/iphone) folder: 44 | 45 | Filename | Devices | Scale | Recommended Size 46 | ---------|---------|-------|----------------- 47 | LaunchLogo~iphone.png | iPhone 3G and older | 1x | 320x320 48 | LaunchLogo@2x~iphone.png | iPhone 4, 4s 5, 5s, 6, 6s | 2x | 374x374 49 | LaunchLogo@3x~iphone.png | iPhone 6 Plus, 6s Plus | 3x | 621x621 50 | LaunchLogo~ipad.png | iPad 1, 2, Mini 1 | 1x | 384x384 51 | LaunchLogo@2x~ipad.png | iPad 3, 4, Air, Air 2, Mini 2, 3, 4 | 2x | 1024x1024 52 | 53 | You can generate these images with TiCons [Web](http://ticons.fokkezb.nl/) or [CLI](https://www.npmjs.com/package/ticons) `--storyboard` option. 54 | 55 | ### Customising the Background Color 56 | 57 | By default the background color is white. You can set a different color via the `` section of your [tiapp.xml](tiapp.xml#L31). 58 | 59 | This will also change the background color of your app between after the launch files is dismissed and before a view (with a solid background color) is opened, or [Ti.UI.backgroundColor](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI-property-backgroundColor) is set. The sample [opens with a 2s delay](app/controllers/index.js#L23-L30) so you can see this better. 60 | 61 | ## Option B: Use a custom Storyboard 62 | 63 | To use a custom Storyboard, put this file in [platform/ios/LaunchScreen.storyboard](https://github.com/appcelerator/titanium_mobile/blob/master/iphone/iphone/LaunchScreen.storyboard). As you can see the sample has it disabled using a `_` prefix. Just remove the underscore and do a clean build to see the difference: 64 | 65 | ![Builtin Storyboard](assets/launch-custom.png) 66 | 67 | As you can see I've used an iOS Activity Indicator. Notice that it is not spinning as iOS uses a snapshot image of the storyboard. 68 | 69 | ### Using images 70 | 71 | To use an image in your custom Storyboard, simply set the `Image` property of an *Image View* to the path under `app/assets/` without the image modifier (`~ipad`, `@2x`) or extension: 72 | 73 | ![Image](assets/image.png) 74 | 75 | > **NOTE:** [Currently](https://jira.appcelerator.org/browse/TIMOB-20429) Titanium does not package the `LaunchLogo*.png` file if you use a custom storyboard. You need to rename this image before you can use it. 76 | 77 | If you have the [optional app-thinning](http://docs.appcelerator.com/platform/latest/#!/guide/tiapp.xml_and_timodule.xml_Reference-section-29004921_tiapp.xmlandtimodule.xmlReference-use-app-thinning) enabled, you will have to use the name of the generated asset catalog. This is a hash based on the image path. To find out the hash for your image build the app, look up the right `[hash].imageset` under `build/iphone/Assets.xcassets/` and use the `[hash]` part. 78 | 79 | ## Dealing with Launch File Cache 80 | 81 | As you modify the (custom) storyboard, you might not always see your changes immediately. This is because iOS caches the snapshot it makes from your Launch File and a [known issue](https://jira.appcelerator.org/browse/TIMOB-20430) where Titanium does not always recompile the storyboard. 82 | 83 | To deal with this follow these steps before you build: 84 | 85 | 1. Use Simulator > Reset Content and Settings... 86 | 2. Use Project > Clean... or `appc ti clean` from CLI. 87 | 88 | Alternatively you can reset an individual app using a tool like [SimPholders](https://simpholders.com/). With this app, just hold `alt/⌥` and click the app from the dropdown: 89 | 90 | ![SimPholders](assets/simpholders.png) 91 | 92 | ## Enabling Slide Over and Split View 93 | 94 | On to iPad multitasking. 95 | 96 | The reason this requires Launch Files is that your app might be opened as Slide Over in either landscape or portrait. This would have required a 6 more launch images for the 3 sizes of iPad screens out there. 97 | 98 | Because your app needs to deal with all these sizes as well, Auto Layout is required. So the first thing we need to do is enable this under the `` section of [tiapp.xml](tiapp.xml#L34): 99 | 100 | true 101 | 102 | To inform iOS that our app no longer requires fullscreen, we need to add a flag to the `` section of [tiapp.xml](tiapp.xml#L40-L41): 103 | 104 | UIRequiresFullScreen 105 | 106 | 107 | ## Responding to Slide Over and Split View 108 | 109 | Though Auto Layout should take care of resizing your UI properly, you might want to leave out certain views on smaller sizes. 110 | 111 | To respond to your app changing between full screen, Slide Over and quarter or half Split View you can listen to the existing [Ti.App:resumed](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.App-event-resumed) event. This will fire on all occasions [except for one](https://jira.appcelerator.org/browse/TIMOB-20461). When your app is on the left side of a Split View and moves back to fullscreen because the other app closes or switches to Slide Over you will not get notified. 112 | 113 | In [index controller](app/controllers/index.js#L105) of the sample app I log the dimensions of the TabGroup each time the `resumed` event is received. -------------------------------------------------------------------------------- /docs/livephotos.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0: iOS Live Photos 2 | 3 | [Titanium 5.2.0](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/) has added support for [Live Photos](http://www.apple.com/iphone-6s/films/index.html#film-live-photos) that Apple [introduced with iOS 9.1](https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9_1.html) for the [iPhone 6s](http://www.apple.com/iphone-6s/cameras/). It allows you to select existing Live Photos and display them. 4 | 5 | In this blog post I'll walk you through all of this using the new [Titanium 5.2.0 Sample App](http://github.com/appcelerator-developer-relations/appc-sample-ti520): 6 | 7 | [![video](http://img.youtube.com/vi/XAxrq1hq7JA/0.jpg)](https://www.youtube.com/watch?v=XAxrq1hq7JA) 8 | 9 | ## Capturing a Live Photo 10 | Although Apple's [Reference](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIImagePickerController_Class/index.html#//apple_ref/doc/uid/TP40007070-CH3-DontLinkElementID_2) isn't really clear about it does say: 11 | 12 | > Live Photos is a Camera app feature on supported devices ... 13 | 14 | And that has indeed been our experience and that of app developers that work directly in Objective-C or Swift. Even when we do include the Live Photo media type, the UI for taking a new photo within another app will not include the *Live* icon and does not return a Live Photo. We will provide support soon after Apple does. 15 | 16 | ## Selecting a Live Photo 17 | To select a Live Photo from your device you use [Ti.Media.openPhotoGallery()](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Media-method-openPhotoGallery) as always. Live Photos will always be selectable, but only if you include `Ti.Media.MEDIA_TYPE_LIVEPHOTO` in the [mediaTypes](http://docs.appcelerator.com/platform/latest/#!/api/PhotoGalleryOptionsType-property-mediaTypes) will you get an actual [livePhoto](http://docs.appcelerator.com/platform/latest/#!/api/CameraMediaItemType-property-livePhoto) in the success response. Both ways, the existing [media](http://docs.appcelerator.com/platform/latest/#!/api/CameraMediaItemType-property-media) property will always get you the plain photo. 18 | 19 | > **NOTE:** You cannot use `Ti.Media.MEDIA_TYPE_LIVEPHOTO` without also including `Ti.Media.MEDIA_TYPE_PHOTO` in `mediaTypes`. 20 | 21 | See the the Sample App's [livephoto.js](../app/controllers/ios/livephoto.js) controller for the implementation. 22 | 23 | ## Displaying a Live Photo 24 | Live Photos cannot be displayed in a `Ti.UI.ImageView`, but only the new [Ti.UI.iOS.LivePhotoView](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView). 25 | 26 | Alloy [does not yet support LivePhotoView](https://jira.appcelerator.org/browse/ALOY-1356) which means we have to tell Alloy to use the `Ti.UI.iOS` namespace [ourselves](../app/views/ios/livephoto.xml#L10-L11): 27 | 28 | 29 | 30 | Set the view's [livePhoto](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView-property-livePhoto) property to the [Ti.UI.iOS.LivePhoto](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhoto) proxy that you received from `Ti.Media.openPhotoGallery()`. 31 | 32 | The view supports force touch interaction with the Live Photo out of the box. Just force touch the view to play the Live Photo. 33 | 34 | ## Programmatic Playback 35 | You can also programmatically start and stop the playback. Use [Ti.UI.iOS.LivePhotoView.startPlaybackWithStyle()](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView-method-startPlaybackWithStyle) to start and [stopPlayback()](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView-method-stopPlayback) to cancel. The first method accepts a [parameter](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView-method-stopPlayback) to select full playback or the hint style that you also see as a LivePhoto scrolls into view in the Photos app. This is also the only use case that Apple suggests you should use this method for. 36 | 37 | In the [livephoto.js](../app/controllers/ios/livephoto.js#L34) controller we playback with hint style after we've initialised the LivePhotoView with the Live Photo you selected: 38 | 39 | $.livePhotoView.startPlaybackWithStyle(Ti.UI.iOS.LIVEPHOTO_PLAYBACK_STYLE_HINT); 40 | 41 | # Events 42 | In addition to regular events, the view also features a [start](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView-event-start) and [stop](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.LivePhotoView-event-stop) event to inform you when the Live Photo has plays. 43 | -------------------------------------------------------------------------------- /docs/streetview.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0: Google Street View Panorama 2 | 3 | The [ti.map 2.3.6](https://github.com/appcelerator-modules/ti.map) module that comes with [Titanium 5.2.0](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/) adds support for [Google StreetViewPanorama](https://developers.google.com/maps/documentation/android-api/streetview). This allows you to integrate Street View in your Titanium Android apps. 4 | 5 | In this blog post I'll walk you through all of this using the new [Titanium 5.2.0 Sample App](http://github.com/appcelerator-developer-relations/appc-sample-ti520): 6 | 7 | ![Sample App](assets/streetview.png) 8 | 9 | *Yes, that's our [San Jose HQ](https://goo.gl/maps/1bAiuvwBoQ42) you're looking at!* 10 | 11 | ## Add the Maps Module 12 | 13 | Since the module is bundled with the Titanium SDK you don't need to download it. You do need to add it to your [tiapp.xml](tiapp.xml#L112-L113): 14 | 15 | 16 | ti.map 17 | 18 | 19 | In Studio you can use the TiApp Editor: 20 | 21 | ![Installing a module](assets/module.png) 22 | 23 | ## Initialize the Maps Module 24 | 25 | Google requires you to [request an API key](http://docs.appcelerator.com/platform/latest/#!/guide/Google_Maps_v2_for_Android-section-36739898_GoogleMapsv2forAndroid-ObtainandAddaGoogleAPIKey) that is linked to your App ID and the keystore you use when you build the app. You need to then add this API key to your `tiapp.xml` as well: 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | The Sample App has an [API key configured](../tiapp.xml#L101) that is valid for its App ID and our [builtin development keystore](https://github.com/appcelerator/titanium_mobile/blob/master/support/android/dev_keystore). 36 | 37 | ## Add the StreetViewPanorama 38 | 39 | To add the new StreetViewPanorama we have used Alloy's `module` attribute in the [streetview.xml](../app/views/android/streetview.xml#L6) view: 40 | 41 | 42 | 43 | You should know that Alloy normally transpiles `` elements to `Ti.UI.createFoo()`. You can use the `ns` attribute to let Alloy using something else then `Ti.UI`, which is what we needed for [Live Photos](livephotos.md). The `module` attribute is very similar but its value will be wrapped in `require(..)`. This means we can load any native or CommonJS module to deliver us the view factory method(s) we need. 44 | 45 | ## Configure the StreetViewPanorama 46 | 47 | The [API reference](http://docs.appcelerator.com/platform/latest/#!/api/Modules.Map) for the StreetViewPanorama is currently [missing](https://jira.appcelerator.org/browse/TIDOC-2450). Luckily there's just a few properties and the samples shows you all of them. 48 | 49 | ### Set the location 50 | First of all we need to set the position. We use the ID we've assigned the tag in the above XML view to set the position in [streetview.tss](../app/styles/android/streetview.tss#L1-L8): 51 | 52 | '#streetView': { 53 | position: { 54 | latitude: 37.3676332, 55 | longitude: -121.9139205 56 | } 57 | } 58 | 59 | > **NOTE:** Strange enough the [Android API](https://developers.google.com/maps/documentation/android-api/streetview#set_the_location_of_the_panorama) does not allow you set the heading. It seems always start headed North. 60 | 61 | ### Customize the user-controlled functionality 62 | There are a few features you can disable. All of them are on by default. In the Sample App I have [overlaid some buttons](../app/views/android/streetview.xml#L8-L13) so you can easily [toggle](../app/controllers/android/streetview.js#L5-L13) these boolean properties. 63 | 64 | * `panning`: Determines whether the user will be able to re-orient the camera by dragging. 65 | * `userNavigation`: Determines whether the user will be able to move to a different panorama. Users can use a single tap on navigation links, or double tap the view, to move to a new panorama. 66 | * `zoom`: Determines whether the user will be able to pinch to zoom. 67 | * `streetNames`: Determines whether the user is able to see street names displayed on the ground. 68 | 69 | ## Run on Android Device or Emulator 70 | 71 | To use Google Maps the device or emulator needs to have [Google Play Services](https://developers.google.com/android/guides/overview) installed. This comes - and is silently updated - with the Google Play app that you will find on pretty much any Android device. 72 | 73 | Unfortunately, the popular [Genymotion](https://www.genymotion.com/) emulator [comes without Google Apps](https://www.genymotion.com/faq/#google-apps-missing) because of a legal dispute with Google. You can find instructions on how to add Google Apps to Genymotion emulators on [Google](https://www.google.com/search?q=genymotion%20google%20apps). 74 | 75 | However, you might also consider giving the stock AVDs (Android Virtual Device) another try. Most of them include Google APIs, the performance has improved a lot recently and [Android Studio](http://developer.android.com/sdk/index.html) makes it very easy to [manage AVDs](http://developer.android.com/tools/devices/managing-avds.html) for tons of common devices:

76 | 77 | ![AVD](https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/master/docs/assets/avd.png) 78 | 79 | And yes, these AVDs work fine with Titanium! 80 | 81 | Code Strong! 🚀 82 | -------------------------------------------------------------------------------- /docs/transitions.md: -------------------------------------------------------------------------------- 1 | # Titanium 5.2.0: Android Activity & Shared Element Transitions 2 | 3 | Android 5.0 (API level 21) introduced [Material Design](http://developer.android.com/design/material/index.html): a vision, [design guidelines](http://www.google.com/design/spec/material-design/introduction.html) as well as new components and animations. Earlier in Titanium 5.1.0 we added support for [CardView](https://github.com/appcelerator-developer-relations/appc-sample-ti510#cardview), the [Reveal Effect](https://github.com/appcelerator-developer-relations/appc-sample-ti510#reveal-effect) animation as additional support for the [material design theme](https://github.com/appcelerator-developer-relations/appc-sample-ti510#progressbar-color). 4 | 5 | Now in [Titanium 5.2.0](http://www.appcelerator.com/blog/2016/02/ga-release-of-cli-5-2-titanium-5-2-and-studio-4-5/) we add support for customized [Activity & Shared Element Transitions](https://developer.android.com/training/material/animations.html#Transitions). In this blog post I'll walk you through this using the new [Titanium 5.2.0 Sample App](http://github.com/appcelerator-developer-relations/appc-sample-ti520): 6 | 7 | [![video](http://img.youtube.com/vi/Cg8HmQBP4jk/0.jpg)](https://www.youtube.com/watch?v=Cg8HmQBP4jk) 8 | 9 | ## What is an Activity? 10 | In Titanium each Window or TabGroup creates and is linked to a new [Activity](http://developer.android.com/guide/components/activities.html). When the user presses the [system back button](http://developer.android.com/training/implementing-navigation/temporal.html) he will return to the previous activity on the stack. You can access the Activity via the [activity property](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Window-property-activity). 11 | 12 | ## What Activity Transitions are there? 13 | 14 | It's important to understand the difference between the different transitions an activity goes through that you can customize. You can see all four of them explained in the following diagram: 15 | 16 | ![Transition Lifecycle](assets/transitions.png) 17 | 18 | As you go from Window A to B, Window A will **exit** and B will **enter**. When you press the system back button to return to Window A, then Window B will **return** and A will **reenter**. 19 | 20 | > **NOTE:** It's a known issue that when you programmatically close a Window using its `close()` the **return** and **reenter** transitions are ignored ([TIMOB-20451](https://jira.appcelerator.org/browse/TIMOB-20451)). The system back button shows the expected behaviour. 21 | 22 | For more details I recommend Alex Lockwood's [Getting Started with Activity & Fragment Transitions](http://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html). 23 | 24 | ## How to customize Activity Transitions? 25 | 26 | First of all, the Android APIs are designed in such a way that as soon as you define shared elements, both the `activity*Transition`s and `sharedElement*Transition`s get defaults (which I'll get to soon) that you're unlikely to need to change at all. 27 | 28 | > **NOTE:** Currently Activity Transitions will only work if you have declared shared elements. We're looking into making them work without as well ([TIMOB-20507](https://jira.appcelerator.org/browse/TIMOB-20507)). 29 | 30 | To customize the transitions you can use the following properties: 31 | 32 | * `Ti.UI.Window.activityExitTransition` 33 | * `Ti.UI.Window.activityEnterTransition` 34 | * `Ti.UI.Window.activityReturnTransition` 35 | * `Ti.UI.Window.activityReenterTransition` 36 | 37 | > **NOTE:** Unfortunately the API reference of these properties currently has them located under the Window `open()` and `close()` [parameters](http://docs.appcelerator.com/platform/latest/#!/api/openWindowParams) ([TIDOC-2454](https://jira.appcelerator.org/browse/TIDOC-2454)). 38 | 39 | The above properties can be set to the following constants: 40 | 41 | * [`Ti.UI.Android.TRANSITION_EXPLODE`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_EXPLODE) 42 | * [`Ti.UI.Android.TRANSITION_FADE_IN`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_FADE_IN) 43 | * [`Ti.UI.Android.TRANSITION_FADE_OUT`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_FADE_OUT) 44 | * [`Ti.UI.Android.TRANSITION_SLIDE_TOP`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_SLIDE_TOP) 45 | * [`Ti.UI.Android.TRANSITION_SLIDE_RIGHT`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-SLIDE_RIGHT) 46 | * [`Ti.UI.Android.TRANSITION_SLIDE_BOTTOM`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-SLIDE_BOTTOM) 47 | * [`Ti.UI.Android.TRANSITION_SLIDE_LEFT`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-SLIDE_LEFT) 48 | * [`Ti.UI.Android.TRANSITION_NONE`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_NONE) 49 | 50 | The sample lets you [set these properties](../app/views/android/transitions_a.xml#L8) from within the app to play with the options. 51 | 52 | ### Transition defaults 53 | In most cases you will only set **enter** and **exit** because **reenter** will default to **exit** as will **return** to **enter**. In turn, **exit** defaults to no animation and **enter** to `FADE_INT`. 54 | 55 | ### Disable transitions 56 | You can disable transitions at all time by passing `{animated:false}` to the Window `open()` or `close()` method. As mentioned, they will currently also not be used if you don't declare any shared elements. 57 | 58 | ## What Shared Element Transitions are there? 59 | Again, Alex Lockwood does a great job at explaining working with [Shared Elements](http://www.androiddesignpatterns.com/2015/01/activity-fragment-shared-element-transitions-in-depth-part3a.html). 60 | 61 | What it comes down to is that as you transition from one Window to the next you can link individual related views between both Windows and have them animate from one to the other as if they were one. 62 | 63 | If you scroll back to the screenrecording of our Sample App you can see that the Appcelerator logo and the next underneath display this behaviour. Again, the sample allows you to change the transition style for these shared elements. 64 | 65 | ## How to customize Shared Element Transitions? 66 | 67 | Like I said the Android APIs are designed in such a way that you're unlikely to want to change the defaults. But as with Activity Transitions, we have four properties we can use to do so anyway. Their names might be very similar to those for the Activity Transitions, but their meaning is slightly different. 68 | 69 | > **NOTE:** Unfortunately the API reference of these properties currently has them located under the Window `open()` and `close()` [parameters](http://docs.appcelerator.com/platform/latest/#!/api/openWindowParams) ([TIDOC-2454](https://jira.appcelerator.org/browse/TIDOC-2454)). 70 | 71 | Let's start with two properties you can set on Window B: 72 | 73 | * `Ti.UI.Window.activitySharedElementEnterTransition` to determine how shared elements animate from A to B. Defaults to all of them in parallel. 74 | * `Ti.UI.Window.activitySharedElementReturnTransition` to determine how shared elements animate form B to A. Defaults to all of them in parallel. 75 | 76 | Additionally you can also set two properties on Window A. Now as Alex [points out](http://www.androiddesignpatterns.com/2015/01/activity-fragment-shared-element-transitions-in-depth-part3a.html#footnote1) there are very use cases for these two. In fact, the animations Titanium currently exposes would not be noticeable. 77 | 78 | * `Ti.UI.Window.activitySharedElementExitTransition` animates shared elements **before** they use B's **enter** transition to animate from A to B. 79 | * `Ti.UI.Window.activitySharedElementReeenterTransition` animated shared elements **after** they use B's **return** transition to animate from B to A. Defaults to the **exit** transition. 80 | 81 | You can set these four properties to the following constants: 82 | 83 | * [`Ti.UI.Android.TRANSITION_CHANGE_BOUNDS`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_CHANGE_BOUNDS) 84 | * [`Ti.UI.Android.TRANSITION_CHANGE_CLIP_BOUNDS`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_CLIP_BOUNDS) 85 | * [`Ti.UI.Android.TRANSITION_CHANGE_TRANSFORM`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_CHANGE_TRANSFORM) 86 | * [`Ti.UI.Android.TRANSITION_CHANGE_IMAGE_TRANSFORM`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_CHANGE_IMAGE_TRANSFORM) 87 | * [`Ti.UI.Android.TRANSITION_NONE`](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Android-property-TRANSITION_NONE) 88 | 89 | ## How to define Shared Elements to enable these Transitions? 90 | 91 | Now how do we put all these properties and constants into use and actually define Shared Elements so that we can see both the Activity and Shared Element Transitions in action? 92 | 93 | 1. In both Windows we need to set the new [transitionName](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.View-property-transitionName) property to the same value for each shared element. You can see we've done this in [Window A](../app/views/android/transitions_a.xml#L66-L67) and [Window B](../app/views/android/transitions_b.xml#L7-L9) of our Sample App. The name should be unique within each Window. 94 | 2. Before we open Window B we then need to use its new [addSharedElement()](http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Window-method-addSharedElement) method. This method takes two properties. The first should be a reference to the shared view in Window A. The second is the value of `transitionName` as it can be found in Window B. 95 | 96 | Sounds confusing? 97 | 98 | Have a look at the Sample's [transitions_a.xml](../app/views/android/transitions_a.xml#L66-L67), [transitions_b.xml](../app/views/android/transitions_b.xml#L7-L9) and [transition_a.js](../app/controllers/android/transitions_a.js#L30-L31). In the end, when you rely on the default transition animations, this is all you need to set. 99 | 100 | In both views: 101 | 102 | ``` 103 | 104 | 105 | ``` 106 | 107 | In the controller for Window A, before opening Window B: 108 | 109 | ``` 110 | win.addSharedElement($.logo, 'logo'); 111 | win.addSharedElement($.text, 'text'); 112 | ``` 113 | 114 | Let's make some truly *animating* Titanium Android apps! 115 | 116 | \- Code Strong 🚀 117 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "24x24", 5 | "idiom" : "watch", 6 | "filename" : "icon-24@2x.png", 7 | "scale" : "2x", 8 | "role" : "notificationCenter", 9 | "subtype" : "38mm" 10 | }, 11 | { 12 | "size" : "27.5x27.5", 13 | "idiom" : "watch", 14 | "filename" : "icon-27.5@2x.png", 15 | "scale" : "2x", 16 | "role" : "notificationCenter", 17 | "subtype" : "42mm" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "watch", 22 | "filename" : "icon-29@2x.png", 23 | "role" : "companionSettings", 24 | "scale" : "2x" 25 | }, 26 | { 27 | "size" : "29x29", 28 | "idiom" : "watch", 29 | "filename" : "icon-29@3x.png", 30 | "role" : "companionSettings", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "watch", 36 | "filename" : "icon-40@2x.png", 37 | "scale" : "2x", 38 | "role" : "appLauncher", 39 | "subtype" : "38mm" 40 | }, 41 | { 42 | "size" : "44x44", 43 | "idiom" : "watch", 44 | "filename" : "icon-44@2x.png", 45 | "scale" : "2x", 46 | "role" : "longLook", 47 | "subtype" : "42mm" 48 | }, 49 | { 50 | "size" : "86x86", 51 | "idiom" : "watch", 52 | "filename" : "icon-86@2x.png", 53 | "scale" : "2x", 54 | "role" : "quickLook", 55 | "subtype" : "38mm" 56 | }, 57 | { 58 | "size" : "98x98", 59 | "idiom" : "watch", 60 | "filename" : "icon-98@2x.png", 61 | "scale" : "2x", 62 | "role" : "quickLook", 63 | "subtype" : "42mm" 64 | } 65 | ], 66 | "info" : { 67 | "version" : 1, 68 | "author" : "xcode" 69 | } 70 | } -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-24@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-24@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-27.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-27.5@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-44@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-44@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-86@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-86@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-98@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appcelerator-developer-relations/appc-sample-ti520/e91e8b14182114b2912d60cd4604dc06170df8e7/extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Assets.xcassets/AppIcon.appiconset/icon-98@2x.png -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Base.lproj/Interface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Ti 5.2.0 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | UISupportedInterfaceOrientations 26 | 27 | UIInterfaceOrientationPortrait 28 | UIInterfaceOrientationPortraitUpsideDown 29 | 30 | WKCompanionAppBundleIdentifier 31 | com.appcelerator.sample.ti520 32 | WKWatchKitApp 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/Assets.xcassets/README__ignoredByTemplate__: -------------------------------------------------------------------------------- 1 | Did you know that git does not support storing empty directories? 2 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/ExtensionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionDelegate.h 3 | // Ti 5.2.0 WatchKit Extension 4 | // 5 | // Created by Appcelerator on 2/18/2016. 6 | // 2016 by Appcelerator, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ExtensionDelegate : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/ExtensionDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionDelegate.m 3 | // Ti 5.2.0 WatchKit Extension 4 | // 5 | // Created by Appcelerator on 2/18/2016. 6 | // 2016 by Appcelerator, Inc. All rights reserved. 7 | // 8 | 9 | #import "ExtensionDelegate.h" 10 | 11 | @implementation ExtensionDelegate 12 | 13 | - (void)applicationDidFinishLaunching { 14 | // Perform any final initialization of your application. 15 | } 16 | 17 | - (void)applicationDidBecomeActive { 18 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 19 | } 20 | 21 | - (void)applicationWillResignActive { 22 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 23 | // Use this method to pause ongoing tasks, disable timers, etc. 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Ti 5.2.0 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | WKAppBundleIdentifier 30 | com.appcelerator.sample.ti520.watchkitapp 31 | 32 | NSExtensionPointIdentifier 33 | com.apple.watchkit 34 | 35 | RemoteInterfacePrincipalClass 36 | $(PRODUCT_MODULE_NAME).InterfaceController 37 | WKExtensionDelegateClassName 38 | $(PRODUCT_MODULE_NAME).ExtensionDelegate 39 | 40 | 41 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/InterfaceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.h 3 | // Ti 5.2.0 WatchKit Extension 4 | // 5 | // Created by Appcelerator on 2/18/2016. 6 | // 2016 by Appcelerator, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface InterfaceController : WKInterfaceController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/InterfaceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.m 3 | // Ti 5.2.0 WatchKit Extension 4 | // 5 | // Created by Appcelerator on 2/18/2016. 6 | // 2016 by Appcelerator, Inc. All rights reserved. 7 | // 8 | 9 | #import "InterfaceController.h" 10 | 11 | 12 | @interface InterfaceController() 13 | 14 | @end 15 | 16 | 17 | @implementation InterfaceController 18 | 19 | - (instancetype)init { 20 | self = [super init]; 21 | 22 | if (self) { 23 | 24 | if ([WCSession isSupported]) { 25 | WCSession* session = [WCSession defaultSession]; 26 | session.delegate = self; 27 | [session activateSession]; 28 | } 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (void)awakeWithContext:(id)context { 35 | [super awakeWithContext:context]; 36 | 37 | // Configure interface objects here. 38 | } 39 | 40 | - (void)willActivate { 41 | // This method is called when watch view controller is about to be visible to user 42 | [super willActivate]; 43 | } 44 | 45 | - (void)didDeactivate { 46 | // This method is called when watch view controller is no longer visible 47 | [super didDeactivate]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/NotificationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationController.h 3 | // Ti 5.2.0 WatchKit Extension 4 | // 5 | // Created by Appcelerator on 2/18/2016. 6 | // 2016 by Appcelerator, Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface NotificationController : WKUserNotificationInterfaceController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/NotificationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationController.m 3 | // Ti 5.2.0 WatchKit Extension 4 | // 5 | // Created by Appcelerator on 2/18/2016. 6 | // 2016 by Appcelerator, Inc. All rights reserved. 7 | // 8 | 9 | #import "NotificationController.h" 10 | 11 | 12 | @interface NotificationController() 13 | 14 | @end 15 | 16 | 17 | @implementation NotificationController 18 | 19 | - (instancetype)init { 20 | self = [super init]; 21 | if (self){ 22 | // Initialize variables here. 23 | // Configure interface objects here. 24 | 25 | } 26 | return self; 27 | } 28 | 29 | - (void)willActivate { 30 | // This method is called when watch view controller is about to be visible to user 31 | [super willActivate]; 32 | } 33 | 34 | - (void)didDeactivate { 35 | // This method is called when watch view controller is no longer visible 36 | [super didDeactivate]; 37 | } 38 | 39 | /* 40 | - (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { 41 | // This method is called when a local notification needs to be presented. 42 | // Implement it if you use a dynamic notification interface. 43 | // Populate your dynamic notification interface as quickly as possible. 44 | // 45 | // After populating your dynamic notification interface call the completion block. 46 | completionHandler(WKUserNotificationInterfaceTypeCustom); 47 | } 48 | */ 49 | 50 | /* 51 | - (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { 52 | // This method is called when a remote notification needs to be presented. 53 | // Implement it if you use a dynamic notification interface. 54 | // Populate your dynamic notification interface as quickly as possible. 55 | // 56 | // After populating your dynamic notification interface call the completion block. 57 | completionHandler(WKUserNotificationInterfaceTypeCustom); 58 | } 59 | */ 60 | 61 | @end 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0 WatchKit Extension/PushNotificationPayload.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "alert": { 4 | "body": "Test message", 5 | "title": "Optional title" 6 | }, 7 | "category": "myCategory" 8 | }, 9 | 10 | "WatchKit Simulator Actions": [ 11 | { 12 | "title": "First Button", 13 | "identifier": "firstButtonAction" 14 | } 15 | ], 16 | 17 | "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App." 18 | } 19 | -------------------------------------------------------------------------------- /extensions/Ti 5.2.0/Ti 5.2.0.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 83BEF1CF1B5453F4006F38C4 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 83BEF1CD1B5453F4006F38C4 /* Interface.storyboard */; }; 11 | 83BEF1D11B5453F4006F38C4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83BEF1D01B5453F4006F38C4 /* Assets.xcassets */; }; 12 | 83BEF1D81B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 83BEF1D71B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 13 | 83BEF1E01B5453F4006F38C4 /* InterfaceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEF1DF1B5453F4006F38C4 /* InterfaceController.m */; }; 14 | 83BEF1E31B5453F4006F38C4 /* ExtensionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEF1E21B5453F4006F38C4 /* ExtensionDelegate.m */; }; 15 | 83BEF1E61B5453F4006F38C4 /* NotificationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEF1E51B5453F4006F38C4 /* NotificationController.m */; }; 16 | 83BEF1EB1B5453F4006F38C4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83BEF1EA1B5453F4006F38C4 /* Assets.xcassets */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 83BEF1D91B5453F4006F38C4 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 83BEF18B1B5453D8006F38C4 /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 83BEF1D61B5453F4006F38C4; 25 | remoteInfo = "Ti 5.2.0 WatchKit Extension"; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXCopyFilesBuildPhase section */ 30 | 83BEF1F31B5453F4006F38C4 /* Embed App Extensions */ = { 31 | isa = PBXCopyFilesBuildPhase; 32 | buildActionMask = 2147483647; 33 | dstPath = ""; 34 | dstSubfolderSpec = 13; 35 | files = ( 36 | 83BEF1D81B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension.appex in Embed App Extensions */, 37 | ); 38 | name = "Embed App Extensions"; 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXCopyFilesBuildPhase section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 83BEF1CB1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ti 5.2.0 WatchKit App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 83BEF1CE1B5453F4006F38C4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; 46 | 83BEF1D01B5453F4006F38C4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | 83BEF1D21B5453F4006F38C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 83BEF1D71B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Ti 5.2.0 WatchKit Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 83BEF1DD1B5453F4006F38C4 /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = ""; }; 50 | 83BEF1DE1B5453F4006F38C4 /* InterfaceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InterfaceController.h; sourceTree = ""; }; 51 | 83BEF1DF1B5453F4006F38C4 /* InterfaceController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InterfaceController.m; sourceTree = ""; }; 52 | 83BEF1E11B5453F4006F38C4 /* ExtensionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExtensionDelegate.h; sourceTree = ""; }; 53 | 83BEF1E21B5453F4006F38C4 /* ExtensionDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtensionDelegate.m; sourceTree = ""; }; 54 | 83BEF1E41B5453F4006F38C4 /* NotificationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationController.h; sourceTree = ""; }; 55 | 83BEF1E51B5453F4006F38C4 /* NotificationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationController.m; sourceTree = ""; }; 56 | 83BEF1EA1B5453F4006F38C4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 57 | 83BEF1EC1B5453F4006F38C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 83BEF1D41B5453F4006F38C4 /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 83BEF18A1B5453D8006F38C4 = { 72 | isa = PBXGroup; 73 | children = ( 74 | 83BEF1CC1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App */, 75 | 83BEF1DB1B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension */, 76 | 83BEF1941B5453D8006F38C4 /* Products */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 83BEF1941B5453D8006F38C4 /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 83BEF1CB1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App.app */, 84 | 83BEF1D71B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension.appex */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | 83BEF1CC1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 83BEF1CD1B5453F4006F38C4 /* Interface.storyboard */, 93 | 83BEF1D01B5453F4006F38C4 /* Assets.xcassets */, 94 | 83BEF1D21B5453F4006F38C4 /* Info.plist */, 95 | ); 96 | path = "Ti 5.2.0 WatchKit App"; 97 | sourceTree = ""; 98 | }; 99 | 83BEF1DB1B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 83BEF1DE1B5453F4006F38C4 /* InterfaceController.h */, 103 | 83BEF1DF1B5453F4006F38C4 /* InterfaceController.m */, 104 | 83BEF1E11B5453F4006F38C4 /* ExtensionDelegate.h */, 105 | 83BEF1E21B5453F4006F38C4 /* ExtensionDelegate.m */, 106 | 83BEF1E41B5453F4006F38C4 /* NotificationController.h */, 107 | 83BEF1E51B5453F4006F38C4 /* NotificationController.m */, 108 | 83BEF1EA1B5453F4006F38C4 /* Assets.xcassets */, 109 | 83BEF1EC1B5453F4006F38C4 /* Info.plist */, 110 | 83BEF1DC1B5453F4006F38C4 /* Supporting Files */, 111 | ); 112 | path = "Ti 5.2.0 WatchKit Extension"; 113 | sourceTree = ""; 114 | }; 115 | 83BEF1DC1B5453F4006F38C4 /* Supporting Files */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 83BEF1DD1B5453F4006F38C4 /* PushNotificationPayload.apns */, 119 | ); 120 | name = "Supporting Files"; 121 | sourceTree = ""; 122 | }; 123 | /* End PBXGroup section */ 124 | 125 | /* Begin PBXNativeTarget section */ 126 | 83BEF1CA1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App */ = { 127 | isa = PBXNativeTarget; 128 | buildConfigurationList = 83BEF1F41B5453F4006F38C4 /* Build configuration list for PBXNativeTarget "Ti 5.2.0 WatchKit App" */; 129 | buildPhases = ( 130 | 83BEF1C91B5453F4006F38C4 /* Resources */, 131 | 83BEF1F31B5453F4006F38C4 /* Embed App Extensions */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | 83BEF1DA1B5453F4006F38C4 /* PBXTargetDependency */, 137 | ); 138 | name = "Ti 5.2.0 WatchKit App"; 139 | productName = "Ti 5.2.0 WatchKit App"; 140 | productReference = 83BEF1CB1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App.app */; 141 | productType = "com.apple.product-type.application.watchapp2"; 142 | }; 143 | 83BEF1D61B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension */ = { 144 | isa = PBXNativeTarget; 145 | buildConfigurationList = 83BEF1F01B5453F4006F38C4 /* Build configuration list for PBXNativeTarget "Ti 5.2.0 WatchKit Extension" */; 146 | buildPhases = ( 147 | 83BEF1D31B5453F4006F38C4 /* Sources */, 148 | 83BEF1D41B5453F4006F38C4 /* Frameworks */, 149 | 83BEF1D51B5453F4006F38C4 /* Resources */, 150 | ); 151 | buildRules = ( 152 | ); 153 | dependencies = ( 154 | ); 155 | name = "Ti 5.2.0 WatchKit Extension"; 156 | productName = "Ti 5.2.0 WatchKit Extension"; 157 | productReference = 83BEF1D71B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension.appex */; 158 | productType = "com.apple.product-type.watchkit2-extension"; 159 | }; 160 | /* End PBXNativeTarget section */ 161 | 162 | /* Begin PBXProject section */ 163 | 83BEF18B1B5453D8006F38C4 /* Project object */ = { 164 | isa = PBXProject; 165 | attributes = { 166 | LastUpgradeCheck = 0700; 167 | ORGANIZATIONNAME = Appcelerator; 168 | TargetAttributes = { 169 | 83BEF1CA1B5453F4006F38C4 = { 170 | CreatedOnToolsVersion = 7.0; 171 | }; 172 | 83BEF1D61B5453F4006F38C4 = { 173 | CreatedOnToolsVersion = 7.0; 174 | }; 175 | }; 176 | }; 177 | buildConfigurationList = 83BEF18E1B5453D8006F38C4 /* Build configuration list for PBXProject "Ti 5.2.0" */; 178 | compatibilityVersion = "Xcode 3.2"; 179 | developmentRegion = English; 180 | hasScannedForEncodings = 0; 181 | knownRegions = ( 182 | en, 183 | Base, 184 | ); 185 | mainGroup = 83BEF18A1B5453D8006F38C4; 186 | productRefGroup = 83BEF1941B5453D8006F38C4 /* Products */; 187 | projectDirPath = ""; 188 | projectRoot = ""; 189 | targets = ( 190 | 83BEF1CA1B5453F4006F38C4 /* Ti 5.2.0 WatchKit App */, 191 | 83BEF1D61B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension */, 192 | ); 193 | }; 194 | /* End PBXProject section */ 195 | 196 | /* Begin PBXResourcesBuildPhase section */ 197 | 83BEF1C91B5453F4006F38C4 /* Resources */ = { 198 | isa = PBXResourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | 83BEF1D11B5453F4006F38C4 /* Assets.xcassets in Resources */, 202 | 83BEF1CF1B5453F4006F38C4 /* Interface.storyboard in Resources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | 83BEF1D51B5453F4006F38C4 /* Resources */ = { 207 | isa = PBXResourcesBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | 83BEF1EB1B5453F4006F38C4 /* Assets.xcassets in Resources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | /* End PBXResourcesBuildPhase section */ 215 | 216 | /* Begin PBXSourcesBuildPhase section */ 217 | 83BEF1D31B5453F4006F38C4 /* Sources */ = { 218 | isa = PBXSourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | 83BEF1E31B5453F4006F38C4 /* ExtensionDelegate.m in Sources */, 222 | 83BEF1E01B5453F4006F38C4 /* InterfaceController.m in Sources */, 223 | 83BEF1E61B5453F4006F38C4 /* NotificationController.m in Sources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXSourcesBuildPhase section */ 228 | 229 | /* Begin PBXTargetDependency section */ 230 | 83BEF1DA1B5453F4006F38C4 /* PBXTargetDependency */ = { 231 | isa = PBXTargetDependency; 232 | target = 83BEF1D61B5453F4006F38C4 /* Ti 5.2.0 WatchKit Extension */; 233 | targetProxy = 83BEF1D91B5453F4006F38C4 /* PBXContainerItemProxy */; 234 | }; 235 | /* End PBXTargetDependency section */ 236 | 237 | /* Begin PBXVariantGroup section */ 238 | 83BEF1CD1B5453F4006F38C4 /* Interface.storyboard */ = { 239 | isa = PBXVariantGroup; 240 | children = ( 241 | 83BEF1CE1B5453F4006F38C4 /* Base */, 242 | ); 243 | name = Interface.storyboard; 244 | sourceTree = ""; 245 | }; 246 | /* End PBXVariantGroup section */ 247 | 248 | /* Begin XCBuildConfiguration section */ 249 | 83BEF1BE1B5453D8006F38C4 /* Debug */ = { 250 | isa = XCBuildConfiguration; 251 | buildSettings = { 252 | ALWAYS_SEARCH_USER_PATHS = NO; 253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 254 | CLANG_CXX_LIBRARY = "libc++"; 255 | CLANG_ENABLE_MODULES = YES; 256 | CLANG_ENABLE_OBJC_ARC = YES; 257 | CLANG_WARN_BOOL_CONVERSION = YES; 258 | CLANG_WARN_CONSTANT_CONVERSION = YES; 259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 260 | CLANG_WARN_EMPTY_BODY = YES; 261 | CLANG_WARN_ENUM_CONVERSION = YES; 262 | CLANG_WARN_INT_CONVERSION = YES; 263 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 264 | CLANG_WARN_UNREACHABLE_CODE = YES; 265 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 266 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 267 | COPY_PHASE_STRIP = NO; 268 | DEBUG_INFORMATION_FORMAT = dwarf; 269 | ENABLE_STRICT_OBJC_MSGSEND = YES; 270 | ENABLE_TESTABILITY = YES; 271 | GCC_C_LANGUAGE_STANDARD = gnu99; 272 | GCC_DYNAMIC_NO_PIC = NO; 273 | GCC_NO_COMMON_BLOCKS = YES; 274 | GCC_OPTIMIZATION_LEVEL = 0; 275 | GCC_PREPROCESSOR_DEFINITIONS = ( 276 | "DEBUG=1", 277 | "$(inherited)", 278 | ); 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 286 | MTL_ENABLE_DEBUG_INFO = YES; 287 | ONLY_ACTIVE_ARCH = YES; 288 | SDKROOT = iphoneos; 289 | TARGETED_DEVICE_FAMILY = "1,2"; 290 | }; 291 | name = Debug; 292 | }; 293 | 83BEF1BF1B5453D8006F38C4 /* Release */ = { 294 | isa = XCBuildConfiguration; 295 | buildSettings = { 296 | ALWAYS_SEARCH_USER_PATHS = NO; 297 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 298 | CLANG_CXX_LIBRARY = "libc++"; 299 | CLANG_ENABLE_MODULES = YES; 300 | CLANG_ENABLE_OBJC_ARC = YES; 301 | CLANG_WARN_BOOL_CONVERSION = YES; 302 | CLANG_WARN_CONSTANT_CONVERSION = YES; 303 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 304 | CLANG_WARN_EMPTY_BODY = YES; 305 | CLANG_WARN_ENUM_CONVERSION = YES; 306 | CLANG_WARN_INT_CONVERSION = YES; 307 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 308 | CLANG_WARN_UNREACHABLE_CODE = YES; 309 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 310 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 311 | COPY_PHASE_STRIP = NO; 312 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 313 | ENABLE_NS_ASSERTIONS = NO; 314 | ENABLE_STRICT_OBJC_MSGSEND = YES; 315 | GCC_C_LANGUAGE_STANDARD = gnu99; 316 | GCC_NO_COMMON_BLOCKS = YES; 317 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 318 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 319 | GCC_WARN_UNDECLARED_SELECTOR = YES; 320 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 321 | GCC_WARN_UNUSED_FUNCTION = YES; 322 | GCC_WARN_UNUSED_VARIABLE = YES; 323 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 324 | MTL_ENABLE_DEBUG_INFO = NO; 325 | SDKROOT = iphoneos; 326 | TARGETED_DEVICE_FAMILY = "1,2"; 327 | VALIDATE_PRODUCT = YES; 328 | }; 329 | name = Release; 330 | }; 331 | 83BEF1F11B5453F4006F38C4 /* Debug */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; 335 | INFOPLIST_FILE = "Ti 5.2.0 WatchKit Extension/Info.plist"; 336 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; 337 | PRODUCT_BUNDLE_IDENTIFIER = com.appcelerator.sample.ti520.watchkitapp.watchkitextension; 338 | PRODUCT_NAME = "${TARGET_NAME}"; 339 | SDKROOT = watchos; 340 | SKIP_INSTALL = YES; 341 | TARGETED_DEVICE_FAMILY = 4; 342 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 343 | }; 344 | name = Debug; 345 | }; 346 | 83BEF1F21B5453F4006F38C4 /* Release */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; 350 | INFOPLIST_FILE = "Ti 5.2.0 WatchKit Extension/Info.plist"; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; 352 | PRODUCT_BUNDLE_IDENTIFIER = com.appcelerator.sample.ti520.watchkitapp.watchkitextension; 353 | PRODUCT_NAME = "${TARGET_NAME}"; 354 | SDKROOT = watchos; 355 | SKIP_INSTALL = YES; 356 | TARGETED_DEVICE_FAMILY = 4; 357 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 358 | }; 359 | name = Release; 360 | }; 361 | 83BEF1F51B5453F4006F38C4 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 365 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; 366 | IBSC_MODULE = Ti_5_2_0_WatchKit_Extension; 367 | INFOPLIST_FILE = "Ti 5.2.0 WatchKit App/Info.plist"; 368 | PRODUCT_BUNDLE_IDENTIFIER = com.appcelerator.sample.ti520.watchkitapp; 369 | PRODUCT_NAME = "$(TARGET_NAME)"; 370 | SDKROOT = watchos; 371 | SKIP_INSTALL = YES; 372 | TARGETED_DEVICE_FAMILY = 4; 373 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 374 | }; 375 | name = Debug; 376 | }; 377 | 83BEF1F61B5453F4006F38C4 /* Release */ = { 378 | isa = XCBuildConfiguration; 379 | buildSettings = { 380 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 381 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; 382 | IBSC_MODULE = Ti_5_2_0_WatchKit_Extension; 383 | INFOPLIST_FILE = "Ti 5.2.0 WatchKit App/Info.plist"; 384 | PRODUCT_BUNDLE_IDENTIFIER = com.appcelerator.sample.ti520.watchkitapp; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | SDKROOT = watchos; 387 | SKIP_INSTALL = YES; 388 | TARGETED_DEVICE_FAMILY = 4; 389 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 390 | }; 391 | name = Release; 392 | }; 393 | /* End XCBuildConfiguration section */ 394 | 395 | /* Begin XCConfigurationList section */ 396 | 83BEF18E1B5453D8006F38C4 /* Build configuration list for PBXProject "Ti 5.2.0" */ = { 397 | isa = XCConfigurationList; 398 | buildConfigurations = ( 399 | 83BEF1BE1B5453D8006F38C4 /* Debug */, 400 | 83BEF1BF1B5453D8006F38C4 /* Release */, 401 | ); 402 | defaultConfigurationIsVisible = 0; 403 | defaultConfigurationName = Release; 404 | }; 405 | 83BEF1F01B5453F4006F38C4 /* Build configuration list for PBXNativeTarget "Ti 5.2.0 WatchKit Extension" */ = { 406 | isa = XCConfigurationList; 407 | buildConfigurations = ( 408 | 83BEF1F11B5453F4006F38C4 /* Debug */, 409 | 83BEF1F21B5453F4006F38C4 /* Release */, 410 | ); 411 | defaultConfigurationIsVisible = 0; 412 | }; 413 | 83BEF1F41B5453F4006F38C4 /* Build configuration list for PBXNativeTarget "Ti 5.2.0 WatchKit App" */ = { 414 | isa = XCConfigurationList; 415 | buildConfigurations = ( 416 | 83BEF1F51B5453F4006F38C4 /* Debug */, 417 | 83BEF1F61B5453F4006F38C4 /* Release */, 418 | ); 419 | defaultConfigurationIsVisible = 0; 420 | }; 421 | /* End XCConfigurationList section */ 422 | }; 423 | rootObject = 83BEF18B1B5453D8006F38C4 /* Project object */; 424 | } 425 | -------------------------------------------------------------------------------- /platform/ios/_LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /plugins/ti.alloy/hooks/alloy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Alloy 3 | * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved. 4 | * See LICENSE for more information on licensing. 5 | */ 6 | 7 | exports.cliVersion = '>=3.X'; 8 | exports.version = '1.0.0'; 9 | var SILENT = true; 10 | 11 | exports.init = function (logger, config, cli, appc) { 12 | var path = require('path'), 13 | fs = require('fs'), 14 | afs = appc.fs, 15 | i18n = appc.i18n(__dirname), 16 | __ = i18n.__, 17 | __n = i18n.__n, 18 | pkginfo = appc.pkginfo.package(module), 19 | exec = require('child_process').exec, 20 | spawn = require('child_process').spawn, 21 | parallel = appc.async.parallel; 22 | 23 | if(!process.env.sdk) { 24 | process.env.sdk = cli.sdk.name; 25 | } 26 | 27 | function run(deviceFamily, deployType, target, finished, silent) { 28 | var appDir = path.join(cli.argv['project-dir'], 'app'); 29 | if (!afs.exists(appDir)) { 30 | logger.info(__('Project not an Alloy app, continuing')); 31 | finished(); 32 | return; 33 | } 34 | logger.info(__('Found Alloy app in %s', appDir.cyan)); 35 | 36 | // TODO: Make this check specific to a TiSDK version 37 | // create a .alloynewcli file to tell old plugins not to run 38 | var buildDir = path.join(cli.argv['project-dir'], 'build'); 39 | if (!afs.exists(buildDir)) { 40 | fs.mkdirSync(buildDir); 41 | } 42 | fs.writeFileSync(path.join(buildDir, '.alloynewcli'), ''); 43 | 44 | var cRequire = afs.resolvePath(__dirname, '..', 'Alloy', 'commands', 'compile', 'index.js'), 45 | config = { 46 | platform: /(?:iphone|ipad)/.test(cli.argv.platform) ? 'ios' : cli.argv.platform, 47 | version: '0', 48 | simtype: 'none', 49 | devicefamily: /(?:iphone|ios)/.test(cli.argv.platform) ? deviceFamily : 'none', 50 | deploytype: deployType || cli.argv['deploy-type'] || 'development', 51 | target: target 52 | }; 53 | if(silent) { 54 | // turn off all logging output for code analyzer build hook 55 | config.noBanner = 'true'; 56 | config.logLevel = '-1'; 57 | } 58 | 59 | config = Object.keys(config).map(function (c) { 60 | return c + '=' + config[c]; 61 | }).join(','); 62 | 63 | if (afs.exists(cRequire)) { 64 | // we're being invoked from the actual alloy directory! 65 | // no need to subprocess, just require() and run 66 | var origLimit = Error.stackTraceLimit; 67 | Error.stackTraceLimit = Infinity; 68 | try { 69 | require(cRequire)({}, { 70 | config: config, 71 | outputPath: cli.argv['project-dir'], 72 | _version: pkginfo.version 73 | }); 74 | } catch (e) { 75 | logger.error(__('Alloy compiler failed')); 76 | e.toString().split('\n').forEach(function (line) { 77 | if (line) { logger.error(line); } 78 | }); 79 | process.exit(1); 80 | } 81 | Error.stackTraceLimit = origLimit; 82 | finished(); 83 | } else { 84 | // we have no clue where alloy is installed, so we're going to subprocess 85 | // alloy and hope it's in the system path or a well known place 86 | var paths = {}; 87 | var locatorCmd = process.platform === 'win32' ? 'where' : 'which'; 88 | parallel(this, ['alloy', 'node'].map(function (bin) { 89 | return function (done) { 90 | var envName = 'ALLOY_' + (bin === 'node' ? 'NODE_' : '') + 'PATH'; 91 | 92 | paths[bin] = process.env[envName]; 93 | if (paths[bin]) { 94 | done(); 95 | } else if (process.platform === 'win32' && bin === 'alloy') { 96 | paths.alloy = 'alloy.cmd'; 97 | done(); 98 | } else { 99 | exec(locatorCmd + ' ' + bin, function (err, stdout, strerr) { 100 | if (!err) { 101 | paths[bin] = stdout.trim(); 102 | done(); 103 | } else { 104 | parallel(this, [ 105 | '/usr/local/bin/' + bin, 106 | '/opt/local/bin/' + bin, 107 | path.join(process.env.HOME, 'local/bin', bin), 108 | '/opt/bin/' + bin, 109 | '/usr/bin/' + bin 110 | ].map(function (p) { 111 | return function (cb) { 112 | if (afs.exists(p)) { paths[bin] = p; } 113 | cb(); 114 | }; 115 | }), done); 116 | } 117 | }); 118 | } 119 | }; 120 | }), function () { 121 | 122 | // compose alloy command execution 123 | var cmd = [paths.node, paths.alloy, 'compile', appDir, '--config', config]; 124 | if (cli.argv['no-colors'] || cli.argv['color'] === false) { cmd.push('--no-colors'); } 125 | 126 | // process each line of output from alloy 127 | function checkLine(line) { 128 | var re = new RegExp( 129 | '^(?:\u001b\\[\\d+m)?\\[?(' + 130 | logger.getLevels().join('|') + 131 | ')\\]?\s*(?:\u001b\\[\\d+m)?(.*)', 'i' 132 | ); 133 | if (line) { 134 | var m = line.match(re); 135 | if (m) { 136 | logger[m[1].toLowerCase()](m[2].trim()); 137 | } else { 138 | logger.debug(line); 139 | } 140 | } 141 | } 142 | 143 | // execute alloy in os-specific manner 144 | var child; 145 | if (process.platform === 'win32' && paths.alloy === 'alloy.cmd') { 146 | cmd.shift(); 147 | logger.info(__('Executing Alloy compile: %s', 148 | ['cmd','/s','/c'].concat(cmd).join(' ').cyan)); 149 | 150 | // arg processing from https://github.com/MarcDiethelm/superspawn 151 | child = spawn('cmd', [['/s', '/c', '"' + 152 | cmd.map(function(a) { 153 | if (/^[^"].* .*[^"]/.test(a)) return '"'+a+'"'; return a; 154 | }).join(" ") + '"'].join(" ")], { 155 | stdio: 'inherit', 156 | windowsVerbatimArguments: true 157 | } 158 | ); 159 | } else { 160 | logger.info(__('Executing Alloy compile: %s', cmd.join(' ').cyan)); 161 | child = spawn(cmd.shift(), cmd); 162 | child.stdout.on('data', function (data) { 163 | data.toString().split('\n').forEach(checkLine); 164 | }); 165 | child.stderr.on('data', function (data) { 166 | data.toString().split('\n').forEach(checkLine); 167 | }); 168 | } 169 | 170 | // handle the completion of alloy, success or otherwise 171 | child.on('exit', function (code) { 172 | if (code) { 173 | logger.error(__('Alloy compiler failed')); 174 | process.exit(1); 175 | } else { 176 | logger.info(__('Alloy compiler completed successfully')); 177 | 178 | afs.exists(path.join(cli.argv["project-dir"], 'build', 'i18n')) && process.argv.push('--i18n-dir', 'build'); 179 | afs.exists(path.join(cli.argv["project-dir"], 'build', 'platform')) && (cli.argv['platform-dir'] = 'build/platform'); 180 | } 181 | finished(); 182 | }); 183 | 184 | }); 185 | } 186 | } 187 | 188 | cli.addHook('build.pre.compile', function (build, finished) { 189 | var deployType = build.deployType, 190 | target = build.target; 191 | 192 | run(build.deviceFamily, deployType, target, finished); 193 | }); 194 | 195 | cli.addHook('codeprocessor.pre.run', function (build, finished) { 196 | run('none', 'development', undefined, finished, SILENT); 197 | }); 198 | }; 199 | -------------------------------------------------------------------------------- /plugins/ti.alloy/hooks/deepclean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Alloy 3 | * Copyright (c) 2014 by Appcelerator, Inc. All Rights Reserved. 4 | * See LICENSE for more information on licensing. 5 | */ 6 | 7 | exports.cliVersion = '>=3.X'; 8 | var SILENT = true; 9 | 10 | exports.init = function (logger, config, cli, appc) { 11 | var path = require('path'), 12 | fs = require('fs'), 13 | afs = appc.fs; 14 | 15 | function run(finished) { 16 | if(cli.argv['shallow'] === '') { 17 | logger.info('Not cleaning the Resources directory'); 18 | finished(); 19 | return; 20 | } 21 | var appDir = path.join(cli.argv['project-dir'], 'app'); 22 | if (!afs.exists(appDir)) { 23 | logger.debug('Project not an Alloy app, exiting.'); 24 | finished(); 25 | return; 26 | } 27 | 28 | var resourcesDir = path.join(cli.argv['project-dir'], 'Resources'); 29 | if (!afs.exists(resourcesDir)) { 30 | logger.debug('Resources directory does not exist.'); 31 | finished(); 32 | return; 33 | } 34 | rmdir(resourcesDir, fs, path, logger); 35 | logger.debug('Resources directory of %s has been emptied', appDir.cyan); 36 | finished(); 37 | } 38 | 39 | cli.addHook('clean.post', function (build, finished) { 40 | run(finished); 41 | }); 42 | 43 | }; 44 | 45 | function rmdir(dirPath, fs, path, logger, removeSelf) { 46 | var files; 47 | try { 48 | files = fs.readdirSync(dirPath); 49 | } 50 | catch(e) { 51 | return; 52 | } 53 | if (files.length > 0) { 54 | for (var i = 0; i < files.length; i++) { 55 | var filePath = path.join(dirPath, files[i]); 56 | if (fs.statSync(filePath).isFile()) { 57 | fs.unlinkSync(filePath); 58 | } else { 59 | rmdir(filePath, fs, path, logger, true); 60 | } 61 | } 62 | } 63 | if (removeSelf) { 64 | fs.rmdirSync(dirPath); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /plugins/ti.alloy/plugin.py: -------------------------------------------------------------------------------- 1 | import os, sys, subprocess, hashlib 2 | 3 | import subprocess 4 | 5 | def check_output(*popenargs, **kwargs): 6 | r"""Run command with arguments and return its output as a byte string. 7 | 8 | Backported from Python 2.7 as it's implemented as pure python on stdlib. 9 | 10 | >>> check_output(['/usr/bin/python', '--version']) 11 | Python 2.6.2 12 | """ 13 | process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 14 | output, unused_err = process.communicate() 15 | retcode = process.poll() 16 | if retcode: 17 | cmd = kwargs.get("args") 18 | if cmd is None: 19 | cmd = popenargs[0] 20 | error = subprocess.CalledProcessError(retcode, cmd) 21 | error.output = output 22 | raise error 23 | return output 24 | 25 | def compile(config): 26 | paths = {} 27 | binaries = ["alloy","node"] 28 | 29 | dotAlloy = os.path.abspath(os.path.join(config['project_dir'], 'build', '.alloynewcli')) 30 | if os.path.exists(dotAlloy): 31 | print "[DEBUG] build/.alloynewcli file found, skipping plugin..." 32 | os.remove(dotAlloy) 33 | else: 34 | for binary in binaries: 35 | try: 36 | # see if the environment variable is defined 37 | paths[binary] = os.environ["ALLOY_" + ("NODE_" if binary == "node" else "") + "PATH"] 38 | except KeyError as ex: 39 | # next try PATH, and then our guess paths 40 | if sys.platform == "darwin" or sys.platform.startswith('linux'): 41 | userPath = os.environ["HOME"] 42 | guessPaths = [ 43 | "/usr/local/bin/"+binary, 44 | "/opt/local/bin/"+binary, 45 | userPath+"/local/bin/"+binary, 46 | "/opt/bin/"+binary, 47 | "/usr/bin/"+binary, 48 | "/usr/local/share/npm/bin/"+binary 49 | ] 50 | 51 | try: 52 | binaryPath = check_output(["which",binary], stderr=subprocess.STDOUT).strip() 53 | print "[DEBUG] %s installed at '%s'" % (binary,binaryPath) 54 | except: 55 | print "[WARN] Couldn't find %s on your PATH:" % binary 56 | print "[WARN] %s" % os.environ["PATH"] 57 | print "[WARN]" 58 | print "[WARN] Checking for %s in a few default locations:" % binary 59 | for p in guessPaths: 60 | sys.stdout.write("[WARN] %s -> " % p) 61 | if os.path.exists(p): 62 | binaryPath = p 63 | print "FOUND" 64 | break 65 | else: 66 | print "not found" 67 | binaryPath = None 68 | 69 | if binaryPath is None: 70 | print "[ERROR] Couldn't find %s" % binary 71 | sys.exit(1) 72 | else: 73 | paths[binary] = binaryPath 74 | 75 | # no guesses on windows, just use the PATH 76 | elif sys.platform == "win32": 77 | paths["alloy"] = "alloy.cmd" 78 | 79 | f = os.path.abspath(os.path.join(config['project_dir'], 'app')) 80 | if os.path.exists(f): 81 | print "[INFO] alloy app found at %s" % f 82 | rd = os.path.abspath(os.path.join(config['project_dir'], 'Resources')) 83 | 84 | devicefamily = 'none' 85 | simtype = 'none' 86 | version = '0' 87 | deploytype = 'development' 88 | 89 | if config['platform']==u'ios': 90 | version = config['iphone_version'] 91 | devicefamily = config['devicefamily'] 92 | deploytype = config['deploytype'] 93 | if config['platform']==u'android': 94 | builder = config['android_builder'] 95 | version = builder.tool_api_level 96 | deploytype = config['deploy_type'] 97 | if config['platform']==u'mobileweb': 98 | builder = config['mobileweb_builder'] 99 | deploytype = config['deploytype'] 100 | 101 | cfg = "platform=%s,version=%s,simtype=%s,devicefamily=%s,deploytype=%s," % (config['platform'],version,simtype,devicefamily,deploytype) 102 | 103 | if sys.platform == "win32": 104 | cmd = [paths["alloy"], "compile", f, "--no-colors", "--config", cfg] 105 | else: 106 | cmd = [paths["node"], paths["alloy"], "compile", f, "--no-colors", "--config", cfg] 107 | 108 | print "[INFO] Executing Alloy compile:" 109 | print "[INFO] %s" % " ".join(cmd) 110 | 111 | try: 112 | print check_output(cmd, stderr=subprocess.STDOUT) 113 | except subprocess.CalledProcessError as ex: 114 | if hasattr(ex, 'output'): 115 | print ex.output 116 | print "[ERROR] Alloy compile failed" 117 | retcode = 1 118 | if hasattr(ex, 'returncode'): 119 | retcode = ex.returncode 120 | sys.exit(retcode) 121 | except EnvironmentError as ex: 122 | print "[ERROR] Unexpected error with Alloy compiler plugin: %s" % ex.strerror 123 | sys.exit(2) 124 | -------------------------------------------------------------------------------- /plugins/ti.version/1.0/hooks/version.js: -------------------------------------------------------------------------------- 1 | exports.init = function(logger, config, cli, appc) { 2 | if (cli.tiapp.properties['ti.version.range']) { 3 | if (!appc.version.satisfies(cli.sdk.manifest.name, cli.tiapp.properties['ti.version.range'].value)) { 4 | logger.error('This app requires Titanium SDK ' + cli.tiapp.properties['ti.version.range'].value + ' instead of ' + cli.sdk.name + ' (' + cli.sdk.manifest.name + ')'); 5 | process.exit(1); 6 | } 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /tiapp.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | com.appcelerator.sample.ti520 5 | Ti 5.2.0 6 | 1.0 7 | Appcelerator 8 | http://www.appcelerator.com 9 | This app demonstrates new features in Titanium 5.2.0 10 | 2016 by Appcelerator, Inc. 11 | appicon.png 12 | false 13 | 14 | true 15 | false 16 | 11111111-1111-1111-1111-111111111111 17 | dp 18 | >=5.2.2 <5.3 19 | 20 | 21 | 9.0 22 | 26 | true 27 | 28 | #C7172C 29 | 30 | true 31 | 32 | 33 | 34 | UIRequiresFullScreen 35 | 36 | 37 | NSUserActivityTypes 38 | 39 | com.appcelerator.sample.ti520.tab 40 | 41 | UISupportedInterfaceOrientations~iphone 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UISupportedInterfaceOrientations~ipad 48 | 49 | UIInterfaceOrientationPortrait 50 | UIInterfaceOrientationPortraitUpsideDown 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIRequiresPersistentWiFi 55 | 56 | UIPrerenderedIcon 57 | 58 | UIStatusBarHidden 59 | 60 | UIStatusBarStyle 61 | UIStatusBarStyleLightContent 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | ti.map 99 | 100 | 101 | true 102 | true 103 | true 104 | false 105 | false 106 | 107 | 5.2.2.GA 108 | 109 | ti.alloy 110 | ti.version 111 | 112 | 113 | --------------------------------------------------------------------------------