@@ -11,28 +11,53 @@ export abstract class AbstractController implements IController {
store: Store<IStore>;
app: IBackgroundCore;

eventListeners: Dictionary<EventHandlerType> = {};

constructor(app: IBackgroundCore, store: Store<IStore>) {
this.app = app;
this.store = store;
}

/**
* @param {string} event
* @param {EventHandlerType} eventCallback
*/
protected bindEventListener(event: string, eventCallback: EventHandlerType) {
this.eventListeners[event] = eventCallback;
}

/**
* @returns {Dictionary<EventHandlerType>}
*/
getEventListeners(): Dictionary<EventHandlerType> {
return {} as Dictionary<EventHandlerType>;
return this.eventListeners;
}

/**
* @returns {IBackgroundCore}
*/
getApp(): IBackgroundCore {
return this.app;
}

/**
* @param {AnyAction} action
*/
dispatchStore(action: AnyAction) {
this.store.dispatch.call(this, action);
}

/**
* @returns {IStore}
*/
getState(): IStore {
return this.store.getState();
}

storeSubscribe(listener: (...any) => void) {
/**
* @param {() => void} listener
*/
storeSubscribe(listener: () => void) {
this.store.subscribe(listener);
}
}
@@ -2,16 +2,14 @@ export enum StartUpEvent {
Prepare = 'START_UP::PREPARE'
}


export enum TickerEvent {
ChangeCurrentFiat = 'TICKER::CHANGE_CURRENT_FIAT'
}


export enum WalletEvent {
ActivateCoin = 'WALLET::ACTIVATE_COIN',
DisActivateCoin = 'WALLET::DIS_ACTIVATE_COIN',
CreateTrasaction = 'WALLET::CREATE_TRANSACTION'
CreateTransaction = 'WALLET::CREATE_TRANSACTION'
}

export enum KeyringEvent {

This file was deleted.

@@ -0,0 +1,71 @@
declare global {
export interface Window {
browser: any
}
}

declare type SendMessageEvent = (request: any, responseCallback?: (response: any) => void) => void;

interface RuntimeInterface {
onMessage: chrome.runtime.ExtensionMessageEvent;
sendMessage: SendMessageEvent;
onInstalled: chrome.runtime.ExtensionMessageEvent;

/**
* Create port and connect it
*
* @param {chrome.runtime.ConnectInfo} connectInfo
* @returns {chrome.runtime.Port}
*/
connect(connectInfo?: chrome.runtime.ConnectInfo): chrome.runtime.Port;

/**
* Returning current extension manifest
*
* @returns {any}
*/
getManifest(): chrome.runtime.Manifest;

tabs: TabsInterface;

reload(): void;
}

interface TabsInterface {
create(props?: chrome.tabs.CreateProperties): void;
}

interface ExtensionInterface {
alarms?: any;
bookmarks?: any;
browserAction?: any;
commands?: any;
contextMenus?: any;
cookies?: any;
downloads?: any;
events?: any;
extension?: any;
extensionTypes?: string[];
history?: any;
i18n?: any;
idle?: any;
notifications?: any;
pageAction?: any;
runtime?: RuntimeInterface | any;
storage?: any;
tabs?: TabsInterface;
webNavigation?: any;
webRequest?: any;
windows?: any;
api?: any;

initBaseApi(): void;
}


export {
SendMessageEvent,
RuntimeInterface,
ExtensionInterface,
TabsInterface
}
@@ -1,10 +1,4 @@
import {BrowserExtension} from 'Core/Declarations/BrowserExtension'

declare global {
export interface Window {
browser: any
}
}
import * as Declarations from './Declarations'

const browserApiList: string[] = [
'alarms',
@@ -30,21 +24,21 @@ const browserApiList: string[] = [
'windows',
];

class Extension implements BrowserExtension.ExtensionInterface {
class ExtensionProxy implements Declarations.ExtensionInterface {

alarms?: any;
bookmarks?: any;
browserAction?: any;
commands?: any;
contextMenus?: any;
cookies?: any;
idle?: any;
contextMenus?: any;
downloads?: any;
events?: any;
extension?: any;
extensionTypes?: string[];
history?: any;
i18n?: any;
idle?: any;
notifications?: any;
pageAction?: any;
runtime?: any;
@@ -75,7 +69,6 @@ class Extension implements BrowserExtension.ExtensionInterface {

initBaseApi(): void {
browserApiList.forEach((api) => {

this[api] = null;

try {
@@ -107,4 +100,6 @@ class Extension implements BrowserExtension.ExtensionInterface {
}
}

export default Extension;
export {
ExtensionProxy
};
@@ -0,0 +1,52 @@
import * as Declarations from './Declarations';
import {ExtensionProxy} from './ExtensionProxy';
import CreateProperties = chrome.tabs.CreateProperties;
import Manifest = chrome.runtime.Manifest;


class Platform {

protected extension: ExtensionProxy;

constructor() {
this.extension = new ExtensionProxy();
}

getExtension(): ExtensionProxy {
return this.extension;
}

/**
* extract Runtime object function
*/
getRuntime(): Declarations.RuntimeInterface {
return this.getExtension().runtime;
}

/**
* Extract Tabs function
*/
getTabs(): Declarations.TabsInterface {
return this.getExtension().tabs;
}

reload() {
this.getRuntime().reload();
}

openWindow(createProperties: CreateProperties, callback: Function = null) {
this.getExtension().tabs.create(createProperties, callback);
}

getManifest(): Manifest {
return this.getRuntime().getManifest();
}

getNotifications(): any {
return this.getExtension().notifications;
}
}

export {
Platform
}
@@ -0,0 +1,13 @@
import * as Declarations from './Declarations';
import {ExtensionProxy} from "./ExtensionProxy";
import {Platform} from './Platform';

const extensionInstance: Platform = new Platform();

export {
Declarations,
Platform,
ExtensionProxy,

extensionInstance
}

This file was deleted.

@@ -1,5 +1,5 @@
import LocalStorageStore from 'obs-store/lib/localStorage';
import { STATE_STORAGE_KEY } from 'Core/Constant';
import {STATE_STORAGE_KEY} from 'Core/Constant';

const stateStorage = new LocalStorageStore({
storageKey: STATE_STORAGE_KEY

This file was deleted.

This file was deleted.

@@ -1,8 +1,6 @@
import React from 'react';
import classNames from 'classnames';
import ExtensionPlatform from 'Core/Extension';
import {Background} from 'Popup/Service';
import {KeyringEvent} from 'Core/Actions/Controller';
import {MIN_PASSCODE_CHARS, validatePasscode} from 'Core/Passcode';


export default class EnterSeedStep extends React.Component {
@@ -18,8 +16,10 @@ export default class EnterSeedStep extends React.Component {
}

onTextareaChange = (event) => {
this.setState({
seed: event.target.value.toLowerCase()
this.setState(() => {
return {
seed: event.target.value.toLowerCase()
};
});
};

@@ -30,10 +30,10 @@ export default class EnterSeedStep extends React.Component {
onSendSeed = (event) => {
event.preventDefault();
const seedWords = this.seedWordArray();
ExtensionPlatform.getRuntime().sendMessage({
type: KeyringEvent.CheckSeed,
payload: seedWords
}, this.onPreparedResponse);

Background
.sendRequest(KeyringEvent.CheckSeed, {seed: seedWords})
.then(this.onPreparedResponse);
};

onPreparedResponse = (response) => {
@@ -1,9 +1,6 @@
import React from 'react';
import classNames from 'classnames';
import ExtensionPlatform from 'Core/Extension';
import {Background} from 'Popup/Service';
import {KeyringEvent} from 'Core/Actions/Controller';
import {findCoin, CoinInterface, TxDirection} from "Core/Coins";
import {MIN_PASSCODE_CHARS, validatePasscode} from 'Core/Passcode';

import EnterSeedStep from './EnterSeedStep';
import SuccessSeedStep from './SuccessSeedStep';
@@ -42,24 +39,22 @@ export default class ForgotPasscode extends React.Component {

const {seed} = this.state;

this.setState({
step: ForgotStep.SuccessPasscode,
passcode: newPasscode
this.setState(() => {
return {
step: ForgotStep.SuccessPasscode,
passcode: newPasscode
};
});

ExtensionPlatform.getRuntime().sendMessage({
type: KeyringEvent.SetNewPasscode,
payload: {
passcode: newPasscode,
seed: seed
}
Background.sendRequest(KeyringEvent.SetNewPasscode, {
passcode: newPasscode,
seed: seed
});
};

onGotIt = () => {
ExtensionPlatform.getRuntime().sendMessage({
type: KeyringEvent.TryPassword,
payload: this.state.passcode
Background.sendRequest(KeyringEvent.TryPassword, {
passcode: this.state.passcode
});
};

@@ -3,8 +3,6 @@ import classNames from 'classnames';
import {KeyringEvent} from 'Core/Actions/Controller';
import {Background} from 'Popup/Service';

import {MIN_PASSCODE_CHARS, validatePasscode} from 'Core/Passcode';

export default class EnterPasscodeModal extends React.Component {

state = {
@@ -29,7 +27,7 @@ export default class EnterPasscodeModal extends React.Component {
const {passcode} = this.state;

Background
.sendRequest(KeyringEvent.TryPassword, passcode)
.sendRequest(KeyringEvent.TryPassword, {passcode: passcode})
.catch((error) => {
const {onError = null} = this.props;
onError && onError('Oh snap! Wrong passcode. Please try again.')
@@ -2,7 +2,7 @@ import React from 'react';
import {connect} from 'react-redux';
import {map, filter} from 'lodash';
import {fiatList} from 'Core/Coins';
import ExtensionPlatform from "Core/Extension";
import {Background} from 'Popup/Service';
import {TickerEvent} from "Core/Actions/Controller";
import {AnalyticsObserver} from "Popup/Service/Analytics";
import SearchInputComponent from './Components/SearchInputComponent';
@@ -47,10 +47,9 @@ export default class FiatsScreen extends React.Component {
onChangeFiat = (event) => {
const fiatKey = event.target.value;

ExtensionPlatform.getRuntime().sendMessage({
type: TickerEvent.ChangeCurrentFiat,
payload: fiatKey
}, this.onPreparedResponse);
Background
.sendRequest(TickerEvent.ChangeCurrentFiat, {fiat: fiatKey})
.then(this.onPreparedResponse);

AnalyticsObserver.event('ChooseFiat', fiatKey);
};
@@ -62,7 +62,7 @@ export default class WalletsScreen extends React.Component {
};
}

Background.sendRequest(type, toTriggerCoin).then(callback);
Background.sendRequest(type, {coin: toTriggerCoin}).then(callback);
};

renderCoinRow = (coin) => {
@@ -2,13 +2,13 @@ import React from 'react';
import {connect} from 'react-redux';
import {mapWalletCoinToProps} from 'Popup/Store/WalletCoinConnector';
import TrackScreenView from 'Popup/Service/ScreenViewAnalitics';
import Extension from 'Core/Extension';
import {extensionInstance} from 'Core/Extension';
import QRCode from 'qrcode-react';
import ReactSVG from 'react-svg';
import classNames from 'classnames';
import querystring from 'querystring';

const browserTabs = Extension.getTabs();
const browserTabs = extensionInstance.getTabs();

const ButtonComponent = (props) => {
return (
@@ -66,8 +66,7 @@ export default class SendScreen extends React.Component {
onSendValue = (event) => {
Background
.sendRequest(
Controller.WalletEvent.CreateTrasaction,
{
Controller.WalletEvent.CreateTransaction, {
coinKey: this.props.coin.key,
address: this.state.address,
value: this.getCoinValue()
@@ -40,7 +40,9 @@ export default class ChooseCoinsScreen extends React.Component {
newSelected.push(key);
}

this.setState({selected: newSelected});
this.setState(() => {
return {selected: newSelected};
});
}
};

@@ -59,7 +61,7 @@ export default class ChooseCoinsScreen extends React.Component {
wrapperClassName: "coin-icon-wrapper",
style: {width: 30, height: 30}
};

return (
<div {...itemProps}>
<ReactSVG {...coinSvgIconProps}/>
@@ -1,12 +1,14 @@
import React from 'react';
import {Background} from 'Popup/Service';
import {StartUpEvent} from 'Core/Actions/Controller';
import screenHistory from 'Popup/ScreenAddressHistory';
import ExtensionPlatform from 'Core/Extension';

export default class PrepareWalletScreen extends React.Component {

componentDidMount() {
ExtensionPlatform.getRuntime().sendMessage({type: StartUpEvent.Prepare}, this.onPreparedResponse);
Background
.sendRequest(StartUpEvent.Prepare)
.then(this.onPreparedResponse);
}

onPreparedResponse = (response) => {
@@ -1,4 +1,4 @@
import Extension from 'Core/Extension';
import {extensionInstance} from 'Core/Extension';

const UniversalAnalytics = require('universal-analytics');
const uuidv4 = require('uuid/v4');
@@ -9,7 +9,7 @@ const USER_UUID_KEY = 'USER_UUID';
const AnalyticsOptions = {
GA_IDENTIFY: 'UA-64948076-6',
NAME: 'BERRYWALLET',
VERSION: Extension.getManifest().version
VERSION: extensionInstance.getManifest().version
};

let visitorUUID = localStorage.get(USER_UUID_KEY);
@@ -1,29 +1,38 @@
import ExtensionPlatform from 'Core/Extension';
import {extensionInstance} from 'Core/Extension';

export function sendRequest(type: any | string, payload: any): Promise<any> {
export function sendRequest(type: any | string, payload: any = null): Promise<any> {
const message = {
type: type,
payload: payload
payload: payload || null
};

/**
* @param resolve
* @param reject
*/
const promiseResolver = (resolve, reject) => {
ExtensionPlatform.getRuntime().sendMessage(message, (response) => {

// @TODO WHAT THE FUCK IS GOING ON???
console.log('Event response', response);
/**
* @param response
*/
const responseHandler = (response) => {

// @TODO Have to check response data and something else
if (!response) {
return;
}

if (response.error) {
if ("error" in response) {
reject(response.error);
return;
}

resolve(response);
});
if ("data" in response) {
resolve(response.data);
}
};

extensionInstance.getRuntime().sendMessage(message, responseHandler);
};

return new Promise<any>(promiseResolver);
@@ -1,5 +1,5 @@
import React from 'react';
import Extension from "Core/Extension";
import {extensionInstance} from "Core/Extension";

interface IProps {
to: string;
@@ -13,7 +13,7 @@ export default class RemoteLink extends React.Component<IProps, IState> {
onClickLink = () => {
const {to} = this.props;

Extension.getTabs().create({url: to});
extensionInstance.getTabs().create({url: to});
};

render() {
@@ -1,5 +1,5 @@
import React from 'react';
import Extension from "Core/Extension";
import {extensionInstance} from "Core/Extension";

interface IProps {
to: string;
@@ -13,7 +13,7 @@ export default class RemoteLink extends React.Component<IProps, IState> {
onClickLink = () => {
const {to} = this.props;

Extension.getTabs().create({url: to});
extensionInstance.getTabs().create({url: to});
};

render() {
@@ -1,12 +1,12 @@
import {initializeBackgroundApplication} from 'Background/Application';
import ExtensionPlatform from 'Core/Extension';
import {extensionInstance} from 'Core/Extension';

document.addEventListener('DOMContentLoaded', initializeBackgroundApplication);

ExtensionPlatform.getRuntime().onInstalled.addListener((event) => {
extensionInstance.getRuntime().onInstalled.addListener((event) => {
switch (event.reason) {
case 'install':
ExtensionPlatform.getTabs().create({url: 'https://berrywallet.com'});
extensionInstance.getTabs().create({url: 'https://berrywallet.com'});
break;

case 'update':