import angular from 'angular' ; import { Component , OnInit } from 'angular-ts-decorators' ; import autobind from 'autobind-decorator' ; import { AppEventType , RoutePath } from '../../app/app.enum' ; import { AppMainComponent } from '../../app/app-main/app-main.component' ; import { AppHelperService } from '../../app/shared/app-helper/app-helper.service' ; import { AlertService } from '../../shared/alert/alert.service' ; import { BookmarkMetadata } from '../../shared/bookmark/bookmark.interface' ; import { BookmarkHelperService } from '../../shared/bookmark/bookmark-helper/bookmark-helper.service' ; import Globals from '../../shared/global-shared.constants' ; import { PlatformService } from '../../shared/global-shared.interface' ; import { LogService } from '../../shared/log/log.service' ; import { NetworkService } from '../../shared/network/network.service' ; import { SettingsService } from '../../shared/settings/settings.service' ; import { StoreKey } from '../../shared/store/store.enum' ; import { StoreService } from '../../shared/store/store.service' ; import { SyncService } from '../../shared/sync/sync.service' ; import { UpgradeService } from '../../shared/upgrade/upgrade.service' ; import { UtilityService } from '../../shared/utility/utility.service' ; import { WorkingContext } from '../../shared/working/working.enum' ; import { WorkingService } from '../../shared/working/working.service' ; import { AndroidPlatformService } from '../android-shared/android-platform/android-platform.service' ; import { AndroidAlert } from './android-app.interface' ; import { AndroidAppHelperService } from './shared/android-app-helper/android-app-helper.service' ; @ autobind @ Component ( { controllerAs : 'vm' , selector : 'app' , styles : [ require ( './android-app.component.scss' ) ] , template : require ( '../../app/app-main/app-main.component.html' ) } ) export class AndroidAppComponent extends AppMainComponent implements OnInit { $interval : ng . IIntervalService ; appHelperSvc : AndroidAppHelperService ; platformSvc : AndroidPlatformService ; syncSvc : SyncService ; upgradeSvc : UpgradeService ; darkThemeEnabled = false ; static $inject = [ '$interval' , '$location' , '$q' , '$scope' , '$timeout' , 'AlertService' , 'AppHelperService' , 'BookmarkHelperService' , 'LogService' , 'NetworkService' , 'PlatformService' , 'SettingsService' , 'StoreService' , 'SyncService' , 'UpgradeService' , 'UtilityService' , 'WorkingService' ] ; constructor ( $interval , $location , $q , $scope , $timeout , AlertSvc , AppHelperSvc , BookmarkHelperSvc , LogSvc , NetworkSvc , PlatformSvc , SettingsSvc , StoreSvc , SyncSvc , UpgradeSvc , UtilitySvc , WorkingSvc ) { super ( $location , $q , $scope , $timeout , AlertSvc , AppHelperSvc , BookmarkHelperSvc , LogSvc , NetworkSvc , PlatformSvc , SettingsSvc , StoreSvc , UtilitySvc , WorkingSvc ) ; this . $interval = $interval ; this . syncSvc = SyncSvc ; this . upgradeSvc = UpgradeSvc ; } checkForInstallOrUpgrade ( ) { return this . platformSvc . getAppVersion ( ) . then ( ( appVersion ) => { const localStorageAppVersion = localStorage . getItem ( 'xBrowserSync-mobileAppVersion' ) ; return this . $q < string > ( ( resolve ) => { window . NativeStorage . getItem ( 'appVersion' , resolve , ( ) => resolve ( ) ) ; } ) . then ( ( nativeStorageAppVersion ) => { return nativeStorageAppVersion ?? localStorageAppVersion ?? undefined ; } ) . then ( ( legacyAppVersion ) => { return this . upgradeSvc . getLastUpgradeVersion ( ) . then ( ( lastUpgradeVersion ) => { if ( angular . isUndefined ( lastUpgradeVersion ) ) { if ( angular . isUndefined ( legacyAppVersion ) ) { return this . handleInstall ( appVersion ) ; } return this . upgradeSvc . setLastUpgradeVersion ( legacyAppVersion ) ; } } ) . then ( ( ) => { return this . upgradeSvc . checkIfUpgradeRequired ( appVersion ) . then ( ( upgradeRequired ) => { if ( upgradeRequired ) { return this . handleUpgrade ( appVersion ) ; } } ) ; } ) ; } ) ; } ) ; } checkForNewVersion ( ) { this . $timeout ( ( ) => { this . platformSvc . getAppVersion ( ) . then ( ( appVersion ) => { this . utilitySvc . checkForNewVersion ( appVersion ) . then ( ( newVersion ) => { if ( ! newVersion ) { return ; } this . alertSvc . setCurrentAlert ( { message : this . platformSvc . getI18nString ( this . Strings . Alert . AppUpdateAvailable . Message ) . replace ( '{version}' , `v${ newVersion }` ) , action : this . platformSvc . getI18nString ( this . Strings . Button . View ) , actionCallback : ( ) => { this . platformSvc . openUrl ( `${ Globals . ReleaseNotesUrlStem }${ newVersion }` ) ; } } as AndroidAlert ) ; } ) ; } ) ; } , 1e3 ) ; } executeSync ( workingContext ) { return this . $q . resolve ( ) . then ( ( ) => { if ( ! this . networkSvc . isNetworkConnected ( ) ) { return ; } return this . appHelperSvc . getSyncQueueLength ( ) . then ( ( syncQueueLength ) => { return syncQueueLength === 0 ? this . syncSvc . checkForUpdates ( ) . catch ( ( ) => false ) : true ; } ) . then ( ( runSync ) => { if ( ! runSync ) { return ; } return this . platformSvc . executeSync ( false , workingContext ) . then ( ( ) => this . utilitySvc . broadcastEvent ( AppEventType . RefreshBookmarkSearchResults ) ) . catch ( ( err ) => { return this . appHelperSvc . syncBookmarksFailed ( err ) . then ( ( ) => { throw err ; } ) ; } ) ; } ) ; } ) ; } getSharedBookmark ( ) { return this . $q < any > ( ( resolve , reject ) => window . plugins . intentShim . getIntent ( resolve , reject ) ) . then ( ( intent ) => { if ( intent ?. type !== 'text/plain' || ! intent ?. extras ) { return ; } const intentText = intent . extras [ window . plugins . intentShim . EXTRA_TEXT ] ; const intentSubject = intent . extras [ window . plugins . intentShim . EXTRA_SUBJECT ] ; this . logSvc . logInfo ( `Detected new intent: ${ intentText }` ) ; const url = intentText ?. match ( new RegExp ( Globals . URL . ValidUrlRegex , 'i' ) ) ?. find ( Boolean ) ; return { title : intentSubject , url } ; } ) . then ( ( sharedBookmark ) => { if ( angular . isUndefined ( sharedBookmark ) ) { return ; } const txt = document . createElement ( 'textarea' ) ; txt . innerHTML = sharedBookmark . title ? sharedBookmark . title . trim ( ) : '' ; sharedBookmark . title = txt . value ; return sharedBookmark ; } ) ; } handleBackButton ( event ) { if ( this . utilitySvc . checkCurrentRoute ( RoutePath . Bookmark ) || this . utilitySvc . checkCurrentRoute ( RoutePath . Help ) || this . utilitySvc . checkCurrentRoute ( RoutePath . Scan ) || this . utilitySvc . checkCurrentRoute ( RoutePath . Settings ) || this . utilitySvc . checkCurrentRoute ( RoutePath . Support ) || this . utilitySvc . checkCurrentRoute ( RoutePath . Updated ) ) { event . preventDefault ( ) ; this . appHelperSvc . switchView ( ) ; } else { event . preventDefault ( ) ; this . appHelperSvc . exitApp ( ) ; } } handleBookmarkShared ( sharedBookmark ) { if ( ! angular . isUndefined ( sharedBookmark ) ) { this . platformSvc . currentPage = sharedBookmark ; } } handleDeviceReady ( success , failure ) { this . $q . all ( [ this . bookmarkHelperSvc . getCachedBookmarks ( ) , this . settingsSvc . all ( ) ] ) . catch ( ( ) => { } ) ; return ( this . platformSvc . initI18n ( ) . then ( ( ) => { document . addEventListener ( 'backbutton' , this . handleBackButton , false ) ; document . addEventListener ( 'touchstart' , this . handleTouchStart , false ) ; window . addEventListener ( 'keyboardDidShow' , this . handleKeyboardDidShow ) ; window . addEventListener ( 'keyboardWillHide' , this . handleKeyboardWillHide ) ; window . cordova . plugins . backgroundMode . setDefaults ( { hidden : true , silent : true } ) ; window . cordova . plugins . backgroundMode . on ( 'activate' , ( ) => { window . cordova . plugins . backgroundMode . disableWebViewOptimizations ( ) ; } ) ; return this . checkForInstallOrUpgrade ( ) ; } ) . then ( this . handleStartup ) . then ( success ) . catch ( failure ) ) ; } handleInstall ( installedVersion ) { return ( this . storeSvc . init ( ) . then ( ( ) => this . upgradeSvc . setLastUpgradeVersion ( installedVersion ) ) . then ( ( ) => this . logSvc . logInfo ( `Installed ${ installedVersion }` ) ) ) ; } handleKeyboardDidShow ( event ) { document . body . style . height = `calc(100% - ${ event . keyboardHeight }px)` ; setTimeout ( ( ) => { ( document . activeElement as any ) . scrollIntoViewIfNeeded ( ) ; } , 100 ) ; } handleKeyboardWillHide ( ) { document . body . style . removeProperty ( 'height' ) ; } handleResume ( ) { return this . utilitySvc . isSyncEnabled ( ) . then ( ( syncEnabled ) => { if ( ! syncEnabled ) { return ; } return this . getSharedBookmark ( ) . then ( ( sharedBookmark ) => { if ( ! angular . isUndefined ( sharedBookmark ) ) { this . handleBookmarkShared ( sharedBookmark ) ; return this . appHelperSvc . switchView ( RoutePath . Bookmark ) ; } this . executeSync ( WorkingContext . DelayedSyncing ) ; } ) ; } ) ; } handleStartup ( ) { this . logSvc . logInfo ( 'Starting up' ) ; return this . $q . all ( [ this . platformSvc . getAppVersionName ( ) , this . platformSvc . getCurrentLocale ( ) , this . settingsSvc . checkForAppUpdates ( ) , this . storeSvc . get ( [ StoreKey . LastUpdated , StoreKey . SyncId ] ) , this . utilitySvc . getServiceUrl ( ) , this . utilitySvc . getSyncVersion ( ) , this . utilitySvc . isSyncEnabled ( ) ] ) . then ( ( result ) => { const [ appVersion , currentLocale , checkForAppUpdates , storeContent , serviceUrl , syncVersion , syncEnabled ] = result ; const debugInfo = angular . copy ( storeContent ) as any ; debugInfo . appVersion = appVersion ; debugInfo . checkForAppUpdates = checkForAppUpdates ; debugInfo . currentLocale = currentLocale ; debugInfo . platform = { name : window . device . platform , device : `${ window . device . manufacturer } ${ window . device . model }` } ; debugInfo . serviceUrl = serviceUrl ; debugInfo . syncEnabled = syncEnabled ; debugInfo . syncVersion = syncVersion ; this . logSvc . logInfo ( Object . keys ( debugInfo ) . filter ( ( key ) => { return debugInfo [ key ] != null ; } ) . reduce ( ( prev , current ) => { prev [ current ] = debugInfo [ current ] ; return prev ; } , { } ) ) ; if ( checkForAppUpdates ) { this . checkForNewVersion ( ) ; } if ( ! syncEnabled ) { return ; } return this . getSharedBookmark ( ) . then ( ( sharedBookmark ) => { if ( ! angular . isUndefined ( sharedBookmark ) ) { return this . handleBookmarkShared ( sharedBookmark ) ; } this . executeSync ( WorkingContext . DelayedSyncing ) ; } ) ; } ) ; } handleTouchStart ( event ) { if ( ! this . utilitySvc . isTextInput ( event . target as Element ) && this . utilitySvc . isTextInput ( document . activeElement ) ) { this . $timeout ( ( ) => { ( document . activeElement as HTMLInputElement ) . blur ( ) ; } , 100 ) ; } } handleUpgrade ( upgradeToVersion ) { return this . upgradeSvc . upgrade ( upgradeToVersion ) . then ( ( ) => this . storeSvc . set ( StoreKey . DisplayUpdated , true ) ) ; } ngOnInit ( ) { return ( this . $q < void > ( ( resolve , reject ) => { document . addEventListener ( 'deviceready' , ( ) => { this . handleDeviceReady ( resolve , reject ) ; } , false ) ; document . addEventListener ( 'resume' , this . handleResume , false ) ; } ) . then ( ( ) => { if ( ! angular . isUndefined ( this . platformSvc . currentPage ) ) { return this . appHelperSvc . switchView ( RoutePath . Bookmark ) ; } } ) . then ( ( ) => super . ngOnInit ( ) ) ) ; } workingCancelAction ( ) { this . utilitySvc . broadcastEvent ( AppEventType . WorkingCancelAction ) ; return this . $q . resolve ( ) ; } }