parent
6bd5e6f6e2
commit
3afa7ed4e3
|
@ -14,6 +14,7 @@
|
|||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -24,8 +25,8 @@ EventHandler::EventHandler()
|
|||
//create a event to create handlers
|
||||
_eventHandlerStatic = this;
|
||||
|
||||
_menu = new MenuHandler("Nextcloud");
|
||||
_nextcloud = new Nextcloud();
|
||||
_menu = std::unique_ptr<MenuHandler>(new MenuHandler("Nextcloud"));
|
||||
_nextcloud = std::unique_ptr<Nextcloud>(new Nextcloud());
|
||||
_loginView = nullptr;
|
||||
_listView = nullptr;
|
||||
|
||||
|
@ -33,22 +34,17 @@ EventHandler::EventHandler()
|
|||
{
|
||||
if (_nextcloud->login())
|
||||
{
|
||||
_listView = new ListView(_menu->getContentRect(), _nextcloud->getItems());
|
||||
_listView = std::unique_ptr<ListView>(new ListView(_menu->getContentRect(), _nextcloud->getItems()));
|
||||
FullUpdate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_loginView = new LoginView(_menu->getContentRect());
|
||||
_loginView = std::unique_ptr<LoginView>(new LoginView(_menu->getContentRect()));
|
||||
_loginView->drawLoginView();
|
||||
|
||||
FullUpdate();
|
||||
}
|
||||
EventHandler::~EventHandler()
|
||||
{
|
||||
delete _nextcloud;
|
||||
delete _listView;
|
||||
delete _menu;
|
||||
}
|
||||
|
||||
int EventHandler::eventDistributor(const int type, const int par1, const int par2)
|
||||
{
|
||||
|
@ -101,9 +97,9 @@ void EventHandler::mainMenuHandler(const int index)
|
|||
return;
|
||||
}
|
||||
_nextcloud->logout();
|
||||
delete _listView;
|
||||
_listView = nullptr;
|
||||
_loginView = new LoginView(_menu->getContentRect());
|
||||
_listView.reset();
|
||||
|
||||
_loginView = std::unique_ptr<LoginView>(new LoginView(_menu->getContentRect()));
|
||||
_loginView->drawLoginView();
|
||||
FullUpdate();
|
||||
break;
|
||||
|
@ -133,15 +129,14 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
|
|||
if (_nextcloud->getItems()[itemID].getType() == Itemtype::IFOLDER)
|
||||
{
|
||||
FillAreaRect(_menu->getContentRect(), WHITE);
|
||||
irect loadingScreenRect = iRect(_menu->getContentRect()->w / 2 - 125, _menu->getContentRect()->h / 2 - 50, 250, 100, ALIGN_CENTER);
|
||||
DrawTextRect2(&loadingScreenRect, "Loading...");
|
||||
PartialUpdate(loadingScreenRect.x, loadingScreenRect.y, loadingScreenRect.w, loadingScreenRect.h);
|
||||
_menu->drawLoadingScreen();
|
||||
|
||||
string tempPath = _nextcloud->getItems()[itemID].getPath();
|
||||
|
||||
if (!tempPath.empty())
|
||||
_nextcloud->getDataStructure(tempPath);
|
||||
|
||||
_listView.reset(new ListView(_menu->getContentRect(), _nextcloud->getItems()));
|
||||
_listView->drawHeader(tempPath.substr(NEXTCLOUD_ROOT_PATH.length()));
|
||||
}
|
||||
else
|
||||
|
@ -185,9 +180,6 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
|
|||
}
|
||||
}
|
||||
|
||||
delete _listView;
|
||||
_listView = new ListView(_menu->getContentRect(), _nextcloud->getItems());
|
||||
|
||||
PartialUpdate(_menu->getContentRect()->x, _menu->getContentRect()->y, _menu->getContentRect()->w, _menu->getContentRect()->h);
|
||||
|
||||
return 1;
|
||||
|
@ -198,8 +190,8 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
|
|||
{
|
||||
if (_nextcloud->login(_loginView->getURL(), _loginView->getUsername(), _loginView->getPassword()))
|
||||
{
|
||||
_listView = new ListView(_menu->getContentRect(), _nextcloud->getItems());
|
||||
delete _loginView;
|
||||
_listView = std::unique_ptr<ListView>(new ListView(_menu->getContentRect(), _nextcloud->getItems()));
|
||||
_loginView.reset();
|
||||
FullUpdate();
|
||||
}
|
||||
return 1;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "listView.h"
|
||||
#include "loginView.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
const string LOG_PATH = "/mnt/ext1/system/config/nextcloud";
|
||||
|
||||
class EventHandler
|
||||
|
@ -24,11 +26,6 @@ public:
|
|||
*/
|
||||
EventHandler();
|
||||
|
||||
/**
|
||||
* Destructor destroys pointer to game and menu
|
||||
*/
|
||||
~EventHandler();
|
||||
|
||||
/**
|
||||
* Handles events and redirects them
|
||||
*
|
||||
|
@ -41,11 +38,10 @@ public:
|
|||
|
||||
private:
|
||||
static EventHandler *_eventHandlerStatic;
|
||||
MenuHandler *_menu;
|
||||
Nextcloud *_nextcloud;
|
||||
ListView *_listView;
|
||||
LoginView *_loginView;
|
||||
|
||||
std::unique_ptr<MenuHandler> _menu;
|
||||
std::unique_ptr<Nextcloud> _nextcloud;
|
||||
std::unique_ptr<ListView> _listView;
|
||||
std::unique_ptr<LoginView> _loginView;
|
||||
|
||||
/**
|
||||
* Functions needed to call C function, redirects to real function
|
||||
|
@ -75,5 +71,7 @@ private:
|
|||
* @return int returns if the event was handled
|
||||
*/
|
||||
int pointerHandler(const int type, const int par1, const int par2);
|
||||
|
||||
static void DialogHandlerStatic(int clicked);
|
||||
};
|
||||
#endif
|
|
@ -10,6 +10,7 @@
|
|||
#include "menuHandler.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -22,25 +23,22 @@ MenuHandler::MenuHandler(const string &name)
|
|||
_panelMenuBeginX = ScreenWidth() - _mainMenuWidth;
|
||||
|
||||
_menuButtonRect = iRect(_mainMenuWidth * 2, _panelMenuBeginY, _mainMenuWidth, _panelMenuHeight, ALIGN_RIGHT);
|
||||
_menuFont = std::unique_ptr<ifont>(OpenFont("LiberationMono-Bold", _panelMenuHeight / 2, 1));
|
||||
|
||||
_menuFont = OpenFont("LiberationMono-Bold", _panelMenuHeight / 2, 1);
|
||||
SetFont(_menuFont, BLACK);
|
||||
|
||||
SetFont(_menuFont.get(), BLACK);
|
||||
DrawTextRect(0, _panelMenuBeginY, ScreenWidth(), _panelMenuHeight, name.c_str(), ALIGN_CENTER);
|
||||
DrawTextRect2(&_menuButtonRect, "Menu");
|
||||
DrawLine(0, _panelMenuHeight - 1, ScreenWidth(), _panelMenuHeight - 1, BLACK);
|
||||
|
||||
_contentRect = iRect(0, _panelMenuHeight, ScreenWidth(), (ScreenHeight() - PanelHeight() - _panelMenuHeight), 0);
|
||||
|
||||
_loadingScreenRect = iRect (_contentRect.w/2-125,_contentRect.h / 2 - 50, 250,100, ALIGN_CENTER);
|
||||
_loadingFont = std::unique_ptr<ifont>(OpenFont("LiberationMono",_loadingScreenRect.h /4 , 1));
|
||||
|
||||
SetHardTimer("PANELUPDATE", panelHandlerStatic, 110000);
|
||||
DrawPanel(NULL, "", NULL, -1);
|
||||
}
|
||||
|
||||
MenuHandler::~MenuHandler()
|
||||
{
|
||||
CloseFont(_menuFont);
|
||||
}
|
||||
|
||||
void MenuHandler::panelHandlerStatic()
|
||||
{
|
||||
DrawPanel(NULL, "", NULL, -1);
|
||||
|
@ -50,14 +48,14 @@ void MenuHandler::panelHandlerStatic()
|
|||
int MenuHandler::createMenu(bool loggedIn, bool workOffline, iv_menuhandler handler)
|
||||
{
|
||||
char *text = "Work offline";
|
||||
if(workOffline)
|
||||
if (workOffline)
|
||||
text = "Work online";
|
||||
|
||||
imenu mainMenu[] =
|
||||
{
|
||||
{ITEM_HEADER, 0, "Menu", NULL},
|
||||
//show logged in
|
||||
{loggedIn ? ITEM_ACTIVE : ITEM_HIDDEN, 101, text , NULL},
|
||||
{loggedIn ? ITEM_ACTIVE : ITEM_HIDDEN, 101, text, NULL},
|
||||
{loggedIn ? ITEM_ACTIVE : ITEM_HIDDEN, 102, "Logout", NULL},
|
||||
//show always
|
||||
{ITEM_ACTIVE, 103, "Exit"},
|
||||
|
@ -75,4 +73,11 @@ int MenuHandler::createMenu(bool loggedIn, bool workOffline, iv_menuhandler hand
|
|||
OpenMenu(mainMenu, 0, _panelMenuBeginX, _panelMenuBeginY, handler);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void MenuHandler::drawLoadingScreen()
|
||||
{
|
||||
SetFont(_loadingFont.get(), BLACK);
|
||||
DrawTextRect2(&_loadingScreenRect, "Loading...");
|
||||
PartialUpdate(_loadingScreenRect.x, _loadingScreenRect.y, _loadingScreenRect.w, _loadingScreenRect.h);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define MENU_HANDLER
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -23,11 +24,6 @@ public:
|
|||
*/
|
||||
MenuHandler(const string &name);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~MenuHandler();
|
||||
|
||||
irect *getContentRect() { return &_contentRect; };
|
||||
irect *getMenuButtonRect() { return &_menuButtonRect; };
|
||||
|
||||
|
@ -40,14 +36,18 @@ public:
|
|||
*/
|
||||
int createMenu(bool loggedIn, bool workOffline, iv_menuhandler handler);
|
||||
|
||||
void drawLoadingScreen();
|
||||
|
||||
private:
|
||||
ifont *_menuFont;
|
||||
std::unique_ptr<ifont> _menuFont;
|
||||
std::unique_ptr<ifont> _loadingFont;
|
||||
|
||||
int _panelMenuBeginX;
|
||||
int _panelMenuBeginY;
|
||||
int _panelMenuHeight;
|
||||
int _mainMenuWidth;
|
||||
irect _menuButtonRect;
|
||||
irect _loadingScreenRect;
|
||||
|
||||
imenu _mainMenu;
|
||||
irect _contentRect;
|
||||
|
|
35
src/main.cpp
35
src/main.cpp
|
@ -1,16 +1,15 @@
|
|||
//------------------------------------------------------------------
|
||||
// main.h
|
||||
//
|
||||
// Author: JuanJakobo
|
||||
// Author: JuanJakobo
|
||||
// Date: 14.06.2020
|
||||
// Description: sets the inkview main handler
|
||||
// Description: sets the inkview main handler
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
#include <inkview.h>
|
||||
#include <eventHandler.h>
|
||||
|
||||
EventHandler* events = nullptr;
|
||||
#include "inkview.h"
|
||||
#include "eventHandler.h"
|
||||
|
||||
EventHandler *events = nullptr;
|
||||
/**
|
||||
* Handles events and redirects them
|
||||
*
|
||||
|
@ -19,29 +18,31 @@ EventHandler* events = nullptr;
|
|||
* @param par2 second argument of the event
|
||||
* @return int returns if the event was handled
|
||||
*/
|
||||
int Inkview_handler(int type, int par1, int par2){
|
||||
|
||||
if(type==EVT_INIT)
|
||||
int Inkview_handler(int type, int par1, int par2)
|
||||
{
|
||||
if (type == EVT_INIT)
|
||||
{
|
||||
events = new EventHandler();
|
||||
return 1;
|
||||
}else if(type==EVT_EXIT || type==EVT_HIDE)
|
||||
}
|
||||
else if (type == EVT_EXIT || type == EVT_HIDE)
|
||||
{
|
||||
delete events;
|
||||
return 1;
|
||||
}else
|
||||
{
|
||||
return events->eventDistributor(type,par1,par2);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return events->eventDistributor(type, par1, par2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(){
|
||||
int main()
|
||||
{
|
||||
|
||||
OpenScreen();
|
||||
SetOrientation(0);
|
||||
SetOrientation(0);
|
||||
InkViewMain(Inkview_handler);
|
||||
return 0;
|
||||
}
|
|
@ -14,16 +14,18 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
ListView::ListView(irect *contentRect, const vector<Item> &items) : _contentRect(contentRect), _items(items)
|
||||
{
|
||||
_font = OpenFont("LiberationMono", 30, 1);
|
||||
SetFont(_font, BLACK);
|
||||
FillAreaRect(_contentRect, WHITE);
|
||||
|
||||
_titleFont = std::unique_ptr<ifont>(OpenFont("LiberationMono", 35, 1));
|
||||
_footerFont = std::unique_ptr<ifont>(OpenFont("LiberationMono", 30, 1));
|
||||
|
||||
_entries.clear();
|
||||
|
||||
int itemCount = 7;
|
||||
|
@ -61,16 +63,12 @@ ListView::ListView(irect *contentRect, const vector<Item> &items) : _contentRect
|
|||
|
||||
ListView::~ListView()
|
||||
{
|
||||
delete _font;
|
||||
}
|
||||
|
||||
void ListView::drawHeader(string headerText)
|
||||
{
|
||||
SetFont(_titleFont.get(), BLACK);
|
||||
headerText = Util::replaceString(headerText,"%20"," ");
|
||||
|
||||
_font = OpenFont("LiberationMono", 35, 1);
|
||||
SetFont(_font, BLACK);
|
||||
|
||||
DrawTextRect(_contentRect->x, _contentRect->y, _contentRect->w, _headerHeight - 1, headerText.c_str(), ALIGN_LEFT);
|
||||
|
||||
int line = (_contentRect->y + _headerHeight) - 2;
|
||||
|
@ -79,8 +77,8 @@ void ListView::drawHeader(string headerText)
|
|||
|
||||
void ListView::drawFooter()
|
||||
{
|
||||
SetFont(_footerFont.get(), WHITE);
|
||||
string footer = Util::valueToString<int>(_shownPage) + "/" + Util::valueToString<int>(_page);
|
||||
SetFont(_font, WHITE);
|
||||
FillAreaRect(&_pageButton, BLACK);
|
||||
DrawTextRect2(&_pageButton, footer.c_str());
|
||||
}
|
||||
|
@ -96,8 +94,6 @@ void ListView::drawEntries()
|
|||
|
||||
int ListView::listClicked(int x, int y)
|
||||
{
|
||||
SetFont(_font, BLACK);
|
||||
|
||||
if (IsInRect(x, y, &_pageButton))
|
||||
{
|
||||
if (_page > 1)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -65,9 +66,8 @@ public:
|
|||
private:
|
||||
irect *_contentRect;
|
||||
const vector<Item> _items;
|
||||
|
||||
ifont *_font;
|
||||
|
||||
std::unique_ptr<ifont> _titleFont;
|
||||
std::unique_ptr<ifont> _footerFont;
|
||||
vector<ListViewEntry> _entries;
|
||||
int _page;
|
||||
int _shownPage;
|
||||
|
|
|
@ -11,32 +11,35 @@
|
|||
#include "listViewEntry.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
ListViewEntry::ListViewEntry(int page, irect rect) : _page(page), _position(rect)
|
||||
{
|
||||
_fontHeight = 30;
|
||||
_entryFont = std::unique_ptr<ifont>(OpenFont("LiberationMono", _fontHeight, 1));
|
||||
_entryFontBold = std::unique_ptr<ifont>(OpenFont("LiberationMono-Bold", _fontHeight, 1));
|
||||
}
|
||||
|
||||
void ListViewEntry::draw(const Item &item)
|
||||
{
|
||||
int fontHeight = 30;
|
||||
_font = OpenFont("LiberationMono", fontHeight, 1);
|
||||
SetFont(_font, BLACK);
|
||||
SetFont(_entryFontBold.get(), BLACK);
|
||||
DrawTextRect(_position.x, _position.y, _position.w, _fontHeight, item.getTitle().c_str(), ALIGN_LEFT);
|
||||
|
||||
SetFont(_entryFont.get(), BLACK);
|
||||
if (item.getType() == IFILE)
|
||||
{
|
||||
DrawTextRect(_position.x, _position.y + fontHeight, _position.w, fontHeight, item.getFiletype().c_str(), ALIGN_LEFT);
|
||||
DrawTextRect(_position.x, _position.y + _fontHeight, _position.w, _fontHeight, item.getFiletype().c_str(), ALIGN_LEFT);
|
||||
if (item.isDownloaded())
|
||||
{
|
||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Synced", ALIGN_RIGHT);
|
||||
DrawTextRect(_position.x, _position.y + 3 * _fontHeight, _position.w, _fontHeight, "Synced", ALIGN_RIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, "Download", ALIGN_RIGHT);
|
||||
DrawTextRect(_position.x, _position.y + 3 * _fontHeight, _position.w, _fontHeight, "Click to Download", ALIGN_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
DrawTextRect(_position.x, _position.y, _position.w, fontHeight, item.getTitle().c_str(), ALIGN_LEFT);
|
||||
DrawTextRect(_position.x, _position.y + 2 * fontHeight, _position.w, fontHeight, item.getLastEditDate().c_str(), ALIGN_LEFT);
|
||||
DrawTextRect(_position.x, _position.y + 3 * fontHeight, _position.w, fontHeight, item.getSize().c_str(), ALIGN_LEFT);
|
||||
DrawTextRect(_position.x, _position.y + 2 * _fontHeight, _position.w, _fontHeight, item.getLastEditDate().c_str(), ALIGN_LEFT);
|
||||
DrawTextRect(_position.x, _position.y + 3 * _fontHeight, _position.w, _fontHeight, item.getSize().c_str(), ALIGN_LEFT);
|
||||
|
||||
int line = (_position.y + _position.h) - 1;
|
||||
DrawLine(0, line, ScreenWidth(), line, BLACK);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "inkview.h"
|
||||
#include "item.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class ListViewEntry
|
||||
{
|
||||
public:
|
||||
|
@ -35,8 +37,9 @@ public:
|
|||
|
||||
private:
|
||||
int _page;
|
||||
ifont *_font;
|
||||
|
||||
int _fontHeight;
|
||||
std::unique_ptr<ifont> _entryFont;
|
||||
std::unique_ptr<ifont> _entryFontBold;
|
||||
irect _position;
|
||||
};
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
#include "eventHandler.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -19,37 +20,30 @@ LoginView *LoginView::_loginViewStatic;
|
|||
LoginView::LoginView(irect *contentRect) : _contentRect(contentRect)
|
||||
{
|
||||
_loginViewStatic = this;
|
||||
_loginFont = OpenFont("LiberationMono", 40, 1);
|
||||
}
|
||||
|
||||
LoginView::~LoginView()
|
||||
{
|
||||
CloseFont(_loginFont);
|
||||
_loginFont = std::unique_ptr<ifont>(OpenFont("LiberationMono", 40, 1));
|
||||
}
|
||||
|
||||
void LoginView::drawLoginView()
|
||||
{
|
||||
FillAreaRect(_contentRect, WHITE);
|
||||
SetFont(_loginFont.get(), BLACK);
|
||||
|
||||
FillAreaRect(_contentRect, WHITE);
|
||||
_urlButton = iRect(50, 200, (ScreenWidth() - 50), 75, ALIGN_CENTER);
|
||||
DrawLine(20, 275, (ScreenWidth() - 20), 275, BLACK);
|
||||
SetFont(_loginFont, BLACK);
|
||||
DrawTextRect2(&_urlButton, "Url");
|
||||
|
||||
_usernameButton = iRect(50, 400, ScreenWidth() - 50, 75, ALIGN_CENTER);
|
||||
DrawLine(20, 475, (ScreenWidth() - 20), 475, BLACK);
|
||||
SetFont(_loginFont, BLACK);
|
||||
DrawTextRect2(&_usernameButton, "Username");
|
||||
|
||||
_passwordButton = iRect(50, 600, (ScreenWidth() - 50), 75, ALIGN_CENTER);
|
||||
DrawLine(20, 675, (ScreenWidth() - 20), 675, BLACK);
|
||||
SetFont(_loginFont, BLACK);
|
||||
DrawTextRect2(&_passwordButton, "Password");
|
||||
|
||||
_loginButton = iRect(ScreenWidth() / 2 - (200 / 2), 700, 200, 50, ALIGN_CENTER);
|
||||
|
||||
FillAreaRect(&_loginButton, BLACK);
|
||||
SetFont(_loginFont, WHITE);
|
||||
SetFont(_loginFont.get(), WHITE);
|
||||
DrawTextRect2(&_loginButton, "Login");
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "inkview.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -21,7 +22,6 @@ class LoginView
|
|||
{
|
||||
public:
|
||||
LoginView(irect *contentRect);
|
||||
~LoginView();
|
||||
|
||||
void drawLoginView();
|
||||
int logginClicked(int x, int y);
|
||||
|
@ -32,7 +32,7 @@ public:
|
|||
|
||||
private:
|
||||
static LoginView *_loginViewStatic;
|
||||
ifont *_loginFont;
|
||||
std::unique_ptr<ifont> _loginFont;
|
||||
irect *_contentRect;
|
||||
irect _urlButton;
|
||||
irect _loginButton;
|
||||
|
|
|
@ -28,7 +28,6 @@ Item::Item(const string &xmlItem)
|
|||
{
|
||||
_type = IFOLDER;
|
||||
_title = _title.substr(0, _path.length() - 1);
|
||||
//TODO whatfor do i need the size as double?
|
||||
setSize(atof(Util::getXMLAttribute(xmlItem, "d:quota-used-bytes").c_str()));
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue