From 8546beaa1f003a2450706f0d664e3b6d14b81b0f Mon Sep 17 00:00:00 2001 From: brianjjones Date: Thu, 6 Mar 2014 15:18:15 -0800 Subject: [PATCH] Initial commit of the Appmanager app Change-Id: Ia1ca0c7298ce6018f27ca2fc556b6a743c6f8cf5 --- Makefile | 20 ++ config.xml | 21 ++ css/carouselview.css | 65 ++++ css/popularApps.css | 83 +++++ css/store_library.css | 104 +++++++ css/style.css | 175 +++++++++++ icon.png | Bin 0 -> 3738 bytes index.html | 77 +++++ js/main.js | 399 ++++++++++++++++++++++++ js/packagerepository.js | 333 ++++++++++++++++++++ js/popularController.js | 53 ++++ js/store_library.js | 487 ++++++++++++++++++++++++++++++ packaging/html5-ui-appmanager.changes | 4 + packaging/html5-ui-appmanager.spec | 36 +++ templates/carouselDelegate.html | 12 + templates/detailApplicationContainer.html | 68 +++++ templates/popularAppsContainer.html | 33 ++ templates/storeLibraryAppsDelegate.html | 24 ++ 18 files changed, 1994 insertions(+) create mode 100644 Makefile create mode 100644 config.xml create mode 100644 css/carouselview.css create mode 100644 css/popularApps.css create mode 100644 css/store_library.css create mode 100644 css/style.css create mode 100644 icon.png create mode 100644 index.html create mode 100644 js/main.js create mode 100644 js/packagerepository.js create mode 100644 js/popularController.js create mode 100644 js/store_library.js create mode 100644 packaging/html5-ui-appmanager.changes create mode 100644 packaging/html5-ui-appmanager.spec create mode 100644 templates/carouselDelegate.html create mode 100644 templates/detailApplicationContainer.html create mode 100644 templates/popularAppsContainer.html create mode 100644 templates/storeLibraryAppsDelegate.html diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5dbf4c1 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +PROJECT = html5UIAppmanager + +VERSION := 0.0.1 +PACKAGE = $(PROJECT)-$(VERSION) + +INSTALL_FILES = $(PROJECT).wgt +INSTALL_DIR = ${DESTDIR}/opt/usr/apps/.preinstallWidgets + +wgtPkg: + cp -r ${DESTDIR}/opt/usr/apps/_common/js/services js/ + cp -r ${DESTDIR}/opt/usr/apps/_common/css/* css/ + zip -r $(PROJECT).wgt config.xml css icon.png index.html js templates + +install: + @echo "Installing Appmanager, stand by..." + mkdir -p $(INSTALL_DIR)/ + cp $(PROJECT).wgt $(INSTALL_DIR)/ + +dist: + tar czf ../$(PACKAGE).tar.bz2 . diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..78b5cb2 --- /dev/null +++ b/config.xml @@ -0,0 +1,21 @@ + + + AppManager + + + + + + + + + + + + + + + + + + diff --git a/css/carouselview.css b/css/carouselview.css new file mode 100644 index 0000000..3fecf1c --- /dev/null +++ b/css/carouselview.css @@ -0,0 +1,65 @@ +.carousel { + -webkit-transition: 2s; + position: absolute; + top: 230px; + left: -15px; + width: 12000px; + padding: 0; + margin: 0; +} + +.appsCarousel li { + display: block; + float: left; +} + +.carouselItem { + /*float: left;*/ + width: 240px; + height: 240px; + margin-right: 15px; + padding: 0; + white-space: normal; + background-color: rgb(0, 0, 0); + background-color: rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 30px rgba(0, 0, 0, .7); + border-width: 1px; + border-style: solid; + text-transform: uppercase; +} + +.carouselItemSelected { + box-shadow: 0 0 5px 1px #1DA2FF /*background-color:#BFBFFF;*/ +} + +.carouselImage { + width: 100%; + height: 100%; +} + +.albumCarouselDescription { + position: absolute; + width: 100%; + top: 145px; + left: 0; + height: 95px; + text-align: center; +} + +.albumCarouselDescriptionText { + width: 220px; + margin: 18px auto 0 auto; + text-align: center; + overflow: hidden; +} + +.carouselShadow { + position: relative; + width: 246px; + height: 110px; + top: -100px; + opacity: 0.2; + -webkit-transform: rotateX(180deg); + -webkit-transform-origin: 50% 50%; + display: none; +} \ No newline at end of file diff --git a/css/popularApps.css b/css/popularApps.css new file mode 100644 index 0000000..52e6dcc --- /dev/null +++ b/css/popularApps.css @@ -0,0 +1,83 @@ +.divider { + border-bottom: solid 1px; + margin-top: 50px; + position: absolute; + top: 480px; + width: 100%; +} + +.popularHeader { + position: absolute; + top: 80px; +} + +.popularAppsContainer { + margin-left: -30px; + position: absolute; + width: 720px; + top: 145px; + overflow-x: hidden; + overflow-y: scroll; + height: 80%; + right: -40px; +} + +.popularItem { + height: 182px; + width: 182px; + margin: 0 29px 58px 29px; + float: left; +} + +.detailPopIcon { + width: 182px; + height: 182px; + margin: 0 auto; +} + +.storePopAppInfo { + float: left; + position: relative; + width: 100%; + height: 96px; + left: 0; + top: -95px; + text-transform: uppercase; + text-align: center; + z-index: 9; +} + +.storePopAppTitle { + margin-top: 5px; + overflow: hidden; + height: 28px; +} + + +.storePopAppInfoImage { + width: 182px; + height: 182px; +} + +.ratingPopTable +{ + width:182px; + height:36px; + margin: 3px 45px; +} + +.iconPopStarActive +{ + display:inline-block; +} + + +.transparent { + background-color: #111; + position: relative; + opacity: 0.65; + z-index: 8; + top: -95px; +} + + diff --git a/css/store_library.css b/css/store_library.css new file mode 100644 index 0000000..4a9b7c6 --- /dev/null +++ b/css/store_library.css @@ -0,0 +1,104 @@ +.storeLibraryContentList .appElement { + padding: 10px 0 10px 0; + height: 70px; + box-shadow: none; + border-bottom-style: solid; + border-bottom-width: 2px; + overflow: hidden; + white-space: nowrap; + line-height: 0; + text-align: left; + cursor: pointer; +} + +.storeLibraryContentList .appImage { + width: 70px; + height: 70px; + display: inline-block; + margin-right: 20px; + background-position: center center; + background-repeat: no-repeat; + background-size: 100% 100%; +} + +.storeLibraryContentList .appImage img { + width: 100%; + height: 100%; +} + +.storeLibraryContentList .appInfoBox { + display: inline-block; + vertical-align: top; + padding-top: 11px; + background-color: transparent !important; +} + +.storeLibraryContentList .appTitle { + text-transform: uppercase; +} + +.storeLibraryContentList .appSubtitle { + text-transform: uppercase; + display: inline-block; + vertical-align: middle; +} + +.storeLibraryContentList .appRating { + display: inline-block; + vertical-align: middle; +} + +.storeLibraryContentGrid { + line-height: 0; +} + +.storeLibraryContentGrid .appElement { + width: 180px; + height: 180px; + display: inline-block; + margin-right: 7px; + margin-bottom: 10px; + line-height: 0; + vertical-align: top; + cursor: pointer; +} + +.storeLibraryContentGrid .appImage { + width: 100%; + height: 100%; + background-position: center center; + background-repeat: no-repeat; + background-size: 100% 100%; +} + +.storeLibraryContentGrid .appImage img { + width: 100%; + height: 100%; +} + +.storeLibraryContentGrid .appInfoBox { + position: absolute; + top: 95px; + left: 0; + width: 180px; + height: 85px; + text-align: center; +} + +.storeLibraryContentGrid .appTitle { + white-space: nowrap; + overflow: hidden; + width: 160px; + margin: 10px auto 0 auto; + text-transform: uppercase; +} + +.storeLibraryContentGrid .appSubtitle { + text-transform: uppercase; +} + +.storeLibraryContentGrid .appRating { + width: 100px; + text-align: center; + margin: 0 auto; +} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..ebf5512 --- /dev/null +++ b/css/style.css @@ -0,0 +1,175 @@ +#backgroundStore +{ + position: absolute; + width: 720px; + height: 1280px; + +} +#appDetailWraper{ + /*position: absolute;*/ + top:480px; + left :30px; + width:660px; + height:600px; +} + +.storePromotedAppsCellHidden { + display: none; +} + +.storePromotedAppsCellImage { + height: 148px; + width: 181px; + margin: 3px; +} +.storePromotedAppsCellText { + text-align: center; + font-size: x-large; + color: white; + text-shadow: none; + position: relative; + background-color: #111111; + width: 100%; + height: 30px; + opacity: 0.6; + left: 0; + top: -30px; + +} +.ratingIcons +{ + width: 20px; + height: 18px; + background-repeat: no-repeat; +} + + +/*new added after code clear in detailApplication.css*/ +.iconElement { + position: absolute; + top: 30px; + left: 15px; + width: 145px; + height: 136px; + margin: 0 auto; +} + +.detailIcon { + width: 145px; + height: 145px; + margin: 0 auto; +} + +.ratingTableDetail { + position: absolute; + top: 155px; + left: 20px; + width: 250px; + height: 40px; +} + +.ratingIcons { + float: left; +} +.iconStarActive { + display: block; + background-repeat: no-repeat; +} +.iconStarInActive { + display: block; + background-repeat: no-repeat; +} + +.priceElement { + position: absolute; + left: 250px; + top: 35px; + width: 250px; +} +.priceTitle { + display: inline-block; + width: 100px; +} +.priceAmount { + position: relative; + display: inline-block; +} +.installButtons{ + position: relative; + top:20px; + width:150px; + height:30px; + padding:10px; + border:5px; + border-style:solid; +} +.btnText { + text-align:center; +} +.infoWrapper { + left: 15px; + /*width: 900px;*/ +} +.descriptionElement { + position: relative; + top: 80px; +} +.versionElement { + position: relative; + top: 100px; +} +.detailDescription { + position: relative; + top: 3px; + width: 600px; +} +.versionTitle { + position: relative; + display: inline-block; + +} +.versionNumber { + position: relative; + display: inline-block; +} +.imagesElement { + position: relative; + top: 120px; + left: 0; + +} + +.imageElement { + width: 180px; + height: 400px; + float: left; + overflow: hidden; + margin-top: 10px; + margin-left: 5px; + background-repeat:no-repeat; +} + +.textPanel { + position: relative; + width: 405px; + top: 50px; + display: none; +} + +.installText { + text-align: left; +} + +.progressBar { + position: absolute; + top: 40px; + left: 0; + width: 325px; + height: 10px; + border-style: solid; + border-width: 0 0 4px 0; +} + +.appDetail { + height: 200px; +} diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fe38f7eae68e779100813340b6d2a7fdb69317ff GIT binary patch literal 3738 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 + + + + + + +Store + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
MORE + APPS
+ +
+ +
+ +
+
+ +
+
+ + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..d9b175b --- /dev/null +++ b/js/main.js @@ -0,0 +1,399 @@ +/*global Bootstrap, StoreLibrary, PackageRepository, packageRepository, template, Speech, AppModel, ThemeKeyColor, _applicationDetail, _categories, popularAppsModel, popularController */ + +/** + * Store application provides access to [remote package server](../../package_server/index.html) with installable WGT packages. Packages are grouped + * into package categories like *System*, *Utilities* or *Media*. Package server takes following information from WGT + * package `config.xml` file: + * + * * application icon + * * application name + * * application version + * + * Package server provides additional metadata processed by Store application: + * + * * application rating + * * category + * * application description + * * price for application + * * application screenshots + * * flag assigning application into Promoted and/or Popular groups + * + * Store application uses {{#crossLink "PackageRepository"}}{{/crossLink}} class to download, install and uninstall applications. + * + * Package server address and credentials can be configured by updating {{#crossLink "Store/Config:property"}}{{/crossLink}} property. + * Please refer to [Package server documenation](../../package_server/index.html) for more details. + * + * Hover and click on elements in images below to navigate to components of Store application. + * + * + * + * top bar icons + * clock + * bottom panel + * Settings + * Store Library + * Popular applications + * Promoted applications + * + * + * @module StoreApplication + * @main StoreApplication + * @class Store + **/ + +var moved = false; + +/** + * Configuration object holding url and authentication access to remote store server + * @property Config + * @static + **/ +var Config = { + httpPrefix: "http://localhost:80", + username: "intel", + pwd: "TiZ3N456!", + defaultIcon: "css/car/images/default_icon.png" +}; + +/** + * Reference to instance of object holding data about promoted applications + * @property promotedApplicationsModel {Object} + */ +var promotedApplicationsModel; + +/** + * Object handling speech commands to install or uninstall application + * @property speechObj {Object} + */ +var speechObj; + +/** + * Object holding data about apps installed on the device + * @property installedApps {Object} + */ +var installedApps; + +var bootstrap; + +/** + * Method fills Promoted Applications carousel with data and rendering + * @method setupCarousel + * @static + **/ +function setupCarousel() { + "use strict"; + template.compile(promotedApplicationsModel, "templates/carouselDelegate.html", "#carousel_wrap", function() { + $('#carousel_wrap').carouFredSel({ + auto: false, + width: 720, + items: { + visible: 3 + }, + swipe: { + onMouse: true, + onTouch: true + }, + scroll: { + items: 1 + } + }); + + $('.carouselItem').on("touchstart", function (event) { + moved = false; + }); + + $('.carouselItem').on("touchmove", function (event) { + moved = true; + }); + }); +} + +/** + * Function invoked after `touchend` event on the carousel item + * @method triggerTouchEnd + * @param cat {String} Category + * @param app {String} Application + * @static + **/ +function triggerTouchEnd(cat, app) { + "use strict"; + if (moved === false) { + StoreLibrary.setAppDetailAndCategory(cat, app); + } +} + +/** + * Adds http prefix to application icons' urls for apps from the store + * @method enhanceModelUrls + * @static + **/ +function enhanceModelUrls(model) { + "use strict"; + $.each(model, function (itemIndex, item) { + if (item.iconUrl.indexOf(Config.httpPrefix) < 0) { + item.iconUrl = Config.httpPrefix + item.iconUrl; + } + }); +} + +/** + * Looks for application icon file and provides a path to default one if not found + * @method getAppIcon + * @static + **/ +function getAppIcon(appIconPath, callback) { + "use strict"; + try { + tizen.filesystem.resolve(appIconPath, function (iconFile) { + callback(iconFile.fullPath); + }, function (error) { + callback(Config.defaultIcon); + }); + } catch(ex) { + console.log("EXCEPTION when trying to find icon file: " + ex.message); + } +} + +/** + * Applies selected theme to application icons + * @method setThemeImageColor + * @static + **/ +function setThemeImageColor() { + "use strict"; + var imageSource; + $('body').find('img').each(function() { + var self = this; + imageSource = $(this).attr('src'); + + if (typeof(imageSource) !== 'undefined' && $(this.parentElement).hasClass('themeImage') === false && + (imageSource.indexOf(Config.httpPrefix) >= 0 || imageSource.indexOf('base64') >= 0)) { + var img = new Image(); + var ctx = document.createElement('canvas').getContext('2d'); + img.onload = function () { + var w = ctx.canvas.width = img.width; + var h = ctx.canvas.height = img.height; + ctx.fillStyle = ThemeKeyColor; + ctx.fillRect(0, 0, w, h); + ctx.globalCompositeOperation = 'destination-in'; + ctx.drawImage(img, 0, 0); + + $(self).attr('src', ctx.canvas.toDataURL()); + $(self).hide(0, function() { $(self).show();}); + }; + + img.src = imageSource; + } + }); +} + +/** + * Sets up voice recognition listeners for un/installing applications + * @method setupSpeechRecognition + * @static + **/ +function setupSpeechRecognition() { + "use strict"; + console.log("Store setupSpeechRecognition"); + Speech.addVoiceRecognitionListener({ + onapplicationinstall : function() { + console.log("Speech application install invoked"); + if (_applicationDetail.id !== undefined && $('#storeLibrary').library('isVisible') && + (!_applicationDetail.installed || _applicationDetail.installed === false)) { + StoreLibrary.installApp(_applicationDetail.id); + } + }, + onapplicationuninstall : function() { + console.log("Speech application uninstall invoked"); + if (_applicationDetail.id !== undefined && $('#storeLibrary').library('isVisible') && _applicationDetail.installed === true) { + StoreLibrary.uninstallApp(_applicationDetail.id); + } + } + + }); +} + +/** + * Applies Base64 conversion to icon urls in the model + * @method setThemeIconColorBeforeRender + * @static + **/ +function setThemeIconColorBeforeRender(model) { + "use strict"; + if (!!model) { + $.each(model, function (itemIndex, item) { + if (item.iconUrl.indexOf(Config.httpPrefix) >= 0 || item.iconUrl.indexOf('base64') >= 0 || item.iconUrl.indexOf('intelPoc') >= 0) { + var img = new Image(); + var aIcon = item.iconUrl; + var ctx = document.createElement('canvas').getContext('2d'); + img.onload = function () { + var w = ctx.canvas.width = img.width; + var h = ctx.canvas.height = img.height; + ctx.fillStyle = ThemeKeyColor; + ctx.fillRect(0, 0, w, h); + ctx.globalCompositeOperation = 'destination-in'; + ctx.drawImage(img, 0, 0); + item.iconUrl = ctx.canvas.toDataURL(); + }; + + img.src = item.iconUrl; + } + }); + } +} + +/** + * Loads store data and builds the page based on the data + * @method loadUi + * @static + **/ +function loadUi() { + "use strict"; + var self; + packageRepository = new PackageRepository(); + packageRepository.availableApplications(function (appData) { + AppModel = appData; + enhanceModelUrls(AppModel); + setThemeIconColorBeforeRender(AppModel); + + promotedApplicationsModel = packageRepository.getPromotedApplications(); + setTimeout(function() { + setupCarousel(); + + packageRepository.getAppsInfo(function (appsInfo) { + installedApps = appsInfo; + var appsNotInStore = []; + var foundInStore = false; + var appsLength = appsInfo.length; + var appModelLength = AppModel.length; + + var processApplication = function(i) { + for (var j = 0; j < appModelLength; j++) { + if (appsInfo[i].name === AppModel[j].name) { + foundInStore = true; + AppModel[j].installed = true; + + break; + } else if (!AppModel[j].installed) { + AppModel[j].installed = false; + } + } + if (foundInStore === false && + (appsInfo[i].name.toLowerCase() !== "store" && appsInfo[i].name.toLowerCase() !== "homescreen" && appsInfo[i].name.toLowerCase() !== "home screen")) { + var appNotInStore = {}; + appNotInStore.id = appsInfo[i].id; + appNotInStore.name = appsInfo[i].name; + appNotInStore.version = 0; + appNotInStore.silentInstall = false; + /* jshint camelcase: false */ + appNotInStore.category_id = "system"; + /* jshint camelcase: true */ + appNotInStore.price = "0"; + appNotInStore.rating = "0"; + appNotInStore.description = ""; + appNotInStore.isPromoted = false; + appNotInStore.isPopular = false; + appNotInStore.screenshots = []; + appNotInStore.downloadUrl = ""; + getAppIcon(appsInfo[i].iconPath, function(resolvedPath) { + appNotInStore.iconUrl = resolvedPath; + }); + appNotInStore.installed = true; + AppModel.push(appNotInStore); + } + foundInStore = false; + }; + + for (var i = 0; i < appsLength; i++) { + processApplication(i); + } + popularAppsModel = packageRepository.getPopularApplications(); + popularController.addHeader(); + popularController.fillView(popularAppsModel); + }); + + },500); + }, function() { + packageRepository.getAppsInfo(function (appsInfo) { + installedApps = appsInfo; + var appsNotInStore = []; + var appsLength = appsInfo.length; + + var processApplication = function(i) { + if (appsInfo[i].name.toLowerCase() !== "store" && appsInfo[i].name.toLowerCase() !== "homescreen" && appsInfo[i].name.toLowerCase() !== "home screen") { + var appNotInStore = {}; + appNotInStore.id = appsInfo[i].id; + appNotInStore.name = appsInfo[i].name; + appNotInStore.version = 0; + appNotInStore.silentInstall = false; + /* jshint camelcase: false */ + appNotInStore.category_id = "system"; + /* jshint camelcase: true */ + appNotInStore.price = "0"; + appNotInStore.rating = "0"; + appNotInStore.description = ""; + appNotInStore.isPromoted = false; + appNotInStore.isPopular = false; + appNotInStore.screenshots = []; + appNotInStore.downloadUrl = ""; + getAppIcon(appsInfo[i].iconPath, function(resolvedPath) { + appNotInStore.iconUrl = resolvedPath; + }); + appNotInStore.installed = true; + AppModel.push(appNotInStore); + } + }; + + for (var i = 0; i < appsLength; i++) { + processApplication(i); + } + }); + }); + packageRepository.getCategories(function (catData) { + _categories = catData; + }); + +} + +/** + * Initialize plugins and register events for Store app. + * @method init + * @static + **/ +var init = function () { + "use strict"; + bootstrap = new Bootstrap(function (status) { + $("#topBarIcons").topBarIconsPlugin('init', 'store'); + $("#clockElement").ClockPlugin('init', 5); + $("#clockElement").ClockPlugin('startTimer'); + $('#bottomPanel').bottomPanel('init'); + + loadUi(); + if (tizen.speech) { + setupSpeechRecognition(); + } else { + console.log("Store: Speech Recognition not running, voice control will be unavailable"); + } + + bootstrap.themeEngine.addStatusListener(function (eData) { + setThemeImageColor(); + }); + }); +}; + +$(document).ready(init); + +/** + * Opens store library after it's initialization or initialize library if it's not. + * @method openStoreLibrary + * @static + **/ +function openStoreLibrary() { + "use strict"; + if (!StoreLibrary.initialized) { + StoreLibrary.init(); + } else { + StoreLibrary.show(); + } + setThemeIconColorBeforeRender(AppModel); +} \ No newline at end of file diff --git a/js/packagerepository.js b/js/packagerepository.js new file mode 100644 index 0000000..b35846d --- /dev/null +++ b/js/packagerepository.js @@ -0,0 +1,333 @@ +/*global Config, StoreLibrary, _applicationDetail, installedApps */ + +/** + * Provides Javascript wrapper around AJAX-based requests to package server providing categories, lists of applications, + * download (using [tizen.download API](https://developer.tizen.org/dev-guide/2.2.1/org.tizen.web.device.apireference/tizen/download.html)) + * and allows installation or uninstallation of downloaded packages through + * [tizen.package API](https://developer.tizen.org/dev-guide/2.2.1/org.tizen.web.device.apireference/tizen/package.html). + * + * @class PackageRepository + * @module StoreApplication + **/ + +/** + * object holding info about applications available on the server as well as apps installed in the system + * @property AppModel + * @static + **/ +var AppModel = []; + +var PackageRepository = (function() { + "use strict"; + function PackageRepository() { + console.info("Starting up PackageRepository"); + } + + PackageRepository.prototype = function() {}; + + PackageRepository.prototype._storage = "downloads"; + + /** + * Gets only promoted applications from list of available apps + * @method getPromotedApplications + * @param callback {Function(results)} Callback function providing array of promoted applications. + **/ + PackageRepository.prototype.getPromotedApplications = function (callback) { + if (AppModel.length === 0) { + this.availableApplications(function () { + var result = AppModel.filter(function (app) { + return app.isPromoted === true; + }); + if (callback) { + callback(result); + } else { + return result; + } + }); + } else { + var result = AppModel.filter(function (app) { + return app.isPromoted === true; + }); + if (callback) { + callback(result); + } else { + return result; + } + } + }; + + /** + * Gets only popular applications from list of available apps + * @method getPopularApplications + * @param callback {Function(results)} Callback function providing array of popular applications. + **/ + PackageRepository.prototype.getPopularApplications = function (callback) { + var result = AppModel.filter(function (app) { + return app.isPopular === true; + }); + if (callback) { + callback(result); + } else { + return result; + } + }; + + /** + * Gets list of available categories from package server. + * @method getCategories + * @param callback {Function(results)} Callback function providing array of categories. + * @param errorCallback {Function(error)} Callback function providing error in case if any issue was detected. + **/ + PackageRepository.prototype.getCategories = function (callback, errorCallback) { + $.ajax({ + type: 'GET', + url: Config.httpPrefix + '/packages/categories', + dataType: 'json', + async: true, + username: Config.username, + password: Config.pwd, + data:'{}' + }).done(function(resCategories) { + console.log('categories: ' + JSON.stringify(resCategories)); + if (callback) { + callback(resCategories); + } else { + return resCategories; + } + }).fail(function (jqXHR, textStatus) { + console.log('getCategories fail: ' + textStatus); + if (errorCallback) { + errorCallback(); + } + }); + + }; + + /** + * Gets only applications beloging to specified category from list of available apps + * @method getCategoryApplications + * @param catId {String} Category identifier. + * @param callback {Function(results)} Callback function providing array of popular applications. + **/ + PackageRepository.prototype.getCategoryApplications = function (catId, callback) { + var result = AppModel.filter(function (app) { + /* jshint camelcase: false */ + var res = app.category_id === catId; + /* jshint camelcase: true */ + return res; + }); + if (callback) { + callback(result); + } else { + return result; + } + }; + + /** + * Gets all application data for specified application. + * @method getApplicationDetail + * @param appId {String} Application identifier. + * @param callback {Function(result)} Callback function providing array of popular applications. + **/ + PackageRepository.prototype.getApplicationDetail = function (appId, callback) { + var result = AppModel.filter(function (app) { + return app.id === appId; + }); + if (callback) { + callback(result); + } else { + return result; + } + }; + + /** + * Gets list of available applications from package server. + * @method availableApplications + * @param callback {Function(results)} Callback function providing array of applications. + * @param errorCallback {Function(error)} Callback function providing error in case if any issue was detected. + **/ + PackageRepository.prototype.availableApplications = function (callback, errorCallback) { + $.ajax({ + type: 'GET', + url: Config.httpPrefix + '/packages/available', + dataType: 'json', + async: true, + username: Config.username, + password: Config.pwd, + data:'{}' + }).done(function(resp) { + if (callback) { + callback(resp); + } + }).fail(function (jqXHR, textStatus) { + console.log('availableApplications fail: ' + textStatus); + if (errorCallback) { + errorCallback(); + } + }); + }; + + + /** + * Starts package download identified by applidation identifier via [tizen.download API]() + * @method downloadApplication + * @param appId {String} Application Id + * @param callback {Function(error, appId, packageUri)} Callback function providing information about status about download. + **/ + PackageRepository.prototype.downloadApplication = function (appId, callback) { + var listener = { + onprogress: function(id, receivedSize, totalSize) { + console.log('Received with id: ' + id + ', ' + receivedSize + '/' + totalSize); + }, + onpaused: function(id) { + console.log('Paused with id: ' + id); + }, + oncanceled: function(id) { + console.log('Canceled with id: ' + id); + }, + oncompleted: function(id, fullPath) { + console.log('Completed with id: ' + id + ', full path: ' + fullPath); + tizen.filesystem.resolve(fullPath, function (file) { + callback(null, id, file.toURI()); + }); + }, + onfailed: function(id, error) { + console.log('Failed with id: ' + id + ', error name: ' + error.name); + } + }; + + // Starts downloading of the file from the Web with the corresponding callbacks. + var downloadRequest = new tizen.DownloadRequest("http://"+Config.username+":"+Config.pwd+"@localhost:80" + _applicationDetail.downloadUrl, "downloads", appId.split("/").pop() + ".wgt"); + + var downloadId = tizen.download.start(downloadRequest, listener); + }; + + /** + * Provides list of installed application using [tizen application API](). + * @method getAppsInfo + * @param callback {Function(results)} Callback function providing array of installed applications. + **/ + PackageRepository.prototype.getAppsInfo = function (callback) { + try { + tizen.application.getAppsInfo(function (installedAppData) { + callback(installedAppData); + }, function(err) { + console.log('Failed to get installed apps info.'); + }); + } catch (exc) { + console.error(exc.message); + } + }; + + /** + * Method performs installation of specified application ID using [tizen package API]() by following process: + * + * * download package + * * install package + * * cleanup of downloaded package + * + * @method install + * @param appId application Id + * @param callback {Function(error)} Callback function invoked after installation is finished or error occurs. + **/ + PackageRepository.prototype.install = function (appId, callback) { + var installationFile; + var self = this; + callback = callback || function() {}; + + var cleanup = function(err) { + console.log("Removing installation file " + installationFile); + tizen.filesystem.resolve(self._storage, function(directory) { + directory.deleteFile(installationFile, + function() { + self.getAppsInfo(function (appsInfo) { + installedApps = appsInfo; + callback(err); + }); + }, + function(error) { callback(err || error); } + ); + }); + }; + + var onInstallation = { + onprogress: function(packageId, percentage) { + console.log("On installation(" + packageId + ") : progress(" + percentage + ")"); + StoreLibrary.displayInstallProgress(true, percentage); + }, + oncomplete: function(packageId) { + console.log("Installation(" + packageId + ") Complete"); + cleanup(); + this.getAppsInfo(function (appsInfo) { + installedApps = appsInfo; + callback(); + }); + } + }; + + var onError = function (err) { + console.error("Error occurred on installation : " + err.name); + callback(err); + }; + + this.downloadApplication(appId, function(error, fileName, fullPath) { + if (error) { + this.cleanup(error); + } else { + installationFile = fullPath; + tizen.package.install(fullPath, onInstallation, onError); + } + }); + }; + + /** + * Method performs uninstallation of specified application ID using [tizen package API]() + * + * @method uninstall + * @param appId application Id + * @param callback {Function(error)} Callback function invoked after installation is finished or error occurs. + **/ + PackageRepository.prototype.uninstall = function (appId, callback) { + var onInstallation = { + onprogress: function(packageId, percentage) { + console.log("On uninstallation(" + packageId + ") : progress(" + percentage + ")"); + StoreLibrary.displayInstallProgress(false, percentage); + }, + oncomplete: function(packageId) { + console.log("Uninstallation(" + packageId + ") Complete"); + if (callback) { + callback(true); + } + } + }; + + var onError = function (err) { + console.log("Error occurred on uninstallation : " + err.name); + if (callback) { + callback(false); + } + }; + var uninstPackageName = this.getPackageId(_applicationDetail.name); + console.log("Trying to uninstall "+ _applicationDetail.name); + if (uninstPackageName === undefined) { + console.log("Package name not available."); + } else { + tizen.package.uninstall(uninstPackageName, onInstallation, onError); + } + }; + + /** + * Function returns package id for specified application name. + * @method getPackageId + * @param appName {String} Application name + **/ + PackageRepository.prototype.getPackageId = function (appName) { + for (var i in installedApps) { + if (installedApps[i].name === appName) { + return installedApps[i].packageId; + } + } + }; + + return PackageRepository; +}()); diff --git a/js/popularController.js b/js/popularController.js new file mode 100644 index 0000000..0179d89 --- /dev/null +++ b/js/popularController.js @@ -0,0 +1,53 @@ +/*global template, setThemeImageColor*/ + +/** + * Provides controller for popular applications list. + * @class popularController + * @module StoreApplication + * @static + **/ + +/** + * Hols popular apps model. + * @property popularAppsModel + * @type object + * @default null + * @static + **/ +var popularAppsModel = null; +/** + * Holds popular apps model length. + * @property popularAppsModelLenght + * @type int + * @default null + * @static + **/ +var popularAppsModelLenght; +var popularController = { + /** + * Adds header bar to store app. + * @method addHeader + **/ + addHeader: function () { + "use strict"; + $('#appDetailWraper').append('
MOST POPULAR
'); + $('#appDetailWraper').append('
'); + }, + /** + * Creates store view based on model parameter. + * @method fillView + * @param model {array} Contains array of objects which holds popular apps informations. + **/ + fillView: function (model) { + "use strict"; + popularAppsModelLenght = model.length; + console.log("filling popular view with " + popularAppsModelLenght + " items"); + var i; + for (i = 0; i < popularAppsModelLenght; i++) { + model[i].index = i; + } + template.compile(model, "templates/popularAppsContainer.html", "#popularApps", function () { + setThemeImageColor(); + }); + } + }; \ No newline at end of file diff --git a/js/store_library.js b/js/store_library.js new file mode 100644 index 0000000..4150953 --- /dev/null +++ b/js/store_library.js @@ -0,0 +1,487 @@ +/*global PackageRepository, setThemeImageColor, GRID_TAB, LIST_TAB, Config, AppModel, popularAppsModel, popularController */ + +/** + * Provides implementation of {{#crossLink "Library"}}{{/crossLink}} object for Store application. Applications are displayed in + * following hierarchy: + * + * * List of application categories + * * List of applications for one category + * * Application detail + * + * + * @class StoreLibrary + * @module StoreApplication + * @static + **/ + +/** + * Holds array of apps categories. + * @property _categories + * @type array + * @default empty + * @static + **/ +var _categories = []; + +/** + * Holds object of selected apps category. + * @property _selectedCategory + * @type object + * @default empty + * @static + **/ +var _selectedCategory = {}; + +/** + * Hols array of apps in selected category. + * @property _categoryApplications + * @type array + * @default empty + * @static + **/ +var _categoryApplications = []; + +/** + * Hols object of selected app detailed informations. + * @property _selectedCategory + * @type object + * @default empty + * @static + **/ +var _applicationDetail = {}; + +/** + * Hols object of instalation timer. + * @property _progress + * @type timer + * @default null + * @static + **/ +var _progress; + +/** + * Hols object of uninstalation timer. + * @property _unProgress + * @type timer + * @default null + * @static + **/ +var _unProgress; + +/** + * Hols object of package repository. + * @property packageRepository + * @type PackageRepository + * @default null + * @static + **/ +var packageRepository; + +var StoreLibrary = { + /** + * Indicates if store library is initialized. + * @property initialized + * @type bool + * @default false + **/ + initialized: false, + /** + * Provides initialization of store library. + * @method init + * @param showApps {bool} If true shows apps in store library ordered by category ID. + **/ + init: function (showApps) { + "use strict"; + $('#storeLibrary').library("setSectionTitle", "APP STORE"); + $('#storeLibrary').library("init"); + + if (_categories.length > 0 ) { + StoreLibrary.showStoreLibrary(showApps); + } else { + if (typeof PackageRepository !== 'undefined') { + packageRepository = new PackageRepository(); + packageRepository.getCategories(function (jsonObject) { + if ((typeof jsonObject).toLowerCase() === "string") { + try { + _categories = JSON.parse(jsonObject); + } catch (error) { + console.log("Unable to parse categories: " + error.message); + } + } else { + _categories = jsonObject; + } + StoreLibrary.showStoreLibrary(); + }, function(error) { + _categories.length = 0; + _categories.push({"id": "system", "description": "", "name": "System", "url": "/packageRepository/category?id=system"}); + StoreLibrary.showStoreLibrary(); + }); + } else { + console.warn("packageRepository is not available."); + } + } + }, + + /** + * Shows library of apps in Store application. + * @method show + **/ + show: function () { + "use strict"; + $('#storeLibrary').library("showPage"); + }, + + /** + * Builds and displays the Store library view + * @method showStoreLibrary + * @param showApps {bool} indicator + **/ + showStoreLibrary: function (showApps) { + "use strict"; + var i = 0; + for (i = 0; i < _categories.length; ++i) { + if (i === 0) { + _categories[i].selected = true; + _selectedCategory = _categories[i]; + if (showApps === true || showApps === undefined) { + StoreLibrary.showAppsByCategoryId(_selectedCategory.id); + } + } + _categories[i].text = _categories[i].name; + _categories[i].action = "StoreLibrary.showAppsByCategoryId('" + _categories[i].id + "');"; + } + + var tabMenuModel = { + Tabs: _categories + }; + + $('#storeLibrary').library("tabMenuTemplateCompile", tabMenuModel, function() { + setThemeImageColor(); + }); + + $('#storeLibrary').bind('eventClick_GridViewBtn', function () { + $('#storeLibrary').library('closeSubpanel'); + StoreLibrary.showAppsByCategoryId(_categories[$('#storeLibrary').library('getSelectetTopTabIndex')].id); + }); + + $('#storeLibrary').bind('eventClick_ListViewBtn', function () { + $('#storeLibrary').library('closeSubpanel'); + StoreLibrary.showAppsByCategoryId(_categories[$('#storeLibrary').library('getSelectetTopTabIndex')].id); + }); + + $('#storeLibrary').bind('eventClick_SearchViewBtn', function () { + + }); + + $('#storeLibrary').bind('eventClick_menuItemBtn', function (e, data) { + $('#storeLibrary').library('closeSubpanel'); + StoreLibrary.showAppsByCategoryId(_categories[$('#storeLibrary').library('getSelectetTopTabIndex')].id); + }); + + $('#storeLibrary').bind('eventClick_closeSubpanel', function () { + StoreLibrary.showAppsByCategoryId(_categories[$('#storeLibrary').library('getSelectetTopTabIndex')].id); + }); + + var heightWithoutScrollbar = $('#libraryTabsID').scrollHeight; + $('#libraryTopPanel').height($('#libraryTopPanel').height() - heightWithoutScrollbar); + StoreLibrary.initialized = true; + StoreLibrary.show(); + }, + + /** + * Sets category and detail of application. + * @method setAppDetailAndCategory + * @param categoryID {int} Contains ID of category to set. + * @param applicationID {int} Contains ID of app to show details. + **/ + setAppDetailAndCategory: function (categoryID, applicationID) { + "use strict"; + var tabID = 0, i = 0; + for (i = 0; i < _categories.length; i++) { + if (_categories[i].id === categoryID) { + tabID = i; + break; + } + } + $('#storeLibrary').library('setTopTabIndex', tabID); + if (!StoreLibrary.initialized) { + StoreLibrary.init(false); + } + StoreLibrary.openAppDetail(applicationID); + setThemeImageColor(); + StoreLibrary.show(); + }, + + /** + * Shows apps sorted by specific categry. + * @method showAppsByCategoryId + * @param categoryID {int} Contains ID of category. + **/ + showAppsByCategoryId: function (categoryID) { + "use strict"; + packageRepository.getCategoryApplications(categoryID, function (jsonObject) { + if ((typeof jsonObject).toLowerCase() === "string") { + try { + _categoryApplications = JSON.parse(jsonObject); + } catch (error) { + console.log("Unable to parse category applications: " + error.message); + } + } else { + _categoryApplications = jsonObject; + } + + switch ($('#storeLibrary').library('getSelectetLeftTabIndex')) { + case GRID_TAB: + StoreLibrary.renderAppsGridView(_categoryApplications); + break; + case LIST_TAB: + StoreLibrary.renderAppsListView(_categoryApplications); + break; + default: + break; + } + }); + }, + + /** + * Shows apps in grid view. + * @method renderAppsGridView + * @param model {object} Contains model of applications. + **/ + renderAppsGridView: function (model) { + "use strict"; + $('#storeLibrary').library("setContentDelegate", "templates/storeLibraryAppsDelegate.html"); + $('#storeLibrary').library("contentTemplateCompile", model, "storeLibraryContentGrid", function() { + setThemeImageColor(); + }); + }, + + /** + * Shows apps in list view. + * @method renderAppsGridView + * @param model {object} Contains model of applications. + **/ + renderAppsListView: function (model) { + "use strict"; + $('#storeLibrary').library("setContentDelegate", "templates/storeLibraryAppsDelegate.html"); + $('#storeLibrary').library("contentTemplateCompile", model, "storeLibraryContentList", function() { + setThemeImageColor(); + }); + }, + + /** + * If model of an app dosen't contain screenshot, function set default one to model. + * @method enhanceModelsUrls + * @param appDetail {array} Contains array of objects which holds promotedapps informations. + * @return appDetail {array} Returns enhanced model of promoted apps. + **/ + enhanceModelUrls: function (appDetail) { + "use strict"; + appDetail.imageObjects = []; + if (!!appDetail.screenshots) { + $.each(appDetail.screenshots, function (imageIndex, urlobject) { + appDetail.imageObjects.push({ + url: Config.httpPrefix + urlobject + }); + }); + } + return appDetail; + }, + + /** + * Opens app detail view. + * @method openAppDetail + * @param appID {string} Contains ID of app to show detail of it. + **/ + openAppDetail: function (appID) { + "use strict"; + packageRepository.getApplicationDetail(appID, function (jsonObject) { + // _applicationDetail = jsonObject; + _applicationDetail = StoreLibrary.enhanceModelUrls(jsonObject[0]); + StoreLibrary.renderAppDetailView(_applicationDetail); + }); + }, + + /** + * Creates detail view of app. + * @method renderAppDetailView + * @param app {object} Contains object with app data. + **/ + renderAppDetailView: function (app) { + "use strict"; + var subpanelModel = { + /* jshint camelcase: false */ + textTitle: StoreLibrary.getCategoryTitleById(app.category_id), + /* jshint camelcase: true */ + textSubtitle: app.name || "-" + }; + $('#storeLibrary').library("subpanelContentTemplateCompile", subpanelModel, function () { + $("#libraryTopSubPanelTitle").boxCaptionPlugin('initSmall', subpanelModel.textTitle); + }); + $('#storeLibrary').library('showSubpanel'); + $('#storeLibrary').library("setContentDelegate", "templates/detailApplicationContainer.html"); + $('#storeLibrary').library("contentTemplateCompile", app, "", function () { + setThemeImageColor(); + + var height = $('#storeLibrary').height(); + if ($("#libraryTopPanel").is(":visible")) { + height = height - $("#libraryTopPanel").outerHeight(); + } + if ($("#libraryTopSubPanel").is(":visible")) { + height = height - $("#libraryTopSubPanel").outerHeight(); + } + height = height - $('.appDetail').outerHeight(); + $('.infoWrapper').height(height); + }); + }, + + /** + * Creates search view in store. + * @method renderSearchView + **/ + renderSearchView: function () { + "use strict"; + $('#storeLibrary').library("clearContent"); + }, + + /** + * Returns title of a category based on category ID. + * @method getCategoryTitleById + * @param categoryID {string} Contains object with app data. + * @return {string} Title of category. + **/ + getCategoryTitleById: function (categoryID) { + "use strict"; + var i = 0; + for (i = 0; i < _categories.length; i++) { + if (_categories[i].id === categoryID) { + return _categories[i].name; + } + } + return "-"; + }, + + /** + * Install a new app based on app id. + * @method installApp + * @param id {string} Contains app id. + **/ + installApp: function (id) { + "use strict"; + console.log('INSTALL APP... ' + id); + + StoreLibrary.displayInstallProgress(true, 0); + packageRepository.install(id, function (instError) { + packageRepository.getApplicationDetail(id, function (appDetail) { + if (instError) { + appDetail[0].installed = false; + StoreLibrary.installResult(instError, true, appDetail[0]); + } else { + appDetail[0].installed = true; + StoreLibrary.installResult(null, true, appDetail[0]); + } + }); + }); + }, + + /** + * Uninstall a new app based on app id. + * @method uninstallApp + * @param id {string} Contains app id. + **/ + uninstallApp: function (id) { + "use strict"; + console.log('UNINSTALL APP... ' + id); + StoreLibrary.displayInstallProgress(false, 0); + packageRepository.uninstall(id, function (jsonObject) { + var instError = jsonObject.error; + if (!!instError) { + packageRepository.getApplicationDetail(id, function (appDetail) { + appDetail[0].installed = true; + StoreLibrary.installResult(instError, false, appDetail[0]); + }); + } else { + packageRepository.getApplicationDetail(id, function (appDetail) { + appDetail[0].installed = false; + StoreLibrary.installResult(instError, false, appDetail[0]); + }); + } + }); + }, + + /** + * Called as callback after installing or uninstalling application. + * @method installResult + * @param error {bool} Error indicator. + * @param install {bool} Indicates if app was installed (true) or uninstalled (false). + * @param app {object} Object of app which was installed/uninstalled. + **/ + installResult: function (error, install, app) { + "use strict"; + var instLabel1 = 'INSTALLATION'; + var instLabel2 = 'INSTALLED'; + if (install === false) { + instLabel1 = 'UNINSTALLATION'; + instLabel2 = 'UNINSTALLED'; + } + if (!!error) { + $('#installText').html(instLabel1 + ' FAILED'); + } else { + $('#installText').html(instLabel2 + ' SUCCESSFULLY'); + $('#installBar').css({ + width: '100%' + }); + } + setTimeout(function () { + /* jshint camelcase: false */ + if (app.category_id === "system") { + /* jshint camelcase: true */ + var appToRemoveIndex = AppModel.indexOf(app); + if (appToRemoveIndex >= 0) { + AppModel.splice(appToRemoveIndex, 1); + } + /* jshint camelcase: false */ + StoreLibrary.showAppsByCategoryId(app.category_id); + /* jshint camelcase: true */ + $('#storeLibrary').library('closeSubpanel'); + } else { + StoreLibrary.renderAppDetailView(app); + StoreLibrary.refreshPopularApps(app); + } + }, 3000); + }, + + /** + * Displays progress of installation or uninstallation. + * @method displayInstallProgress + * @param install {bool} Indicates if app was installed (true) or uninstalled (false). + **/ + displayInstallProgress: function (install, percent) { + "use strict"; + if (install === false) { + $('#installText').html('UNINSTALLING...'); + } + $('.textPanel').css('display', 'inline-block'); + $('.installButtons').css('display', 'none'); + $('#installBar').css({ + width: percent + '%' + }); + + }, + + /** + * Updates the model object and rerenders popular apps view + * @method refreshPopularApps + * @param app updated application object + **/ + refreshPopularApps: function (app) { + "use strict"; + for (var i in popularAppsModel) { + if (popularAppsModel[i].id === app.id) { + popularAppsModel[i].installed = app.installed; + popularController.fillView(popularAppsModel); + break; + } + } + } + }; \ No newline at end of file diff --git a/packaging/html5-ui-appmanager.changes b/packaging/html5-ui-appmanager.changes new file mode 100644 index 0000000..81132a1 --- /dev/null +++ b/packaging/html5-ui-appmanager.changes @@ -0,0 +1,4 @@ +* Thu Mar 06 2014 brianjjones c8620ac +- Initial commit of the Appmanager app + + diff --git a/packaging/html5-ui-appmanager.spec b/packaging/html5-ui-appmanager.spec new file mode 100644 index 0000000..d23ea34 --- /dev/null +++ b/packaging/html5-ui-appmanager.spec @@ -0,0 +1,36 @@ +Name: html5_UI_Appmanager +Summary: A proof of concept pure html5 UI +Version: 0.0.1 +Release: 1 +Group: Applications/System +License: Apache 2.0 +URL: http://www.tizen.org +Source0: %{name}-%{version}.tar.bz2 +BuildRequires: zip +BuildRequires: html5_UI_Common +Requires: wrt-installer +Requires: wrt-plugins-ivi + +%description +A proof of concept pure html5 UI + +%prep +%setup -q -n %{name}-%{version} + +%build + +make wgtPkg + +%install +rm -rf %{buildroot} +%make_install + +%post + wrt-installer -i /opt/usr/apps/.preinstallWidgets/html5UIAppmanager.wgt; + +%postun + wrt-installer -un html5POC03.Appmanager + +%files +%defattr(-,root,root,-) +/opt/usr/apps/.preinstallWidgets/html5UIAppmanager.wgt diff --git a/templates/carouselDelegate.html b/templates/carouselDelegate.html new file mode 100644 index 0000000..5e7caf9 --- /dev/null +++ b/templates/carouselDelegate.html @@ -0,0 +1,12 @@ +
  • + +
    + +
    +
    {{:name}} +
    +
    +
    +
  • + diff --git a/templates/detailApplicationContainer.html b/templates/detailApplicationContainer.html new file mode 100644 index 0000000..9ec59b4 --- /dev/null +++ b/templates/detailApplicationContainer.html @@ -0,0 +1,68 @@ +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    PRICE:
    +
    {{if + price ==0 }}FREE{{else}}{{:price}} EUR{{/if}}
    +
    +
    INSTALLING...
    +
    +
    + {{if category_id != "user_theme" && category_id != "system" && name.toLowerCase() != "store" && name.toLowerCase() != "home screen"}} +
    + {{if installed !=true}} + +
    +
    INSTALL
    +
    + + {{/if}} + {{if installed ==true}} +
    +
    UNINSTALL
    +
    + {{/if}} +
    + {{/if}} +
    + +
    +
    +
    +
    DESCRIPTION:
    +
    {{:description}}
    +
    +
    +
    VERSION:
    +
    {{:version}}
    +
    + +
    +
    SCREENSHOTS:
    + + {{foreach imageObjects}} +
    +
    + {{/foreach}} + +
    +
    + \ No newline at end of file diff --git a/templates/popularAppsContainer.html b/templates/popularAppsContainer.html new file mode 100644 index 0000000..b3c0c9b --- /dev/null +++ b/templates/popularAppsContainer.html @@ -0,0 +1,33 @@ +
    +
    + +
    + +
    +
    + {{:name}}
    +
    {{if + installed==true}}Installed{{else if price ==0 + }}Free{{else}}{{:price}} Eur{{/if}}
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/templates/storeLibraryAppsDelegate.html b/templates/storeLibraryAppsDelegate.html new file mode 100644 index 0000000..9357063 --- /dev/null +++ b/templates/storeLibraryAppsDelegate.html @@ -0,0 +1,24 @@ +
    +
    + +
    +
    +
    {{:name}}
    +
    {{if + installed==true}}Installed{{else if price ==0 + }}Free{{else}}{{:price}} Eur{{/if}}
    +
    +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file -- 2.7.4