diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj index be97279c2..765da0bda 100644 --- a/CrossPlatformModules.csproj +++ b/CrossPlatformModules.csproj @@ -61,6 +61,16 @@ + + + details-page.xml + + + main-page.xml + + + + list-picker.xml @@ -602,6 +612,21 @@ + + Always + + + + Always + + + Designer + + + + + + @@ -1536,6 +1561,9 @@ PreserveNewest + + PreserveNewest + @@ -1618,7 +1646,7 @@ False - + \ No newline at end of file diff --git a/apps/cuteness.unoptimized/app.ts b/apps/cuteness.unoptimized/app.ts new file mode 100644 index 000000000..c55cfec5e --- /dev/null +++ b/apps/cuteness.unoptimized/app.ts @@ -0,0 +1,7 @@ +import application = require("application"); + +// Set the start module for the application +application.mainModule = "main-page"; + +// Start the application +application.start(); diff --git a/apps/cuteness.unoptimized/details-page.css b/apps/cuteness.unoptimized/details-page.css new file mode 100644 index 000000000..57988b016 --- /dev/null +++ b/apps/cuteness.unoptimized/details-page.css @@ -0,0 +1,14 @@ +Page { + background-color: #363940; +} + +.detailsTitle { + color: #FFFFFF; + font-size: 30; + margin: 10; +} + +ActivityIndicator { + width: 50; + height: 50; +} diff --git a/apps/cuteness.unoptimized/details-page.ts b/apps/cuteness.unoptimized/details-page.ts new file mode 100644 index 000000000..0e71a4e76 --- /dev/null +++ b/apps/cuteness.unoptimized/details-page.ts @@ -0,0 +1,10 @@ +import pages = require("ui/page"); +import observable = require("data/observable"); + +// Event handler for Page "navigatedTo" event attached in details-page.xml +export function pageNavigatedTo(args: observable.EventData) { + // Get the event sender + var page = args.object; + + page.bindingContext = page.navigationContext; +} diff --git a/apps/cuteness.unoptimized/details-page.xml b/apps/cuteness.unoptimized/details-page.xml new file mode 100644 index 000000000..0c3843dbe --- /dev/null +++ b/apps/cuteness.unoptimized/details-page.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/cuteness.unoptimized/main-page.css b/apps/cuteness.unoptimized/main-page.css new file mode 100644 index 000000000..115f58fbc --- /dev/null +++ b/apps/cuteness.unoptimized/main-page.css @@ -0,0 +1,29 @@ +.title { + font-size: 20; + margin: 3; +} + +.author { + font-size: 14; + horizontal-align: left; + vertical-align: bottom; + margin: 3; +} + +.comments { + color: #10C2B0; + font-size: 14; + vertical-align: bottom; + margin: 3; +} + +.thumbnail { + width: 72; + height: 72; + margin: 3; + vertical-align: top; +} + +TabView { + background-color: white; +} \ No newline at end of file diff --git a/apps/cuteness.unoptimized/main-page.ts b/apps/cuteness.unoptimized/main-page.ts new file mode 100644 index 000000000..7f72da258 --- /dev/null +++ b/apps/cuteness.unoptimized/main-page.ts @@ -0,0 +1,34 @@ +import observable = require("data/observable"); +import pages = require("ui/page"); +import frames = require("ui/frame"); +import listView = require("ui/list-view"); + +import redditAppViewModel = require("./reddit-app-view-model"); + +var appViewModel = new redditAppViewModel.AppViewModel(); + +// Event handler for Page "loaded" event attached in main-page.xml +export function pageLoaded(args: observable.EventData) { + // Get the event sender + var page = args.object; + + page.bindingContext = appViewModel; + appViewModel.loadItemsAsync(); + + // Enable platform specific feature (in this case Android page caching) + if (frames.topmost().android) { + frames.topmost().android.cachePagesOnNavigate = true; + } +} + +export function listViewItemTap(args: listView.ItemEventData) { + // Navigate to the details page with context set to the data item for specified index + frames.topmost().navigate({ + moduleName: "./details-page", + context: appViewModel.redditItems.getItem(args.index) + }); +} + +export function listViewLoadMoreItems(args: observable.EventData) { + appViewModel.loadItemsAsync(); +} diff --git a/apps/cuteness.unoptimized/main-page.xml b/apps/cuteness.unoptimized/main-page.xml new file mode 100644 index 000000000..cb0deaf94 --- /dev/null +++ b/apps/cuteness.unoptimized/main-page.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/cuteness.unoptimized/package.json b/apps/cuteness.unoptimized/package.json new file mode 100644 index 000000000..18fba5cbb --- /dev/null +++ b/apps/cuteness.unoptimized/package.json @@ -0,0 +1,2 @@ +{ "name" : "cuteness.unoptimized", + "main" : "app.js" } \ No newline at end of file diff --git a/apps/cuteness.unoptimized/reddit-app-view-model.ts b/apps/cuteness.unoptimized/reddit-app-view-model.ts new file mode 100644 index 000000000..32eeec9ac --- /dev/null +++ b/apps/cuteness.unoptimized/reddit-app-view-model.ts @@ -0,0 +1,67 @@ +import imageSource = require("image-source"); +import observableArray = require("data/observable-array"); +import http = require("http"); +import observable = require("data/observable"); +import imageCache = require("ui/image-cache"); + +import redditModel = require("./reddit-model"); +import redditViewModel = require("./reddit-item-view-model"); + +var aboutText = "Cuteness is a proof of concept app demonstrating the Telerik's NativeScript for writing native mobile applications using JavaScript."; +export var defaultThumbnailImageSource = imageSource.fromFile("~/res/reddit-logo.png"); +export var defaultNoThumbnailImageSource = imageSource.fromFile("~/res/no-image.png"); + +var redditUrl = "http://www.reddit.com/r/aww.json?limit=50"; + +// initialize the image cache for the main list +export var cache = new imageCache.Cache(); +cache.placeholder = defaultThumbnailImageSource; +cache.maxRequests = 5; + +export class AppViewModel extends observable.Observable { + private _redditItems = new observableArray.ObservableArray(); + private _isLoading = false; + private _after = ""; + + get redditItems(): observableArray.ObservableArray { + return this._redditItems; + } + + public loadItemsAsync() { + if (this._isLoading) { + return; + } + this._isLoading = true; + var requestUrl = redditUrl + this._after; + //console.log(`>>> Requesting ${requestUrl}`); + var that = this; + http.getJSON(requestUrl).then(result => { + //console.log(`>>> Received ${result.data.children.length} reddit items`); + var newItems = result.data.children.map(i=> { + return new redditViewModel.RedditViewModel(i.data); + }); + that._redditItems.push(newItems); + that._after = "&after=" + newItems[newItems.length - 1].source.name; + that._isLoading = false; + },(e) => { + console.log(e.message); + that._isLoading = false; + }) + .catch(function (e) { + that._isLoading = false; + setTimeout(function () { throw e; }); + }); + } + + get aboutText(): string { + return aboutText; + } + + get defaultThumbnailImageSource(): imageSource.ImageSource { + return defaultThumbnailImageSource; + } + + get defaultNoThumbnailImageSource(): imageSource.ImageSource { + return defaultNoThumbnailImageSource; + } +} \ No newline at end of file diff --git a/apps/cuteness.unoptimized/reddit-item-view-model.ts b/apps/cuteness.unoptimized/reddit-item-view-model.ts new file mode 100644 index 000000000..8ea1dadae --- /dev/null +++ b/apps/cuteness.unoptimized/reddit-item-view-model.ts @@ -0,0 +1,101 @@ +import observable = require("data/observable"); +import imageSource = require("image-source"); + +import redditModel = require("./reddit-model"); +import redditAppViewModel = require("./reddit-app-view-model"); + +var firstThumbnailImageSource = imageSource.fromFile("~/res/first-image.png"); +var defaultImageSource = imageSource.fromFile("~/res/reddit-logo-transparent.png"); + +var ISLOADING = "isLoading"; +var THUMBNAIL_IMAGE = "thumbnailImage"; +var IMAGE_SOURCE = "imageSource"; + +export class RedditViewModel extends observable.Observable { + + private _source: redditModel.ItemData; + constructor(source: redditModel.ItemData) { + super(); + + this._source = source; + + if (this._source) { + var property: string; + for (property in this._source) { + this.set(property, this._source[property]); + } + } + } + + get source(): redditModel.ItemData { + return this._source; + } + + private _isLoading = false; + get isLoading(): boolean { + return this._isLoading; + } + set isLoading(value: boolean) { + if (this._isLoading !== value) { + this._isLoading = value; + this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: ISLOADING, value: value }); + } + } + + get thumbnailImage(): imageSource.ImageSource { + if (!this._source) { + return redditAppViewModel.defaultThumbnailImageSource; + } + + if (this._source.title === "reddit 101") { + return firstThumbnailImageSource; + } + + var url = this._source.thumbnail; + + if (!_isValidImageUrl(url)) { + return redditAppViewModel.defaultNoThumbnailImageSource + } + + var image = redditAppViewModel.cache.get(url); + if (image) { + return image; + } + + this.isLoading = true; + redditAppViewModel.cache.push({ + key: url, + url: url, + completed: (image: any, key: string) => { + if (url === key) { + this.isLoading = false; + this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: THUMBNAIL_IMAGE, value: image }); + } + } + }); + + return redditAppViewModel.defaultThumbnailImageSource; + } + + get imageSource(): imageSource.ImageSource { + if (this._source) { + var url = this._source.url; + + if (_isValidImageUrl(url)) { + + this.isLoading = true; + + imageSource.fromUrl(url).then(result => { + this.isLoading = false; + this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: IMAGE_SOURCE, value: result }); + }); + } + } + + return defaultImageSource; + } +} + +function _isValidImageUrl(url: string): boolean { + return url && (url.indexOf(".png") !== -1 || url.indexOf(".jpg") !== -1); +} diff --git a/apps/cuteness.unoptimized/reddit-model.d.ts b/apps/cuteness.unoptimized/reddit-model.d.ts new file mode 100644 index 000000000..776f77867 --- /dev/null +++ b/apps/cuteness.unoptimized/reddit-model.d.ts @@ -0,0 +1,57 @@ +export interface Data { + kind: string; + data: Items; +} + +export interface Items { + modhash: string; + children: Array; +} + +export interface Item { + kind: string; + data: ItemData; +} + +export interface ItemData { + domain: any; + banned_by: any; + media_embed: any; + subreddit: any; + selftext_html: any; + selftext: any; + likes: any; + secure_media: any; + link_flair_text: any; + id: string; + gilded: any; + secure_media_embed: any; + clicked: boolean; + stickied: boolean; + author: any; + media: any; + score: number; + approved_by: any; + over_18: boolean; + hidden: boolean; + thumbnail: string; + subreddit_id: any; + edited: boolean; + link_flair_css_class: any; + author_flair_css_class: any; + downs: number; + saved: boolean; + is_self: boolean; + permalink: string; + name: string; + created: number; + url: string; + author_flair_text: string; + title: string; + created_utc: number; + ups: number; + num_comments: number; + visited: boolean; + num_reports: any; + distinguished: any +} \ No newline at end of file diff --git a/apps/cuteness.unoptimized/res/first-image.png b/apps/cuteness.unoptimized/res/first-image.png new file mode 100644 index 000000000..8d322529c Binary files /dev/null and b/apps/cuteness.unoptimized/res/first-image.png differ diff --git a/apps/cuteness.unoptimized/res/no-image.png b/apps/cuteness.unoptimized/res/no-image.png new file mode 100644 index 000000000..9c215b192 Binary files /dev/null and b/apps/cuteness.unoptimized/res/no-image.png differ diff --git a/apps/cuteness.unoptimized/res/reddit-logo-transparent.png b/apps/cuteness.unoptimized/res/reddit-logo-transparent.png new file mode 100644 index 000000000..6936ebd19 Binary files /dev/null and b/apps/cuteness.unoptimized/res/reddit-logo-transparent.png differ diff --git a/apps/cuteness.unoptimized/res/reddit-logo.png b/apps/cuteness.unoptimized/res/reddit-logo.png new file mode 100644 index 000000000..de99da231 Binary files /dev/null and b/apps/cuteness.unoptimized/res/reddit-logo.png differ diff --git a/apps/cuteness.unoptimized/res/telerik-logo.png b/apps/cuteness.unoptimized/res/telerik-logo.png new file mode 100644 index 000000000..880af63d6 Binary files /dev/null and b/apps/cuteness.unoptimized/res/telerik-logo.png differ