mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-22 02:45:49 -04:00
cleanup
- add CCArray::firstObject and CCArray::removeFirstObject - add minizip zip headers and sources (going to add file::Zip class soon) - redesign Notifications to be simpler - rework Result to not have dual implementations - Result::expect now has one default named argument for formatting the error in
This commit is contained in:
parent
c113e97844
commit
2c78b8e620
12 changed files with 2880 additions and 789 deletions
loader
include/Geode
src
cocos2d-ext
hooks
loader
ui/nodes
utils
|
@ -184,6 +184,11 @@ public:
|
|||
CCString* stringAtIndex(unsigned int index);
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns first element, or null if empty
|
||||
* @note Geode addition
|
||||
*/
|
||||
CCObject* firstObject();
|
||||
/** Returns last element */
|
||||
CCObject* lastObject();
|
||||
/** Returns a random element */
|
||||
|
@ -210,6 +215,11 @@ public:
|
|||
|
||||
// Removing Objects
|
||||
|
||||
/**
|
||||
* Remove first object, or do nothing if array is empty
|
||||
* @note Geode addition
|
||||
*/
|
||||
void removeFirstObject(bool bReleaseObj = true);
|
||||
/** Remove last object */
|
||||
void removeLastObject(bool bReleaseObj = true);
|
||||
/** Remove a certain object */
|
||||
|
|
363
loader/include/Geode/cocos/support/zip_support/zip.h
Normal file
363
loader/include/Geode/cocos/support/zip_support/zip.h
Normal file
|
@ -0,0 +1,363 @@
|
|||
/* zip.h -- IO on .zip files using zlib
|
||||
Version 1.1, February 14h, 2010
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Condition of use and distribution are the same than zlib :
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Changes
|
||||
|
||||
See header of zip.h
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _zip12_H
|
||||
#define _zip12_H
|
||||
|
||||
//#define HAVE_BZIP2
|
||||
|
||||
#include "../../platform/CCPlatformDefine.h"
|
||||
|
||||
#ifndef _ZLIB_H
|
||||
#include "../../platform/IncludeZlib.h"
|
||||
#endif
|
||||
|
||||
#include "ioapi.h"
|
||||
|
||||
#ifdef HAVE_BZIP2
|
||||
#include "bzlib.h"
|
||||
#endif
|
||||
|
||||
namespace cocos2d {
|
||||
|
||||
#define Z_BZIP2ED 12
|
||||
|
||||
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
|
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */
|
||||
typedef struct TagzipFile__ { int unused; } zipFile__;
|
||||
typedef zipFile__ *zipFile;
|
||||
#else
|
||||
typedef voidp zipFile;
|
||||
#endif
|
||||
|
||||
#define ZIP_OK (0)
|
||||
#define ZIP_EOF (0)
|
||||
#define ZIP_ERRNO (Z_ERRNO)
|
||||
#define ZIP_PARAMERROR (-102)
|
||||
#define ZIP_BADZIPFILE (-103)
|
||||
#define ZIP_INTERNALERROR (-104)
|
||||
|
||||
#ifndef DEF_MEM_LEVEL
|
||||
# if MAX_MEM_LEVEL >= 8
|
||||
# define DEF_MEM_LEVEL 8
|
||||
# else
|
||||
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
|
||||
# endif
|
||||
#endif
|
||||
/* default memLevel */
|
||||
|
||||
/* tm_zip contain date/time info */
|
||||
typedef struct tm_zip_s
|
||||
{
|
||||
int tm_sec; /* seconds after the minute - [0,59] */
|
||||
int tm_min; /* minutes after the hour - [0,59] */
|
||||
int tm_hour; /* hours since midnight - [0,23] */
|
||||
int tm_mday; /* day of the month - [1,31] */
|
||||
int tm_mon; /* months since January - [0,11] */
|
||||
int tm_year; /* years - [1980..2044] */
|
||||
} tm_zip;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
tm_zip tmz_date; /* date in understandable format */
|
||||
uLong dosDate; /* if dos_date == 0, tmu_date is used */
|
||||
/* uLong flag; */ /* general purpose bit flag 2 bytes */
|
||||
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */
|
||||
uLong external_fa; /* external file attributes 4 bytes */
|
||||
} zip_fileinfo;
|
||||
|
||||
typedef const char* zipcharpc;
|
||||
|
||||
|
||||
#define APPEND_STATUS_CREATE (0)
|
||||
#define APPEND_STATUS_CREATEAFTER (1)
|
||||
#define APPEND_STATUS_ADDINZIP (2)
|
||||
|
||||
extern zipFile CC_ZIP_DLL zipOpen OF((const char *pathname, int append));
|
||||
extern zipFile CC_ZIP_DLL zipOpen64 OF((const void *pathname, int append));
|
||||
/*
|
||||
Create a zipfile.
|
||||
pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
|
||||
an Unix computer "zlib/zlib113.zip".
|
||||
if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
|
||||
will be created at the end of the file.
|
||||
(useful if the file contain a self extractor code)
|
||||
if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
|
||||
add files in existing zip (be sure you don't add file that doesn't exist)
|
||||
If the zipfile cannot be opened, the return value is NULL.
|
||||
Else, the return value is a zipFile Handle, usable with other function
|
||||
of this zip package.
|
||||
*/
|
||||
|
||||
/* Note : there is no delete function into a zipfile.
|
||||
If you want delete file into a zipfile, you must open a zipfile, and create another
|
||||
Of couse, you can use RAW reading and writing to copy the file you did not want delte
|
||||
*/
|
||||
|
||||
extern zipFile CC_ZIP_DLL zipOpen2 OF((const char *pathname,
|
||||
int append,
|
||||
zipcharpc* globalcomment,
|
||||
zlib_filefunc_def* pzlib_filefunc_def));
|
||||
|
||||
extern zipFile CC_ZIP_DLL zipOpen2_64 OF((const void *pathname,
|
||||
int append,
|
||||
zipcharpc* globalcomment,
|
||||
zlib_filefunc64_def* pzlib_filefunc_def));
|
||||
|
||||
extern zipFile CC_ZIP_DLL zipOpen3 OF((const void *pathname,
|
||||
int append,
|
||||
zipcharpc* globalcomment,
|
||||
zlib_filefunc64_32_def* pzlib_filefunc64_32_def));
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level));
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip64 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int zip64));
|
||||
|
||||
/*
|
||||
Open a file in the ZIP for writing.
|
||||
filename : the filename in zip (if NULL, '-' without quote will be used
|
||||
*zipfi contain supplemental information
|
||||
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
|
||||
contains the extrafield data the the local header
|
||||
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
|
||||
contains the extrafield data the the local header
|
||||
if comment != NULL, comment contain the comment string
|
||||
method contain the compression method (0 for store, Z_DEFLATED for deflate)
|
||||
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
|
||||
zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
|
||||
this MUST be '1' if the uncompressed size is >= 0xffffffff.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip2 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int raw));
|
||||
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip2_64 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int raw,
|
||||
int zip64));
|
||||
/*
|
||||
Same than zipOpenNewFileInZip, except if raw=1, we write raw file
|
||||
*/
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip3 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int raw,
|
||||
int windowBits,
|
||||
int memLevel,
|
||||
int strategy,
|
||||
const char* password,
|
||||
uLong crcForCrypting));
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip3_64 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int raw,
|
||||
int windowBits,
|
||||
int memLevel,
|
||||
int strategy,
|
||||
const char* password,
|
||||
uLong crcForCrypting,
|
||||
int zip64
|
||||
));
|
||||
|
||||
/*
|
||||
Same than zipOpenNewFileInZip2, except
|
||||
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
|
||||
password : crypting password (NULL for no crypting)
|
||||
crcForCrypting : crc of file to compress (needed for crypting)
|
||||
*/
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip4 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int raw,
|
||||
int windowBits,
|
||||
int memLevel,
|
||||
int strategy,
|
||||
const char* password,
|
||||
uLong crcForCrypting,
|
||||
uLong versionMadeBy,
|
||||
uLong flagBase
|
||||
));
|
||||
|
||||
|
||||
extern int CC_ZIP_DLL zipOpenNewFileInZip4_64 OF((zipFile file,
|
||||
const char* filename,
|
||||
const zip_fileinfo* zipfi,
|
||||
const void* extrafield_local,
|
||||
uInt size_extrafield_local,
|
||||
const void* extrafield_global,
|
||||
uInt size_extrafield_global,
|
||||
const char* comment,
|
||||
int method,
|
||||
int level,
|
||||
int raw,
|
||||
int windowBits,
|
||||
int memLevel,
|
||||
int strategy,
|
||||
const char* password,
|
||||
uLong crcForCrypting,
|
||||
uLong versionMadeBy,
|
||||
uLong flagBase,
|
||||
int zip64
|
||||
));
|
||||
/*
|
||||
Same than zipOpenNewFileInZip4, except
|
||||
versionMadeBy : value for Version made by field
|
||||
flag : value for flag field (compression level info will be added)
|
||||
*/
|
||||
|
||||
|
||||
extern int CC_ZIP_DLL zipWriteInFileInZip OF((zipFile file,
|
||||
const void* buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Write data in the zipfile
|
||||
*/
|
||||
|
||||
extern int CC_ZIP_DLL zipCloseFileInZip OF((zipFile file));
|
||||
/*
|
||||
Close the current file in the zipfile
|
||||
*/
|
||||
|
||||
extern int CC_ZIP_DLL zipCloseFileInZipRaw OF((zipFile file,
|
||||
uLong uncompressed_size,
|
||||
uLong crc32));
|
||||
|
||||
extern int CC_ZIP_DLL zipCloseFileInZipRaw64 OF((zipFile file,
|
||||
ZPOS64_T uncompressed_size,
|
||||
uLong crc32));
|
||||
|
||||
/*
|
||||
Close the current file in the zipfile, for file opened with
|
||||
parameter raw=1 in zipOpenNewFileInZip2
|
||||
uncompressed_size and crc32 are value for the uncompressed size
|
||||
*/
|
||||
|
||||
extern int CC_ZIP_DLL zipClose OF((zipFile file,
|
||||
const char* global_comment));
|
||||
/*
|
||||
Close the zipfile
|
||||
*/
|
||||
|
||||
|
||||
extern int CC_ZIP_DLL zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));
|
||||
/*
|
||||
zipRemoveExtraInfoBlock - Added by Mathias Svensson
|
||||
|
||||
Remove extra information block from a extra information data for the local file header or central directory header
|
||||
|
||||
It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
|
||||
|
||||
0x0001 is the signature header for the ZIP64 extra information blocks
|
||||
|
||||
usage.
|
||||
Remove ZIP64 Extra information from a central director extra field data
|
||||
zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
|
||||
|
||||
Remove ZIP64 Extra information from a Local File Header extra field data
|
||||
zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
#endif /* _zip64_H */
|
|
@ -1,180 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
#include "../utils/cocos.hpp"
|
||||
#include "SceneManager.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <cocos2d.h>
|
||||
#include <cocos-ext.h>
|
||||
#include <Geode/binding/TextAlertPopup.hpp>
|
||||
#include "../utils/cocos.hpp"
|
||||
|
||||
namespace geode {
|
||||
enum class NotificationLocation {
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomCenter,
|
||||
BottomRight,
|
||||
constexpr auto NOTIFICATION_DEFAULT_TIME = 1.f;
|
||||
|
||||
enum class NotificationIcon {
|
||||
None,
|
||||
Loading,
|
||||
Success,
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
|
||||
static constexpr float DEFAULT_NOTIFICATION_TIME = 4.f;
|
||||
static constexpr NotificationLocation PLATFORM_NOTIFICATION_LOCATION =
|
||||
#ifdef GEODE_IS_DESKTOP
|
||||
NotificationLocation::BottomRight;
|
||||
#else
|
||||
NotificationLocation::TopCenter;
|
||||
#endif
|
||||
|
||||
class Notification;
|
||||
class NotificationManager;
|
||||
|
||||
struct GEODE_DLL NotificationBuilder {
|
||||
Mod* m_owner = Mod::get();
|
||||
std::string m_title = "";
|
||||
std::string m_text = "";
|
||||
std::string m_icon = "GJ_infoIcon_001.png";
|
||||
Ref<cocos2d::CCNode> m_iconNode = nullptr;
|
||||
std::string m_bg = "GJ_square02.png";
|
||||
std::function<void(Notification*)> m_callback = nullptr;
|
||||
float m_time = DEFAULT_NOTIFICATION_TIME;
|
||||
NotificationLocation m_location = PLATFORM_NOTIFICATION_LOCATION;
|
||||
bool m_hideOnClick = true;
|
||||
|
||||
inline NotificationBuilder& from(Mod* owner) {
|
||||
m_owner = owner;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& title(std::string const& title) {
|
||||
m_title = title;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& text(std::string const& text) {
|
||||
m_text = text;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& icon(std::string const& icon) {
|
||||
m_icon = icon;
|
||||
m_iconNode = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& icon(cocos2d::CCNode* icon) {
|
||||
m_icon = "";
|
||||
m_iconNode = icon;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& loading() {
|
||||
auto spr = cocos2d::CCSprite::create("loadingCircle.png");
|
||||
spr->runAction(cocos2d::CCRepeat::create(cocos2d::CCRotateBy::create(1.f, 360.f), 40000)
|
||||
);
|
||||
spr->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
return this->icon(spr);
|
||||
}
|
||||
|
||||
inline NotificationBuilder& bg(std::string const& bg) {
|
||||
m_bg = bg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& location(NotificationLocation location) {
|
||||
m_location = location;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& time(float time) {
|
||||
m_time = time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& stay() {
|
||||
m_time = .0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline NotificationBuilder& clicked(
|
||||
std::function<void(Notification*)> cb, bool hide = true
|
||||
) {
|
||||
m_callback = cb;
|
||||
m_hideOnClick = hide;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Notification* show();
|
||||
};
|
||||
|
||||
class GEODE_DLL Notification : public cocos2d::CCLayer {
|
||||
class GEODE_DLL Notification : public cocos2d::CCNodeRGBA {
|
||||
protected:
|
||||
Mod* m_owner;
|
||||
std::function<void(Notification*)> m_callback = nullptr;
|
||||
static Ref<cocos2d::CCArray> s_queue;
|
||||
cocos2d::extension::CCScale9Sprite* m_bg;
|
||||
cocos2d::CCNode* m_icon = nullptr;
|
||||
cocos2d::CCLabelBMFont* m_title = nullptr;
|
||||
Ref<cocos2d::CCArray> m_labels = nullptr;
|
||||
cocos2d::CCPoint m_showDest;
|
||||
cocos2d::CCPoint m_hideDest;
|
||||
cocos2d::CCPoint m_posAtTouchStart;
|
||||
NotificationLocation m_location;
|
||||
cocos2d::CCLabelBMFont* m_label;
|
||||
cocos2d::CCSprite* m_icon = nullptr;
|
||||
float m_time;
|
||||
bool m_hiding = false;
|
||||
bool m_clicking;
|
||||
bool m_hovered;
|
||||
bool m_hideOnClicked = true;
|
||||
float m_targetScale = 1.f;
|
||||
bool m_showing = false;
|
||||
|
||||
bool init(
|
||||
Mod* owner, std::string const& title, std::string const& text, cocos2d::CCNode* icon,
|
||||
char const* bg, std::function<void(Notification*)> callback, bool hideOnClick
|
||||
);
|
||||
bool init(std::string const& text, cocos2d::CCSprite* icon, float time);
|
||||
void updateLayout();
|
||||
|
||||
Notification();
|
||||
virtual ~Notification();
|
||||
|
||||
bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) override;
|
||||
void ccTouchEnded(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) override;
|
||||
void ccTouchMoved(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) override;
|
||||
void registerWithTouchDispatcher() override;
|
||||
|
||||
void clicked();
|
||||
static cocos2d::CCSprite* createIcon(NotificationIcon icon);
|
||||
|
||||
void animateIn();
|
||||
void animateOut();
|
||||
void animateOutClicked();
|
||||
void animateClicking();
|
||||
|
||||
void hidden();
|
||||
void showForReal();
|
||||
|
||||
friend class NotificationManager;
|
||||
void showNextNotification();
|
||||
void wait();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a notification, similar to TextAlertPopup but more customizable
|
||||
* @param text Notification text
|
||||
* @param icon Icon to show in the notification
|
||||
* @param time Time to show the notification on screen; pass 0 to show
|
||||
* the notification indefinitely until hide() is called
|
||||
* @returns The new notification. Make sure to call show() to show the
|
||||
* notification
|
||||
*/
|
||||
static Notification* create(
|
||||
Mod* owner, std::string const& title, std::string const& text, cocos2d::CCNode* icon,
|
||||
char const* bg, std::function<void(Notification*)> callback, bool hideOnClick
|
||||
std::string const& text,
|
||||
NotificationIcon icon = NotificationIcon::None,
|
||||
float time = NOTIFICATION_DEFAULT_TIME
|
||||
);
|
||||
/**
|
||||
* Create a notification with a custom icon
|
||||
* @param text Notification text
|
||||
* @param icon Icon to show in the notification
|
||||
* @param time Time to show the notification on screen; pass 0 to show
|
||||
* the notification indefinitely until hide() is called
|
||||
* @returns The new notification. Make sure to call show() to show the
|
||||
* notification
|
||||
*/
|
||||
static Notification* create(
|
||||
std::string const& text,
|
||||
cocos2d::CCSprite* icon,
|
||||
float time
|
||||
);
|
||||
static NotificationBuilder build();
|
||||
|
||||
void show(
|
||||
NotificationLocation = PLATFORM_NOTIFICATION_LOCATION,
|
||||
float time = DEFAULT_NOTIFICATION_TIME
|
||||
);
|
||||
void setString(std::string const& text);
|
||||
void setIcon(NotificationIcon icon);
|
||||
void setIcon(cocos2d::CCSprite* icon);
|
||||
void setTime(float time);
|
||||
|
||||
/**
|
||||
* Adds the notification to the current scene if it doesn't have a
|
||||
* parent yet, and displays the show animation. If the time for the
|
||||
* notification was specified, the notification waits that time and
|
||||
* then automatically hides
|
||||
*/
|
||||
void show();
|
||||
|
||||
/**
|
||||
* Hide the notification. If you passed a time to the create function,
|
||||
* this function doesn't need to be called manually, unless you want
|
||||
* to prematurily hide the notification
|
||||
*/
|
||||
void hide();
|
||||
};
|
||||
|
||||
class NotificationManager {
|
||||
protected:
|
||||
std::unordered_map<NotificationLocation, std::vector<Ref<Notification>>> m_notifications;
|
||||
|
||||
void push(Notification*);
|
||||
void pop(Notification*);
|
||||
|
||||
bool isInQueue(Notification*);
|
||||
|
||||
friend class Notification;
|
||||
|
||||
public:
|
||||
static NotificationManager* get();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <variant>
|
||||
#include <fmt/format.h>
|
||||
|
||||
// clang-format off
|
||||
|
||||
namespace geode {
|
||||
namespace {
|
||||
struct AnyType {
|
||||
|
@ -20,10 +22,124 @@ namespace geode {
|
|||
|
||||
using DefaultValue = std::monostate;
|
||||
using DefaultError = std::string;
|
||||
|
||||
template<class T, class E>
|
||||
struct Storage {
|
||||
std::variant<T, E> m_value;
|
||||
|
||||
bool holdsOk() const {
|
||||
return std::holds_alternative<T>(m_value);
|
||||
}
|
||||
|
||||
T getOk() const requires std::is_copy_constructible_v<T> {
|
||||
return std::get<T>(m_value);
|
||||
}
|
||||
|
||||
T&& getOk() requires(!std::is_copy_constructible_v<T>) {
|
||||
return std::move(std::get<T>(m_value));
|
||||
}
|
||||
|
||||
E getErr() const requires std::is_copy_constructible_v<E> {
|
||||
return std::get<E>(m_value);
|
||||
}
|
||||
|
||||
E&& getErr() requires(!std::is_copy_constructible_v<E>) {
|
||||
return std::move(std::get<E>(m_value));
|
||||
}
|
||||
|
||||
template<class T2, class E2>
|
||||
requires
|
||||
std::is_convertible_v<T2, T> &&
|
||||
std::is_convertible_v<E2, E>
|
||||
Storage(Storage<T2, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<T> &&
|
||||
std::is_copy_constructible_v<E>
|
||||
{
|
||||
if (other.holdsOk()) {
|
||||
m_value = other.getOk();
|
||||
} else {
|
||||
m_value = other.getErr();
|
||||
}
|
||||
}
|
||||
|
||||
Storage(T const& value)
|
||||
requires std::is_copy_constructible_v<T>
|
||||
: m_value(value) {}
|
||||
|
||||
Storage(T&& value)
|
||||
requires std::is_move_constructible_v<T>
|
||||
: m_value(std::forward<T>(value)) {}
|
||||
|
||||
Storage(E const& value, std::monostate)
|
||||
requires std::is_copy_constructible_v<E>
|
||||
: m_value(value) {}
|
||||
|
||||
Storage(E&& value, std::monostate)
|
||||
requires std::is_move_constructible_v<E>
|
||||
: m_value(std::forward<E>(value)) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Storage<T, T> {
|
||||
bool m_holdsOk;
|
||||
T m_value;
|
||||
|
||||
bool holdsOk() const {
|
||||
return m_holdsOk;
|
||||
}
|
||||
|
||||
T getOk() const requires std::is_copy_constructible_v<T> {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T&& getOk() requires(!std::is_copy_constructible_v<T>) {
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
T getErr() const requires std::is_copy_constructible_v<T> {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T&& getErr() requires(!std::is_copy_constructible_v<T>) {
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
template<class T2, class E2>
|
||||
requires
|
||||
std::is_convertible_v<T2, T> &&
|
||||
std::is_convertible_v<E2, T>
|
||||
Storage(Storage<T2, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<T> &&
|
||||
std::is_copy_constructible_v<T>
|
||||
: m_value(other.holdsOk() ? other.getOk() : other.getErr()),
|
||||
m_holdsOk(other.holdsOk()) {}
|
||||
|
||||
Storage(T const& value)
|
||||
requires std::is_copy_constructible_v<T>
|
||||
: m_value(value),
|
||||
m_holdsOk(true) {}
|
||||
|
||||
Storage(T&& value)
|
||||
requires std::is_move_constructible_v<T>
|
||||
: m_value(std::forward<T>(value)),
|
||||
m_holdsOk(true) {}
|
||||
|
||||
Storage(T const& value, std::monostate)
|
||||
requires std::is_copy_constructible_v<T>
|
||||
: m_value(value),
|
||||
m_holdsOk(false) {}
|
||||
|
||||
Storage(T&& value, std::monostate)
|
||||
requires std::is_move_constructible_v<T>
|
||||
: m_value(std::forward<T>(value)),
|
||||
m_holdsOk(false) {}
|
||||
};
|
||||
}
|
||||
|
||||
template <class T = DefaultValue, class E = DefaultError>
|
||||
class [[nodiscard]] Result {
|
||||
class [[nodiscard]] Result final {
|
||||
public:
|
||||
using value_type = std::remove_reference_t<T>;
|
||||
using error_type = std::remove_reference_t<E>;
|
||||
|
@ -39,265 +155,168 @@ namespace geode {
|
|||
);
|
||||
|
||||
protected:
|
||||
std::variant<value_type, error_type> m_value;
|
||||
Storage<value_type, error_type> m_value;
|
||||
|
||||
public:
|
||||
Storage<value_type, error_type> const& _Raw_Storage() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool isOk() const {
|
||||
return std::holds_alternative<value_type>(m_value);
|
||||
return m_value.holdsOk();
|
||||
}
|
||||
|
||||
bool isErr() const {
|
||||
return std::holds_alternative<error_type>(m_value);
|
||||
return !m_value.holdsOk();
|
||||
}
|
||||
|
||||
template<class ... Args>
|
||||
Result<T, std::string> expect(const char* str, Args&&... args) {
|
||||
if (isErr()) {
|
||||
return Result(fmt::format(str, std::forward<Args>(args)...));
|
||||
return Result<T, std::string>(fmt::format(
|
||||
str,
|
||||
std::forward<Args>(args)...,
|
||||
fmt::arg("error", unwrapErr())
|
||||
), std::monostate());
|
||||
} else {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
explicit Result(value_type const& value
|
||||
) requires std::is_copy_constructible_v<value_type> : m_value(value) {}
|
||||
explicit Result(value_type const& value)
|
||||
requires std::is_copy_constructible_v<value_type>
|
||||
: m_value(value) {}
|
||||
|
||||
explicit Result(value_type&& value) requires std::is_move_constructible_v<value_type> :
|
||||
m_value(std::forward<value_type>(value)) {}
|
||||
explicit Result(value_type&& value)
|
||||
requires std::is_move_constructible_v<value_type>
|
||||
: m_value(std::forward<value_type>(value)) {}
|
||||
|
||||
explicit Result(error_type const& value
|
||||
) requires std::is_copy_constructible_v<error_type> : m_value(value) {}
|
||||
explicit Result(error_type const& value, std::monostate)
|
||||
requires std::is_copy_constructible_v<error_type>
|
||||
: m_value(value, std::monostate()) {}
|
||||
|
||||
explicit Result(error_type&& value) requires std::is_move_constructible_v<error_type> :
|
||||
m_value(std::forward<error_type>(value)) {}
|
||||
explicit Result(error_type&& value, std::monostate)
|
||||
requires std::is_move_constructible_v<error_type>
|
||||
: m_value(std::forward<error_type>(value), std::monostate()) {}
|
||||
|
||||
Result(Result<T, E> const& other) requires std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
= default;
|
||||
Result(Result<T, E> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
= default;
|
||||
|
||||
Result(Result<T, E>&& other
|
||||
) requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) =
|
||||
default;
|
||||
Result(Result<T, E>&& other)
|
||||
requires(
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
) = default;
|
||||
|
||||
template <class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> Result(
|
||||
Result<T2, E2> const& other
|
||||
)
|
||||
|
||||
requires std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
{
|
||||
if (other.isOk()) {
|
||||
m_value = other.unwrap();
|
||||
} else {
|
||||
m_value = other.unwrapErr();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, E> Result(
|
||||
Result<T2, E2>&& other
|
||||
)
|
||||
|
||||
requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
|
||||
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()) {}
|
||||
template<class T2, class E2>
|
||||
requires
|
||||
std::is_convertible_v<T2, T> &&
|
||||
std::is_convertible_v<E2, E>
|
||||
Result(Result<T2, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
: m_value(other._Raw_Storage()) {}
|
||||
|
||||
template <class T2>
|
||||
requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType> const& other)
|
||||
|
||||
requires std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type> : Result(value_type(other.unwrap())) {}
|
||||
requires ConvertibleToResult<T2, T>
|
||||
Result(Result<T2, AnyType> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
: Result(value_type(other.unwrap())) {}
|
||||
|
||||
template <class E2>
|
||||
requires ConvertibleToResult<E2, E> Result(Result<AnyType, E2> const& other)
|
||||
|
||||
requires std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type> :
|
||||
m_value(std::forward<E2>(other.unwrapErr())) {}
|
||||
requires ConvertibleToResult<E2, E>
|
||||
Result(Result<AnyType, E2> const& other)
|
||||
requires
|
||||
std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_constructible_v<error_type>
|
||||
: m_value(std::forward<E2>(other.unwrapErr()), std::monostate()) {}
|
||||
|
||||
template <class T2>
|
||||
requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType>&& other)
|
||||
|
||||
requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
|
||||
m_value(other.unwrap()) {}
|
||||
requires ConvertibleToResult<T2, T>
|
||||
Result(Result<T2, AnyType>&& other)
|
||||
requires(
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
)
|
||||
: m_value(other.unwrap()) {}
|
||||
|
||||
template <class E2>
|
||||
requires ConvertibleToResult<E2, E> Result(Result<AnyType, E2>&& other)
|
||||
|
||||
requires(!std::is_copy_constructible_v<value_type> || !std::is_copy_constructible_v<error_type>) :
|
||||
Result(std::forward<error_type>(other.unwrapErr())) {}
|
||||
requires ConvertibleToResult<E2, E>
|
||||
Result(Result<AnyType, E2>&& other)
|
||||
requires(
|
||||
!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_constructible_v<error_type>
|
||||
)
|
||||
: Result(std::forward<error_type>(other.unwrapErr()), std::monostate()) {}
|
||||
|
||||
value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
|
||||
return std::get<value_type>(m_value);
|
||||
return m_value.getOk();
|
||||
}
|
||||
|
||||
value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
|
||||
return std::move(std::get<value_type>(m_value));
|
||||
return std::forward<value_type>(m_value.getOk());
|
||||
}
|
||||
|
||||
error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
|
||||
return std::get<error_type>(m_value);
|
||||
return m_value.getErr();
|
||||
}
|
||||
|
||||
error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
|
||||
return std::move(std::get<error_type>(m_value));
|
||||
return std::forward<error_type>(m_value.getErr());
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
requires(!std::is_same_v<T, bool> && !std::is_same_v<E, bool>) {
|
||||
return this->isOk();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class [[nodiscard]] Result<T, T> {
|
||||
public:
|
||||
using value_type = std::remove_reference_t<T>;
|
||||
using error_type = std::remove_reference_t<T>;
|
||||
|
||||
// for some reason doing requires causes errors with pch...
|
||||
static_assert(
|
||||
std::is_copy_constructible_v<value_type> ||
|
||||
std::is_move_constructible_v<value_type>,
|
||||
"T must be copiable or movable!"
|
||||
);
|
||||
|
||||
protected:
|
||||
bool m_success;
|
||||
value_type m_value;
|
||||
|
||||
public:
|
||||
bool isOk() const {
|
||||
return m_success;
|
||||
}
|
||||
|
||||
bool isErr() const {
|
||||
return !m_success;
|
||||
}
|
||||
|
||||
template<class ... Args>
|
||||
Result<T, std::string> expect(const char* str, Args&&... args) {
|
||||
if (isErr()) {
|
||||
return Result(fmt::format(str, std::forward<Args>(args)...), false);
|
||||
} else {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
explicit Result(value_type const& value, bool success) requires
|
||||
std::is_copy_constructible_v<value_type> :
|
||||
m_value(value),
|
||||
m_success(success) {}
|
||||
|
||||
explicit Result(value_type&& value, bool success) requires
|
||||
std::is_move_constructible_v<value_type> :
|
||||
m_value(std::forward<value_type>(value)),
|
||||
m_success(success) {}
|
||||
|
||||
Result(Result<T, T> const& other) requires std::is_copy_constructible_v<value_type>
|
||||
= default;
|
||||
|
||||
Result(Result<T, T>&& other
|
||||
) requires(!std::is_copy_constructible_v<value_type>) = default;
|
||||
|
||||
template <class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> Result(
|
||||
Result<T2, E2> const& other
|
||||
)
|
||||
|
||||
requires std::is_copy_constructible_v<value_type> :
|
||||
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()),
|
||||
m_success(other.isOk()) {}
|
||||
|
||||
template <class T2, class E2>
|
||||
requires ConvertibleToResult<T2, T> && ConvertibleToResult<E2, T> Result(
|
||||
Result<T2, E2>&& other
|
||||
)
|
||||
|
||||
requires(!std::is_copy_constructible_v<value_type>) :
|
||||
m_value(other.isOk() ? other.unwrap() : other.unwrapErr()), m_success(other.isOk()) {}
|
||||
|
||||
template <class T2>
|
||||
requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType> const& other)
|
||||
|
||||
requires std::is_copy_constructible_v<value_type> :
|
||||
Result(value_type(other.unwrap()), true) {}
|
||||
|
||||
template <class T2>
|
||||
requires ConvertibleToResult<T2, T> Result(Result<T2, AnyType>&& other)
|
||||
|
||||
requires(!std::is_copy_constructible_v<value_type>) :
|
||||
Result(std::forward<value_type>(other.unwrap()), true) {}
|
||||
|
||||
template <class E2>
|
||||
requires ConvertibleToResult<E2, T> Result(Result<AnyType, E2> const& other)
|
||||
|
||||
requires std::is_copy_constructible_v<value_type> :
|
||||
Result(error_type(other.unwrapErr()), false) {}
|
||||
|
||||
template <class E2>
|
||||
requires ConvertibleToResult<E2, T> Result(Result<AnyType, E2>&& other)
|
||||
|
||||
requires(!std::is_copy_constructible_v<value_type>) :
|
||||
Result(std::forward<error_type>(other.unwrapErr()), false) {}
|
||||
|
||||
value_type unwrap() const requires std::is_copy_constructible_v<value_type> {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
value_type&& unwrap() requires(!std::is_copy_constructible_v<value_type>) {
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
error_type unwrapErr() const requires std::is_copy_constructible_v<error_type> {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
error_type&& unwrapErr() requires(!std::is_copy_constructible_v<error_type>) {
|
||||
return std::move(m_value);
|
||||
}
|
||||
|
||||
explicit operator bool() const requires(!std::is_same_v<T, bool>) {
|
||||
explicit operator bool() const requires(
|
||||
!std::is_same_v<T, bool> &&
|
||||
!std::is_same_v<E, bool>
|
||||
) {
|
||||
return this->isOk();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T = DefaultValue, class E = AnyType>
|
||||
|
||||
requires std::is_copy_constructible_v<T> Result<T, E> Ok(T value = T()) {
|
||||
requires std::is_copy_constructible_v<T>
|
||||
Result<T, E> Ok(T value = T()) {
|
||||
return Result<T, E>(value);
|
||||
}
|
||||
|
||||
template <class T = DefaultValue, class E = AnyType>
|
||||
|
||||
requires(!std::is_copy_constructible_v<T>) Result<T, E> Ok(T&& value) {
|
||||
requires(!std::is_copy_constructible_v<T>)
|
||||
Result<T, E> Ok(T&& value) {
|
||||
return Result<T, E>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
template <class E = DefaultError, class T = AnyType>
|
||||
|
||||
requires std::is_copy_constructible_v<E> Result<T, E> Err(E error = E()) {
|
||||
return Result<T, E>(error);
|
||||
requires std::is_copy_constructible_v<E>
|
||||
Result<T, E> Err(E error) {
|
||||
return Result<T, E>(error, std::monostate());
|
||||
}
|
||||
|
||||
template <class E = DefaultError, class T = AnyType>
|
||||
|
||||
requires(!std::is_copy_constructible_v<E>) Result<T, E> Err(E&& error) {
|
||||
return Result<T, E>(std::forward<E>(error));
|
||||
requires(!std::is_copy_constructible_v<E>)
|
||||
Result<T, E> Err(E&& error) {
|
||||
return Result<T, E>(std::forward<E>(error), std::monostate());
|
||||
}
|
||||
|
||||
#define GEODE_UNWRAP_INTO(into, ...) \
|
||||
auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \
|
||||
if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \
|
||||
return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
|
||||
} \
|
||||
into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap())
|
||||
|
||||
#define GEODE_UNWRAP(...) \
|
||||
{ \
|
||||
#define GEODE_UNWRAP_INTO(into, ...) \
|
||||
auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \
|
||||
if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \
|
||||
return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
|
||||
} \
|
||||
}
|
||||
into = std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrap())
|
||||
|
||||
#define GEODE_UNWRAP(...) \
|
||||
{ \
|
||||
auto GEODE_CONCAT(unwrap_res_, __LINE__) = (__VA_ARGS__); \
|
||||
if (GEODE_CONCAT(unwrap_res_, __LINE__).isErr()) { \
|
||||
return Err(std::move(GEODE_CONCAT(unwrap_res_, __LINE__).unwrapErr())); \
|
||||
} \
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
|
19
loader/src/cocos2d-ext/CCArray.cpp
Normal file
19
loader/src/cocos2d-ext/CCArray.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include <cocos2d.h>
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4273)
|
||||
|
||||
CCObject* CCArray::firstObject() {
|
||||
if (data->num) {
|
||||
return data->arr[0];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CCArray::removeFirstObject(bool bReleaseObj) {
|
||||
this->removeObjectAtIndex(0, bReleaseObj);
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
|
@ -75,11 +75,6 @@ void CCFileUtils::updatePaths() {
|
|||
this->addSearchPath(path.c_str());
|
||||
}
|
||||
DONT_ADD_PATHS = false;
|
||||
|
||||
log::debug("Search Paths: {}", m_searchPathArray.size());
|
||||
for (auto& path : m_searchPathArray) {
|
||||
log::debug("Path: {}", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
|
2008
loader/src/cocos2d-ext/zip/zip.cpp
Normal file
2008
loader/src/cocos2d-ext/zip/zip.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -33,30 +33,23 @@ static void addUpdateIcon(char const* icon = "updates-available.png"_spr) {
|
|||
|
||||
static void updateIndexProgress(UpdateStatus status, std::string const& info, uint8_t progress) {
|
||||
if (status == UpdateStatus::Failed) {
|
||||
g_indexUpdateNotif->hide();
|
||||
g_indexUpdateNotif->setIcon(NotificationIcon::Error);
|
||||
g_indexUpdateNotif->setString("Index update failed");
|
||||
g_indexUpdateNotif->setTime(2.f);
|
||||
g_indexUpdateNotif = nullptr;
|
||||
NotificationBuilder()
|
||||
.title("Index Update")
|
||||
.text("Index update failed :(")
|
||||
.icon("info-alert.png"_spr)
|
||||
.show();
|
||||
addUpdateIcon("updates-failed.png"_spr);
|
||||
}
|
||||
|
||||
if (status == UpdateStatus::Finished) {
|
||||
g_indexUpdateNotif->hide();
|
||||
g_indexUpdateNotif = nullptr;
|
||||
g_indexUpdateNotif->setIcon(NotificationIcon::Success);
|
||||
if (Index::get()->areUpdatesAvailable()) {
|
||||
NotificationBuilder()
|
||||
.title("Updates available")
|
||||
.text("Some mods have updates available!")
|
||||
.icon("updates-available.png"_spr)
|
||||
.clicked([](auto) -> void {
|
||||
ModListLayer::scene();
|
||||
})
|
||||
.show();
|
||||
g_indexUpdateNotif->setString("Updates Available");
|
||||
addUpdateIcon();
|
||||
}
|
||||
} else {
|
||||
g_indexUpdateNotif->setString("Everything Up-to-Date");
|
||||
}
|
||||
g_indexUpdateNotif->setTime(2.f);
|
||||
g_indexUpdateNotif = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,12 +100,15 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
|
|||
}
|
||||
|
||||
// show if some mods failed to load
|
||||
auto failed = Loader::get()->getFailedMods();
|
||||
if (failed.size()) {
|
||||
NotificationBuilder()
|
||||
.title("Failed to load")
|
||||
.text("Some mods failed to load")
|
||||
.show();
|
||||
static bool shownFailedNotif = false;
|
||||
if (!shownFailedNotif) {
|
||||
shownFailedNotif = true;
|
||||
if (Loader::get()->getFailedMods().size()) {
|
||||
Notification::create(
|
||||
"Some mods failed to load",
|
||||
NotificationIcon::Error
|
||||
)->show();
|
||||
}
|
||||
}
|
||||
|
||||
// show crash info
|
||||
|
@ -140,12 +136,10 @@ struct CustomMenuLayer : Modify<CustomMenuLayer, MenuLayer> {
|
|||
|
||||
// update mods index
|
||||
if (!g_indexUpdateNotif && !Index::get()->isIndexUpdated()) {
|
||||
g_indexUpdateNotif = NotificationBuilder()
|
||||
.title("Index Update")
|
||||
.text("Updating index...")
|
||||
.loading()
|
||||
.stay()
|
||||
.show();
|
||||
g_indexUpdateNotif = Notification::create(
|
||||
"Updating Index", NotificationIcon::Loading, 0
|
||||
);
|
||||
g_indexUpdateNotif->show();
|
||||
|
||||
Index::get()->updateIndex(updateIndexProgress);
|
||||
}
|
||||
|
|
|
@ -181,7 +181,10 @@ Result<ModInfo> ModInfo::createFromGeodeZip(file::Unzip& unzip) {
|
|||
}
|
||||
|
||||
// Read mod.json & parse if possible
|
||||
GEODE_UNWRAP_INTO(auto jsonData, unzip.extract("mod.json"));
|
||||
GEODE_UNWRAP_INTO(
|
||||
auto jsonData,
|
||||
unzip.extract("mod.json").expect("Unable to read mod.json: {error}")
|
||||
);
|
||||
ModJson json;
|
||||
try {
|
||||
json = ModJson::parse(std::string(jsonData.begin(), jsonData.end()));
|
||||
|
@ -197,7 +200,10 @@ Result<ModInfo> ModInfo::createFromGeodeZip(file::Unzip& unzip) {
|
|||
auto info = res.unwrap();
|
||||
info.m_path = unzip.getPath();
|
||||
|
||||
GEODE_UNWRAP(info.addSpecialFiles(unzip));
|
||||
GEODE_UNWRAP(
|
||||
info.addSpecialFiles(unzip)
|
||||
.expect("Unable to add extra files: {error}")
|
||||
);
|
||||
|
||||
return Ok(info);
|
||||
}
|
||||
|
|
|
@ -1,234 +1,110 @@
|
|||
#include <Geode/binding/GameSoundManager.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <Geode/binding/LoadingCircle.hpp>
|
||||
#include <Geode/ui/Notification.hpp>
|
||||
#include <Geode/ui/TextRenderer.hpp>
|
||||
#include <Geode/utils/cocos.hpp>
|
||||
#include <Geode/utils/ranges.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
// todo: make sure notifications dont disappear
|
||||
// off the screen if the user happens to switch
|
||||
// scenes or smth that causes actions from being
|
||||
// run / completed
|
||||
constexpr auto NOTIFICATION_FADEIN = .3f;
|
||||
constexpr auto NOTIFICATION_FADEOUT = 1.f;
|
||||
|
||||
Notification::Notification() {}
|
||||
Ref<CCArray> Notification::s_queue = CCArray::create();
|
||||
|
||||
Notification::~Notification() {
|
||||
CCDirector::sharedDirector()->getTouchDispatcher()->decrementForcePrio(2);
|
||||
}
|
||||
|
||||
void Notification::registerWithTouchDispatcher() {
|
||||
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
|
||||
}
|
||||
|
||||
static bool isHovered(CCNode* node, CCTouch* touch) {
|
||||
auto csize = node->getScaledContentSize();
|
||||
if (CCRect { node->getPositionX() - csize.width / 2, node->getPositionY() - csize.height / 2,
|
||||
csize.width, csize.height }
|
||||
.containsPoint(touch->getLocation())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool shouldHideNotification(CCTouch* touch, NotificationLocation const& location) {
|
||||
static constexpr float const HIDE_THRESHOLD = 20.f;
|
||||
auto dist = touch->getLocation() - touch->getStartLocation();
|
||||
switch (location) {
|
||||
case NotificationLocation::BottomLeft:
|
||||
case NotificationLocation::TopLeft: return dist.x < -HIDE_THRESHOLD;
|
||||
|
||||
case NotificationLocation::BottomRight:
|
||||
case NotificationLocation::TopRight: return dist.x > HIDE_THRESHOLD;
|
||||
|
||||
case NotificationLocation::BottomCenter: return dist.y < -HIDE_THRESHOLD;
|
||||
|
||||
case NotificationLocation::TopCenter: return dist.y > HIDE_THRESHOLD;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Notification::ccTouchMoved(CCTouch* touch, CCEvent* event) {
|
||||
auto dist = touch->getLocation() - touch->getStartLocation();
|
||||
switch (m_location) {
|
||||
case NotificationLocation::BottomLeft:
|
||||
case NotificationLocation::TopLeft:
|
||||
this->setPositionX(m_posAtTouchStart.x + dist.x);
|
||||
if (this->getPositionX() > m_showDest.x) {
|
||||
this->setPositionX(m_showDest.x);
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::BottomRight:
|
||||
case NotificationLocation::TopRight:
|
||||
this->setPositionX(m_posAtTouchStart.x + dist.x);
|
||||
if (this->getPositionX() < m_showDest.x) {
|
||||
this->setPositionX(m_showDest.x);
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::BottomCenter:
|
||||
this->setPositionY(m_posAtTouchStart.y + dist.y);
|
||||
if (this->getPositionY() > m_showDest.y) {
|
||||
this->setPositionY(m_showDest.y);
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::TopCenter:
|
||||
this->setPositionY(m_posAtTouchStart.y + dist.y);
|
||||
if (this->getPositionY() < m_showDest.y) {
|
||||
this->setPositionY(m_showDest.y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
auto clicking = !shouldHideNotification(touch, m_location);
|
||||
if (m_clicking != clicking) {
|
||||
m_clicking = clicking;
|
||||
this->animateClicking();
|
||||
}
|
||||
auto hovered = isHovered(this, touch);
|
||||
if (m_hovered != hovered) {
|
||||
m_hovered = hovered;
|
||||
if (hovered) {
|
||||
m_bg->setColor({ 150, 150, 150 });
|
||||
}
|
||||
else {
|
||||
m_bg->setColor({ 255, 255, 255 });
|
||||
}
|
||||
this->animateClicking();
|
||||
}
|
||||
}
|
||||
|
||||
bool Notification::ccTouchBegan(CCTouch* touch, CCEvent* event) {
|
||||
if (!isHovered(this, touch)) {
|
||||
bool Notification::init(std::string const& text, CCSprite* icon, float time) {
|
||||
if (!CCNodeRGBA::init())
|
||||
return false;
|
||||
}
|
||||
m_bg->setColor({ 150, 150, 150 });
|
||||
this->stopAllActions();
|
||||
m_posAtTouchStart = this->getPosition();
|
||||
m_clicking = true;
|
||||
m_hovered = true;
|
||||
this->animateClicking();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notification::ccTouchEnded(CCTouch* touch, CCEvent* event) {
|
||||
m_clicking = false;
|
||||
m_hovered = false;
|
||||
this->animateClicking();
|
||||
m_bg->setColor({ 255, 255, 255 });
|
||||
if (shouldHideNotification(touch, m_location)) {
|
||||
return this->hide();
|
||||
}
|
||||
if (isHovered(this, touch)) {
|
||||
this->animateIn();
|
||||
this->clicked();
|
||||
}
|
||||
}
|
||||
|
||||
void Notification::clicked() {
|
||||
if (m_callback) {
|
||||
m_callback(this);
|
||||
if (m_hideOnClicked) {
|
||||
this->animateOutClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Notification::init(
|
||||
Mod* owner, std::string const& title, std::string const& text, CCNode* icon, char const* bg,
|
||||
std::function<void(Notification*)> callback, bool hideOnClick
|
||||
) {
|
||||
if (!CCLayer::init()) return false;
|
||||
|
||||
m_owner = owner;
|
||||
m_callback = callback;
|
||||
m_hideOnClicked = hideOnClick;
|
||||
|
||||
// m_labels is Ref so no need to call
|
||||
// retain manually
|
||||
m_labels = CCArray::create();
|
||||
|
||||
m_bg = CCScale9Sprite::create(bg);
|
||||
m_bg->setScale(.6f);
|
||||
|
||||
// using TextRenderer to create the text
|
||||
// so it automatically wraps the lines
|
||||
auto renderer = TextRenderer::create();
|
||||
renderer->begin(this, CCPointZero, { 120.f, 20.f });
|
||||
|
||||
renderer->pushBMFont("chatFont.fnt");
|
||||
renderer->pushScale(.4f);
|
||||
for (auto& label : renderer->renderString(text + "\n(from " + owner->getName() + ")")) {
|
||||
m_labels->addObject(label.m_node);
|
||||
}
|
||||
|
||||
renderer->end();
|
||||
renderer->release();
|
||||
|
||||
// add icon
|
||||
float iconSpace = .0f;
|
||||
if (icon) {
|
||||
m_icon = icon;
|
||||
iconSpace = 20.f;
|
||||
m_icon->setPosition({ -m_obContentSize.width / 2 + iconSpace / 2, .0f });
|
||||
limitNodeSize(m_icon, { iconSpace - 8.f, m_obContentSize.height - 8.f }, 1.f, .1f);
|
||||
this->addChild(m_icon);
|
||||
}
|
||||
|
||||
// add title
|
||||
if (title.size()) {
|
||||
m_title = CCLabelBMFont::create(title.c_str(), "goldFont.fnt");
|
||||
m_title->limitLabelWidth(m_obContentSize.width - iconSpace, .4f, .01f);
|
||||
m_obContentSize.height += 14;
|
||||
m_title->setPosition(
|
||||
-m_obContentSize.width / 2 + iconSpace, m_obContentSize.height / 2 - 6.f
|
||||
);
|
||||
m_title->setAnchorPoint({ .0f, .5f });
|
||||
this->addChild(m_title);
|
||||
}
|
||||
|
||||
// move text content if an icon is present
|
||||
m_obContentSize.width += iconSpace;
|
||||
m_icon->setPositionX(m_icon->getPositionX() - iconSpace / 2);
|
||||
m_title->setPositionX(m_title->getPositionX() - iconSpace / 2);
|
||||
for (auto label : CCArrayExt<CCNode>(m_labels)) {
|
||||
label->setPosition(
|
||||
label->getPositionX() + iconSpace - m_obContentSize.width / 2,
|
||||
label->getPositionY() - m_obContentSize.height / 2 + 2.f
|
||||
);
|
||||
}
|
||||
|
||||
// fit bg to content
|
||||
m_bg->setContentSize(m_obContentSize / m_bg->getScale() + CCSize { 6.f, 6.f });
|
||||
m_bg->setPosition(0, 0);
|
||||
m_bg->setZOrder(-1);
|
||||
|
||||
m_time = time;
|
||||
|
||||
m_bg = CCScale9Sprite::create("square02b_small.png", { 0, 0, 40, 40 });
|
||||
m_bg->setColor({ 0, 0, 0 });
|
||||
this->addChild(m_bg);
|
||||
|
||||
// set anchor point to middle so the
|
||||
// notification properly scales
|
||||
this->setAnchorPoint({ .0f, .0f });
|
||||
this->setVisible(false);
|
||||
m_label = CCLabelBMFont::create(text.c_str(), "bigFont.fnt");
|
||||
m_label->setScale(.6f);
|
||||
m_bg->addChild(m_label);
|
||||
|
||||
// make sure ~CCLayer properly removes
|
||||
// the notification from touch dispatcher
|
||||
this->setTouchEnabled(true);
|
||||
if (m_icon = icon) {
|
||||
m_bg->addChild(icon);
|
||||
}
|
||||
|
||||
// make this notification the most important
|
||||
// touch fella on the screen
|
||||
CCDirector::sharedDirector()->getTouchDispatcher()->incrementForcePrio(2);
|
||||
this->registerWithTouchDispatcher();
|
||||
this->setScale(.75f);
|
||||
this->updateLayout();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notification::updateLayout() {
|
||||
constexpr auto PADDING = 5.f;
|
||||
auto size = m_label->getScaledContentSize();
|
||||
|
||||
float spaceForIcon = 0.f;
|
||||
if (m_icon) {
|
||||
limitNodeSize(m_icon, { size.height, size.height }, 1.f, .1f);
|
||||
spaceForIcon += m_icon->getScaledContentSize().width + PADDING;
|
||||
}
|
||||
size += CCSize { spaceForIcon + PADDING * 2, PADDING * 2 };
|
||||
m_bg->setContentSize(size);
|
||||
|
||||
if (m_icon) {
|
||||
m_icon->setPosition({ size.height / 2, size.height / 2 });
|
||||
m_label->setPosition(size / 2 + CCSize { spaceForIcon / 2, .0f });
|
||||
} else {
|
||||
m_label->setPosition(size / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void Notification::showNextNotification() {
|
||||
m_showing = false;
|
||||
SceneManager::get()->forget(this);
|
||||
// remove self from front of queue
|
||||
s_queue->removeFirstObject();
|
||||
if (auto obj = s_queue->firstObject()) {
|
||||
as<Notification*>(obj)->show();
|
||||
}
|
||||
this->removeFromParent();
|
||||
}
|
||||
|
||||
CCSprite* Notification::createIcon(NotificationIcon icon) {
|
||||
switch (icon) {
|
||||
default:
|
||||
case NotificationIcon::None: {
|
||||
return nullptr;
|
||||
} break;
|
||||
|
||||
case NotificationIcon::Loading: {
|
||||
auto icon = CCSprite::create("loadingCircle.png");
|
||||
icon->runAction(CCRepeatForever::create(
|
||||
CCRotateBy::create(1.f, 360.f)
|
||||
));
|
||||
icon->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
return icon;
|
||||
} break;
|
||||
|
||||
case NotificationIcon::Success: {
|
||||
return CCSprite::createWithSpriteFrameName("GJ_completesIcon_001.png");
|
||||
} break;
|
||||
|
||||
case NotificationIcon::Warning: {
|
||||
return CCSprite::createWithSpriteFrameName("info-alert.png"_spr);
|
||||
} break;
|
||||
|
||||
case NotificationIcon::Error: {
|
||||
return CCSprite::createWithSpriteFrameName("GJ_deleteIcon_001.png");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
Notification* Notification::create(
|
||||
Mod* owner, std::string const& title, std::string const& text, CCNode* icon, char const* bg,
|
||||
std::function<void(Notification*)> callback, bool hideOnClick
|
||||
std::string const& text,
|
||||
NotificationIcon icon,
|
||||
float time
|
||||
) {
|
||||
return Notification::create(text, createIcon(icon), time);
|
||||
}
|
||||
|
||||
Notification* Notification::create(std::string const& text, CCSprite* icon, float time) {
|
||||
auto ret = new Notification();
|
||||
if (ret && ret->init(owner, title, text, icon, bg, callback, hideOnClick)) {
|
||||
if (ret && ret->init(text, icon, time)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
|
@ -236,198 +112,89 @@ Notification* Notification::create(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void Notification::showForReal() {
|
||||
if (!m_pParent) {
|
||||
CCDirector::sharedDirector()->getRunningScene()->addChild(this);
|
||||
}
|
||||
SceneManager::get()->keepAcrossScenes(this);
|
||||
// haha i am incredibly mature
|
||||
this->setZOrder(0xB00B1E5);
|
||||
this->setVisible(true);
|
||||
|
||||
static constexpr float const pad = 15.f;
|
||||
|
||||
float xMovement = .0f, yMovement = .0f;
|
||||
float xStart = .0f, yStart = .0f;
|
||||
switch (m_location) {
|
||||
case NotificationLocation::TopLeft:
|
||||
{
|
||||
xMovement = this->getScaledContentSize().width + pad * 2;
|
||||
xStart = -this->getScaledContentSize().width / 2 - pad;
|
||||
yStart = m_pParent->getContentSize().height - pad -
|
||||
this->getScaledContentSize().height / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::BottomLeft:
|
||||
{
|
||||
xMovement = this->getScaledContentSize().width + pad * 2;
|
||||
xStart = -this->getScaledContentSize().width / 2 - pad;
|
||||
yStart = pad + this->getScaledContentSize().height / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::TopRight:
|
||||
{
|
||||
xMovement = -this->getScaledContentSize().width - pad * 2;
|
||||
xStart = m_pParent->getContentSize().width +
|
||||
this->getScaledContentSize().width / 2 + pad;
|
||||
yStart = m_pParent->getContentSize().height - pad -
|
||||
this->getScaledContentSize().height / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::BottomRight:
|
||||
{
|
||||
xMovement = -this->getScaledContentSize().width - pad * 2;
|
||||
xStart = m_pParent->getContentSize().width +
|
||||
this->getScaledContentSize().width / 2 + pad;
|
||||
yStart = pad + this->getScaledContentSize().height / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::BottomCenter:
|
||||
{
|
||||
yMovement = pad * 2 + this->getScaledContentSize().height;
|
||||
xStart = m_pParent->getContentSize().width / 2;
|
||||
yStart = -pad - this->getScaledContentSize().height / 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case NotificationLocation::TopCenter:
|
||||
{
|
||||
yMovement = -pad * 2 - this->getScaledContentSize().height;
|
||||
xStart = m_pParent->getContentSize().width / 2;
|
||||
yStart = m_pParent->getContentSize().height + pad +
|
||||
this->getScaledContentSize().height / 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_hideDest = CCPoint { xStart, yStart };
|
||||
m_showDest = CCPoint { xStart + xMovement, yStart + yMovement };
|
||||
|
||||
GameSoundManager::sharedManager()->playEffect("newNotif03.ogg"_spr, 1.f, 1.f, 1.f);
|
||||
|
||||
this->setPosition(xStart, yStart);
|
||||
this->animateIn();
|
||||
void Notification::setString(std::string const& text) {
|
||||
m_label->setString(text.c_str());
|
||||
this->updateLayout();
|
||||
}
|
||||
|
||||
void Notification::hide() {
|
||||
// if this notification has already been hidden,
|
||||
// don't do anything
|
||||
if (m_hiding || !NotificationManager::get()->isInQueue(this)) {
|
||||
return;
|
||||
void Notification::setIcon(NotificationIcon icon) {
|
||||
this->setIcon(createIcon(icon));
|
||||
}
|
||||
|
||||
void Notification::setIcon(cocos2d::CCSprite* icon) {
|
||||
if (m_icon) {
|
||||
m_icon->removeFromParent();
|
||||
}
|
||||
GameSoundManager::sharedManager()->playEffect("byeNotif00.ogg"_spr, 1.f, 1.f, 1.f);
|
||||
m_hiding = true;
|
||||
this->animateOut();
|
||||
if (m_icon = icon) {
|
||||
m_bg->addChild(icon);
|
||||
}
|
||||
this->updateLayout();
|
||||
}
|
||||
|
||||
void Notification::setTime(float time) {
|
||||
m_time = time;
|
||||
this->wait();
|
||||
}
|
||||
|
||||
void Notification::animateIn() {
|
||||
this->runAction(CCEaseInOut::create(CCMoveTo::create(.3f, m_showDest), 6.f));
|
||||
m_label->setOpacity(0);
|
||||
m_icon->setOpacity(0);
|
||||
m_bg->setOpacity(0);
|
||||
m_label->runAction(CCFadeTo::create(NOTIFICATION_FADEIN, 255));
|
||||
m_icon->runAction(CCFadeTo::create(NOTIFICATION_FADEIN, 255));
|
||||
m_bg->runAction(CCFadeTo::create(NOTIFICATION_FADEIN, 150));
|
||||
}
|
||||
|
||||
void Notification::animateOut() {
|
||||
m_label->runAction(CCFadeTo::create(NOTIFICATION_FADEOUT, 0));
|
||||
m_icon->runAction(CCFadeTo::create(NOTIFICATION_FADEOUT, 0));
|
||||
m_bg->runAction(CCFadeTo::create(NOTIFICATION_FADEOUT, 0));
|
||||
}
|
||||
|
||||
void Notification::show() {
|
||||
if (!m_showing) {
|
||||
if (!s_queue->containsObject(this)) {
|
||||
s_queue->addObject(this);
|
||||
}
|
||||
if (s_queue->firstObject() != this) {
|
||||
return;
|
||||
}
|
||||
if (!this->getParent()) {
|
||||
auto winSize = CCDirector::get()->getWinSize();
|
||||
this->setPosition(winSize.width / 2, winSize.height / 4);
|
||||
CCDirector::get()->getRunningScene()->addChild(this);
|
||||
}
|
||||
SceneManager::get()->keepAcrossScenes(this);
|
||||
m_showing = true;
|
||||
}
|
||||
this->runAction(CCSequence::create(
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::animateIn)),
|
||||
// wait for fade-in to finish
|
||||
CCDelayTime::create(NOTIFICATION_FADEIN),
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::wait)),
|
||||
nullptr
|
||||
));
|
||||
}
|
||||
|
||||
void Notification::wait() {
|
||||
this->stopAllActions();
|
||||
if (m_time) {
|
||||
this->runAction(CCSequence::create(
|
||||
CCDelayTime::create(m_time),
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::hide)), nullptr
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::hide)),
|
||||
nullptr
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void Notification::animateOut() {
|
||||
void Notification::hide() {
|
||||
this->stopAllActions();
|
||||
this->runAction(CCSequence::create(
|
||||
CCEaseInOut::create(CCMoveTo::create(.3f, { m_hideDest }), 6.f),
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::hidden)), nullptr
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::animateOut)),
|
||||
// wait for fade-out to finish
|
||||
CCDelayTime::create(NOTIFICATION_FADEOUT),
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::showNextNotification)),
|
||||
nullptr
|
||||
));
|
||||
}
|
||||
|
||||
void Notification::animateOutClicked() {
|
||||
this->runAction(CCSequence::create(
|
||||
CCEaseBackIn::create(CCScaleTo::create(.2f, .0f)),
|
||||
CCCallFunc::create(this, callfunc_selector(Notification::hidden)), nullptr
|
||||
));
|
||||
}
|
||||
|
||||
void Notification::animateClicking() {
|
||||
this->runAction(CCEaseInOut::create(
|
||||
CCScaleTo::create(.1f, ((m_clicking && m_hovered) ? m_targetScale * .9f : m_targetScale)),
|
||||
2.f
|
||||
));
|
||||
}
|
||||
|
||||
void Notification::show(NotificationLocation location, float time) {
|
||||
if (location == NotificationLocation::TopCenter) {
|
||||
// the notification is larger at top center to
|
||||
// be more easily readable on mobile
|
||||
this->setScale(1.5f);
|
||||
}
|
||||
else {
|
||||
this->setScale(1.2f);
|
||||
}
|
||||
m_targetScale = m_fScaleX;
|
||||
|
||||
m_time = time;
|
||||
m_location = location;
|
||||
NotificationManager::get()->push(this);
|
||||
}
|
||||
|
||||
void Notification::hidden() {
|
||||
NotificationManager::get()->pop(this);
|
||||
this->removeFromParent();
|
||||
SceneManager::get()->forget(this);
|
||||
}
|
||||
|
||||
NotificationBuilder Notification::build() {
|
||||
return std::move(NotificationBuilder());
|
||||
}
|
||||
|
||||
Notification* NotificationBuilder::show() {
|
||||
auto icon = m_iconNode;
|
||||
if (!icon && m_icon.size()) {
|
||||
icon = CCSprite::create(m_icon.c_str());
|
||||
if (!icon) icon = CCSprite::createWithSpriteFrameName(m_icon.c_str());
|
||||
}
|
||||
auto notif = Notification::create(
|
||||
m_owner, m_title, m_text, icon, m_bg.c_str(), m_callback, m_hideOnClick
|
||||
);
|
||||
notif->show(m_location, m_time);
|
||||
return notif;
|
||||
}
|
||||
|
||||
bool NotificationManager::isInQueue(Notification* notification) {
|
||||
auto location = notification->m_location;
|
||||
if (m_notifications.count(location)) {
|
||||
return utils::ranges::contains(m_notifications.at(location), Ref(notification));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NotificationManager::push(Notification* notification) {
|
||||
auto location = notification->m_location;
|
||||
if (!m_notifications.count(location)) {
|
||||
m_notifications[location] = { notification };
|
||||
notification->showForReal();
|
||||
}
|
||||
else {
|
||||
m_notifications[location].push_back(notification);
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::pop(Notification* notification) {
|
||||
auto location = notification->m_location;
|
||||
if (m_notifications.count(location)) {
|
||||
auto ref = Ref(notification);
|
||||
ranges::remove(m_notifications.at(location), ref);
|
||||
if (!m_notifications.at(location).size()) {
|
||||
m_notifications.erase(location);
|
||||
}
|
||||
else {
|
||||
m_notifications.at(location).front()->showForReal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotificationManager* NotificationManager::get() {
|
||||
static auto inst = new NotificationManager;
|
||||
return inst;
|
||||
}
|
||||
|
|
|
@ -295,8 +295,7 @@ template <class Json>
|
|||
void JsonMaybeObject<Json>::checkUnknownKeys() {
|
||||
for (auto& [key, _] : self().m_json.items()) {
|
||||
if (!m_knownKeys.count(key)) {
|
||||
// log::debug(self().m_hierarchy + " contains unknown key \"" + key + "\"");
|
||||
log::debug("{} contains unknown key \"{}\"", self().m_hierarchy, key);
|
||||
log::warn("{} contains unknown key \"{}\"", self().m_hierarchy, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <Geode/utils/file.hpp>
|
||||
#include <Geode/utils/string.hpp>
|
||||
#include <Geode/utils/map.hpp>
|
||||
#include <Geode/loader/Log.hpp>
|
||||
#include <fstream>
|
||||
#include <../support/zip_support/ZipUtils.h>
|
||||
#include <../support/zip_support/ioapi.h>
|
||||
|
@ -155,7 +156,7 @@ public:
|
|||
while (true) {
|
||||
// Read file and add to entries
|
||||
unz_file_pos pos;
|
||||
if (unzGetFilePos(m_zip, &pos)) {
|
||||
if (unzGetFilePos(m_zip, &pos) == UNZ_OK) {
|
||||
m_entries.insert({
|
||||
fileName, ZipEntry {
|
||||
.m_pos = pos,
|
||||
|
@ -166,8 +167,8 @@ public:
|
|||
}
|
||||
// Read next file, or break on error
|
||||
if (unzGoToNextFile64(
|
||||
m_zip, &fileInfo, fileName, sizeof(fileName) - 1)
|
||||
) {
|
||||
m_zip, &fileInfo, fileName, sizeof(fileName) - 1
|
||||
) != UNZ_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -181,16 +182,16 @@ public:
|
|||
|
||||
auto entry = m_entries.at(name);
|
||||
|
||||
if (!unzGoToFilePos(m_zip, &entry.m_pos)) {
|
||||
if (unzGoToFilePos(m_zip, &entry.m_pos) != UNZ_OK) {
|
||||
return Err("Unable to navigate to entry");
|
||||
}
|
||||
if (!unzOpenCurrentFile(m_zip)) {
|
||||
if (unzOpenCurrentFile(m_zip) != UNZ_OK) {
|
||||
return Err("Unable to open entry");
|
||||
}
|
||||
byte_array res;
|
||||
res.reserve(entry.m_uncompressedSize);
|
||||
res.resize(entry.m_uncompressedSize);
|
||||
auto size = unzReadCurrentFile(m_zip, res.data(), entry.m_uncompressedSize);
|
||||
if (size == 0 || size == entry.m_uncompressedSize) {
|
||||
if (size < 0 || size != entry.m_uncompressedSize) {
|
||||
return Err("Unable to extract entry");
|
||||
}
|
||||
unzCloseCurrentFile(m_zip);
|
||||
|
@ -232,6 +233,7 @@ Result<Unzip> Unzip::create(Path const& file) {
|
|||
}
|
||||
auto impl = new UnzipImpl(zip, file);
|
||||
if (!impl->loadEntries()) {
|
||||
delete impl;
|
||||
return Err("Unable to read zip file");
|
||||
}
|
||||
return Ok(Unzip(impl));
|
||||
|
|
Loading…
Reference in a new issue