diff --git a/src/Core/Crawl.qrc b/src/Core/Crawl.qrc index c596ba9..0d84981 100644 --- a/src/Core/Crawl.qrc +++ b/src/Core/Crawl.qrc @@ -26,5 +26,6 @@ CrawlModule/particles/Wint.qml CrawlModule/PreviewControl.qml CrawlModule/StoreView.qml + CrawlModule/SelectLevelView.qml diff --git a/src/Core/CrawlModule/SelectLevelView.qml b/src/Core/CrawlModule/SelectLevelView.qml new file mode 100644 index 0000000..75c80cf --- /dev/null +++ b/src/Core/CrawlModule/SelectLevelView.qml @@ -0,0 +1,64 @@ +import QtQuick +import ViewSolutionsModule +import QtQuick.Controls +import QtQuick.Controls.Material +import QtQuick.Layouts + +Page { + id: store + property var model: null; + visible: model && model.visible + ColumnLayout { + anchors.fill: parent + ListView { + id: listView + Layout.fillHeight: true + Layout.fillWidth: true + model: store.model + delegate: delegateRow + + Component { + id: delegateRow + + Rectangle { + anchors.fill: parent + + color: (itemId == currentLevel) ? "#ffaf2c": "#00000000" + RowLayout { + width: listView.width + height: 100 + Image { + id: img + fillMode: Image.PreserveAspectCrop + source: itemImage + Layout.fillHeight: true + Layout.preferredWidth: height * 2 + } + + Label { + text: itemName + Layout.fillHeight: true + } + + Label { + text: itemDescription + Layout.fillWidth: true + Layout.fillHeight: true + } + + Button { + text: qsTr("Select"); + visible: !itemWasBuy + + onClicked: () => { + if (store.model) + store.model.select(itemId); + } + } + } + } + + } + } + } +} diff --git a/src/Core/private/availablelevelsmodel.cpp b/src/Core/private/availablelevelsmodel.cpp new file mode 100644 index 0000000..5224b2e --- /dev/null +++ b/src/Core/private/availablelevelsmodel.cpp @@ -0,0 +1,45 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "availablelevelsmodel.h" +#include "user.h" +#include + +namespace CRAWL { + +AvailableLevelsModel::AvailableLevelsModel() { + +} + +void AvailableLevelsModel::setAllLevels(const QList &newAllLevels) { + _allLevels = newAllLevels; + QList keys; + for (auto level: qAsConst(_allLevels)) { + keys += level->itemId(); + } + + setKeys(keys); +} + +int AvailableLevelsModel::getCurrentLevel() const { + return currentLevel; +} + +void AvailableLevelsModel::setCurrentLevel(int newCurrentLevel) { + if (currentLevel == newCurrentLevel) + return; + currentLevel = newCurrentLevel; + emit currentLevelChanged(); +} + +void AvailableLevelsModel::select(int levelId) { + if (getUser()->isUnlocked(levelId)) { + emit sigUserSelectLevel(levelId); + } +} + +} diff --git a/src/Core/private/availablelevelsmodel.h b/src/Core/private/availablelevelsmodel.h new file mode 100644 index 0000000..9d31813 --- /dev/null +++ b/src/Core/private/availablelevelsmodel.h @@ -0,0 +1,88 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef AVAILABLELEVELSMODEL_H +#define AVAILABLELEVELSMODEL_H + +#include "baseuserlistmodel.h" + +namespace CRAWL { + +class User; +class IItem; + +/** + * @brief The AvailableLevelsModel class is model of the available levels qml view. + * This model just show available levels of the current user. + */ +class AvailableLevelsModel: public BaseUserListModel +{ + Q_OBJECT + /** + * @brief currentLevel This property contains id of the loaded level. + * @see AvailableLevelsModel::getCurrentLevel + * @see AvailableLevelsModel::setCurrentLevel + * @see AvailableLevelsModel::currentLevelChanged + + */ + Q_PROPERTY(int currentLevel READ getCurrentLevel WRITE setCurrentLevel NOTIFY currentLevelChanged) + +public: + AvailableLevelsModel(); + + /** + * @brief setAllLevels This method sets list of the available levels in game. + * @param newAllLevels This is new value of thge availabel games list. + */ + void setAllLevels(const QList &newAllLevels); + + /** + * @brief getCurrentLevel This method return value of the curernt level property + * @return value of the curernt level property + * @see AvailableLevelsModel::currentLevel + * @see AvailableLevelsModel::setCurrentLevel + * @see AvailableLevelsModel::currentLevelChanged + */ + int getCurrentLevel() const; + + /** + * @brief setCurrentLevel This method sets new current level. + * @param newCurrentLevel This is new value of the current level. + * @see AvailableLevelsModel::getCurrentLevel + * @see AvailableLevelsModel::currentLevel + * @see AvailableLevelsModel::currentLevelChanged + */ + void setCurrentLevel(int newCurrentLevel); + + /** + * @brief select This method select new level of user. + * @param levelId This is id of the selected level. + */ + Q_INVOKABLE void select(int levelId); + +signals: + /** + * @brief currentLevelChanged This signal emited when the currentLevel propertye is changed. + * @see AvailableLevelsModel::getCurrentLevel + * @see AvailableLevelsModel::setCurrentLevel + * @see AvailableLevelsModel::currentLevel + */ + void currentLevelChanged(); + + /** + * @brief sigUserSelectLevel This signal emited when user select new level. + * @param level This is level id that user selected. + */ + void sigUserSelectLevel(int level); + +private: + QList _allLevels; + int currentLevel = -1; +}; + +} +#endif // AVAILABLELEVELSMODEL_H diff --git a/src/Core/private/baseuserlistmodel.cpp b/src/Core/private/baseuserlistmodel.cpp new file mode 100644 index 0000000..b7c4df2 --- /dev/null +++ b/src/Core/private/baseuserlistmodel.cpp @@ -0,0 +1,144 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + + +#include "baseuserlistmodel.h" +#include "user.h" + +#include + +namespace CRAWL { + +BaseUserListModel::BaseUserListModel() { + +} + +void BaseUserListModel::setUser(User *newUser) { + if (_user) { + disconnect(_user, &User::sigDropped, + this, &BaseUserListModel::handleDroppedItem); + disconnect(_user, &User::sigUnlcoked, + this, &BaseUserListModel::handleUnlockedItem); + disconnect(_user, &User::sigUlockedItemsChanged, + this, &BaseUserListModel::handleUnlockedItemsListChanged); + } + + _user = newUser; + + if (_user) { + connect(_user, &User::sigDropped, + this, &BaseUserListModel::handleDroppedItem); + connect(_user, &User::sigUnlcoked, + this, &BaseUserListModel::handleUnlockedItem); + connect(_user, &User::sigUlockedItemsChanged, + this, &BaseUserListModel::handleUnlockedItemsListChanged); + } +} + +int BaseUserListModel::getIndexById(int id) const { + return _keysIndexes.value(id, -1); +} + +const QList &BaseUserListModel::keys() const { + return _keys; +} + +void BaseUserListModel::setKeys(const QList &visibleKeysList) { + int diff = visibleKeysList.size() - _keys.size(); + + auto update = [this](const QList & list) { + _keys = list; + for (int index = 0; index < _keys.size(); ++index) { + _keysIndexes[_keys[index]] = index; + } + }; + + if (diff > 0) { + beginInsertRows({}, _keys.size(), visibleKeysList.size() - 1); + update(visibleKeysList); + endInsertRows(); + + } else if (diff == 0) { + emit dataChanged(index(0,0), index(rowCount() - 1, columnCount() - 1)); + + } else { + beginRemoveRows({}, visibleKeysList.size(), _keys.size() - 1); + update(visibleKeysList); + endRemoveRows(); + } +} + +int BaseUserListModel::rowCount(const QModelIndex &) const { + return _keys.size(); +} + +int BaseUserListModel::columnCount(const QModelIndex &) const { + return 1; +} + +QVariant BaseUserListModel::data(const QModelIndex &index, int role) const { + + if (index.row() >= rowCount()) { + return {}; + } + + int id = _keys.at(index.row()); + + const IItem* item = getItem(id); + + if (!item) + return {}; + + switch (role) { + case ItemId: return id; + case ItemName: return item->itemName(); + case ItemImage: return item->image(); + case ItemDescription: return item->description(); + case ItemWasBuy: return getUser() && getUser()->isUnlocked(id); + default: + return {}; + } +} + +QHash BaseUserListModel::roleNames() const { + QHash roles; + + roles[ItemId] = "itemId"; + roles[ItemName] = "itemName"; + roles[ItemDescription] = "itemDescription"; + roles[ItemImage] = "itemImage"; + roles[ItemWasBuy] = "itemWasBuy"; + + return roles; +} + +User *BaseUserListModel::getUser() const { + return _user; +} + +void BaseUserListModel::handleUnlockedItem(int item) { + int idx = _keysIndexes.value(item, -1); + + if (idx >= 0) { + emit dataChanged(index(idx,0), index(idx, 0), {ItemWasBuy}); + } +} + +void BaseUserListModel::handleDroppedItem(int item) { + int idx = _keysIndexes.value(item, -1); + + if (idx >= 0) { + emit dataChanged(index(idx,0), index(idx, 0), {ItemWasBuy}); + } +} + +void BaseUserListModel::handleUnlockedItemsListChanged(const QSet &) { + emit dataChanged(index(0,0), index(_keys.size() - 1, 0), {ItemWasBuy}); + +} + +} diff --git a/src/Core/private/baseuserlistmodel.h b/src/Core/private/baseuserlistmodel.h new file mode 100644 index 0000000..2b863d9 --- /dev/null +++ b/src/Core/private/baseuserlistmodel.h @@ -0,0 +1,107 @@ +//# +//# Copyright (C) 2021-2021 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#ifndef BASEUSERLISTMODEL_H +#define BASEUSERLISTMODEL_H + +#include + +namespace CRAWL { + +class User; +class IItem; + +/** + * @brief The BaseUserListModel class This is base class wint implementation methods for working with user object. + */ +class BaseUserListModel: public QAbstractListModel +{ + Q_OBJECT +public: + BaseUserListModel(); + + /** + * @brief setUser This method update user pointer + * @param user This is new pointer to current user. + */ + void setUser(User *newUser); + + /** + * @brief keys This method retutn curent visible items list. + * @return visible items list. + * @see BaseUserListModel::setKeys + */ + const QList &keys() const; + + /** + * @brief setKeys This method sets lsit of the keys for view. + * @param visibleKeysList This is new valud of the visible keys list. + * @see BaseUserListModel::keys + */ + void setKeys(const QList& visibleKeysList); + + int rowCount(const QModelIndex &parent = {}) const override; + int columnCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + +protected: + + /** + * @brief getUser This method return pointer to current user. + * @return pointer to current user. + */ + User* getUser() const; + + /** + * @brief handleUnlockedItem This slot invoked when emited the User::unclokItem signal. + * @param item This is id of the unlocked item + */ + virtual void handleUnlockedItem(int item); + + /** + * @brief handleUnlockedItem This slot invoked when emited the User::droppItem signal. + * @param item This is id of the dropped item + */ + virtual void handleDroppedItem(int item); + + /** + * @brief handleUnlockedItem This slot invoked when emited the User::setUnlockedItems signal. + * @param item This is new list of the unclod items. + */ + virtual void handleUnlockedItemsListChanged(const QSet& newSet); + + /** + * @brief getItem This method should be return the item by id. Override this method for correct works this model. + * @param id This is item id + * @return const pointer to item object. + */ + virtual const IItem* getItem(int id) const = 0; + + /** + * @brief getIndexById This method return index of the item by id. + * @param id This is id of the needed item + * @return index of the needed item. If the item with id not exists then return -1 + */ + int getIndexById(int id) const; +private: + + enum ViewItemRoles { + ItemId, + ItemName, + ItemImage, + ItemDescription, + ItemWasBuy + }; + + User * _user = nullptr; + QList _keys; + QHash _keysIndexes; +}; + +} +#endif // BASEUSERLISTMODEL_H diff --git a/src/Core/private/storeviewmodel.cpp b/src/Core/private/storeviewmodel.cpp index 67cc00c..51fdcd2 100644 --- a/src/Core/private/storeviewmodel.cpp +++ b/src/Core/private/storeviewmodel.cpp @@ -10,95 +10,10 @@ StoreViewModel::StoreViewModel() { } -int StoreViewModel::rowCount(const QModelIndex &) const { - return _keys.size(); -} - -int StoreViewModel::columnCount(const QModelIndex &) const { - return 1; -} - -QVariant StoreViewModel::data(const QModelIndex &index, int role) const { - if (!_store) - return {}; - - if (index.row() >= rowCount()) { - return {}; - } - - int id = _keys.at(index.row()); - - const IItem* item = _store->getItemById(id); - - if (!item) - return {}; - - switch (role) { - case ItemId: return id; - case ItemName: return item->itemName(); - case ItemImage: return item->image(); - case ItemDescription: return item->description(); - case ItemWasBuy: return _currentUser && _currentUser->isUnlocked(id); - default: - return {}; - } -} - -QHash StoreViewModel::roleNames() const { - QHash roles; - - roles[ItemId] = "itemId"; - roles[ItemName] = "itemName"; - roles[ItemDescription] = "itemDescription"; - roles[ItemImage] = "itemImage"; - roles[ItemWasBuy] = "itemWasBuy"; - - return roles; -} - void StoreViewModel::init(Store *store, User *user) { setUser(user); - - int diff = store->size() - _keys.size(); - - auto update = [this](Store *store) { - _store = store; - _keys = store->keysList(); - for (int index = 0; index < _keys.size(); ++index) { - _keysIndexes[index] = _keys[index]; - } - }; - - if (diff > 0) { - beginInsertRows({}, _keys.size(), store->size() - 1); - update(store); - endInsertRows(); - - } else if (diff == 0) { - emit dataChanged(index(0,0), index(rowCount() - 1, columnCount() - 1)); - - } else { - beginRemoveRows({}, store->size(), _keys.size() - 1); - update(store); - endRemoveRows(); - } -} - -void StoreViewModel::setUser(User *user) { - if (_currentUser) { - disconnect(_currentUser, &User::sigItemsUlocked, - this, &StoreViewModel::handleItemsUnlocked); - - } - - _currentUser = user; - - if (_currentUser) { - connect(_currentUser, &User::sigItemsUlocked, - this, &StoreViewModel::handleItemsUnlocked); - - handleItemsUnlocked(_currentUser->unlockedItems()); - } + setKeys(store->keysList()); + _store = store; } bool StoreViewModel::visible() const { @@ -113,15 +28,16 @@ void StoreViewModel::setVisible(bool newVisible) { } void StoreViewModel::buy(int item) { - if (_store && _currentUser) { - _store->buy(*_currentUser, item); + if (_store && getUser()) { + _store->buy(*getUser(), item); } } -void StoreViewModel::handleItemsUnlocked (const QSet & ) { - - emit dataChanged(index(0,0), index(_keys.size() - 1, 0), {ItemWasBuy}); +const IItem *StoreViewModel::getItem(int id) const { + if (!_store) + return nullptr; + return _store->getItemById(id); } } diff --git a/src/Core/private/storeviewmodel.h b/src/Core/private/storeviewmodel.h index 8bfff79..ca39aa9 100644 --- a/src/Core/private/storeviewmodel.h +++ b/src/Core/private/storeviewmodel.h @@ -8,7 +8,7 @@ #ifndef STOREVIEWMODEL_H #define STOREVIEWMODEL_H -#include +#include "baseuserlistmodel.h" namespace CRAWL { @@ -18,7 +18,7 @@ class User; /** * @brief The StoreViewModel class This is view model of the store. The object of this class should be initialized it he Store class. */ -class StoreViewModel: public QAbstractListModel +class StoreViewModel: public BaseUserListModel { Q_OBJECT /** @@ -29,11 +29,6 @@ class StoreViewModel: public QAbstractListModel public: StoreViewModel(); - int rowCount(const QModelIndex &parent = {}) const override; - int columnCount(const QModelIndex &parent = {}) const override; - QVariant data(const QModelIndex &index, int role) const override; - QHash roleNames() const override; - /** * @brief init This method initialize data of the view model. * @param _store This is poiter to store that contains all inforamtion about store items. @@ -42,12 +37,6 @@ public: */ void init(Store * store, User* user); - /** - * @brief setUser This method update user pointer - * @param user This is new pointer to current user. - */ - void setUser(User* user); - /** * @brief visible This method return true if the store view is visible. * @return true if the store view is visible. @@ -66,33 +55,20 @@ public: */ Q_INVOKABLE void buy(int item); + // BaseUserListModel interface +protected: + const IItem *getItem(int id) const; + signals: /** * @brief visibleChanged This slot emited when store visibel changed */ void visibleChanged(); -private slots: - void handleItemsUnlocked(const QSet &); - private: - void updateView(); - - enum StoreRoles { - ItemId, - ItemName, - ItemImage, - ItemDescription, - ItemWasBuy - }; - Store *_store = nullptr; - QList _keys; - QHash _keysIndexes; - User* _currentUser = nullptr; bool _visible = false; - }; } diff --git a/src/Core/private/user.cpp b/src/Core/private/user.cpp index 917164c..f15c0f6 100644 --- a/src/Core/private/user.cpp +++ b/src/Core/private/user.cpp @@ -60,16 +60,17 @@ bool User::isUnlocked(int item) const { void User::unclokItem(int item) { _unlockedItems.insert(item); - emit sigItemsUlocked({item}); + emit sigUnlcoked(item); } void User::droppItem(int item) { _unlockedItems.remove(item); + emit sigDropped(item); } void User::setUnlockedItems(const QSet &newUnlockedItems) { _unlockedItems = newUnlockedItems; - emit sigItemsUlocked(newUnlockedItems); + emit sigUlockedItemsChanged(newUnlockedItems); } int User::recalcTier() { diff --git a/src/Core/private/user.h b/src/Core/private/user.h index 4ced0e8..e8f96db 100644 --- a/src/Core/private/user.h +++ b/src/Core/private/user.h @@ -145,10 +145,24 @@ signals: void xpChanged(); /** - * @brief sigItemsUlocked This signal emited when user unlocked item. + * @brief sigUlockedItemsChanged This signal emited when users list of unclode items is changed.. * @param unclokedItems This is unlocked items set. Each items in the set is id of the unclocked item. */ - void sigItemsUlocked(const QSet & unclokedItems); + void sigUlockedItemsChanged(const QSet & unclokedItems); + + /** + * @brief sigUnlcoked This signal emmited when user unlock one item. + * @param item This is unlocked item id. + * @see User::unclokItem + */ + void sigUnlcoked(int item); + + /** + * @brief sigDropped This signal emmited when user dropped one item. + * @param item This is dpopped item id. + * @see User::droppItem + */ + void sigDropped(int item); protected: /**