├── app ├── images │ └── .gitkeep ├── views │ ├── about │ │ ├── about.css │ │ ├── about.js │ │ └── about.xml │ ├── login │ │ ├── login.css │ │ ├── login.xml │ │ └── login.js │ ├── orders │ │ ├── orders.css │ │ ├── orders.xml │ │ └── orders.js │ ├── server │ │ ├── server.css │ │ ├── server.js │ │ └── server.xml │ ├── wallet │ │ ├── wallet.css │ │ ├── transaction.css │ │ ├── transaction.js │ │ ├── wallet.xml │ │ ├── transaction.xml │ │ └── wallet.js │ ├── alliance │ │ ├── alliance.css │ │ ├── members.js │ │ ├── members.xml │ │ ├── alliance.js │ │ └── alliance.xml │ ├── alliances │ │ ├── alliances.css │ │ ├── alliances.xml │ │ └── alliances.js │ ├── messages │ │ ├── messages.css │ │ ├── conversation.css │ │ ├── messages.xml │ │ ├── conversation.xml │ │ ├── conversation.js │ │ └── messages.js │ ├── category_template │ │ ├── template.css │ │ ├── template.js │ │ └── template.xml │ ├── profile │ │ ├── profile.css │ │ ├── profile.js │ │ └── profile.xml │ └── console │ │ ├── console.css │ │ ├── console.xml │ │ └── console.js ├── package.json ├── platform.ios.css ├── App_Resources │ ├── iOS │ │ ├── logo.png │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── icon.png │ │ │ │ ├── icon-120.png │ │ │ │ ├── icon-29.png │ │ │ │ ├── icon-40.png │ │ │ │ ├── icon-50.png │ │ │ │ ├── icon-57.png │ │ │ │ ├── icon-60.png │ │ │ │ ├── icon-72.png │ │ │ │ ├── icon-76.png │ │ │ │ ├── icon-29@2x.png │ │ │ │ ├── icon-29@3x.png │ │ │ │ ├── icon-40@2x.png │ │ │ │ ├── icon-40@3x.png │ │ │ │ ├── icon-50@2x.png │ │ │ │ ├── icon-57@2x.png │ │ │ │ ├── icon-57@3x.png │ │ │ │ ├── icon-60@2x.png │ │ │ │ ├── icon-60@3x.png │ │ │ │ ├── icon-72@2x.png │ │ │ │ ├── icon-72@3x.png │ │ │ │ ├── icon-76@2x.png │ │ │ │ ├── icon-76@3x.png │ │ │ │ ├── icon-Small.png │ │ │ │ ├── iTunesArtwork.png │ │ │ │ ├── icon-83.5@2x.png │ │ │ │ ├── icon-Small@2x.png │ │ │ │ ├── icon-Small@3x.png │ │ │ │ ├── iTunesArtwork@2x.png │ │ │ │ └── Contents.json │ │ │ ├── LaunchImage.launchimage │ │ │ │ ├── Default.png │ │ │ │ ├── Default@2x.png │ │ │ │ ├── Default-568h@2x.png │ │ │ │ ├── Default-667h@2x.png │ │ │ │ ├── Default-736h@3x.png │ │ │ │ ├── Default-Portrait.png │ │ │ │ ├── Default-Landscape.png │ │ │ │ ├── Default-Landscape@2x.png │ │ │ │ ├── Default-Landscape@3x.png │ │ │ │ ├── Default-Portrait@2x.png │ │ │ │ └── Contents.json │ │ │ ├── LaunchScreen.Center.imageset │ │ │ │ ├── LaunchScreen-Center.png │ │ │ │ ├── LaunchScreen-Center@2x.png │ │ │ │ └── Contents.json │ │ │ └── LaunchScreen.AspectFill.imageset │ │ │ │ ├── LaunchScreen-AspectFill.png │ │ │ │ ├── LaunchScreen-AspectFill@2x.png │ │ │ │ └── Contents.json │ │ ├── build.xcconfig │ │ ├── Info.plist │ │ └── LaunchScreen.storyboard │ └── Android │ │ ├── playstore-icon.png │ │ ├── drawable-hdpi │ │ ├── icon.png │ │ ├── logo.png │ │ └── background.png │ │ ├── drawable-ldpi │ │ ├── icon.png │ │ ├── logo.png │ │ └── background.png │ │ ├── drawable-mdpi │ │ ├── icon.png │ │ ├── logo.png │ │ └── background.png │ │ ├── drawable-xhdpi │ │ ├── icon.png │ │ ├── logo.png │ │ └── background.png │ │ ├── drawable-xxhdpi │ │ ├── icon.png │ │ ├── logo.png │ │ └── background.png │ │ ├── drawable-xxxhdpi │ │ ├── icon.png │ │ ├── logo.png │ │ └── background.png │ │ ├── values-v21 │ │ ├── colors.xml │ │ └── styles.xml │ │ ├── values │ │ ├── colors.xml │ │ └── styles.xml │ │ ├── drawable-nodpi │ │ └── splash_screen.xml │ │ ├── app.gradle │ │ └── AndroidManifest.xml ├── fonts │ └── fontawesome-webfont.ttf ├── platform.android.css ├── README.md ├── shared │ ├── widgets │ │ ├── header.xml │ │ └── navigation.xml │ └── navtools.js ├── prototypes │ └── numbers.js ├── app.js ├── services │ ├── league.js │ ├── session.js │ └── screeps.js ├── app.css └── www │ └── lib │ ├── nativescript-canvas-interface.js │ ├── nativescript-webview-interface.js │ └── es6-promise.min.js ├── hooks ├── before-prepare │ ├── nativescript-nodeify.js │ └── nativescript-dev-android-snapshot.js └── after-prepare │ └── nativescript-dev-android-snapshot.js ├── README.md ├── .gitignore ├── Makefile ├── LICENSE ├── package.json └── docs └── Roadmap.md /app/images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/about/about.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/login/login.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/orders/orders.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/server/server.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/wallet/wallet.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/alliance/alliance.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/alliances/alliances.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/messages/messages.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/wallet/transaction.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/category_template/template.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/profile/profile.css: -------------------------------------------------------------------------------- 1 | .user_header { 2 | margin: 15; 3 | } -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "app.js", 3 | "name": "spawn1", 4 | "version": "1.0.1" 5 | } -------------------------------------------------------------------------------- /app/platform.ios.css: -------------------------------------------------------------------------------- 1 | /* From platform.ios.css */ 2 | .link { 3 | border-width: 0; 4 | } 5 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/logo.png -------------------------------------------------------------------------------- /app/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/platform.android.css: -------------------------------------------------------------------------------- 1 | /* From platform.android.css */ 2 | .link { 3 | background-color: transparent; 4 | } 5 | -------------------------------------------------------------------------------- /hooks/before-prepare/nativescript-nodeify.js: -------------------------------------------------------------------------------- 1 | module.exports = require("nativescript-nodeify/patch-npm-packages.js"); 2 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /app/App_Resources/Android/playstore-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/playstore-icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-hdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-hdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-ldpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-ldpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-mdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-mdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xhdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xxhdpi/logo.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxxhdpi/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xxxhdpi/logo.png -------------------------------------------------------------------------------- /hooks/after-prepare/nativescript-dev-android-snapshot.js: -------------------------------------------------------------------------------- 1 | module.exports = require("nativescript-dev-android-snapshot/hooks/after-prepare-hook.js"); 2 | -------------------------------------------------------------------------------- /hooks/before-prepare/nativescript-dev-android-snapshot.js: -------------------------------------------------------------------------------- 1 | module.exports = require("nativescript-dev-android-snapshot/hooks/before-prepare-hook.js"); 2 | -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-hdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-hdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-ldpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-ldpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-mdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-mdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xhdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xxhdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-xxxhdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/Android/drawable-xxxhdpi/background.png -------------------------------------------------------------------------------- /app/App_Resources/Android/values-v21/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3d5afe 4 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-120.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-57@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-72@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-Small.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/iTunesArtwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/iTunesArtwork.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-Small@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-Small@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-736h@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Landscape@3x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Default-Portrait@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tedivm/Spawn1/HEAD/app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png -------------------------------------------------------------------------------- /app/App_Resources/Android/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #F5F5F5 4 | #757575 5 | #33B5E5 6 | #272734 7 | -------------------------------------------------------------------------------- /app/views/console/console.css: -------------------------------------------------------------------------------- 1 | Page { 2 | background-color: #243044; 3 | } 4 | .console_background { 5 | background-color: #243044; 6 | color: white 7 | } 8 | .console_output { 9 | background-color: #243044; 10 | font-size: 12; 11 | } 12 | .console_list { 13 | separator-color: #243044; 14 | } -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # NativeScript Tutorial JavaScript Template 2 | 3 | This repo serves as the starting point for NativeScript’s [JavaScript Getting Started Guide](https://docs.nativescript.org/tutorial/chapter-0). 4 | 5 | Please file any issues with this template on the [NativeScript/docs repository](https://github.com/nativescript/docs), which is where the tutorial content lives. -------------------------------------------------------------------------------- /app/App_Resources/Android/drawable-nodpi/splash_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/views/wallet/transaction.js: -------------------------------------------------------------------------------- 1 | var ScreepsAPI = require('../../services/screeps.js') 2 | var Session = require('../../services/session.js') 3 | var frame = require("ui/frame"); 4 | 5 | var page; 6 | 7 | exports.pageLoaded = function(args) { 8 | page = args.object; 9 | var source = {} 10 | drawer = page.getViewById("drawer"); 11 | page.getViewById("title").text = 'Transaction' 12 | // Additional on load actions here 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-Center.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-Center@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchScreen-AspectFill.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchScreen-AspectFill@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /app/App_Resources/iOS/build.xcconfig: -------------------------------------------------------------------------------- 1 | // You can add custom settings here 2 | // for example you can uncomment the following line to force distribution code signing 3 | // CODE_SIGN_IDENTITY = iPhone Distribution 4 | // To build for device with Xcode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html 5 | // DEVELOPMENT_TEAM = YOUR_TEAM_ID; 6 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 7 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 8 | -------------------------------------------------------------------------------- /app/shared/widgets/header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/shared/navtools.js: -------------------------------------------------------------------------------- 1 | var Session = require('../services/session.js') 2 | var frame = require('ui/frame'); 3 | 4 | exports.onTap = function (args) { 5 | var currentPage = frame.topmost().currentPage; 6 | var linkedPageName = args.view.text.toLowerCase() 7 | var drawer = currentPage.getViewById("drawer"); 8 | 9 | if(linkedPageName == 'logout') { 10 | Session.clear() 11 | linkedPageName = 'login' 12 | } 13 | 14 | frame.topmost().navigate({ 15 | 'moduleName': "views/" + linkedPageName + "/" + linkedPageName, 16 | 'clearHistory': true 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /app/App_Resources/Android/app.gradle: -------------------------------------------------------------------------------- 1 | // Add your native dependencies here: 2 | 3 | // Uncomment to add recyclerview-v7 dependency 4 | //dependencies { 5 | // compile 'com.android.support:recyclerview-v7:+' 6 | //} 7 | 8 | android { 9 | defaultConfig { 10 | generatedDensities = [] 11 | applicationId = "org.screepers.Spawn1" 12 | 13 | //override supported platforms 14 | // ndk { 15 | // abiFilters.clear() 16 | // abiFilters "armeabi-v7a" 17 | // } 18 | 19 | } 20 | aaptOptions { 21 | additionalParameters "--no-version-vectors" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/views/server/server.js: -------------------------------------------------------------------------------- 1 | var ScreepsAPI = require('../../services/screeps.js') 2 | var Session = require('../../services/session.js') 3 | var frames = require("ui/frame"); 4 | exports.onTap = require("../../shared/navtools.js").onTap 5 | 6 | var page; 7 | var drawer; 8 | 9 | exports.pageLoaded = function(args) { 10 | page = args.object; 11 | var source = {} 12 | drawer = page.getViewById("drawer"); 13 | page.getViewById("title").text = 'Server Speed' 14 | // Additional on load actions here 15 | }; 16 | 17 | exports.toggleDrawer = function() { 18 | drawer.toggleDrawerState(); 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /app/shared/widgets/navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/views/category_template/template.js: -------------------------------------------------------------------------------- 1 | var ScreepsAPI = require('../../services/screeps.js') 2 | var Session = require('../../services/session.js') 3 | var frame = require("ui/frame"); 4 | exports.onTap = require("../../shared/navtools.js").onTap 5 | 6 | var page; 7 | var drawer; 8 | 9 | exports.pageLoaded = function(args) { 10 | page = args.object; 11 | var source = {} 12 | drawer = page.getViewById("drawer"); 13 | page.getViewById("title").text = 'TITLE' 14 | // Additional on load actions here 15 | }; 16 | 17 | exports.toggleDrawer = function() { 18 | drawer.toggleDrawerState(); 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spawn1 2 | 3 | The Unofficial Mobile Client for Screeps. 4 | 5 | ## Technology 6 | 7 | * NativeScript - code in javascript and compile down to native apps. 8 | * Screeps API - since this is a Screeps client it does pull data down from Screeps. 9 | * League of Automated Nations - data is also pulled in from this site. 10 | 11 | 12 | ## Setup 13 | 14 | 1. [NativeScript Quick Setup](https://docs.nativescript.org/start/quick-setup). 15 | 2. `make` 16 | 3. `tns run ios` or `tns run android` to compile and run. 17 | 18 | 19 | ## Roadmap 20 | 21 | Current plans are outlined on the [Roadmap](docs/Roadmap.md). 22 | -------------------------------------------------------------------------------- /app/prototypes/numbers.js: -------------------------------------------------------------------------------- 1 | 2 | Number.prototype.toAbbreviated = function() { 3 | 4 | if(this > Math.pow(10, 12)) { 5 | var divisor = Math.pow(10, 12) 6 | var unit = 'T' 7 | } else if(this > Math.pow(10, 9)) { 8 | var divisor = Math.pow(10, 9) 9 | var unit = 'B' 10 | } else if(this > Math.pow(10, 6)) { 11 | var divisor = Math.pow(10, 6) 12 | var unit = 'M' 13 | } else if(this > Math.pow(10, 3)) { 14 | var divisor = Math.pow(10, 3) 15 | var unit = 'K' 16 | } else { 17 | var divisor = 1 18 | var unit = '' 19 | } 20 | 21 | return ((this / divisor).toPrecision(3)) + unit 22 | } 23 | -------------------------------------------------------------------------------- /app/views/login/login.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/services/league.js: -------------------------------------------------------------------------------- 1 | var applicationSettings = require("application-settings"); 2 | var timer = require("timer"); 3 | 4 | var leagueurl = 'http://www.leagueofautomatednations.com/' 5 | 6 | class League { 7 | constructor() { 8 | this.users = {} 9 | this.alliances = {} 10 | this.loadAllianceData() 11 | var that = this 12 | 13 | // Update every 30 minutes 14 | timer.setInterval(function(){ 15 | that.loadAllianceData() 16 | }, (1000 * 60 * 30)) 17 | } 18 | 19 | loadAllianceData() { 20 | // Load from application settings if it's available. This way it's possible 21 | // to browser alliance data without an internet connection. 22 | this.alliances = JSON.parse(applicationSettings.getString('league_alliance_data', '{}')) 23 | this.users = JSON.parse(applicationSettings.getString('league_user_data', '{}')) 24 | 25 | console.log('Loading alliance data from ' + leagueurl + 'alliances.js') 26 | var that = this 27 | return fetch(leagueurl + "alliances.js") 28 | .then(response => { 29 | if(!response.ok) { 30 | throw new Error() 31 | } 32 | return response.json() 33 | }) 34 | .then(function (r) { 35 | that.alliances = r 36 | that.users = {} 37 | for(var alliance in that.alliances) { 38 | 39 | if(that.alliances[alliance]['slack_channel']) { 40 | that.alliances[alliance]['slackurl'] = 'slack://channel?team=T0HJCPP9T' 41 | if(that.alliances[alliance]['slack_channelid']) { 42 | that.alliances[alliance]['slackurl'] += '&id=' + that.alliances[alliance]['slack_channelid'] 43 | } 44 | } 45 | 46 | if(that.alliances[alliance]['logo']) { 47 | that.alliances[alliance]['logo'] = leagueurl + 'obj/' + that.alliances[alliance]['logo'] 48 | } else { 49 | that.alliances[alliance]['logo'] = leagueurl + 'static/img/leaguelogo.png' 50 | } 51 | 52 | that.alliances[alliance].memberCount = that.alliances[alliance].members.length 53 | that.alliances[alliance].memberObjects = [] 54 | 55 | that.alliances[alliance].members.sort(function(a,b){ 56 | var textA = a.toUpperCase(); 57 | var textB = b.toUpperCase(); 58 | return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; 59 | }) 60 | 61 | for(var user of that.alliances[alliance].members) { 62 | that.alliances[alliance].memberObjects.push({'name':user}) 63 | that.users[user] = alliance 64 | } 65 | } 66 | 67 | 68 | applicationSettings.setString('league_alliance_data', JSON.stringify(that.alliances)) 69 | applicationSettings.setString('league_user_data', JSON.stringify(that.users)) 70 | 71 | }) 72 | .catch(function(err){ 73 | console.log(err.message) 74 | console.log(err.stack) 75 | }) 76 | } 77 | 78 | getUserAlliance(user) { 79 | return !!this.users[user] ? this.users[user] : false 80 | } 81 | 82 | getAlliance(alliance) { 83 | return !!this.alliances[alliance] ? this.alliances[alliance] : false 84 | } 85 | 86 | getAllianceList() { 87 | return Object.keys(this.alliances()) 88 | } 89 | 90 | getAllianceData() { 91 | return Object.values(this.alliances) 92 | } 93 | 94 | getBadgeUrl(username, alliance=true) { 95 | var prefix = alliance ? 'alliances/' : 'users/' 96 | return leagueurl + 'badges/' + prefix + username + '.png' 97 | } 98 | } 99 | 100 | module.exports = new League() 101 | -------------------------------------------------------------------------------- /app/views/console/console.js: -------------------------------------------------------------------------------- 1 | var League = require('../../services/league.js') 2 | var ScreepsAPI = require('../../services/screeps.js') 3 | var Session = require('../../services/session.js') 4 | var frame = require("ui/frame"); 5 | var timer = require("timer"); 6 | 7 | exports.onTap = require("../../shared/navtools.js").onTap 8 | 9 | 10 | var Observable = require("data/observable").Observable; 11 | var ObservableArray = require("data/observable-array").ObservableArray; 12 | var utils = require("utils/utils"); 13 | 14 | var items = new ObservableArray([]); 15 | var pageData = new Observable(); 16 | 17 | 18 | var page; 19 | var drawer; 20 | var socket = false 21 | var maxbuffer = 1000 22 | 23 | var display_errors = true 24 | var display_log = true 25 | var display_results = true 26 | var display = { 27 | 'error': true, 28 | 'result': true, 29 | 'log': true 30 | } 31 | 32 | 33 | function addItem(type, message) { 34 | 35 | if(!display[type]) { 36 | return 37 | } 38 | 39 | if(message.startsWith('ScreepStats')) { 40 | return 41 | } 42 | 43 | var color = type == 'error' ? 'DD0000' : '#FFFFFF' 44 | 45 | if(items.length >= maxbuffer) { 46 | items.shift() 47 | } 48 | 49 | items.push({ 50 | 'type': type, 51 | 'message': '' + message + '' 52 | }) 53 | 54 | } 55 | 56 | function console_message(socket_data) { 57 | var should_refocus = false 58 | 59 | // Uncaught errors *in game* 60 | if(socket_data['error']) { 61 | should_refocus = true 62 | addItem('error', socket_data['error']) 63 | } 64 | 65 | if(socket_data['messages']) { 66 | // Standard output from console.log 67 | if(socket_data['messages']['log'] && socket_data['messages']['log'].length > 0) { 68 | should_refocus = true 69 | for(var log of socket_data['messages']['log']) { 70 | addItem('log', log) 71 | } 72 | } 73 | 74 | // Return output from console commands 75 | if(socket_data['messages']['results'] && socket_data['messages']['results'].length > 0) { 76 | should_refocus = true 77 | for(var result of socket_data['messages']['results']) { 78 | addItem('result', result) 79 | } 80 | } 81 | } 82 | 83 | if(should_refocus) { 84 | refocus() 85 | } 86 | } 87 | 88 | 89 | function refocus() { 90 | var console_buffer = page.getViewById("console_list"); 91 | if(items.length > 0) { 92 | console_buffer.scrollToIndex(console_buffer.items.length - 1); // scroll to the bottom 93 | } 94 | } 95 | 96 | 97 | exports.pageLoaded = function(args) { 98 | page = args.object; 99 | var source = {} 100 | drawer = page.getViewById("drawer"); 101 | page.getViewById("title").text = 'console' 102 | // Additional on load actions here 103 | 104 | items.length = 0 105 | 106 | page.bindingContext = pageData; 107 | 108 | // create websocket connection to server 109 | console.log('loading socket') 110 | socket = ScreepsAPI.get_web_socket() 111 | socket.registerHandler('console', console_message) 112 | pageData.set("messages", items); 113 | 114 | }; 115 | 116 | exports.pageUnloaded = function (args) { 117 | console.log('unloading console') 118 | if(!!socket) { 119 | socket.deregisterHandler('console', console_message) 120 | } 121 | } 122 | 123 | 124 | exports.toggleDrawer = function() { 125 | drawer.toggleDrawerState(); 126 | } 127 | 128 | exports.sendConsoleCommand = function (args) { 129 | var message_input = page.getViewById("message_input") 130 | var message = message_input.text 131 | ScreepsAPI.user_console(message) 132 | message_input.text = '' 133 | } 134 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "icon-29.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "icon-29@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-29@3x.png", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "icon-40@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-40@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "57x57", 35 | "idiom" : "iphone", 36 | "filename" : "icon-57.png", 37 | "scale" : "1x" 38 | }, 39 | { 40 | "size" : "57x57", 41 | "idiom" : "iphone", 42 | "filename" : "icon-57@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "57x57", 47 | "idiom" : "iphone", 48 | "filename" : "icon-57@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "icon-60.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "icon-60@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "60x60", 65 | "idiom" : "iphone", 66 | "filename" : "icon-60@3x.png", 67 | "scale" : "3x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "icon-29.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "icon-29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "icon-40.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "icon-40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "50x50", 95 | "idiom" : "ipad", 96 | "filename" : "icon-50.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "50x50", 101 | "idiom" : "ipad", 102 | "filename" : "icon-50@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "72x72", 107 | "idiom" : "ipad", 108 | "filename" : "icon-72.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "72x72", 113 | "idiom" : "ipad", 114 | "filename" : "icon-72@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "72x72", 119 | "idiom" : "ipad", 120 | "filename" : "icon-72@3x.png", 121 | "scale" : "3x" 122 | }, 123 | { 124 | "size" : "76x76", 125 | "idiom" : "ipad", 126 | "filename" : "icon-76.png", 127 | "scale" : "1x" 128 | }, 129 | { 130 | "size" : "76x76", 131 | "idiom" : "ipad", 132 | "filename" : "icon-76@2x.png", 133 | "scale" : "2x" 134 | }, 135 | { 136 | "size" : "76x76", 137 | "idiom" : "ipad", 138 | "filename" : "icon-76@3x.png", 139 | "scale" : "3x" 140 | }, 141 | { 142 | "size" : "83.5x83.5", 143 | "idiom" : "ipad", 144 | "filename" : "icon-83.5@2x.png", 145 | "scale" : "2x" 146 | }, 147 | { 148 | "size" : "120x120", 149 | "idiom" : "ipad", 150 | "filename" : "icon120.png", 151 | "scale" : "1x" 152 | }, 153 | 154 | ], 155 | "info" : { 156 | "version" : 1, 157 | "author" : "xcode" 158 | } 159 | } -------------------------------------------------------------------------------- /app/views/messages/conversation.js: -------------------------------------------------------------------------------- 1 | var League = require('../../services/league.js') 2 | var ScreepsAPI = require('../../services/screeps.js') 3 | var Session = require('../../services/session.js') 4 | var frame = require("ui/frame"); 5 | var timer = require("timer"); 6 | 7 | exports.onTap = require("../../shared/navtools.js").onTap 8 | 9 | 10 | var Observable = require("data/observable").Observable; 11 | var ObservableArray = require("data/observable-array").ObservableArray; 12 | var utils = require("utils/utils"); 13 | 14 | var items = new ObservableArray([]); 15 | var processed_messages = [] 16 | var pageData = new Observable(); 17 | 18 | 19 | var page; 20 | var drawer; 21 | 22 | var conversationTimerID = false 23 | var lastMessageTime = false 24 | 25 | 26 | function loadConversation () { 27 | console.log('loading conversation') 28 | ScreepsAPI.messages_list(page.bindingContext.respondent) 29 | .then(function(data){ 30 | var scroll = false 31 | for(var message of data['messages']) { 32 | 33 | if(processed_messages.indexOf(message['_id']) < 0) { 34 | processed_messages.push(message['_id']) 35 | 36 | if(message.type == 'out') { 37 | message.badge_url = League.getBadgeUrl(Session.userdata.username, false) 38 | } else { 39 | message.badge_url = League.getBadgeUrl(page.bindingContext.recipient, false) 40 | } 41 | 42 | var message_date = new Date(message['date']); 43 | lastMessageTime = message_date 44 | message['date_locale'] = message_date.toLocaleString() 45 | items.push(message) 46 | scroll = true 47 | } 48 | } 49 | 50 | // If conversation has new messages scroll to read them. 51 | if(scroll) { 52 | var conversation_list = page.getViewById("conversation_list"); 53 | conversation_list.scrollToIndex(items.length - 1); // scroll to the bottom 54 | } 55 | 56 | }).catch(function(err){ 57 | console.log(err.message) 58 | console.log(err.trace) 59 | }) 60 | } 61 | 62 | 63 | exports.pageLoaded = function(args) { 64 | page = args.object; 65 | var source = {} 66 | drawer = page.getViewById("drawer"); 67 | //page.getViewById("title").text = '' 68 | // Additional on load actions here 69 | 70 | pageData.recipient = page.bindingContext.recipient 71 | pageData.respondent = page.bindingContext.respondent 72 | 73 | processed_messages = [] 74 | items.length = 0 75 | 76 | page.bindingContext = pageData; 77 | loadConversation() 78 | pageData.set("messages", items); 79 | 80 | conversationTimerID = timer.setInterval(function conversationReloadTimer(){ 81 | loadConversation() 82 | if(lastMessageTime) { 83 | // Range between 5 to 90 second delay between reloads. 84 | var elapsed = ((new Date()).getTime() - lastMessageTime.getTime()) 85 | var interval = Math.round(Math.max(Math.min(elapsed/10, 90000), 5000)) 86 | timer.clearInterval(conversationTimerID) 87 | conversationTimerID = false 88 | conversationTimerID = timer.setInterval(conversationReloadTimer, interval) 89 | } 90 | }, 5000) 91 | 92 | }; 93 | 94 | exports.pageUnloaded = function (args) { 95 | if(conversationTimerID !== false) { 96 | timer.clearInterval(conversationTimerID) 97 | conversationTimerID = false 98 | } 99 | } 100 | 101 | 102 | exports.toggleDrawer = function() { 103 | drawer.toggleDrawerState(); 104 | }; 105 | 106 | exports.itemTemplateSelector = function (item) { 107 | return item.type == 'in' ? 'them' : 'me' 108 | } 109 | 110 | exports.addMessage = function (args) { 111 | var message_input = page.getViewById("message_input") 112 | var message = message_input.text; 113 | console.log('making call to api') 114 | ScreepsAPI.messages_send(page.bindingContext.respondent, message) 115 | .then(function(data){ 116 | 117 | message_input.text = '' 118 | loadConversation() 119 | }) 120 | .catch(function(err){ 121 | console.log(err.message) 122 | console.log(err.stack) 123 | }) 124 | } 125 | -------------------------------------------------------------------------------- /app/App_Resources/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 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/views/messages/messages.js: -------------------------------------------------------------------------------- 1 | var League = require('../../services/league.js') 2 | var ScreepsAPI = require('../../services/screeps.js') 3 | var Session = require('../../services/session.js') 4 | var dialogs = require("ui/dialogs"); 5 | var frame = require("ui/frame"); 6 | var timer = require("timer"); 7 | 8 | exports.onTap = require("../../shared/navtools.js").onTap 9 | 10 | 11 | var Observable = require("data/observable").Observable; 12 | var ObservableArray = require("data/observable-array").ObservableArray; 13 | var utils = require("utils/utils"); 14 | 15 | var items = new ObservableArray([]); 16 | var pageData = new Observable(); 17 | 18 | 19 | var page; 20 | var drawer; 21 | var conversationTimerID = false 22 | 23 | var refreshTime = 2 // minutes 24 | 25 | function loadMessages () { 26 | return ScreepsAPI.messages() 27 | .then(function(data){ 28 | 29 | var promiseCollection = [] 30 | var username_mapping = {} 31 | for(var conversation of data['messages']) { 32 | promiseCollection.push( 33 | ScreepsAPI.userdata_from_id(conversation.message.respondent) 34 | .then(function(data){ 35 | username_mapping[data['user']['_id']] = data['user']['username'] 36 | return Promise.resolve(true) 37 | }) 38 | ) 39 | } 40 | 41 | return Promise.all(promiseCollection) 42 | .then(function(){ 43 | for(var conversation of data['messages']) { 44 | conversation['message']['rusername'] = username_mapping[conversation['message']['respondent']] 45 | var date = new Date(conversation['message']['date']); 46 | conversation['message']['date_locale'] = date.toLocaleString() 47 | conversation['message']['badge_url'] = League.getBadgeUrl(conversation['message']['rusername']) 48 | } 49 | return data 50 | }) 51 | }) 52 | 53 | .then(function(data){ 54 | // Remove existing itms and repopulate. 55 | items.length = 0 56 | for(var conversation of data['messages']) { 57 | items.push(conversation['message']) 58 | } 59 | 60 | return Promise.resolve(true) 61 | }) 62 | .catch(function(err) { 63 | console.log(err.message) 64 | console.log(err.stack) 65 | }) 66 | } 67 | 68 | 69 | exports.pageLoaded = function(args) { 70 | page = args.object; 71 | var source = {} 72 | drawer = page.getViewById("drawer"); 73 | page.getViewById("title").text = 'Messages' 74 | 75 | // Additional on load actions here 76 | page.bindingContext = pageData; 77 | loadMessages() 78 | pageData.set("conversations", items); 79 | conversationTimerID = timer.setInterval(function(){ 80 | loadMessages() 81 | }, (1000 * 60 * refreshTime)) 82 | }; 83 | 84 | exports.composeMessage = function (args) { 85 | 86 | dialogs.prompt({ 87 | title: "Compose Message", 88 | message: "Select User", 89 | okButtonText: "Ok", 90 | cancelButtonText: "Cancel", 91 | neutralButtonText: false, 92 | defaultText: "", 93 | inputType: dialogs.inputType.text 94 | }) 95 | .then(function (r) { 96 | return r.text 97 | }) 98 | .then(function(username){ 99 | return ScreepsAPI.userdata_from_username(username) 100 | }) 101 | .then(function(data){ 102 | var pageData = new Observable(); 103 | pageData.recipient = data['user']['username'] 104 | pageData.respondent = data['user']['_id'] 105 | pageData.messages = [] 106 | frame.topmost().navigate({ 107 | moduleName: "views/messages/conversation", 108 | bindingContext: pageData 109 | }) 110 | }) 111 | .catch(function(err){ 112 | console.log(err.message) 113 | console.log(err.stack) 114 | }) 115 | } 116 | 117 | exports.toggleDrawer = function() { 118 | drawer.toggleDrawerState(); 119 | }; 120 | 121 | exports.listViewItemTap = function (args) { 122 | var item = items.getItem(args.index); 123 | var pageData = new Observable(); 124 | pageData.recipient = item.rusername 125 | pageData.respondent = item.respondent 126 | pageData.messages = [] 127 | frame.topmost().navigate({ 128 | moduleName: "views/messages/conversation", 129 | bindingContext: pageData 130 | }) 131 | } 132 | 133 | exports.pageUnloaded = function (args) { 134 | if(conversationTimerID !== false) { 135 | timer.clearInterval(conversationTimerID) 136 | conversationTimerID = false 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/App_Resources/iOS/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-736h@3x.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default-Landscape@3x.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "landscape", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "Default-667h@2x.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "Default@2x.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "Default-568h@2x.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | }, 47 | { 48 | "orientation" : "portrait", 49 | "idiom" : "ipad", 50 | "filename" : "Default-Portrait.png", 51 | "extent" : "full-screen", 52 | "minimum-system-version" : "7.0", 53 | "scale" : "1x" 54 | }, 55 | { 56 | "orientation" : "landscape", 57 | "idiom" : "ipad", 58 | "filename" : "Default-Landscape.png", 59 | "extent" : "full-screen", 60 | "minimum-system-version" : "7.0", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "orientation" : "portrait", 65 | "idiom" : "ipad", 66 | "filename" : "Default-Portrait@2x.png", 67 | "extent" : "full-screen", 68 | "minimum-system-version" : "7.0", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "orientation" : "landscape", 73 | "idiom" : "ipad", 74 | "filename" : "Default-Landscape@2x.png", 75 | "extent" : "full-screen", 76 | "minimum-system-version" : "7.0", 77 | "scale" : "2x" 78 | }, 79 | { 80 | "orientation" : "portrait", 81 | "idiom" : "iphone", 82 | "filename" : "Default.png", 83 | "extent" : "full-screen", 84 | "scale" : "1x" 85 | }, 86 | { 87 | "orientation" : "portrait", 88 | "idiom" : "iphone", 89 | "filename" : "Default@2x.png", 90 | "extent" : "full-screen", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "orientation" : "portrait", 95 | "idiom" : "iphone", 96 | "filename" : "Default-568h@2x.png", 97 | "extent" : "full-screen", 98 | "subtype" : "retina4", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "orientation" : "portrait", 103 | "idiom" : "ipad", 104 | "extent" : "to-status-bar", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "orientation" : "portrait", 109 | "idiom" : "ipad", 110 | "filename" : "Default-Portrait.png", 111 | "extent" : "full-screen", 112 | "scale" : "1x" 113 | }, 114 | { 115 | "orientation" : "landscape", 116 | "idiom" : "ipad", 117 | "extent" : "to-status-bar", 118 | "scale" : "1x" 119 | }, 120 | { 121 | "orientation" : "landscape", 122 | "idiom" : "ipad", 123 | "filename" : "Default-Landscape.png", 124 | "extent" : "full-screen", 125 | "scale" : "1x" 126 | }, 127 | { 128 | "orientation" : "portrait", 129 | "idiom" : "ipad", 130 | "extent" : "to-status-bar", 131 | "scale" : "2x" 132 | }, 133 | { 134 | "orientation" : "portrait", 135 | "idiom" : "ipad", 136 | "filename" : "Default-Portrait@2x.png", 137 | "extent" : "full-screen", 138 | "scale" : "2x" 139 | }, 140 | { 141 | "orientation" : "landscape", 142 | "idiom" : "ipad", 143 | "extent" : "to-status-bar", 144 | "scale" : "2x" 145 | }, 146 | { 147 | "orientation" : "landscape", 148 | "idiom" : "ipad", 149 | "filename" : "Default-Landscape@2x.png", 150 | "extent" : "full-screen", 151 | "scale" : "2x" 152 | } 153 | ], 154 | "info" : { 155 | "version" : 1, 156 | "author" : "xcode" 157 | } 158 | } -------------------------------------------------------------------------------- /app/services/session.js: -------------------------------------------------------------------------------- 1 | var ScreepsAPI = require('./screeps.js') 2 | var League = require('./league.js') 3 | var timer = require("timer"); 4 | 5 | class Session { 6 | 7 | construct() { 8 | this.timer = false 9 | } 10 | 11 | isLoaded() { 12 | return(!!this.userdata && !!this.userdata.username) 13 | } 14 | 15 | loadUser() { 16 | this.userdata = {} 17 | var that = this 18 | var session = that 19 | var current_season = false 20 | var that = this 21 | if(!this.timer) { 22 | this.timer = timer.setInterval(() => { 23 | that.loadUser() 24 | }, 1000 * 60 * 2) 25 | } 26 | 27 | 28 | // Return promise chain 29 | 30 | return ScreepsAPI.whoami() 31 | 32 | .then(function(data){ 33 | 34 | that.userdata.username = data.username 35 | that.userdata.cpu = data.cpu 36 | that.userdata.badge = data.badge 37 | that.userdata.controlpoints = Math.ceil(data.gcl) 38 | that.userdata.gcl = Math.ceil(ScreepsAPI.utils.controlPointsToGcl(data.gcl)) 39 | 40 | var gcl_current_start = ScreepsAPI.utils.gclToControlPoints(that.userdata.gcl) 41 | var gcl_next_start = ScreepsAPI.utils.gclToControlPoints(that.userdata.gcl+1) 42 | 43 | 44 | that.userdata.gcl_progressTotal = Math.ceil(gcl_next_start - gcl_current_start) 45 | that.userdata.gcl_progress = Math.ceil(that.userdata.controlpoints - gcl_current_start) 46 | that.userdata.gcl_progress_percentage = Math.round((that.userdata.gcl_progress / that.userdata.gcl_progressTotal) * 100) 47 | that.userdata.gcl_progressTotal_string = that.userdata.gcl_progressTotal.toAbbreviated() 48 | that.userdata.gcl_progress_string = that.userdata.gcl_progress.toAbbreviated() 49 | 50 | that.userdata.power = data.power 51 | that.userdata.power_level = ScreepsAPI.utils.powerToLevel(data.power) 52 | var power_current_start = ScreepsAPI.utils.powerAtLevel(that.userdata.power_level) 53 | var power_next_start = ScreepsAPI.utils.powerAtLevel(that.userdata.power_level+1) 54 | 55 | that.userdata.power_progressTotal = Math.ceil(power_next_start - power_current_start) 56 | that.userdata.power_progress = Math.ceil(that.userdata.power - power_current_start) 57 | that.userdata.power_progress_percentage = Math.round((that.userdata.power_progress / that.userdata.power_progressTotal) * 100) 58 | that.userdata.power_progressTotal_string = that.userdata.power_progressTotal.toAbbreviated() 59 | that.userdata.power_progress_string = that.userdata.power_progress.toAbbreviated() 60 | 61 | 62 | 63 | that.userdata.money = (Math.round(100*data.money)/100).toFixed(2) 64 | that.userdata.alliance = League.getUserAlliance(data.username) 65 | 66 | var alliance = League.getAlliance(League.getUserAlliance(data.username)) 67 | if(alliance) { 68 | that.userdata.alliance = alliance.abbreviation 69 | that.userdata.alliance_name = alliance.name 70 | } 71 | 72 | that.userdata.badge_url = League.getBadgeUrl(data.username) 73 | return ScreepsAPI.seasons() 74 | }) 75 | 76 | // Set Current Season 77 | .then(function(data){ 78 | var seasons = data['seasons'] 79 | seasons.sort(function(a,b){ 80 | a = new Date(a.dateModified); 81 | b = new Date(b.dateModified); 82 | return a>b ? -1 : a} Returns a promise with value returned by canvas request handler. 67 | */ 68 | NSCanvasInterface._setImage = function (canvasId, functionName, base64IamgeStr, args) { 69 | var image = new Image(); 70 | return new Promise(function (resolve, reject) { 71 | image.onload = function () { 72 | try { 73 | var retnPromise = NSCanvasInterface._callCanvasReqHandler(canvasId, functionName, [image].concat(args)); 74 | if (!retnPromise) { 75 | throw 'Some Error Occurred while executing _callCanvasReqHandler'; 76 | } 77 | retnPromise.then(function (retnValue) { 78 | resolve(retnValue); 79 | }); 80 | } 81 | catch (e) { 82 | reject(e); 83 | } 84 | }; 85 | image.src = base64IamgeStr; 86 | }); 87 | }; 88 | /** 89 | * This function is called from plugin's native side code. 90 | * Executes the specified function with the passed arguments and generates 91 | * base64 encoded image from the canvas context. 92 | * 93 | * @private 94 | * @param {string} canvasId - Value of "id" attribute of the canvas element in web-view. 95 | * @param {string} functionName - Registered name of handler, which preforms canvas manipulation and creates image. 96 | * @param {string} imgFormat - Expected output format of the image. 97 | * @param {any[]} args - Array of arguments to pass while calling canvas request handler. 98 | * @returns {Promise<<{_strImage: string, data: any}>} Returns promise with base64 encoded image string and any data returned from the canvas request handler.. 99 | */ 100 | NSCanvasInterface._createImage = function (canvasId, functionName, imgFormat, args) { 101 | return new Promise(function (resolve, reject) { 102 | try { 103 | var retnPromise = NSCanvasInterface._callCanvasReqHandler(canvasId, functionName, args); 104 | if (!retnPromise) { 105 | throw 'Some Error Occurred while executing _callCanvasReqHandler'; 106 | } 107 | retnPromise.then(function (data) { 108 | var oNSCanvasInterface = NSCanvasInterface._getCanvasInstanceById(canvasId); 109 | var strImage = oNSCanvasInterface.canvas.toDataURL(imgFormat === 'png' ? 'image/png' : 'image/jpeg'); 110 | resolve({ 111 | _strImage: strImage, 112 | data: data 113 | }); 114 | }); 115 | } 116 | catch (e) { 117 | reject(e); 118 | } 119 | }); 120 | }; 121 | /** 122 | * A map of canvasId and its NSCanvasInterface instance. 123 | * 124 | * @private 125 | */ 126 | NSCanvasInterface._canvasInterfaceInstanceMap = {}; 127 | return NSCanvasInterface; 128 | })(); 129 | /** 130 | * Registering NSCanvasInterface class to global window variable, 131 | * to make it accessible to native app and web-view code. 132 | */ 133 | window.NSCanvasInterface = NSCanvasInterface; 134 | -------------------------------------------------------------------------------- /app/www/lib/nativescript-webview-interface.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WebViewInterface class to handle communication between webView and Android/iOS. 3 | */ 4 | var NSWebViewinterface = (function () { 5 | function NSWebViewinterface() { 6 | 7 | /** 8 | * Mapping of native eventName and its handler in webView 9 | */ 10 | this.eventListenerMap = {}; 11 | 12 | /** 13 | * Mapping of JS Call responseId and result for iOS 14 | */ 15 | this._iosResponseMap = {}; 16 | 17 | /** 18 | * Counter of iOS JS Call responseId 19 | */ 20 | this._iosCntResponseId = 0; 21 | } 22 | 23 | /** 24 | * Handles events/commands emitted by android/ios. This function is called from nativescript. 25 | * @param {string} eventName - Native event/command name 26 | * @param {data} data - Payload for the event/command 27 | */ 28 | NSWebViewinterface.prototype._onNativeEvent = function (eventName, data) { 29 | var lstEvtListeners = this.eventListenerMap[eventName] || []; 30 | for (var _i = 0; _i < lstEvtListeners.length; _i++) { 31 | var listener = lstEvtListeners[_i]; 32 | var retnVal = listener && listener(data); 33 | // if any handler return false, not executing any further handlers for that event. 34 | if (retnVal === false) { 35 | break; 36 | } 37 | } 38 | }; 39 | 40 | /** 41 | * Handles JS function calls by android/ios. This function is called from nativescript. 42 | * Result value of JS function call can be promise or any other data. 43 | * @param {number} reqId - Internal communication id 44 | * @param {string} functionName - Function to be executed in webView 45 | * @param {any[]} args 46 | */ 47 | NSWebViewinterface.prototype._callJSFunction = function (reqId, functionName, args) { 48 | var _this = this; 49 | var resolvedFn = _this._getResolvedFunction(functionName); 50 | if(resolvedFn){ 51 | var retnVal = resolvedFn.apply(window, args); 52 | if (retnVal && retnVal.then) { 53 | retnVal.then(function (value) { 54 | _this._sendJSCallResponse(reqId, value); 55 | }, function(error){ 56 | _this._sendJSCallResponse(reqId, error, true); 57 | }); 58 | } 59 | else { 60 | this._sendJSCallResponse(reqId, retnVal); 61 | } 62 | } 63 | } 64 | 65 | /** 66 | * Resolves a function, if the function to be executed is in deep object chain. 67 | * e.g If we want to execute a function 'parent.child.child.fn' from native app, 68 | * this function will extract fn from the object chain. 69 | * We can do it by using eval also, but as there is a way, why to invite unknown security risks? 70 | * 71 | */ 72 | NSWebViewinterface.prototype._getResolvedFunction = function(functionName){ 73 | if(functionName && (functionName = functionName.trim()).length){ 74 | functionName = functionName.indexOf('window.') === 0 ? functionName.replace('window.', '') : functionName; 75 | var arrFnPath = functionName.split('.'); 76 | var fn = window; 77 | for(var i =0; i < arrFnPath.length; i++){ 78 | if(!fn[arrFnPath[i]]){ 79 | fn = null; 80 | break; 81 | } 82 | fn = fn[arrFnPath[i]]; 83 | } 84 | return fn; 85 | } 86 | } 87 | 88 | /** 89 | * Returns JS Call response by emitting internal _jsCallRespone event 90 | */ 91 | NSWebViewinterface.prototype._sendJSCallResponse = function (reqId, response, isError) { 92 | var oResponse = { 93 | reqId: reqId, 94 | response: response || null, 95 | isError: !!isError 96 | }; 97 | this.emit('_jsCallResponse', oResponse); 98 | }; 99 | 100 | /** 101 | * Creates temporary iFrame element to load custom url, for sending handshake message 102 | * to iOS which is necessary to initiate data transfer from webView to iOS 103 | */ 104 | NSWebViewinterface.prototype._createIFrame = function (src) { 105 | var rootElm = document.documentElement; 106 | var newFrameElm = document.createElement("IFRAME"); 107 | newFrameElm.setAttribute("src", src); 108 | rootElm.appendChild(newFrameElm); 109 | return newFrameElm; 110 | }; 111 | 112 | /** 113 | * Sends handshaking signal to iOS using custom url, for sending event payload or JS Call response. 114 | * As iOS do not allow to send any data from webView. Here we are sending data in two steps. 115 | * 1. Send handshake signal, by loading custom url in iFrame with metadata (eventName, unique responseId) 116 | * 2. On intercept of this request, iOS calls _getIOSResponse with the responseId to fetch the data. 117 | */ 118 | NSWebViewinterface.prototype._emitEventToIOS = function (eventName, data) { 119 | this._iosResponseMap[++this._iosCntResponseId] = data; 120 | var metadata = { eventName: eventName, resId: this._iosCntResponseId }; 121 | var url = 'js2ios:' + JSON.stringify(metadata); 122 | var iFrame = this._createIFrame(url); 123 | iFrame.parentNode.removeChild(iFrame); 124 | }; 125 | 126 | /** 127 | * Returns data to iOS. This function is called from iOS. 128 | */ 129 | NSWebViewinterface.prototype._getIOSResponse = function (resId) { 130 | var response = this._iosResponseMap[resId]; 131 | delete this._iosResponseMap[resId]; 132 | return response; 133 | }; 134 | 135 | /** 136 | * Calls native android function to emit event and payload to android 137 | */ 138 | NSWebViewinterface.prototype._emitEventToAndroid = function (eventName, data) { 139 | window.androidWebViewInterface.handleEventFromWebView(eventName, data); 140 | }; 141 | 142 | /** 143 | * Registers handlers for android/ios event/command 144 | */ 145 | NSWebViewinterface.prototype.on = function (eventName, callback) { 146 | var lstListeners = this.eventListenerMap[eventName] || (this.eventListenerMap[eventName] = []); 147 | lstListeners.push(callback); 148 | }; 149 | 150 | /** 151 | * Emits event to android/ios 152 | */ 153 | NSWebViewinterface.prototype.emit = function (eventName, data) { 154 | var strData = typeof data === 'object' ? JSON.stringify(data) : data; 155 | if (window.androidWebViewInterface) { 156 | this._emitEventToAndroid(eventName, strData); 157 | } 158 | else { 159 | this._emitEventToIOS(eventName, strData); 160 | } 161 | }; 162 | return NSWebViewinterface; 163 | })(); 164 | window.nsWebViewInterface = new NSWebViewinterface(); 165 | -------------------------------------------------------------------------------- /app/services/screeps.js: -------------------------------------------------------------------------------- 1 | require('nativescript-websockets'); 2 | 3 | // Time- in milliseconds- after which we reauthenticate. 4 | const authentication_timeout = 45000 5 | 6 | class ScreepsAPI { 7 | 8 | set username (v) { 9 | this.opts.username = v 10 | } 11 | 12 | set password (v) { 13 | this.opts.password = v 14 | } 15 | 16 | constructor(opts) { 17 | this.opts = opts 18 | this.token = false 19 | 20 | if(!this.opts.host) { 21 | this.opts.host = opts.ptr ? 'screeps.com/ptr/' : 'screeps.com/' 22 | } 23 | this.opts.prefix = this.opts.insecure ? 'http://' : 'https://' 24 | } 25 | 26 | authcheck() { 27 | var lastcall = this.lastcall || 1 28 | this.lastcall = (new Date()).getTime() 29 | 30 | if(!this.token || (this.lastcall - lastcall) > authentication_timeout) { 31 | return this.auth() 32 | } 33 | 34 | return Promise.resolve(true) 35 | } 36 | 37 | get_web_socket() { 38 | if(!this.socket) { 39 | this.socket = new ScreepsSocket(this, this.opts) 40 | } 41 | return this.socket 42 | } 43 | 44 | reset() { 45 | delete this.opts.username 46 | delete this.opts.password 47 | this.token = false 48 | } 49 | 50 | req(endpoint, method, body, contenttype) { 51 | var that = this 52 | var request_options = { 53 | method: method, 54 | headers: { 55 | 'X-Token': this.token, 56 | 'X-Username': this.token, 57 | 'Accept': 'application/json, application/xml, text/plain, text/html, *.*', 58 | } 59 | } 60 | 61 | if(contenttype) { 62 | request_options['headers']['Content-Type'] = contenttype 63 | } 64 | 65 | if(body) { 66 | request_options['body'] = body 67 | } 68 | var base = this.opts.prefix + this.opts.host + 'api/' 69 | console.log(base + endpoint) 70 | var that = this 71 | return fetch(base + endpoint, request_options) 72 | 73 | // Update authentication token and procress json response. 74 | // @todo deal with compressed data. 75 | .then(function(response) { 76 | if(!response.ok) { 77 | if(!!that.token && response.status == '403') { 78 | that.token = false 79 | } 80 | throw new Error(response.status + ': ' + response.statusText) 81 | } 82 | if(!!response.headers.has('X-Token')) { 83 | that.token = response.headers.get('X-Token') 84 | } 85 | that.lastcall = (new Date()).getTime() 86 | return response.json() 87 | }) 88 | .then(function(data){ 89 | if(data['token']) { 90 | that.token = data['token'] 91 | } 92 | return data 93 | }) 94 | } 95 | 96 | get(endpoint, args) { 97 | var that = this 98 | return this.authcheck().then(function(){ 99 | if(!!args) { 100 | endpoint += '?' + Object.keys(args).map(function(key) { 101 | return [key, args[key]].map(encodeURIComponent).join("="); 102 | }).join("&"); 103 | } 104 | return that.req(endpoint, 'GET') 105 | }) 106 | } 107 | 108 | post(endpoint, args) { 109 | var that = this 110 | return this.authcheck().then(function(){ 111 | console.log(endpoint) 112 | if(endpoint != 'auth/signin') { 113 | console.log(JSON.stringify(args)) 114 | } 115 | var formData = new FormData(); 116 | var keys = Object.keys(args) 117 | for(var index of keys) { 118 | formData.append(index, args[index]); 119 | } 120 | return that.req(endpoint, 'POST', formData, 'application/x-www-form-urlencoded; charset=utf-8') 121 | }) 122 | } 123 | 124 | auth() { 125 | console.log('auth/signin') 126 | var formData = new FormData(); 127 | formData.append('email', this.opts.username) 128 | formData.append('password', this.opts.password) 129 | return this.req('auth/signin', 'POST', formData, 'application/x-www-form-urlencoded; charset=utf-8') 130 | } 131 | 132 | whoami() { 133 | return this.get('auth/me') 134 | } 135 | 136 | seasons() { 137 | return this.get('leaderboard/seasons') 138 | } 139 | 140 | find(mode, season, user) { 141 | return this.get('leaderboard/find', { 142 | 'mode': mode, 143 | 'season': season, 144 | 'username': user 145 | }) 146 | } 147 | 148 | overview(interval, statName) { 149 | return this.get('user/overview', { 150 | 'interval': interval, 151 | 'statName': statName 152 | }) 153 | } 154 | 155 | my_orders() { 156 | return this.get('game/market/my-orders') 157 | } 158 | 159 | money_history(page=0) { 160 | return this.get('user/money-history', { 161 | 'page': page 162 | }) 163 | } 164 | 165 | user_console(cmd) { 166 | return this.post('user/console', {'expression':cmd}) 167 | } 168 | 169 | messages() { 170 | return this.get('user/messages/index') 171 | } 172 | 173 | messages_list(respondent) { 174 | return this.get('user/messages/list', {'respondent': respondent}) 175 | } 176 | 177 | messages_send(respondent, message) { 178 | return this.post('user/messages/send', {'respondent': respondent, 'text': message}) 179 | } 180 | 181 | userdata_from_id(id) { 182 | if(!this.id_user_map) { 183 | this.id_user_map = {} 184 | } 185 | if(!this.user_id_map) { 186 | this.user_id_map = {} 187 | } 188 | 189 | if(!!this.id_user_map[id]) { 190 | return Promise.resolve(this.id_user_map[id]) 191 | } 192 | var that = this 193 | return this.user_find({'id':id}) 194 | .then(function(data){ 195 | that.id_user_map[id] = data 196 | that.id_user_map[data['user']['username']] = data 197 | return data 198 | }) 199 | } 200 | 201 | userdata_from_username(username) { 202 | if(!this.user_id_map) { 203 | this.user_id_map = {} 204 | } 205 | if(!this.id_user_map) { 206 | this.id_user_map = {} 207 | } 208 | 209 | if(!!this.user_id_map[username]) { 210 | return Promise.resolve(this.user_id_map[username]) 211 | } 212 | var that = this 213 | return this.user_find({'username':username}) 214 | .then(function(data){ 215 | that.user_id_map[username] = data 216 | that.id_user_map[data['user']['_id']] = data 217 | return data 218 | }) 219 | } 220 | 221 | user_find(options) { 222 | return this.get('user/find', options) 223 | } 224 | 225 | } 226 | 227 | class ScreepsSocket { 228 | 229 | constructor(api, opts) { 230 | this.api = api 231 | this.opts = opts 232 | this.socket = false 233 | this.subscriptions = [] 234 | this.handlers = {} 235 | } 236 | 237 | connect() { 238 | 239 | if(!!this.socket) { 240 | // If socket is closed or closing then open a new one. 241 | if(this.socket.readyState == 2 || this.socket.readyState == 3) { 242 | this.socket = false 243 | } else { 244 | return 245 | } 246 | } 247 | 248 | var uri = !!this.opts.insecure ? 'ws://' : 'wss://' 249 | uri += this.opts.host + 'socket/websocket' 250 | console.log('connecting to websocket: ' + uri) 251 | this.socket = new WebSocket(uri) 252 | 253 | var that = this 254 | this.socket.addEventListener('open', function(evt){ 255 | evt.target.send('auth ' + that.api.token) 256 | }) 257 | 258 | 259 | this.socket.addEventListener('message', function(evt){ 260 | console.log('message received') 261 | 262 | var message = evt.data 263 | if(message.startsWith('auth ok')) { 264 | console.log('authenticated') 265 | var splitmessage = message.split(' ') 266 | if(splitmessage.length >= 3) { 267 | that.api.token = splitmessage[2] 268 | } 269 | // Set Subscriptions 270 | for(var watchpoint of that.subscriptions) { 271 | that.subscribe(watchpoint) 272 | } 273 | return 274 | } 275 | 276 | if(message.startsWith('time')) { 277 | return 278 | } 279 | 280 | if(message.startsWith('gz')) { 281 | message = inflate(message) 282 | } 283 | 284 | if (message[0] == '[') { 285 | var data = JSON.parse(message) 286 | } else { 287 | // emulate normal responses but with blank subscription key 288 | // this will mean only raw handlers will run on message 289 | var data = ['', message] 290 | } 291 | 292 | var handlers = [] 293 | switch (true) { 294 | case data[0].endsWith('console'): 295 | var type = 'console' 296 | break; 297 | case data[0].endsWith('cpu'): 298 | var type = 'cpu' 299 | break; 300 | case data[0].endsWith('money'): 301 | var type = 'money' 302 | break; 303 | default: 304 | var type = 'raw' 305 | break; 306 | } 307 | 308 | console.log('websocket handler type: ' + type) 309 | if(that.handlers[type]) { 310 | handlers = that.handlers[type] 311 | } 312 | 313 | if(that.handlers['*']) { 314 | handlers = handlers.concat(that.handlers[raw]) 315 | } 316 | 317 | for(var handler of handlers) { 318 | handler(data[1]) 319 | } 320 | }) 321 | 322 | 323 | this.socket.addEventListener('close', function(evt){ 324 | that.socket = false 325 | console.log("The Socket was Closed:", evt.code, evt.reason); 326 | }) 327 | 328 | 329 | this.socket.addEventListener('error', function(evt){ 330 | console.log("The socket had an error", evt.error) 331 | }) 332 | } 333 | 334 | disconnect() { 335 | if(this.socket) { 336 | console.log('closing socket') 337 | this.socket.close() 338 | this.socket = false 339 | } 340 | } 341 | 342 | subscribe(watchpoint) { 343 | if(this.subscriptions.indexOf(watchpoint) < 0) { 344 | this.subscriptions.push(watchpoint) 345 | this.connect() 346 | } 347 | 348 | if(this.socket && this.socket.readyState == 1) { 349 | var that = this 350 | this.api.userdata_from_username(this.opts.username) 351 | .then(function(userinfo){ 352 | var message = 'subscribe user:' + userinfo['user']['_id'] + '/' + watchpoint 353 | console.log(message) 354 | that.socket.send(message) 355 | }).catch(function(err){ 356 | console.log(err.message) 357 | console.log(err.stack) 358 | }) 359 | } 360 | } 361 | 362 | unsubscribe(watchpoint) { 363 | if(this.socket && this.socket.readyState == 1) { 364 | var that = this 365 | this.api.userdata_from_username(this.opts.username) 366 | .then(function(userinfo){ 367 | var message = 'unsubscribe user:' + userinfo['user']['_id'] + '/' + watchpoint 368 | console.log(message) 369 | that.socket.send(message) 370 | }) 371 | } 372 | var index = this.subscriptions.indexOf(watchpoint) 373 | if(index < 0) { 374 | this.subscriptions.splice(index,1) 375 | } 376 | if(this.subscriptions.length < 1) { 377 | this.disconnect() 378 | } 379 | } 380 | 381 | registerHandler(watchpoint, callback) { 382 | if(!this.handlers[watchpoint]) { 383 | this.handlers[watchpoint] = [] 384 | } 385 | this.handlers[watchpoint].push(callback) 386 | this.subscribe(watchpoint) 387 | } 388 | 389 | deregisterHandler(watchpoint, callback) { 390 | if(!this.handlers[watchpoint]) { 391 | return 392 | } 393 | 394 | var index = this.handlers[watchpoint].indexOf(callback) 395 | if(index >= 0) { 396 | console.log('removing handler from ' + watchpoint) 397 | this.handlers[watchpoint].splice(index, 1) 398 | } else { 399 | console.log('unable to find registered handler for ' + watchpoint) 400 | } 401 | 402 | if(this.handlers[watchpoint].length < 1) { 403 | console.log('unsubscribing from ' + watchpoint + ' due to lack of subscriptions') 404 | delete this.handlers[watchpoint] 405 | this.unsubscribe(watchpoint) 406 | } 407 | 408 | var handlercount = 0 409 | Object.values(this.handlers).forEach(function(e){handlercount += e.length; }) 410 | 411 | if(handlercount < 1) { 412 | console.log('closing socket due to lack of active subscriptions') 413 | this.disconnect() 414 | } 415 | } 416 | } 417 | 418 | 419 | 420 | var GCL_POW= 2.4 421 | var GCL_MULTIPLY = 1000000 422 | 423 | 424 | var POWER_POW = 1.15 425 | var POWER_MULTIPLY = 1000 426 | 427 | var powertotals = [{level:0, total:0}] 428 | var powerlevels = {} 429 | var total = 0 430 | for(var i=1; i <= 350; i++) { 431 | total += Math.pow(POWER_POW, i) * POWER_MULTIPLY 432 | powertotals.push({ 433 | level: i, 434 | total: total 435 | }) 436 | powerlevels[i] = total 437 | } 438 | powertotals.reverse() // store from highest to lowest 439 | 440 | 441 | var ScreepsUtils = { 442 | gclToControlPoints: function(gcl) { 443 | return Math.pow(gcl - 1, GCL_POW) * GCL_MULTIPLY; 444 | }, 445 | 446 | controlPointsToGcl: function(points) { 447 | return Math.floor(Math.pow(points / GCL_MULTIPLY, 1 / GCL_POW) + 1); 448 | }, 449 | 450 | powerToLevel: function (power) { 451 | if(power <= 0) { 452 | 453 | } 454 | for(var powerdata of powertotals) { 455 | if(powerdata.total < power) { 456 | return powerdata.level 457 | } 458 | } 459 | return false 460 | }, 461 | 462 | powerAtLevel: function (level) { 463 | return powerlevels[level] 464 | }, 465 | 466 | powerToNextLevel: function (level) { 467 | return Math.pow(POWER_POW, level) * POWER_MULTIPLY 468 | } 469 | } 470 | 471 | function gz (data) { 472 | let buf = new Buffer(data.slice(3), 'base64') 473 | let zlib = require('zlib') 474 | let ret = zlib.gunzipSync(buf).toString() 475 | return JSON.parse(ret) 476 | } 477 | 478 | function inflate (data) { 479 | let buf = new Buffer(data.slice(3), 'base64') 480 | let zlib = require('zlib') 481 | let ret = zlib.inflateSync(buf).toString() 482 | return JSON.parse(ret) 483 | } 484 | 485 | var api = new ScreepsAPI({}) 486 | api.utils = ScreepsUtils 487 | module.exports = api 488 | -------------------------------------------------------------------------------- /app/www/lib/es6-promise.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @overview es6-promise - a tiny implementation of Promises/A+. 3 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) 4 | * @license Licensed under MIT license 5 | * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE 6 | * @version 3.0.2 7 | */ 8 | 9 | (function(){"use strict";function lib$es6$promise$utils$$objectOrFunction(x){return typeof x==="function"||typeof x==="object"&&x!==null}function lib$es6$promise$utils$$isFunction(x){return typeof x==="function"}function lib$es6$promise$utils$$isMaybeThenable(x){return typeof x==="object"&&x!==null}var lib$es6$promise$utils$$_isArray;if(!Array.isArray){lib$es6$promise$utils$$_isArray=function(x){return Object.prototype.toString.call(x)==="[object Array]"}}else{lib$es6$promise$utils$$_isArray=Array.isArray}var lib$es6$promise$utils$$isArray=lib$es6$promise$utils$$_isArray;var lib$es6$promise$asap$$len=0;var lib$es6$promise$asap$$toString={}.toString;var lib$es6$promise$asap$$vertxNext;var lib$es6$promise$asap$$customSchedulerFn;var lib$es6$promise$asap$$asap=function asap(callback,arg){lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len]=callback;lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len+1]=arg;lib$es6$promise$asap$$len+=2;if(lib$es6$promise$asap$$len===2){if(lib$es6$promise$asap$$customSchedulerFn){lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush)}else{lib$es6$promise$asap$$scheduleFlush()}}};function lib$es6$promise$asap$$setScheduler(scheduleFn){lib$es6$promise$asap$$customSchedulerFn=scheduleFn}function lib$es6$promise$asap$$setAsap(asapFn){lib$es6$promise$asap$$asap=asapFn}var lib$es6$promise$asap$$browserWindow=typeof window!=="undefined"?window:undefined;var lib$es6$promise$asap$$browserGlobal=lib$es6$promise$asap$$browserWindow||{};var lib$es6$promise$asap$$BrowserMutationObserver=lib$es6$promise$asap$$browserGlobal.MutationObserver||lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;var lib$es6$promise$asap$$isNode=typeof process!=="undefined"&&{}.toString.call(process)==="[object process]";var lib$es6$promise$asap$$isWorker=typeof Uint8ClampedArray!=="undefined"&&typeof importScripts!=="undefined"&&typeof MessageChannel!=="undefined";function lib$es6$promise$asap$$useNextTick(){return function(){process.nextTick(lib$es6$promise$asap$$flush)}}function lib$es6$promise$asap$$useVertxTimer(){return function(){lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush)}}function lib$es6$promise$asap$$useMutationObserver(){var iterations=0;var observer=new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);var node=document.createTextNode("");observer.observe(node,{characterData:true});return function(){node.data=iterations=++iterations%2}}function lib$es6$promise$asap$$useMessageChannel(){var channel=new MessageChannel;channel.port1.onmessage=lib$es6$promise$asap$$flush;return function(){channel.port2.postMessage(0)}}function lib$es6$promise$asap$$useSetTimeout(){return function(){setTimeout(lib$es6$promise$asap$$flush,1)}}var lib$es6$promise$asap$$queue=new Array(1e3);function lib$es6$promise$asap$$flush(){for(var i=0;i