Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

Stack With Friends Demo

 import QtQuick 2.0
 import Felgo 3.0
 import"../common"
 import "dialogs"

 SceneBase {
   id: levelScene

   signal backClicked
   signal levelSelected(variant levelData, bool isAuthorLevel, bool isUserLevel, bool isDownloaded, bool isPublished, bool isLoggedInPlayer)
   signal newLevelClicked
   signal clearSelectedItems
   // is called when the fb connection dialog was shown due to no friends
   signal showProfileView
   signal showHighscoreForLevel(string leaderboard)
   signal showInfoClicked(variant levelData)
   signal unpublishLevelClicked(variant levelData)
   // is emitted from LevelItem if the share level button is clicked
   signal shareLevelClicked(variant levelData)
   signal rateLevelClicked(variant levelData)
   signal downloadLevelClicked(variant levelData)

   // can have the following states: "myLevels", "myDownloadedLevels", "communityLevels", "friendLevels"
   state: "myLevels"

   // either is default "", or "noFriendLevelsAndNotConnectedFb", "noLevelPublished"
   property string dialogState
   property variant unpublishLevelData
   Connections {
     target: nativeUtils
     onMessageBoxFinished: {

       if(accepted) {
         if(dialogState === "noFriendLevelsAndNotConnectedFb") {
           // open profile view; or directly call fb-connection here?
           showProfileView()

         } else if(dialogState === "noLevelPublished") {
           // go to the my levels tab to create a new level
           levelScene.state = "myLevels"
         } else if(dialogState === "unpublishConfirmation") {
           levelEditor.unpublishLevel(unpublishLevelData)
           // no need to reset it here - is newly set the next time unpublishLevelClicked() is called anyway
           //unpublishLevelData = undefined
         }
       }
       // reset the dialogState, no matter if accepted or not
       dialogState = ""
     }

   }

   MultiResolutionImage {
     source: "../../assets/img/menubg.png"
     anchors.centerIn: parent
   }

   MultiResolutionImage {
     id: header
     source: "../../assets/img/levelstore-top.png"
     anchors.top: parent.gameWindowAnchorItem.top
     anchors.horizontalCenter: parent.horizontalCenter
     z: 1

     Item {
       width: 39
       height: 39
       y: -1
       x: 5
       MultiResolutionImage {
         source: "../../assets/img/back-button.png"
         anchors.centerIn: parent
       }
       MouseArea {
         anchors.fill: parent
         onClicked: levelScene.backClicked()
       }
     }

     Row {
       id: headerRow

       z: 1
       spacing: 20
       x: 64

       MenuButton {
         text: "My Levels"
         active: levelScene.state === "myLevels" || levelScene.state === "myDownloadedLevels"
         onClicked: {
           flurry.logEvent("LevelSelection.MyLevels")
           levelScene.state = levelScene.previousMyLevelState
         }
       }

       MenuButton {
         text: "Friend Levels"
         active: levelScene.state === "friendLevels"
         onClicked: {
           flurry.logEvent("LevelSelection.FriendLevels")
           levelScene.state = "friendLevels"
         }
       }

       MenuButton {
         text: "Community"
         active: levelScene.state === "communityLevels"
         onClicked: {
           flurry.logEvent("LevelSelection.CommunityLevels")
           levelScene.state = "communityLevels"
         }
       }

       MenuButton {
         text: "Credits: " + levelStore.playerCredits
         onClicked: {
           buyCreditDialog.opacity = 1
         }
         onPressAndHold: {

           // don't add this functionality in publish builds, just during testing
           if(system.publishBuild)
             return

           // just for testing during development to reset the playerCredits
           levelStore.resetCurrency()
         }
       }
     }// headerRow
   }// header

   MultiResolutionImage {
     id: more
     source: "../../assets/img/levelstore-bot.png"
     anchors.bottom: parent.gameWindowAnchorItem.bottom
     anchors.horizontalCenter: parent.horizontalCenter
     z: 1

     MultiResolutionImage {
       source: "../../assets/img/nextprev.png"
       visible: ((levelScene.state === "friendLevels" && levelEditor.userOrFriendsLevelsPageMetaData.page > 1) ||
                (levelScene.state === "communityLevels" && levelEditor.communityLevelsPageMetaData.page > 1)) &&
                // avoid to show while the level items are created
                !currentLevelSelection.isLoading
       x: 7
       MouseArea {
         anchors.fill: parent
         onClicked: currentLevelSelection.prevPage()
       }
     }

     MultiResolutionImage {
       source: "../../assets/img/nextprev.png"
       visible: (levelScene.state === "friendLevels" || levelScene.state === "communityLevels") &&
                levelEditor.userGeneratedLevelsPageMetaData !== undefined && levelEditor.userGeneratedLevelsPageMetaData.page < levelEditor.userGeneratedLevelsPageMetaData.pageCount &&
                // avoid to show while the level items are created
                !currentLevelSelection.isLoading
       mirror: true
       anchors.right: parent.right
       anchors.rightMargin: 13

       MouseArea {
         anchors.fill: parent
         onClicked: currentLevelSelection.nextPage()
       }
     }

     Row {
       id: moreSubRow
       spacing: 25
       y: 1
       anchors.horizontalCenter: parent.horizontalCenter
       visible: levelScene.state === "friendLevels" || levelScene.state === "communityLevels"

       MenuButton {
         text: "All Time"
         active: levelScene.timeLimit === 0
         onClicked: {
           flurry.logEvent("LevelSelection.AllTime")
           levelScene.timeLimit = 0
         }
       }
       MenuButton {
         text: "This Week"
         active: levelScene.timeLimit === 24*7
         onClicked: {
           flurry.logEvent("LevelSelection.ThisWeek")
           levelScene.timeLimit = 24*7
         }
       }
       MenuButton {
         text: "Today"
         active: levelScene.timeLimit === 24
         onClicked: {
           flurry.logEvent("LevelSelection.Today")
           levelScene.timeLimit = 24
         }
       }
       MenuButton {
         text: levelScene.orderString()
         onClicked: {
           orderLevelsDialog.opacity = 1
         }
       }
     } // moreSubRow

     Row {
       id: moreSubRowMyLevels
       spacing: 25
       y: 1
       anchors.horizontalCenter: parent.horizontalCenter
       visible: levelScene.state === "myLevels" || levelScene.state === "myDownloadedLevels"

       Item {
         width: 39
         height: 39
         y: -1
         visible: levelScene.state === "myLevels"
         MultiResolutionImage {
           source: "../../assets/img/new-level-button.png"
           anchors.centerIn: parent
         }
         MouseArea {
           anchors.fill: parent
           onClicked: newLevelClicked()
         }
       }

       MenuButton {
         text: "Created Levels"
         active: levelScene.state === "myLevels"
         onClicked: {
           levelScene.state = "myLevels"
           previousMyLevelState = levelScene.state
         }
       }
       MenuButton {
         text: "Downloaded Levels"
         active: levelScene.state === "myDownloadedLevels"
         onClicked: {
           levelScene.state = "myDownloadedLevels"
           previousMyLevelState = levelScene.state
         }
         onPressAndHold: {
           // don't add this functionality in publish builds, just during testing
           if(system.publishBuild)
             return

           // this is just during testing, to test the behavior of no downloaded(=bought) levels
           console.debug("clearing all bought levels...")
           levelStore.clearAllBoughtLevels()
         }
       }
     } // moreSubRowMyLevels
   } // more

   // is set in onStateChanged
   property variant currentLevelSelection

   LevelSelection {
     id: myLevelSelection

     visible: levelScene.state === "myLevels"
     levelMetaDataArray: levelEditor.authorGeneratedLevels
   }

   LevelSelection {
     id: downloadedLevelSelection

     visible: levelScene.state === "myDownloadedLevels"
     levelMetaDataArray: levelEditor.downloadedLevels
   }

   LevelSelection {
     id: userOrFriendLevelSelection

     visible: levelScene.state === "friendLevels"
     levelMetaDataArray: levelEditor.userOrFriendsLevels
     pageCount: levelEditor.userOrFriendsLevelsPageMetaData.pageCount

     onLevelMetaDataArrayChanged: {

       // to avoid calling this function at app start (the default state is myLevels)
       if(levelScene.state !== "friendLevels") {
         return
       }

       //
       var friendLevels = new Array
       var myLevels = new Array
       for(var i=0; levelMetaDataArray && i<levelMetaDataArray.length; i++) {
         var level = levelMetaDataArray[i]
         if(level.user.id === gameNetwork.user.userId) {
           myLevels.push(level)
         } else {
           friendLevels.push(level)
         }
       }

       console.debug("LevelScene: onLevelMetaDataArrayChanged: myLevels:", JSON.stringify(myLevels), ", friendLevels:", JSON.stringify(friendLevels))

       if(myLevels.length === 0) {
         dialogState = "noLevelPublished"

         // show this every time, so the user publishes at least one level!
         nativeUtils.displayMessageBox("You do not have published a level yet", "Would you like to create and publish and create a level now?\n\nBy publishing a level you get credits and can then download new community levels.", 2)
         return
       }

       // if the user connected with fb already, no need to inform him about the friend levels
       // if on not fb-supported platforms, also skip the dialog below because he cannot connect!
       if(gameNetwork.facebookConnectionSuccessful || system.desktopPlatform || system.isPlatform(System.BlackBerry) )
         return

       if(friendLevels.length === 0) {
         dialogState = "noFriendLevelsAndNotConnectedFb"

         nativeUtils.displayMessageBox("Connect with Facebook to see Friend Levels", "Would you like to connect with Facebook to see the levels of your friends?\n\n", 2)
       }

     }//onLevelMetaDataArrayChanged

   }

   LevelSelection {
     id: communityLevelSelection

     visible: levelScene.state === "communityLevels"
     levelMetaDataArray: levelEditor.communityLevels
     pageCount: levelEditor.communityLevelsPageMetaData.pageCount
   }

   Connections {
     target: levelStore
     onInsufficientFundsError: {
       flurry.logEvent("Level.InsufficientFunds")
       buyCreditDialog.opacity = 1
     }
     onLevelBoughtSuccessfully: {
       flurry.logEvent("Level.BoughtSucc")
       console.debug("level bought:", JSON.stringify(levelData))
     }
     onLevelDownloadedSuccessfully: {
       flurry.logEvent("Level.Downloaded")
       console.debug("level downloaded:", JSON.stringify(levelData))
     }
   }

   RatingDialog {
     id: ratingDialog
     z: 100
     opacity: 0

     property int levelId

     onLevelRated: {
       flurry.logEvent("Level.Rated",ratingDialog.levelId,rateValue)
       // levelId is required
       levelEditor.rateLevel( {levelId: ratingDialog.levelId, quality: rateValue })
       // to reload the server levels, maybe call another load here; but we don't know what was the last request (friend or all levels, which ordering, filtering etc.)
       // refresh level list after rating so it is visible
       reloadLevels()
     }
   }

   InfoDialog {
     id: infoDialog
     opacity: 0
     z: 100
   }

   BuyCreditDialog {
     id: buyCreditDialog
     opacity: 0
     z: 100
   }

   OrderLevelsDialog {
     id: orderLevelsDialog
     opacity: 0
     z: 100
     onLevelOrderSelected: {
       levelScene.order = levelOrder
     }
   }

   onLevelSelected: {
     if((isUserLevel && isDownloaded) || (isAuthorLevel && isPublished) || levelScene.state === "myDownloadedLevels" || (isUserLevel && isLoggedInPlayer)) {
       levelEditor.loadSingleLevel(levelData)
       gameScene.goToPlayMode()
       gameScene.cameFromScene = levelScene.state
       mainItem.state = "game"
       flurry.logEvent("Level.GoToPlayMode")
     } else if(isAuthorLevel && !isPublished) {
       levelEditor.loadSingleLevel(levelData)
       gameScene.goToLevelEditingMode()
       gameScene.cameFromScene = levelScene.state
       mainItem.state = "game"
       flurry.logEvent("Level.GoToEditMode")
     }
   }

   onShareLevelClicked: {
     console.debug("TODO: open fb wall post")
     // open the native fb wall posting here, if there is a valid fbItem
   }

   onRateLevelClicked: {
     // show a 5 star rating, and then rate with its value
     ratingDialog.opacity = 1
     ratingDialog.levelId = levelData.levelId
     if(levelData && levelData["rating"])
       ratingDialog.currentRating = levelData["rating"]["quality"]
     else
       ratingDialog.currentRating = 0
   }

   onDownloadLevelClicked: {
     // it's up to the developer if he wants to support the LevelStore - if so, then a direct download is not possible but only a buy
     // on iOS & Android, do not open the store yet, as too tedious to set up during development
     // this should be the other way around in the end, or use buyLevel for both platforms, as basic Store functionality is now also supported on desktop
     // NOTE: the supported property does also return FALSE on iOS & Android, thus a bug in Store plugin!
     //if(levelStore.supported) {

     // for testing the purchase process with the build server, by default the "stage" property is set to "test"
     // this means the build server signs the app with the Felgo certificate to allow quick testing & deployment
     // however, in-app-purchases and the Store plugin require a publish build because in-app purchases are not working with the Felgo certificate but require YOUR OWN certificate
     // thus for final testing including in-app purchases on iOS & Android, do change to publish build by changing the config.json "stage" property to "publish"
     // and to simulate the correct purchase process on build server for test builds, we directly download the level without an actual purchase on iOS & Android
     if( (system.isPlatform(System.IOS) || system.isPlatform(System.Android)) && !system.publishBuild ) {
       levelEditor.downloadLevel(levelData)
     } else {
       levelStore.buyLevel(levelData)
     }
   }

   onShowInfoClicked: {
     infoDialog.levelData = levelData
     infoDialog.opacity = 1
   }

   onUnpublishLevelClicked: {
     dialogState = "unpublishConfirmation"
     // must be saved so we know the levelId to unpublish after confirmation
     unpublishLevelData = levelData
     nativeUtils.displayMessageBox("Unpublish Confirmation", "Do you really want to unpublish your level? This removes all ratings and download stats for this level.", 2)
   }

   onStateChanged: {
     if(state === "myLevels") {
       levelEditor.loadAllLevelsFromStorageLocation(levelEditor.authorGeneratedLevelsLocation)
       currentLevelSelection = myLevelSelection
     } else if(state === "myDownloadedLevels") {
       levelEditor.loadAllLevelsFromStorageLocation(levelEditor.downloadedLevelsLocation)
       currentLevelSelection = downloadedLevelSelection
     } else if (state === "friendLevels") {
       // the levelSelection must be set BEFORE reloadLevels() is called, otherwise the old page information would be used!
       currentLevelSelection = userOrFriendLevelSelection
       // this takes into account the current ordering and timeLimit
       levelScene.reloadLevels()
     } else if (state === "communityLevels") {
       // the levelSelection must be set BEFORE reloadLevels() is called, otherwise the old page information would be used!
       currentLevelSelection = communityLevelSelection
       // this takes into account the current ordering and timeLimit
       levelScene.reloadLevels()
     } else {
       console.debug("ERROR: LevelScene: undefined state!", state)
     }
   }

   // is either "myLevels" or "myDownloadedLevels", and is needed to go back to these levels when "My Levels" is selected
   property string previousMyLevelState: "myLevels"

   //order - Order results by fields, newest/highst quality first Has to be one of ["created_at", "average_quality", "average_difficulty", "times_favored", "times_played", "times_downloaded"]. Default: created_at.
   property string order: "created_at"
   onOrderChanged: {
     currentLevelSelection.page = 1
     reloadLevels()
   }
   function orderString() {
     if(order === "created_at")
       return "Newest"
     else if(order === "average_quality")
       return "Highest Rated"
     else if(order === "times_downloaded")
       return "Most Downloaded"

     return "XXX"
   }

   //timeLimit - Only return levels that have been created within time_limit hours (integer).
   property int timeLimit
   onTimeLimitChanged: {
     currentLevelSelection.page = 1
     reloadLevels()
   }

   function reloadLevels() {
     var params = {}
     if(timeLimit > 0) {
       params.timeLimit = timeLimit
     }
     params.order = order
     params.perPage = currentLevelSelection.pageSize
     params.page = currentLevelSelection.page

     if(levelScene.state === "communityLevels") {
       levelEditor.loadCommunityLevels(params)
     } else if(levelScene.state === "friendLevels") {
       // if also the own published levels should be shown, use params.filters = ["created_by_friends", "created_by_user"] - but this information is available in the "My Levels" list anyway
       // it is better to show the own levels as well, so the player can compare with his friends
       params.filters = ["created_by_friends", "created_by_user"]
       levelEditor.loadUserOrFriendsLevels(params)
     }
   }

   function levelArrayFromState() {
     if(state === "myLevels")
       return levelEditor.authorGeneratedLevels
     else if(state === "myDownloadedLevels")
       return levelEditor.downloadedLevels
     else if(state === "friendLevels")
       return levelEditor.userOrFriendsLevels
     else if(state === "communityLevels")
       return levelEditor.communityLevels

     console.debug("ERROR: LevelScene: undefined state!", state)

     return undefined

Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded