TopInformations.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. #include "TopInformations.hpp"
  2. #include "AssetManager.hpp"
  3. #include "DownloadQueue.hpp"
  4. #include "Notification.hpp"
  5. #include "Theme.hpp"
  6. #include "Util.hpp"
  7. #include "Config.hpp"
  8. #include "States/StateIdentifiers.hpp"
  9. #include "States/DialogState.hpp"
  10. #include "States/SyncState.hpp"
  11. #include <cpp3ds/System/I18n.hpp>
  12. #include <cpp3ds/System/FileSystem.hpp>
  13. #include <TweenEngine/Tween.h>
  14. #include <time.h>
  15. #include <stdlib.h>
  16. namespace FreeShop {
  17. TopInformations::TopInformations()
  18. : m_batteryPercent(-1)
  19. , m_textClockMode(1)
  20. , m_isCollapsed(true)
  21. , m_isTransitioning(false)
  22. , m_canTransition(false)
  23. , m_lowBatteryNotified(false)
  24. , m_noInternetNotified(false)
  25. , m_justWokeUp(false)
  26. {
  27. //Start the clock
  28. m_switchClock.restart();
  29. m_updateClock.restart();
  30. //Get the time to show it in the top part of the App List
  31. time_t t = time(NULL);
  32. struct tm * timeinfo;
  33. timeinfo = localtime(&t);
  34. char timeTextFmt[12];
  35. char tempSec[3];
  36. strftime(tempSec, 3, "%S", timeinfo);
  37. strftime(timeTextFmt, 12, "%H %M", timeinfo);
  38. m_textClock.setString(timeTextFmt);
  39. m_textClock.useSystemFont();
  40. m_textClock.setCharacterSize(14);
  41. if (Theme::isTextThemed)
  42. m_textClock.setFillColor(Theme::primaryTextColor);
  43. else
  44. m_textClock.setFillColor(cpp3ds::Color(80, 80, 80, 255));
  45. //Battery icon
  46. if (fopen(FREESHOP_DIR "/theme/images/battery0.png", "rb"))
  47. m_textureBattery.loadFromFile(FREESHOP_DIR "/theme/images/battery0.png");
  48. else
  49. m_textureBattery.loadFromFile("images/battery0.png");
  50. m_batteryIcon.setPosition(370.f - m_textureBattery.getSize().x, 5.f);
  51. m_batteryIcon.setTexture(m_textureBattery, true);
  52. //Signal icon
  53. if (fopen(FREESHOP_DIR "/theme/images/wifi0.png", "rb"))
  54. m_textureSignal.loadFromFile(FREESHOP_DIR "/theme/images/wifi0.png");
  55. else
  56. m_textureSignal.loadFromFile("images/wifi0.png");
  57. m_signalIcon.setPosition(-50.f, 5.f);
  58. m_signalIcon.setTexture(m_textureSignal, true);
  59. //Define texts position
  60. m_textClock.setPosition(308.f - (m_textureBattery.getSize().x + m_textClock.getLocalBounds().width), -50.f);
  61. //Two points in clock
  62. m_textTwoPoints = m_textClock;
  63. m_textTwoPoints.setString(":");
  64. m_textTwoPoints.setCharacterSize(14);
  65. m_textTwoPoints.setPosition((m_textClock.getPosition().x + (m_textClock.getLocalBounds().width / 2)) - 3, m_textClock.getPosition().y);
  66. #define TWEEN_IN(obj, posY) \
  67. TweenEngine::Tween::to(obj, obj.POSITION_Y, 0.6f).target(posY).delay(0.5f).start(m_tweenManager);
  68. #define TWEEN_IN_NOWAIT(obj, posY) \
  69. TweenEngine::Tween::to(obj, obj.POSITION_Y, 0.6f).target(posY).start(m_tweenManager);
  70. #define TWEEN_IN_X(obj, posX) \
  71. TweenEngine::Tween::to(obj, obj.POSITION_X, 0.6f).target(posX).delay(0.5f).start(m_tweenManager);
  72. #define TWEEN_IN_X_NOWAIT(obj, posX) \
  73. TweenEngine::Tween::to(obj, obj.POSITION_X, 0.6f).target(posX).start(m_tweenManager);
  74. TweenEngine::Tween::to(m_textClock, m_textClock.POSITION_Y, 0.6f).target(5.f).delay(0.5f).setCallback(TweenEngine::TweenCallback::COMPLETE, [this](TweenEngine::BaseTween* source) {m_isCollapsed = false;}).start(m_tweenManager);
  75. TWEEN_IN(m_textTwoPoints, 5.f);
  76. TWEEN_IN_X(m_batteryIcon, 318.f - m_textureBattery.getSize().x);
  77. TWEEN_IN_X(m_signalIcon, 2.f);
  78. //Two points animation
  79. TweenEngine::Tween::to(m_textTwoPoints, util3ds::TweenText::FILL_COLOR_ALPHA, 1.f).target(0).repeatYoyo(-1, 0).start(m_tweenManager);
  80. }
  81. TopInformations::~TopInformations()
  82. {
  83. }
  84. void TopInformations::draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const
  85. {
  86. states.transform *= getTransform();
  87. //Draw clock
  88. target.draw(m_textClock);
  89. //Draw only the two points if the clock text is in clock mode
  90. if (m_textClockMode == 1 && !m_isTransitioning)
  91. target.draw(m_textTwoPoints);
  92. //Draw battery & text
  93. target.draw(m_batteryIcon);
  94. //Draw signal
  95. target.draw(m_signalIcon);
  96. }
  97. void TopInformations::update(float delta)
  98. {
  99. //Update the time to show it in the top part of the App List
  100. time_t t = time(NULL);
  101. struct tm * timeinfo;
  102. timeinfo = localtime(&t);
  103. char timeTextFmt[12];
  104. char tempSec[3];
  105. strftime(tempSec, 3, "%S", timeinfo);
  106. strftime(timeTextFmt, 12, "%H %M", timeinfo);
  107. m_tweenManager.update(delta);
  108. if (m_wokeUpClock.getElapsedTime() >= cpp3ds::seconds(10) && m_justWokeUp)
  109. m_justWokeUp = false;
  110. //Update battery and signal icons
  111. if (m_updateClock.getElapsedTime() >= cpp3ds::seconds(2)) {
  112. m_updateClock.restart();
  113. updateIcons(std::string(timeTextFmt));
  114. }
  115. }
  116. void TopInformations::setCollapsed(bool collapsed)
  117. {
  118. if (collapsed)
  119. m_isCollapsed = collapsed;
  120. if (collapsed) {
  121. TweenEngine::Tween::to(m_textClock, m_textClock.POSITION_Y, 0.6f).target(-50.f).setCallback(TweenEngine::TweenCallback::COMPLETE, [this](TweenEngine::BaseTween* source) {m_isCollapsed = true;}).start(m_tweenManager);
  122. TWEEN_IN_NOWAIT(m_textTwoPoints, -50.f);
  123. TWEEN_IN_X_NOWAIT(m_batteryIcon, 370.f - m_textureBattery.getSize().x);
  124. TWEEN_IN_X_NOWAIT(m_signalIcon, -50.f);
  125. } else {
  126. TweenEngine::Tween::to(m_textClock, m_textClock.POSITION_Y, 0.6f).target(5.f).delay(0.5f).setCallback(TweenEngine::TweenCallback::COMPLETE, [this](TweenEngine::BaseTween* source) {m_isCollapsed = false;}).start(m_tweenManager);
  127. TWEEN_IN(m_textTwoPoints, 5.f);
  128. TWEEN_IN_X(m_batteryIcon, 318.f - m_textureBattery.getSize().x);
  129. TWEEN_IN_X(m_signalIcon, 2.f);
  130. }
  131. }
  132. void TopInformations::updateIcons(std::string timeTextFmt)
  133. {
  134. #ifndef EMULATION
  135. //Update battery icon and percentage
  136. cpp3ds::Uint8 batteryChargeState = 0;
  137. cpp3ds::Uint8 isAdapterPlugged = 0;
  138. cpp3ds::Uint8 batteryLevel = 0;
  139. cpp3ds::Uint8 batteryPercentHolder = 0;
  140. std::string batteryPath;
  141. if (R_SUCCEEDED(PTMU_GetBatteryChargeState(&batteryChargeState)) && batteryChargeState) {
  142. batteryPath = "battery_charging.png";
  143. m_lowBatteryNotified = false;
  144. } else if (R_SUCCEEDED(PTMU_GetAdapterState(&isAdapterPlugged)) && isAdapterPlugged) {
  145. batteryPath = "battery_charging_full.png";
  146. m_lowBatteryNotified = false;
  147. } else if (R_SUCCEEDED(PTMU_GetBatteryLevel(&batteryLevel))) {
  148. batteryPath = "battery" + std::to_string(batteryLevel - 1) + ".png";
  149. if (batteryLevel - 1 == 1 && !m_lowBatteryNotified) {
  150. Notification::spawn(_("Battery power is running low"));
  151. m_lowBatteryNotified = true;
  152. }
  153. }
  154. else
  155. batteryPath = "battery0.png";
  156. //Update battery percentage
  157. if (R_SUCCEEDED(MCUHWC_GetBatteryLevel(&batteryPercentHolder)))
  158. m_batteryPercent = static_cast<int>(batteryPercentHolder);
  159. std::string themedBatteryPath = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/theme/images/" + batteryPath);
  160. if (pathExists(themedBatteryPath.c_str(), false))
  161. m_textureBattery.loadFromFile(themedBatteryPath);
  162. else
  163. m_textureBattery.loadFromFile("images/" + batteryPath);
  164. //Update signal icon
  165. uint32_t wifiStatus = 0;
  166. std::string signalPath;
  167. if (R_SUCCEEDED(ACU_GetWifiStatus(&wifiStatus)) && wifiStatus) {
  168. signalPath = "wifi" + std::to_string(osGetWifiStrength()) + ".png";
  169. m_noInternetNotified = false;
  170. } else {
  171. signalPath = "wifi_disconnected.png";
  172. if (!m_noInternetNotified && !m_justWokeUp) {
  173. m_noInternetNotified = true;
  174. Notification::spawn(_("The console is disconnected from the internet"));
  175. }
  176. }
  177. std::string themedSignalPath = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/theme/images/" + signalPath);
  178. if (pathExists(themedSignalPath.c_str(), false))
  179. m_textureSignal.loadFromFile(themedSignalPath);
  180. else
  181. m_textureSignal.loadFromFile("images/" + signalPath);
  182. #else
  183. //Update battery icon
  184. std::string batteryPath = "battery" + std::to_string(rand() % 5) + ".png";
  185. std::string themedBatteryPath = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/theme/images/" + batteryPath);
  186. m_batteryPercent = rand() % 101;
  187. if (pathExists(themedBatteryPath.c_str(), false))
  188. m_textureBattery.loadFromFile(themedBatteryPath);
  189. else
  190. m_textureBattery.loadFromFile("images/" + batteryPath);
  191. //Update signal icon
  192. std::string signalPath = "wifi" + std::to_string(rand() % 4) + ".png";
  193. std::string themedSignalPath = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/theme/images/" + signalPath);
  194. if (pathExists(themedSignalPath.c_str(), false))
  195. m_textureSignal.loadFromFile(themedSignalPath);
  196. else
  197. m_textureSignal.loadFromFile("images/" + signalPath);
  198. #endif
  199. //Change the mode of the clock if enough time passed
  200. if (m_switchClock.getElapsedTime() >= cpp3ds::seconds(10)) {
  201. //Reset the clock
  202. m_switchClock.restart();
  203. m_isTransitioning = true;
  204. //Switch mode
  205. #ifndef EMULATION
  206. if (m_textClockMode == 1 && Config::get(Config::ShowBattery).GetBool() && m_canTransition && !envIsHomebrew()) {
  207. #else
  208. if (m_textClockMode == 1 && Config::get(Config::ShowBattery).GetBool() && m_canTransition) {
  209. #endif
  210. //Battery percentage mode
  211. m_textClockMode = 2;
  212. //Fade out the old text
  213. TweenEngine::Tween::to(m_textClock, m_textClock.FILL_COLOR_ALPHA, 0.2f)
  214. .target(0.f)
  215. .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
  216. m_textClock.setString(std::to_string(m_batteryPercent) + "%");
  217. if (!m_isCollapsed)
  218. m_textClock.setPosition(308.f - (m_textureBattery.getSize().x + m_textClock.getLocalBounds().width), 5.f);
  219. })
  220. .start(m_tweenManager);
  221. TweenEngine::Tween::to(m_textClock, m_textClock.SCALE_Y, 0.2f)
  222. .target(.5f)
  223. .start(m_tweenManager);
  224. //Fade in the new text
  225. TweenEngine::Tween::to(m_textClock, m_textClock.FILL_COLOR_ALPHA, 0.2f)
  226. .target(255.f)
  227. .delay(0.3f)
  228. .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
  229. m_isTransitioning = false;
  230. })
  231. .start(m_tweenManager);
  232. TweenEngine::Tween::to(m_textClock, m_textClock.SCALE_Y, 0.2f)
  233. .target(1.f)
  234. .delay(0.3f)
  235. .start(m_tweenManager);
  236. } else if (m_textClockMode != 1) {
  237. //Clock mode
  238. m_textClockMode = 1;
  239. //Fade out old text
  240. TweenEngine::Tween::to(m_textClock, m_textClock.FILL_COLOR_ALPHA, 0.2f)
  241. .target(0.f)
  242. .setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
  243. m_textClock.setString(timeTextFmt);
  244. if (!m_isCollapsed)
  245. m_textClock.setPosition(308.f - (m_textureBattery.getSize().x + m_textClock.getLocalBounds().width), 5.f);
  246. })
  247. .start(m_tweenManager);
  248. TweenEngine::Tween::to(m_textClock, m_textClock.SCALE_Y, 0.2f)
  249. .target(.5f)
  250. .start(m_tweenManager);
  251. //Fade in new text
  252. TweenEngine::Tween::to(m_textClock, m_textClock.FILL_COLOR_ALPHA, 0.2f)
  253. .target(255.f)
  254. .delay(0.3f)
  255. .setCallback(TweenEngine::TweenCallback::COMPLETE, [this](TweenEngine::BaseTween* source) {
  256. m_isTransitioning = false;
  257. })
  258. .start(m_tweenManager);
  259. TweenEngine::Tween::to(m_textClock, m_textClock.SCALE_Y, 0.2f)
  260. .target(1.f)
  261. .delay(0.3f)
  262. .start(m_tweenManager);
  263. } else {
  264. m_isTransitioning = false;
  265. }
  266. }
  267. //Don't forget to update the text at each update (except if a transition is occuring)
  268. if (!m_isTransitioning) {
  269. switch (m_textClockMode) {
  270. case 1:
  271. //Clock mode
  272. m_textClock.setString(timeTextFmt);
  273. break;
  274. case 2:
  275. //Battery mode
  276. m_textClock.setString(std::to_string(m_batteryPercent) + "%");
  277. break;
  278. default:
  279. //We should never be here
  280. break;
  281. }
  282. if (!m_isCollapsed)
  283. m_textClock.setPosition(308.f - (m_textureBattery.getSize().x + m_textClock.getLocalBounds().width), 5.f);
  284. }
  285. }
  286. void TopInformations::setTextMode(int newMode)
  287. {
  288. //Update the time to show it in the top part of the App List
  289. time_t t = time(NULL);
  290. struct tm * timeinfo;
  291. timeinfo = localtime(&t);
  292. char timeTextFmt[12];
  293. char tempSec[3];
  294. strftime(tempSec, 3, "%S", timeinfo);
  295. strftime(timeTextFmt, 12, "%H %M", timeinfo);
  296. m_textClockMode = newMode;
  297. updateIcons(timeTextFmt);
  298. }
  299. void TopInformations::setModeChangeEnabled(bool newMode)
  300. {
  301. m_canTransition = newMode;
  302. }
  303. void TopInformations::resetModeTimer()
  304. {
  305. m_switchClock.restart();
  306. }
  307. void TopInformations::wokeUp()
  308. {
  309. m_justWokeUp = true;
  310. m_wokeUpClock.restart();
  311. }
  312. #ifndef EMULATION
  313. Result TopInformations::PTMU_GetAdapterState(u8 *out)
  314. {
  315. Handle serviceHandle = 0;
  316. Result result = srvGetServiceHandle(&serviceHandle, "ptm:u");
  317. u32* ipc = getThreadCommandBuffer();
  318. ipc[0] = 0x50000;
  319. Result ret = svcSendSyncRequest(serviceHandle);
  320. svcCloseHandle(serviceHandle);
  321. if(ret < 0) return ret;
  322. *out = ipc[2];
  323. return ipc[1];
  324. }
  325. // Saw on the awesome 3DShell file explorer homebrew
  326. Result TopInformations::MCUHWC_GetBatteryLevel(u8 *out)
  327. {
  328. Handle serviceHandle = 0;
  329. Result result = srvGetServiceHandle(&serviceHandle, "mcu::HWC");
  330. u32* ipc = getThreadCommandBuffer();
  331. ipc[0] = 0x50000;
  332. Result ret = svcSendSyncRequest(serviceHandle);
  333. svcCloseHandle(serviceHandle);
  334. if(ret < 0) return ret;
  335. *out = ipc[2];
  336. return ipc[1];
  337. }
  338. #endif
  339. } // namespace FreeShop