root.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. (function () {
  2. 'use strict';
  3. angular.module('ariaNg').run(['$window', '$rootScope', '$location', '$document', '$timeout', 'ariaNgSupportedAudioFileTypes', 'ariaNgCommonService', 'ariaNgKeyboardService', 'ariaNgNotificationService', 'ariaNgLogService', 'ariaNgLocalizationService', 'ariaNgSettingService', 'aria2TaskService', 'ariaNgNativeElectronService', 'ariaNgVersionService', function ($window, $rootScope, $location, $document, $timeout, ariaNgSupportedAudioFileTypes, ariaNgCommonService, ariaNgKeyboardService, ariaNgNotificationService, ariaNgLogService, ariaNgLocalizationService, ariaNgSettingService, aria2TaskService, ariaNgNativeElectronService, ariaNgVersionService) {
  4. var autoRefreshAfterPageLoad = false;
  5. var isAnyTextboxOrTextareaFocus = function () {
  6. return angular.element('input[type="text"],textarea').is(':focus');
  7. };
  8. var isUrlMatchUrl2 = function (url, url2) {
  9. if (url === url2) {
  10. return true;
  11. }
  12. var index = url2.indexOf(url);
  13. if (index !== 0) {
  14. return false;
  15. }
  16. var lastPart = url2.substring(url.length);
  17. if (lastPart.indexOf('/') === 0) {
  18. return true;
  19. }
  20. return false;
  21. };
  22. var setLightTheme = function () {
  23. $rootScope.currentTheme = 'light';
  24. angular.element('body').removeClass('theme-dark');
  25. };
  26. var setDarkTheme = function () {
  27. $rootScope.currentTheme = 'dark';
  28. angular.element('body').addClass('theme-dark');
  29. };
  30. var setThemeBySystemSettings = function () {
  31. if (!ariaNgSettingService.isBrowserSupportDarkMode()) {
  32. setLightTheme();
  33. return;
  34. }
  35. var matchPreferColorScheme = $window.matchMedia('(prefers-color-scheme: dark)');
  36. ariaNgLogService.info('[root.setThemeBySystemSettings] system uses ' + (matchPreferColorScheme.matches ? 'dark' : 'light') + ' theme');
  37. if (matchPreferColorScheme.matches) {
  38. setDarkTheme();
  39. } else {
  40. setLightTheme();
  41. }
  42. };
  43. var initTheme = function () {
  44. if (ariaNgSettingService.getTheme() === 'system') {
  45. ariaNgNativeElectronService.setNativeTheme('system');
  46. setThemeBySystemSettings();
  47. } else if (ariaNgSettingService.getTheme() === 'dark') {
  48. ariaNgNativeElectronService.setNativeTheme('dark');
  49. setDarkTheme();
  50. } else {
  51. ariaNgNativeElectronService.setNativeTheme('light');
  52. setLightTheme();
  53. }
  54. };
  55. var initCheck = function () {
  56. var browserFeatures = ariaNgSettingService.getBrowserFeatures();
  57. if (!browserFeatures.localStroage) {
  58. ariaNgLogService.warn('[root.initCheck] LocalStorage is not supported!');
  59. }
  60. if (!browserFeatures.cookies) {
  61. ariaNgLogService.warn('[root.initCheck] Cookies is not supported!');
  62. }
  63. if (!ariaNgSettingService.isBrowserSupportStorage()) {
  64. angular.element('body').prepend('<div class="disable-overlay"></div>');
  65. angular.element('.main-sidebar').addClass('blur');
  66. angular.element('.navbar').addClass('blur');
  67. angular.element('.content-body').addClass('blur');
  68. ariaNgNotificationService.notifyInPage('', 'You cannot use AriaNg because this browser does not meet the minimum requirements for data storage.', {
  69. type: 'error',
  70. delay: false
  71. });
  72. throw new Error('You cannot use AriaNg because this browser does not meet the minimum requirements for data storage.');
  73. }
  74. };
  75. var initNavbar = function () {
  76. angular.element('section.sidebar > ul > li[data-href-match] > a').click(function () {
  77. angular.element('section.sidebar > ul li').removeClass('active');
  78. angular.element(this).parent().addClass('active');
  79. });
  80. angular.element('section.sidebar > ul > li.treeview > ul.treeview-menu > li[data-href-match] > a').click(function () {
  81. angular.element('section.sidebar > ul li').removeClass('active');
  82. angular.element(this).parent().addClass('active').parent().parent().addClass('active');
  83. });
  84. };
  85. var setNavbarSelected = function (location) {
  86. angular.element('section.sidebar > ul li').removeClass('active');
  87. angular.element('section.sidebar > ul > li[data-href-match]').each(function (index, element) {
  88. var match = angular.element(element).attr('data-href-match');
  89. if (isUrlMatchUrl2(match, location)) {
  90. angular.element(element).addClass('active');
  91. }
  92. });
  93. angular.element('section.sidebar > ul > li.treeview > ul.treeview-menu > li[data-href-match]').each(function (index, element) {
  94. var match = angular.element(element).attr('data-href-match');
  95. if (isUrlMatchUrl2(match, location)) {
  96. angular.element(element).addClass('active').parent().parent().addClass('active');
  97. }
  98. });
  99. };
  100. var initContentWrapper = function () {
  101. //copy from AdminLTE app.js
  102. var defaultNavbarWithAppTitleHeight = 74; // defined in "min-height" of ".custom-app-title .main-header .navbar" in app-title.css
  103. var defaultNavbarHeight = 50; // defined in "min-height" of ".main-header .navbar" in AdminLTE.css
  104. var defaultFooterHeight = 1 + 15 + 15 + 17; // defined in "border-top" of ".main-footer" in AdminLTE.css, "padding" of ".main-footer" in AdminLTE.css and "line-height" of ".skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li > a" in default.css;
  105. var windowHeight = $(window).height();
  106. var headerHeight = $('.main-header').outerHeight() || (ariaNgNativeElectronService.useCustomAppTitle() ? defaultNavbarWithAppTitleHeight : defaultNavbarHeight);
  107. var footerHeight = $('.main-footer').outerHeight() || defaultFooterHeight;
  108. var neg = headerHeight + footerHeight;
  109. $('.content-wrapper').css('min-height', windowHeight - footerHeight);
  110. $('.content-body').css('height', windowHeight - neg);
  111. };
  112. var initFileDragSupport = function () {
  113. var getDropFile = function (e) {
  114. if (!e || !e.dataTransfer) {
  115. return null;
  116. }
  117. if (e.dataTransfer.items && e.dataTransfer.items[0] && e.dataTransfer.items[0].kind === 'file') {
  118. return e.dataTransfer.items[0].getAsFile();
  119. } else if (e.dataTransfer.files && e.dataTransfer.files[0]) {
  120. return e.dataTransfer.files[0];
  121. } else {
  122. return null;
  123. }
  124. };
  125. var getDropText = function (e) {
  126. if (!e || !e.dataTransfer) {
  127. return null;
  128. }
  129. return e.dataTransfer.getData('text');
  130. };
  131. var dropzone = angular.element('#dropzone');
  132. var dropzoneFileZone = angular.element('#dropzone-filezone');
  133. angular.element($window).on('dragenter', function (e) {
  134. ariaNgCommonService.closeAllDialogs();
  135. dropzone.show();
  136. e.preventDefault();
  137. });
  138. dropzoneFileZone.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {
  139. e.preventDefault();
  140. e.stopPropagation();
  141. }).on('dragleave dragend drop', function() {
  142. dropzone.hide();
  143. }).on('drop', function(e) {
  144. var file = getDropFile(e.originalEvent);
  145. if (file) {
  146. ariaNgNativeElectronService.notifyMainProcessorNewDropFile({
  147. filePath: file.path,
  148. location: $location.url()
  149. });
  150. return;
  151. }
  152. var text = getDropText(e.originalEvent);
  153. if (text) {
  154. ariaNgNativeElectronService.notifyMainProcessorNewDropText({
  155. text: text,
  156. location: $location.url()
  157. });
  158. }
  159. });
  160. };
  161. var showSidebar = function () {
  162. angular.element('body').removeClass('sidebar-collapse').addClass('sidebar-open');
  163. };
  164. var hideSidebar = function () {
  165. angular.element('body').addClass('sidebar-collapse').removeClass('sidebar-open');
  166. };
  167. var isSidebarShowInSmallScreen = function () {
  168. return angular.element('body').hasClass('sidebar-open');
  169. };
  170. var toggleMaximizeButton = function () {
  171. angular.element('#native-title-maximize-icon').addClass('fa-window-maximize').removeClass('fa-window-restore');
  172. angular.element('#native-title-maximize-btn').attr('title', ariaNgLocalizationService.getLocalizedText('Maximize'));
  173. };
  174. var toggleRestoreButton = function () {
  175. angular.element('#native-title-maximize-icon').addClass('fa-window-restore').removeClass('fa-window-maximize');
  176. angular.element('#native-title-maximize-btn').attr('title', ariaNgLocalizationService.getLocalizedText('Restore Down'));
  177. };
  178. var autoCheckUpdates = function () {
  179. ariaNgVersionService.getTheLatestVersion()
  180. .then(function onSuccess(response) {
  181. ariaNgLogService.debug('[root.autoCheckUpdates] latest version info', response);
  182. if (!response || !response.data || !response.data.tag_name) {
  183. return;
  184. }
  185. var latestVersion = response.data.tag_name;
  186. if (ariaNgVersionService.compareVersion(ariaNgVersionService.getBuildVersionNumber(), latestVersion) < 0) {
  187. if (ariaNgSettingService.getBrowserNotification()) {
  188. ariaNgNotificationService.notifyViaBrowser('AriaNg Native Updates', 'A new version has been released', {
  189. contentParams: {
  190. version: latestVersion
  191. }
  192. });
  193. } else {
  194. ariaNgNotificationService.notifyInPage('', 'A new version has been released', {
  195. delay: false,
  196. type: 'info',
  197. contentParams: {
  198. version: latestVersion
  199. }
  200. });
  201. }
  202. }
  203. }).catch(function onError(response) {
  204. ariaNgLogService.error('[root.autoCheckUpdates] failed to get latest version', response);
  205. });
  206. };
  207. var playSoundAfterDownloadFinished = function () {
  208. if (!ariaNgSettingService.getPlaySoundAfterDownloadFinished()) {
  209. return;
  210. }
  211. if ($rootScope.soundContext.isPlaying()) {
  212. ariaNgLogService.debug('[root.playSoundAfterDownloadFinished] background audio is already playing');
  213. return;
  214. }
  215. $rootScope.soundContext.playSound(ariaNgSettingService.getPlaySoundAfterDownloadFinished(), true);
  216. };
  217. $rootScope.currentTheme = 'light';
  218. $rootScope.searchContext = {
  219. text: '',
  220. setSearchBoxFocused: function () {
  221. angular.element('#search-box').focus();
  222. }
  223. };
  224. $rootScope.taskContext = {
  225. rpcStatus: 'Connecting',
  226. list: [],
  227. selected: {},
  228. enableSelectAll: false,
  229. getSelectedTaskIds: function () {
  230. var result = [];
  231. if (!this.list || !this.selected || this.list.length < 1) {
  232. return result;
  233. }
  234. for (var i = 0; i < this.list.length; i++) {
  235. var task = this.list[i];
  236. if (this.selected[task.gid]) {
  237. result.push(task.gid);
  238. }
  239. }
  240. return result;
  241. },
  242. getSelectedTasks: function () {
  243. var result = [];
  244. if (!this.list || !this.selected || this.list.length < 1) {
  245. return result;
  246. }
  247. for (var i = 0; i < this.list.length; i++) {
  248. var task = this.list[i];
  249. if (this.selected[task.gid]) {
  250. result.push(task);
  251. }
  252. }
  253. return result;
  254. },
  255. isAllSelected: function () {
  256. var isAllSelected = true;
  257. for (var i = 0; i < this.list.length; i++) {
  258. var task = this.list[i];
  259. if (!$rootScope.filterTask(task)) {
  260. continue;
  261. }
  262. if (!this.selected[task.gid]) {
  263. isAllSelected = false;
  264. break;
  265. }
  266. }
  267. return isAllSelected;
  268. },
  269. hasRetryableTask: function () {
  270. for (var i = 0; i < this.list.length; i++) {
  271. var task = this.list[i];
  272. if (!$rootScope.filterTask(task)) {
  273. continue;
  274. }
  275. if ($rootScope.isTaskRetryable(task)) {
  276. return true;
  277. }
  278. }
  279. return false;
  280. },
  281. hasCompletedTask: function () {
  282. for (var i = 0; i < this.list.length; i++) {
  283. var task = this.list[i];
  284. if (!$rootScope.filterTask(task)) {
  285. continue;
  286. }
  287. if (task.status === 'complete') {
  288. return true;
  289. }
  290. }
  291. return false;
  292. },
  293. selectAll: function () {
  294. if (!this.list || !this.selected || this.list.length < 1) {
  295. return;
  296. }
  297. if (!this.enableSelectAll) {
  298. return;
  299. }
  300. var isAllSelected = this.isAllSelected();
  301. for (var i = 0; i < this.list.length; i++) {
  302. var task = this.list[i];
  303. if (!$rootScope.filterTask(task)) {
  304. continue;
  305. }
  306. this.selected[task.gid] = !isAllSelected;
  307. }
  308. },
  309. selectAllFailed: function () {
  310. if (!this.list || !this.selected || this.list.length < 1) {
  311. return;
  312. }
  313. if (!this.enableSelectAll) {
  314. return;
  315. }
  316. var isAllFailedSelected = true;
  317. for (var i = 0; i < this.list.length; i++) {
  318. var task = this.list[i];
  319. if (!$rootScope.filterTask(task)) {
  320. continue;
  321. }
  322. if (!$rootScope.isTaskRetryable(task)) {
  323. continue;
  324. }
  325. if (!this.selected[task.gid]) {
  326. isAllFailedSelected = false;
  327. }
  328. }
  329. for (var i = 0; i < this.list.length; i++) {
  330. var task = this.list[i];
  331. if (!$rootScope.filterTask(task)) {
  332. continue;
  333. }
  334. if (!$rootScope.isTaskRetryable(task)) {
  335. this.selected[task.gid] = false;
  336. continue;
  337. }
  338. this.selected[task.gid] = !isAllFailedSelected;
  339. }
  340. },
  341. selectAllCompleted: function () {
  342. if (!this.list || !this.selected || this.list.length < 1) {
  343. return;
  344. }
  345. if (!this.enableSelectAll) {
  346. return;
  347. }
  348. var isAllFailedSelected = true;
  349. for (var i = 0; i < this.list.length; i++) {
  350. var task = this.list[i];
  351. if (!$rootScope.filterTask(task)) {
  352. continue;
  353. }
  354. if (task.status !== 'complete') {
  355. continue;
  356. }
  357. if (!this.selected[task.gid]) {
  358. isAllFailedSelected = false;
  359. }
  360. }
  361. for (var i = 0; i < this.list.length; i++) {
  362. var task = this.list[i];
  363. if (!$rootScope.filterTask(task)) {
  364. continue;
  365. }
  366. if (task.status !== 'complete') {
  367. this.selected[task.gid] = false;
  368. continue;
  369. }
  370. this.selected[task.gid] = !isAllFailedSelected;
  371. }
  372. }
  373. };
  374. $rootScope.soundContext = {
  375. currentSoundFile: '',
  376. loadSoundFile: function (filePath, callback, silent) {
  377. var player = angular.element('#background-audio')[0];
  378. if (filePath) {
  379. ariaNgNativeElectronService.getLocalFSFileBufferAsync(filePath, function (buffer) {
  380. if (buffer) {
  381. var soundExtension = ariaNgCommonService.getFileExtension(filePath);
  382. var mimeType = ariaNgSupportedAudioFileTypes[soundExtension];
  383. var blob = new Blob([buffer], { type: mimeType });
  384. player.src = URL.createObjectURL(blob);
  385. $rootScope.soundContext.currentSoundFile = filePath;
  386. ariaNgLogService.debug('[root.soundContext.loadSoundFile] background audio is set to ' + filePath);
  387. if (angular.isFunction(callback)) {
  388. callback(filePath);
  389. }
  390. } else {
  391. player.src = '';
  392. $rootScope.soundContext.currentSoundFile = '';
  393. ariaNgLogService.warn('[root.soundContext.loadSoundFile] background audio is set to empty due to the file buffer is null');
  394. if (!silent) {
  395. ariaNgCommonService.showError('Sound file not exists.');
  396. }
  397. }
  398. });
  399. } else {
  400. player.src = '';
  401. $rootScope.soundContext.currentSoundFile = '';
  402. ariaNgLogService.debug('[root.soundContext.loadSoundFile] background audio is set to empty');
  403. }
  404. },
  405. isPlaying: function () {
  406. var player = angular.element('#background-audio')[0];
  407. return !player.paused;
  408. },
  409. playSound: function (filePath, silent) {
  410. if (!filePath) {
  411. return;
  412. }
  413. var player = angular.element('#background-audio')[0];
  414. player.pause();
  415. player.volume = 1.0;
  416. if (this.currentSoundFile !== filePath) {
  417. this.loadSoundFile(filePath, function () {
  418. player.currentTime = 0;
  419. player.play().catch(function (error) {
  420. ariaNgLogService.error('[root.soundContext.playSound] cannot play sound, because ' + error);
  421. if (!silent) {
  422. ariaNgCommonService.showError('Cannot play this sound file.');
  423. }
  424. });
  425. }, !!silent);
  426. } else {
  427. player.currentTime = 0;
  428. player.play().catch(function (error) {
  429. ariaNgLogService.error('[root.soundContext.playSound] cannot play sound, because ' + error);
  430. if (!silent) {
  431. ariaNgCommonService.showError('Cannot play this sound file.');
  432. }
  433. });
  434. }
  435. },
  436. stopPlayingSound: function () {
  437. var player = angular.element('#background-audio')[0];
  438. player.pause();
  439. player.currentTime = 0;
  440. }
  441. };
  442. $rootScope.filterTask = function (task) {
  443. if (!task || !angular.isString(task.taskName)) {
  444. return false;
  445. }
  446. if (!$rootScope.searchContext || !$rootScope.searchContext.text) {
  447. return true;
  448. }
  449. return (task.taskName.toLowerCase().indexOf($rootScope.searchContext.text.toLowerCase()) >= 0);
  450. };
  451. $rootScope.isTaskRetryable = function (task) {
  452. return task && task.status === 'error' && task.errorDescription && !task.bittorrent;
  453. };
  454. $rootScope.keydownActions = {
  455. find: function (event) {
  456. if (event.preventDefault) {
  457. event.preventDefault();
  458. }
  459. $rootScope.searchContext.setSearchBoxFocused();
  460. return false;
  461. }
  462. };
  463. $rootScope.swipeActions = {
  464. leftSwipe: function () {
  465. if (!ariaNgSettingService.getSwipeGesture()) {
  466. return;
  467. }
  468. if (isSidebarShowInSmallScreen()) {
  469. hideSidebar();
  470. return;
  471. }
  472. if (!this.extendLeftSwipe ||
  473. (angular.isFunction(this.extendLeftSwipe) && !this.extendLeftSwipe())) {
  474. hideSidebar();
  475. }
  476. },
  477. rightSwipe: function () {
  478. if (!ariaNgSettingService.getSwipeGesture()) {
  479. return;
  480. }
  481. if (!this.extendRightSwipe ||
  482. (angular.isFunction(this.extendRightSwipe) && !this.extendRightSwipe())) {
  483. showSidebar();
  484. }
  485. }
  486. };
  487. $rootScope.refreshPage = function () {
  488. $window.location.reload();
  489. };
  490. $rootScope.setAutoRefreshAfterPageLoad = function () {
  491. autoRefreshAfterPageLoad = true;
  492. };
  493. $rootScope.setTheme = function (theme) {
  494. if (theme === 'system') {
  495. ariaNgNativeElectronService.setNativeTheme('system');
  496. setThemeBySystemSettings();
  497. } else if (theme === 'dark') {
  498. ariaNgNativeElectronService.setNativeTheme('dark');
  499. setDarkTheme();
  500. } else {
  501. ariaNgNativeElectronService.setNativeTheme('light');
  502. setLightTheme();
  503. }
  504. };
  505. $rootScope.useCustomAppTitle = ariaNgNativeElectronService.useCustomAppTitle();
  506. ariaNgNativeElectronService.getWindowMaximizedAsync(function (maximized) {
  507. if (maximized) {
  508. toggleRestoreButton();
  509. } else {
  510. toggleMaximizeButton();
  511. }
  512. });
  513. $window.addEventListener('contextmenu', function (event) {
  514. event.preventDefault();
  515. event.stopPropagation();
  516. var context = {};
  517. if (angular.isFunction($window.getSelection)) {
  518. var selection = $window.getSelection().toString();
  519. context.selected = !!selection && selection.length > 0;
  520. }
  521. if (angular.element(event.target).attr('readonly') === 'readonly') {
  522. context.editable = false;
  523. }
  524. if (angular.element(event.target).attr('data-support-force-delete-empty') === 'true'
  525. && angular.element(event.target).val() === '') {
  526. context.forceDeleteEmpty = true;
  527. }
  528. if (event.target.nodeName.match(/^(input|textarea)$/i) || event.target.isContentEditable) {
  529. ariaNgNativeElectronService.showTextboxContextMenu(context);
  530. }
  531. });
  532. $window.addEventListener('keydown', function (event) {
  533. if (!ariaNgSettingService.getKeyboardShortcuts()) {
  534. return;
  535. }
  536. var isTextboxOrTextareaFocus = isAnyTextboxOrTextareaFocus();
  537. if (ariaNgKeyboardService.isCtrlAPressed(event) && !isTextboxOrTextareaFocus) {
  538. if (angular.isFunction($rootScope.keydownActions.selectAll)) {
  539. return $rootScope.keydownActions.selectAll(event);
  540. }
  541. } else if (ariaNgKeyboardService.isCtrlFPressed(event)) {
  542. if (angular.isFunction($rootScope.keydownActions.find)) {
  543. return $rootScope.keydownActions.find(event);
  544. }
  545. } else if (ariaNgKeyboardService.isDeletePressed(event) && !isTextboxOrTextareaFocus) {
  546. if (angular.isFunction($rootScope.keydownActions.delete)) {
  547. return $rootScope.keydownActions.delete(event);
  548. }
  549. } else if (ariaNgKeyboardService.isCtrlNPressed(event)) {
  550. $rootScope.$apply(function () {
  551. $location.path('/new');
  552. });
  553. }
  554. }, true);
  555. ariaNgNativeElectronService.onMainWindowMaximize(function () {
  556. toggleRestoreButton();
  557. });
  558. ariaNgNativeElectronService.onMainWindowUnmaximize(function () {
  559. toggleMaximizeButton();
  560. });
  561. ariaNgNativeElectronService.onMainProcessNavigateTo(function (event, routeUrl) {
  562. angular.element('.modal.in:visible').modal('hide');
  563. angular.element('.modal-backdrop').remove();
  564. $rootScope.$apply(function () {
  565. $location.path(routeUrl);
  566. });
  567. });
  568. ariaNgNativeElectronService.onMainProcessShowError(function (event, message) {
  569. ariaNgCommonService.showError(message);
  570. });
  571. ariaNgNativeElectronService.onMainProcessChangeDevMode(function (event, devMode) {
  572. $rootScope.$apply(function () {
  573. ariaNgSettingService.setDebugMode(devMode);
  574. });
  575. });
  576. ariaNgSettingService.setDebugMode(ariaNgNativeElectronService.isDevMode());
  577. ariaNgSettingService.onFirstAccess(function () {
  578. ariaNgNotificationService.notifyInPage('', 'Tap to configure and get started with AriaNg.', {
  579. delay: false,
  580. onClose: function () {
  581. $location.path('/settings/ariang');
  582. }
  583. });
  584. });
  585. aria2TaskService.onFirstSuccess(function (event) {
  586. ariaNgNotificationService.notifyInPage('', 'is connected', {
  587. type: 'success',
  588. contentPrefix: event.rpcName + ' '
  589. });
  590. });
  591. aria2TaskService.onConnectionSuccess(function () {
  592. $timeout(function () {
  593. if ($rootScope.taskContext.rpcStatus !== 'Connected') {
  594. $rootScope.taskContext.rpcStatus = 'Connected';
  595. }
  596. });
  597. });
  598. aria2TaskService.onConnectionFailed(function () {
  599. $timeout(function () {
  600. if ($rootScope.taskContext.rpcStatus !== 'Disconnected') {
  601. $rootScope.taskContext.rpcStatus = 'Disconnected';
  602. }
  603. });
  604. });
  605. aria2TaskService.onConnectionReconnecting(function () {
  606. $timeout(function () {
  607. if ($rootScope.taskContext.rpcStatus !== 'Reconnecting') {
  608. $rootScope.taskContext.rpcStatus = 'Reconnecting';
  609. }
  610. });
  611. });
  612. aria2TaskService.onConnectionWaitingToReconnect(function () {
  613. $timeout(function () {
  614. if ($rootScope.taskContext.rpcStatus !== 'Waiting to reconnect') {
  615. $rootScope.taskContext.rpcStatus = 'Waiting to reconnect';
  616. }
  617. });
  618. });
  619. aria2TaskService.onTaskCompleted(function (event) {
  620. playSoundAfterDownloadFinished(event.task);
  621. ariaNgNotificationService.notifyTaskComplete(event.task);
  622. });
  623. aria2TaskService.onBtTaskCompleted(function (event) {
  624. playSoundAfterDownloadFinished(event.task);
  625. ariaNgNotificationService.notifyBtTaskComplete(event.task);
  626. });
  627. aria2TaskService.onTaskErrorOccur(function (event) {
  628. playSoundAfterDownloadFinished(event.task);
  629. ariaNgNotificationService.notifyTaskError(event.task);
  630. });
  631. $rootScope.$on('$locationChangeStart', function (event) {
  632. ariaNgCommonService.closeAllDialogs();
  633. $rootScope.loadPromise = null;
  634. delete $rootScope.keydownActions.selectAll;
  635. delete $rootScope.keydownActions.delete;
  636. delete $rootScope.swipeActions.extendLeftSwipe;
  637. delete $rootScope.swipeActions.extendRightSwipe;
  638. if (angular.isArray($rootScope.taskContext.list) && $rootScope.taskContext.list.length > 0) {
  639. $rootScope.taskContext.list.length = 0;
  640. }
  641. if (angular.isObject($rootScope.taskContext.selected)) {
  642. $rootScope.taskContext.selected = {};
  643. }
  644. $rootScope.taskContext.enableSelectAll = false;
  645. });
  646. $rootScope.$on('$routeChangeStart', function (event, next, current) {
  647. var location = $location.path();
  648. setNavbarSelected(location);
  649. $document.unbind('keypress');
  650. });
  651. $rootScope.$on('$viewContentLoaded', function () {
  652. ariaNgNativeElectronService.notifyMainProcessViewLoaded($location.path());
  653. });
  654. $rootScope.$on('$translateChangeSuccess', function(event, current, previous) {
  655. ariaNgNativeElectronService.setMainWindowLanguage();
  656. });
  657. if (ariaNgSettingService.isBrowserSupportDarkMode()) {
  658. var matchPreferColorScheme = $window.matchMedia('(prefers-color-scheme: dark)');
  659. matchPreferColorScheme.addEventListener('change', function (e) {
  660. ariaNgLogService.info('[root] system switches to ' + (e.matches ? 'dark' : 'light') + ' theme');
  661. if (ariaNgSettingService.getTheme() === 'system') {
  662. if (e.matches) {
  663. setDarkTheme();
  664. } else {
  665. setLightTheme();
  666. }
  667. }
  668. });
  669. }
  670. if (ariaNgSettingService.getAutoCheckUpdates() && ariaNgSettingService.getAutoCheckUpdates() !== 'never') {
  671. ariaNgNativeElectronService.getLastCheckUpdatesTimeAsync(function (lastCheckUpdatesTime) {
  672. var checkFrequency = ariaNgSettingService.getAutoCheckUpdates();
  673. var currentTime = parseInt(ariaNgCommonService.getCurrentUnixTime());
  674. var oneDaySeconds = 86400; // s
  675. var needCheckUpdates = false;
  676. if (!angular.isNumber(lastCheckUpdatesTime)) {
  677. needCheckUpdates = true;
  678. } else if (checkFrequency === 'daily' && (currentTime - lastCheckUpdatesTime) >= oneDaySeconds) {
  679. needCheckUpdates = true;
  680. } else if (checkFrequency === 'weekly' && (currentTime - lastCheckUpdatesTime) >= oneDaySeconds * 7) {
  681. needCheckUpdates = true;
  682. } else if (checkFrequency === 'monthly' && (currentTime - lastCheckUpdatesTime) >= oneDaySeconds * 31) {
  683. needCheckUpdates = true;
  684. }
  685. if (needCheckUpdates) {
  686. ariaNgLogService.debug('[root] need check for updates, last check time is ' + lastCheckUpdatesTime);
  687. autoCheckUpdates();
  688. ariaNgNativeElectronService.setLastCheckUpdatesTime(currentTime);
  689. } else {
  690. ariaNgLogService.debug('[root] do not need check for updates, last check time is ' + lastCheckUpdatesTime);
  691. }
  692. });
  693. }
  694. $rootScope.$on('$locationChangeSuccess', function (event, newUrl) {
  695. if (autoRefreshAfterPageLoad) {
  696. $window.location.reload();
  697. }
  698. });
  699. initTheme();
  700. initCheck();
  701. initNavbar();
  702. initContentWrapper();
  703. initFileDragSupport();
  704. }]);
  705. }());