187 ReadMe.md
@@ -1,161 +1,126 @@
# The Universal Tox Client
# šŸ”’ The Universal Tox Client

[![Build Status](https://travis-ci.org/Tox-Client/client.svg?branch=master)](https://travis-ci.org/Tox-Client/client) [![dependencies Status](https://david-dm.org/Tox-Client/client/status.svg)](https://david-dm.org/Tox-Client/client) [![devDependencies Status](https://david-dm.org/Tox-Client/client/dev-status.svg)](https://david-dm.org/Tox-Client/client?type=dev)
[![Build Status](https://travis-ci.org/Tox-Client/client.svg?branch=master)](https://travis-ci.org/Tox-Client/client) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)

This project is a fresh start of the new Tox client I'm willing to dev. It's shared between platforms with only one codebase and can run easily on Android, iOS, Linux, OSX, Windows 10/UWP, Windows 7/8, and maybe Windows Phone.

The main goal of this project is to provide the same experience between platforms by giving users an instant messenger application that is both secure and user-friendly.

Behind the hood, it uses React (Web/Desktop) and React Native (Android/iOS) and a pattern based on `Base` component and `Renderer` components that allows us to share the application logic between every pattern but allowing platform-specific stuff in different files. Compiler (webpack/grunt) then takes care of choosing the right file to resolve depending on which platform it's being built for.
## Table of Contents

![](https://0x0.st/sshQ.png)
* [Roadmap](#-roadmap)
* [Compiling](#-compiling)
* [Android](#android)
* [iOS](#ios)
* [Web](#web)
* [Desktop (Electron)](#desktop-electron)
* [Build for production](#-build-for-production)
* [Android/iOS](#androidios)
* [Web](#web-1)
* [Donations](#-donations)
* [License](#-license)

## Libraries/tools
## šŸ¾ Roadmap

This project uses libraries and tools like:
### Milestone 1 (v0.1.0-alpha)

* es6 syntax and [babel](https://babeljs.io)
* [react](https://facebook.github.io/react) for the Website App and Desktop App,
* [react-native](https://facebook.github.io/react-native) for the iOS & Android Apps
* [Electron](http://electron.atom.io) to package the Desktop App
* [redux](http://redux.js.org/) to organize the data flow management
* [css-loader](https://github.com/webpack/css-loader) to integrate the styles in the builds
* [grunt](http://gruntjs.com) to create the builds
* [webpack](https://webpack.github.io) to help during the development phase with hot reloading
Create a library (and publish it on NPM) containing the UI elements that will be used in the client. That means a LOT of small and bigger components that needs to be reusable and that MUST performs/looks the same not depending if that's run on the browser, the desktop client, or the mobile one.

## Basic philosophy
### Milestone 2 (v0.2.0-alpha to v0.5.0-alpha)

All the code is contained in the `src` directory, especially the 3 main entry files that are used for the builds:
Create a library (and publish it on NPM) that allows to use c-toxcore on mobile devices. I will need to create a wrapper for Android in Java (I mostly know that language, so shouldn't be too hard) and one for iOS in Obj-C/Swift, which are languages I have never tried nor used, and that I'll have to learn to get this milestone right.

* `index.ios.js` & `index.android.js` are the ones used to build the iOS & Android Apps
* `index.js` is the one used to build the Website App and Desktop App as the code is strictly the same.
### Milestone 3 (v0.6.0-alpha to v0.8.0-alpha)

### Redux architecture actions/stores
Wire's all the components to redux and map redux actions creators to the `react-toxcore` library done in the previous milestone. Have everything properly working on every platform, whether it's in the browser, iOS, Android, Linux, Windows or OSX. Everything has to look exactly the same, and works the same, and even have the same bugs!

All the [redux](http://redux.js.org/) architecture is share to 100% to all the different builds. This means that all the logic and data management code is done only once and reuse everywhere. This allows us to have an easy tests suite as well and to ensure that our code is working properly on all the devices.
### Milestone 4 (no release)

### Components
Take a break with the client development and create a small promotional website, with a blog and stuffs to aid in getting the app in user's hands. _This website will need to be clear, simple and attractive. The blog will serves as a distribution channel, and thus needs to be polished and localized._

The real interest of the project is in how the components have been structured to shared most of their logic and only redefined what is specific to every device.
### Milestone 5 (v0.9.0-beta)

Basically, every component has a `MainClass` which inherits a `BaseClass` containing all the logic. Then, the main component import a different Render function which has been selected during the build. The file extension `.ios.js`, `.android.js` or `.js` is used by the build tool to import only the right file.
Publish the app on respective App Stores _(App Store, Play Store, Windows Store, and get it in AUR + Fedora + Ubuntu + Solus repos)_ in beta test mode, spread the word and collect users feedbacks.

The `.native.js` files contain code that is shared between both mobile platforms (iOS & Android). Currently, the `.ios.js` and `.android.js` files compose this `.native.js` file since all code is shared right now. However, if a component needed to be different for platform specific reasons, that code would be included in the corresponding platform specific files.
### Milestone 6 (v1.0.0-rc1)

At the end, every component is defined by 6 files. If we look at the screen component, here is its structure.
Fix all the issues reported during the beta-test period and update the branding a little bit to gives beta-tester new "features", giving them more enjoyment ! Release a pre-release for 2 weeks extra bugs reports.

```
Screen
ā”œā”€ā”€ index.js
ā”œā”€ā”€ styles.js (styles of the component)
ā”œā”€ā”€ ScreenBase.js
ā”œā”€ā”€ ScreenRender.ios.js (specific to iOS build
ā”œā”€ā”€ ScreenRender.android.js (specific to Android build)
ā”œā”€ā”€ ScreenRender.native.js (shared mobile app code - iOS & Android)
└── ScreenRender.js (used during Website and Desktop build)
```

And here is the `MainClass` (`index.js`) file which composes the files.

```js
"use strict";
import Base from "./ScreenBase";
import Render from "./ScreenRender";
export default class Screen extends Base {
constructor(props) {
super(props);
}
render() {
return Render.call(this, this.props, this.state);
}
}
```

### Styles

Styles are written in different fashions between React & React Native. This project use [react-native-css](https://github.com/sabeurthabti/react-native-css) to share the stylesheets between web/desktop version and mobile one. This allow for faster iteration cycle and also remove duplicate/not-in-sync styles issues.

# How to build/run the projects

## General requirements before running any specific project

* `npm install` to install all the dependencies, React and React Native among others.
### Milestone 7 (v1.0.0-rc2)

### With some versions of npm (>=v3.3.10 <=v3.6.0)
Finally fixes all the issues from last pre-release 2 weeks time (as they appears) and do release a 1st stable version to peoples.

Some builds from npm included bugs while `npm install`. So if you are using a npm version within the range form 3.3.10 to 3.6.0 included, you must run `npm install` twice. Those versions including npm v3.3.12 are the ones bundled by default with node from version v5.1.0 to v5.5.0.
### Milestone 8 (v1.0.0-rc3)

* `npm install npm`
* `npm install npm` run it twice, because of the packages won't be installed after the first run [#10985](https://github.com/npm/npm/issues/10985)
Take some time to build a list of all the app's strings, prepare them for localization (ICU format), setup tooling to enable people to translate in their languages. Wait 2 weeks for translations to be done, then release.

## The Mobile Apps (iOS & Android)
## šŸ”¬ Compiling

### Requirements for React Native
Before targeting a specific platform, you need to clone the repository and to install required dependencies.

#### iOS
```bash
# Clone the directory as `toxclient`.
$ git clone https://github.com/Tox-Client/client.git toxclient
$ cd toxclient/
* OS X
* Xcode 6.3 or higher is recommended (Xcode only runs on Mac).
* Homebrew is the recommended way to install node, watchman, and flow.
* `brew install node`
* `brew install watchman`. We recommend installing watchman, otherwise you might hit a node file watching bug.
* `brew install flow`. If you want to use flow.

#### Android

* Follow the official documentation guide here: http://facebook.github.io/react-native/docs/getting-started.html#android-setup (includes experimental Windows & Linux support)

### Running the Mobile Apps

#### iOS
# Now install the dependencies with Yarn:
$ yarn
# Or with NPM:
$ npm install
```

* Open iosApp.xcodeproj and hit run in Xcode.
* Hit cmd+R in your iOS simulator to reload the app and see your change!
### Android

#### Android
```bash
$ react-native run-android
```

* Open an emulator. (Genymotion or run `android avd`)
* Run the `react-native run-android` in the root of this project.
* If trying to run on a device, read the following guide: http://facebook.github.io/react-native/docs/running-on-device-android.html#content
### iOS

Congratulations! You've just successfully run the project as an iOS or Android App.
```bash
$ react-native run-ios
```

## The Website App
### Web

### Requirements for React
You can use Yarn or NPM for the following step, depending on your preference.

There isn't any additional requirements since you already installed the deps with `npm install`.
```bash
# Using Yarn:
$ yarn web
### Quick start
# Using NPM:
$ npm run web
```

* `npm run build` to build the project (at least the first time)
* `npm run serve:web` to preview in the browser at http://localhost:8000/index.web.html or http://localhost:8000/webpack-dev-server/index.web.html with webpack-dev-server and hot reload enabled
### Windows

Congratulations! You've just successfully run the project as a Website App.
```bash
$ react-native windows
$ react-native run-windows
```

## The Desktop App
### Desktop (Electron)

### Requirements for Electron
You can use Yarn or NPM for the following step, depending on your preference.

There isn't any additional requirements since you already installed the deps with `npm install`.
```bash
# Using Yarn:
$ yarn electron
### Quick start
# Using NPM:
$ npm run electron
```

* `npm run build` to build the project (at least the first time)
* `npm run serve:electron` to launch the desktop app and enable livereload
## 🄁 Build for production

Congratulations! You've just successfully run the project as a Desktop App.
### Android/iOS

# Run the tests
[This will help](https://facebook.github.io/react-native/docs/running-on-device.html)

To run the tests, simply run:
### Web

```
npm test
```
`npm/yarn run build` (this will build your production ready bundle)

## šŸ’ø Donations

@@ -45,12 +45,12 @@ android_library(

android_build_config(
name = "build_config",
package = "com.konv",
package = "com.toxclient",
)

android_resource(
name = "res",
package = "com.konv",
package = "com.toxclient",
res = "src/main/res",
)

@@ -98,7 +98,7 @@ android {
buildToolsVersion "23.0.1"

defaultConfig {
applicationId "com.konv"
applicationId "com.toxclient"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
@@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.konv"
package="com.toxclient"
android:versionCode="1"
android:versionName="1.0">

This file was deleted.

This file was deleted.

@@ -1,4 +1,4 @@
package com.konv;
package com.toxclient;

import com.facebook.react.ReactActivity;

@@ -10,6 +10,6 @@ public class MainActivity extends ReactActivity {
*/
@Override
protected String getMainComponentName() {
return "Konv";
return "toxclient";
}
}
@@ -1,4 +1,4 @@
package com.konv;
package com.toxclient;

import android.app.Application;

@@ -1,3 +1,3 @@
<resources>
<string name="app_name">Konv</string>
<string name="app_name">toxclient</string>
</resources>
@@ -1,3 +1,3 @@
rootProject.name = 'Konv'
rootProject.name = 'toxclient'

include ':app'
@@ -1,4 +1,4 @@
{
"name": "Konv",
"displayName": "Konv"
"name": "toxclient",
"displayName": "toxclient"
}

This file was deleted.

@@ -1,32 +1,26 @@
"use strict";

const electron = require("electron");
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

const path = require("path");
const url = require("url");

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
title: "Tox - Secure messenger.",
minWidth: 800,
minHeight: 600,
width: 900,
height: 500,
autoHideMenuBar: true
});

// and load the index.html of the app.
if (process.env.NODE_ENV == "production") {
mainWindow.loadURL("file://" + __dirname + "/index.desktop.html");
} else {
mainWindow.loadURL(
"http://localhost:8000/webpack-dev-server/index.web.html"
);
}
mainWindow.loadURL("http://localhost:3000");

// Open the DevTools.
mainWindow.webContents.openDevTools();
@@ -42,6 +36,7 @@ function createWindow() {

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);

// Quit when all windows are closed.
@@ -60,3 +55,6 @@ app.on("activate", function() {
createWindow();
}
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
@@ -1 +1,4 @@
module.exports = require("./src/index");
import { AppRegistry } from 'react-native';
import App from './App';

AppRegistry.registerComponent('toxclient', () => App);

This file was deleted.

@@ -0,0 +1,5 @@
import React, { Component } from "react";
import { AppRegistry } from "react-native";
import App from "./App";

AppRegistry.registerComponent("toxclient", () => App);
File renamed without changes.
File renamed without changes.

Large diffs are not rendered by default.

@@ -29,9 +29,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "Konv-tvOS.app"
BlueprintName = "Konv-tvOS"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient-tvOS.app"
BlueprintName = "toxclient-tvOS"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@@ -43,9 +43,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
BuildableName = "Konv-tvOSTests.xctest"
BlueprintName = "Konv-tvOSTests"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient-tvOSTests.xctest"
BlueprintName = "toxclient-tvOSTests"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -61,19 +61,19 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
BuildableName = "Konv-tvOSTests.xctest"
BlueprintName = "Konv-tvOSTests"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient-tvOSTests.xctest"
BlueprintName = "toxclient-tvOSTests"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "Konv-tvOS.app"
BlueprintName = "Konv-tvOS"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient-tvOS.app"
BlueprintName = "toxclient-tvOS"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
@@ -94,9 +94,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "Konv-tvOS.app"
BlueprintName = "Konv-tvOS"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient-tvOS.app"
BlueprintName = "toxclient-tvOS"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
@@ -113,9 +113,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "Konv-tvOS.app"
BlueprintName = "Konv-tvOS"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient-tvOS.app"
BlueprintName = "toxclient-tvOS"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
@@ -29,9 +29,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "Konv.app"
BlueprintName = "Konv"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient.app"
BlueprintName = "toxclient"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@@ -43,9 +43,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "KonvTests.xctest"
BlueprintName = "KonvTests"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclientTests.xctest"
BlueprintName = "toxclientTests"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -61,19 +61,19 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "KonvTests.xctest"
BlueprintName = "KonvTests"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclientTests.xctest"
BlueprintName = "toxclientTests"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "Konv.app"
BlueprintName = "Konv"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient.app"
BlueprintName = "toxclient"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
@@ -94,9 +94,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "Konv.app"
BlueprintName = "Konv"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient.app"
BlueprintName = "toxclient"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
@@ -113,9 +113,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "Konv.app"
BlueprintName = "Konv"
ReferencedContainer = "container:Konv.xcodeproj">
BuildableName = "toxclient.app"
BlueprintName = "toxclient"
ReferencedContainer = "container:toxclient.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
File renamed without changes.
@@ -21,7 +21,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"Konv"
moduleName:@"toxclient"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
@@ -18,7 +18,7 @@
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Konv" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="toxclient" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
File renamed without changes.
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Konv</string>
<string>toxclient</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
File renamed without changes.
File renamed without changes.
@@ -16,11 +16,11 @@
#define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"

@interface KonvTests : XCTestCase
@interface toxclientTests : XCTestCase

@end

@implementation KonvTests
@implementation toxclientTests

- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
{

This file was deleted.

This file was deleted.

@@ -1,128 +1,47 @@
{
"name": "Konv",
"version": "0.0.1",
"name": "toxclient",
"version": "0.2.4",
"private": true,
"src": "./",
"test": "./tests",
"dist": "./dist",
"mainInput": "main",
"mainOutput": "main",
"main": "index.desktop.html",
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"build": "grunt build",
"travis": "npm run build && npm run react-native:ios && npm run react-native:android && npm test",
"react-native:ios": "react-native bundle --entry-file src/index.ios.js --bundle-output ios/main.jsbundle --platform ios --dev false",
"react-native:android": "react-native bundle --entry-file src/index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --platform android --dev false --assets-dest android/app/src/main/res/",
"serve:web": "grunt serve-web",
"serve:web/dist": "grunt serve-web-dist",
"serve:electron": "grunt serve-electron",
"test": "jest"
},
"window": {
"toolbar": false,
"min_width": 800,
"min_height": 600
},
"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"testFileExtensions": [
"js"
],
"testPathDirs": [
"src"
],
"moduleFileExtensions": [
"js"
],
"verbose": true,
"collectCoverage": true
"test": "jest",
"web": "react-scripts start",
"build": "react-scripts build",
"test:web": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"electron": "react-scripts start & electron .",
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public"
},
"dependencies": {
"@toxclient/shathui": "^0.1.0",
"babel-plugin-add-module-exports": "^0.2.1",
"electron-prebuilt": "^0.37.2",
"es6-promise": "^3.1.2",
"events": "^1.1.0",
"fbjs": "^0.6.0",
"flux": "^2.1.1",
"grunt": "^0.4.5",
"history": "^2.0.1",
"keymirror": "^0.1.1",
"normalize.css": "^3.0.3",
"object-assign": "^4.0.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-native": "0.49.5",
"react-native-css": "^2.1.2",
"react-navigation": "^1.0.0-beta.16",
"react-primitives": "^0.4.3",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-promises": "^1.0.0",
"redux-thunk": "^2.2.0",
"remote-redux-devtools": "^0.5.12",
"serve-static": "^1.13.1",
"styled-components": "^2.2.3",
"uniqid": "^1.0.0"
"react": "16.2.0",
"react-dom": "^16.2.0",
"react-native": "0.53.2",
"react-native-web": "0.1.13",
"react-native-windows": "^0.50.0",
"react-redux": "5.0.6",
"react-router": "4.2.0",
"react-router-dom": "4.2.2",
"react-router-native": "4.2.0",
"redux": "3.7.2",
"redux-thunk": "2.2.0"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.7.2",
"babel-eslint": "^6.1.2",
"babel-jest": "21.2.0",
"babel-loader": "^6.2.4",
"babel-plugin-react-transform": "^2.0.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.3.14",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-react-hmre": "^1.0.1",
"babel-jest": "22.2.2",
"babel-plugin-transform-react-remove-prop-types": "0.4.10",
"babel-preset-react-native": "4.0.0",
"babel-preset-stage-0": "^6.3.13",
"babel-register": "^6.7.2",
"css-loader": "^0.23.1",
"eslint": "^2.4.0",
"eslint-plugin-react": "^4.2.3",
"file-loader": "^0.8.5",
"gh-pages": "^0.11.0",
"grunt-cli": "^0.1.13",
"grunt-concurrent": "^2.2.1",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-connect": "^1.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-exec": "^0.4.6",
"grunt-karma": "^0.12.2",
"grunt-open": "^0.2.3",
"grunt-webpack": "^1.0.11",
"jasmine-core": "^2.4.1",
"jest": "21.2.1",
"jest-cli": "^0.9.2",
"jshint": "^2.9.1",
"jshint-loader": "^0.8.3",
"karma": "^0.13.22",
"karma-chrome-launcher": "^0.2.2",
"karma-firefox-launcher": "^0.1.7",
"karma-jasmine": "^0.3.8",
"karma-phantomjs-launcher": "^1.0.0",
"karma-script-launcher": "^0.2.0",
"karma-webpack": "^1.7.0",
"load-grunt-tasks": "^3.4.1",
"node-sass": "^3.4.2",
"phantomjs-prebuilt": "^2.1.5",
"react-hot-loader": "^3.0.0",
"react-test-renderer": "16.0.0-beta.5",
"react-transform": "^0.0.3",
"react-transform-catch-errors": "^1.0.2",
"redbox-react": "^1.5.0",
"sass-loader": "^3.2.0",
"style-loader": "^0.13.0",
"svg-url-loader": "^2.3.0",
"typecheck": "^0.1.2",
"url-loader": "^0.5.7",
"webpack": "^1.12.14",
"webpack-dev-server": "^1.14.1"
}
"electron": "1.6.11",
"jest": "22.3.0",
"react-scripts": "1.1.0",
"react-test-renderer": "16.2.0",
"@storybook/react": "^3.3.13",
"@storybook/addon-actions": "^3.3.13",
"@storybook/addon-links": "^3.3.13",
"@storybook/addons": "^3.3.13",
"babel-core": "^6.26.0"
},
"jest": {
"preset": "react-native"
},
"main": "index.electron.js"
}
BIN +2.73 KB public/favicon.ico
Binary file not shown.
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="icon" href="%PUBLIC_URL%/favicon.ico">
<link rel="stylesheet" href="%PUBLIC_URL%/styles.global.css">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>toxclient</title>
</head>

<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>

</html>
@@ -0,0 +1,15 @@
{
"short_name": "toxclient",
"name": "Re-base, a re-start template",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
@@ -0,0 +1,13 @@
html,
body {
margin: 0;
padding: 0;
}

#root {
height: 100vh;
}

* {
outline: none !important;
}
@@ -0,0 +1,69 @@
'use strict';

const execSync = require('child_process').execSync;
const fs = require('fs');
const path = require('path');

/**
* Use Yarn if available, it's much faster than the npm client.
* Return the version of yarn installed on the system, null if yarn is not available.
*/
function getYarnVersionIfAvailable() {
let yarnVersion;
try {
// execSync returns a Buffer -> convert to string
yarnVersion = (execSync('yarn --version', {
stdio: [0, 'pipe', 'ignore'],
}).toString() || '').trim();
} catch (error) {
return null;
}
return yarnVersion;
}

function installDevDependencies() {
console.log('Adding dev dependencies for the project...');

const devDependenciesJsonPath = path.resolve('devDependencies.json');
const devDependencies = JSON.parse(fs.readFileSync(devDependenciesJsonPath));
let depsToInstall = [];

for (const depName in devDependencies) {
const depVersion = devDependencies[depName];
const depToInstall = `${depName}@${depVersion}`;
depsToInstall.push(depToInstall);
}

depsToInstall = depsToInstall.join(' ');
console.log(`Adding ${depsToInstall}...`);
if (getYarnVersionIfAvailable()) {
execSync(`yarn add ${depsToInstall} -D`, {stdio: 'inherit'});
} else {
execSync(`npm install ${depsToInstall} --save`);
}
console.log("Deleting devDependencies.json...");
execSync(`rm ${devDependenciesJsonPath}`);
}

//"resolutions": { "moment-timezone/moment": "2.19.0" }

function updatePackageJson() {
const fileName = "package.json";
const packageFile = path.resolve(fileName);
let file = require(packageFile);
//these are the scripts that will be added to package.json
console.log(`Adding scripts for web to package.json`);
file.scripts['web'] = "react-scripts start";
file.scripts["build"] = "react-scripts build";
file.scripts["test:web"] = "react-scripts test --env=jsdom";
file.scripts["eject"] = "react-scripts eject";
file.scripts["electron"] = "react-scripts start & electron .";
console.log(`Adding entry point for electron`);
file['main'] = "index.electron.js";
fs.writeFileSync(fileName, JSON.stringify(file));
}


installDevDependencies();
updatePackageJson();

This file was deleted.

This file was deleted.

@@ -0,0 +1,4 @@
// This file serves as a common location for all your action constants

export const SOMETHING_HAPPENED_SUCCESSFULLY = "SOMETHING_HAPPENED_SUCCESSFULLY";
export const SOMETHING_FAILED = "SOMETHING_FAILED";
@@ -0,0 +1,33 @@
import * as types from "./ActionTypes";
// This is a dumb action just for wire framing purpose
// All your login and processing should go in actions, the should be thick
// example: make a network request, and dispatch the received payload to redux store

const payloadIfSuccess = {message: "Action was successful"}; // sample payload for after action occurs
const payloadIfFailed = {message: "Action execution failed"};

export default function SampleAction(input) {
return (dispatch) => {
if (input === 1) {
dispatch(somethingHappenedSuccessfully(payloadIfSuccess))
}
else if (input === 0) {
dispatch(somethingFailed(payloadIfFailed))

}
}
}

function somethingHappenedSuccessfully(payload) {
return {
type: types.SOMETHING_HAPPENED_SUCCESSFULLY,
data: payload
}
}

function somethingFailed(payload) {
return {
type: types.SOMETHING_FAILED,
data: payload
}
}
File renamed without changes.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -12,10 +12,11 @@ import {
const Touchable = Platform.select({
ios: TouchableHighlight,
android: TouchableNativeFeedback,
windows: TouchableOpacity
windows: TouchableOpacity,
web: TouchableHighlight
});

export default class ButtonRender extends Component {
export default class Button extends Component {
constructor(props) {
super(props);
}
@@ -30,7 +31,8 @@ export default class ButtonRender extends Component {
setTimeout(
() => this.props.onPress && this.props.onPress(),
this.props.onPressDelay ? this.props.onPressDelay : 100
)}
)
}
onLongPress={() => this.props.onLongPress && this.props.onLongPress()}
>
<View
@@ -80,6 +82,10 @@ const styles = {
},
android: {
elevation: 2
},
web: {
boxShadow:
"0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)"
}
}),
backgroundColor: "white",
@@ -1,7 +1,7 @@
import React, { Component } from "react";
import { StyleSheet, TextInput, Platform, Animated } from "react-native";

import Style from "../../style.js";
import Style from "../style.js";

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

@@ -68,15 +68,15 @@ export default class InputRender extends Component {
const styles = {
input: {
paddingHorizontal: 16,
paddingVertical: 8,
paddingVertical: Platform.OS === "web" ? 12 : 8,
marginVertical: 8,
backgroundColor: Style.PRIMARY_DARK_COLOR,
color: "white",
borderRadius: 3
},
input_active: {
paddingHorizontal: 16,
paddingVertical: 8,
paddingVertical: Platform.OS === "web" ? 12 : 8,
marginVertical: 8,
backgroundColor: Style.PRIMARY_DARK_HOVER_COLOR,
color: "white",
@@ -88,6 +88,10 @@ const styles = {
},
android: {
elevation: 2
},
web: {
boxShadow:
"0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)"
}
})
}
@@ -0,0 +1,100 @@
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
Platform,
Image,
TextInput,
Dimensions
} from "react-native";

import Input from "./Input";
import Button from "./Button";
import Logo from "./Logo";

export class LoginForm extends Component {
constructor(props, context) {
super(props, context);
}

render() {
const { width, height } = Dimensions.get("window");
const formWidth = Platform.OS === "web" ? 400 : width - 60;

return (
<View style={[styles.loginView, { width: formWidth }]}>
<Logo
size={"normal"}
variant={"white"}
align={"center"}
style={styles.logo}
/>
<Text style={styles.title}>Login to your Tox profile</Text>
<Input
name="username"
placeholder={"Username..."}
autocomplete={false}
/>
<Input
name="password"
placeholder={"Password..."}
secureTextEntry={true}
autocomplete={false}
/>
<View style={styles.actions}>
<Button
uppercase={true}
onPress={() => this.props.onLoginButtonPress()}
onPressDelay={200}
text="Sign in"
/>
</View>
</View>
);
}
}

const styles = StyleSheet.create({
loginView: {
...Platform.select({
web: {
backgroundColor: "#555",
padding: 32,
borderRadius: 5
}
})
},
logo: {
marginBottom: 32,
alignSelf: "center"
},
title: {
color: "rgba(255,255,255,.87)",
fontSize: 22,
marginBottom: 8,
paddingBottom: 12,
textAlign: "center",
...Platform.select({
web: {
borderBottom: "3px solid rgba(255, 255, 255, .2)"
},
default: {
borderBottomColor: "rgba(255, 255, 255, .3)",
borderBottomWidth: 2
}
})
},
actions: {
marginTop: 16,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
},
createAccount: {
fontSize: 16,
color: "white"
}
});

export default LoginForm;
@@ -0,0 +1,67 @@
import React, { Component } from "react";
import { Platform, View, Image } from "react-native";

const ORIGINAL_WIDTH = 149;
const ORIGINAL_HEIGHT = 60;

export class Logo extends Component {
constructor(props, context) {
super(props, context);
}

render() {
const { size, variant, align } = this.props;

/**
* TODO: Handle variant (color: white, black, muted, colors).
*/
return (
<View
style={{
width: "100%",
alignItems:
align === "center"
? "center"
: align === "right" ? "flex-end" : "flex-start"
}}
{...this.props}
>
<Image
{...this.props}
style={styles[size] || styles.normal}
resizeMode={"contain"}
source={
Platform.OS === "web"
? require("../assets/tox-logo.svg")
: require("../assets/tox-logo.png")
}
/>
</View>
);
}
}

const styles = {
small: {
width: ORIGINAL_WIDTH / 2,
height: ORIGINAL_HEIGHT / 2
},
medium: {
width: ORIGINAL_WIDTH / 1.5,
height: ORIGINAL_HEIGHT / 1.5
},
normal: {
width: ORIGINAL_WIDTH,
height: ORIGINAL_HEIGHT
},
big: {
width: ORIGINAL_WIDTH * 1.5,
height: ORIGINAL_HEIGHT * 1.5
},
bigger: {
width: ORIGINAL_WIDTH * 2,
height: ORIGINAL_HEIGHT * 2
}
};

export default Logo;
@@ -0,0 +1,86 @@
import React, { Component } from "react";
import {
StyleSheet,
Text,
View,
Platform,
Image,
TextInput,
Dimensions
} from "react-native";

import Input from "./Input";
import Button from "./Button";
import Logo from "./Logo";

export class RegisterForm extends Component {
constructor(props, context) {
super(props, context);
}

render() {
const { width, height } = Dimensions.get("window");
const formWidth = Platform.OS === "web" ? 400 : width - 60;

return (
<View style={[styles.loginView, { width: formWidth }]}>
<Logo
size={"normal"}
variant={"white"}
align={"center"}
style={styles.logo}
/>
<Input placeholder={"Choose your username..."} />
<Input placeholder={"Type your password..."} secureTextEntry={true} />
<Input
placeholder={"Confirm your password..."}
secureTextEntry={true}
/>
<View style={styles.actions}>
<Button
uppercase={true}
onPress={() => this.props.onRegisterButtonPress()}
onPressDelay={200}
text="Sign up"
/>
<Text
onPress={() => this.props.onBackLoginButtonPress()}
style={styles.backLogin}
>
Back to login
</Text>
</View>
</View>
);
}
}

const styles = StyleSheet.create({
loginView: {
...Platform.select({
web: {
backgroundColor: "#555",
padding: 32,
borderRadius: 5
}
})
},
logo: {
width: 150,
height: 60,
marginBottom: 32,
alignSelf: "center"
},
actions: {
marginTop: 16,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
},
backLogin: {
fontSize: 16,
color: "white"
}
});

export default RegisterForm;
Empty file.

This file was deleted.

This file was deleted.

@@ -1,49 +1,23 @@
import React, { Component } from "react";
import { render } from "react-dom";
import React from "react";
import { Provider } from "react-redux";
import ReactNative from "react-native";
import store from "./utilities/storage/store";
import LoginScreen from "./screens/LoginScreen";
import RegisterScreen from "./screens/RegisterScreen";
import Routing, { Router, Switch } from "./utilities/routing/index";

// Redux imports.
import { createStore, applyMiddleware } from "redux";
import { Provider, connect } from "react-redux";
import { composeWithDevTools } from "remote-redux-devtools";
import thunk from "redux-thunk";

import { globalRoutes } from "./common/routes";
import { getRootReducer } from "./common/store/rootReducer";
import InitialScreen from "./common/screens/InitialScreen";

// CSS
require("./styles/normalize.css");
require("./styles/components.css");
require("./styles/main.css");

export default class App extends Component {
constructor(props) {
super(props);

const middlewares = [thunk];
const reducer = getRootReducer(null);

this.store = createStore(
reducer,
{},
window.__REDUX_DEVTOOLS_EXTENSION__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__(
applyMiddleware(...middlewares)
)
: applyMiddleware(...middlewares)
);
}

componentWillMount() {}
const Route = Routing.Route;

class App extends React.Component {
render() {
return (
<Provider store={this.store}>
<InitialScreen />
<Provider store={store}>
<Router>
<Route exact path="/" component={LoginScreen} />
</Router>
</Provider>
);
}
}

const content = document.querySelector("#content");
render(<App />, content);
ReactNative.render(<App />, document.getElementById("root"));

This file was deleted.

@@ -0,0 +1,11 @@
/**
* Created by amoghbanta on 04/02/17.
*/
import {combineReducers} from "redux";
import SampleReducer from "./sampleReducer";


//this is the list of final reducers
export default combineReducers({
sampleReducer: SampleReducer,
})
@@ -0,0 +1,21 @@
/**
* Created by amoghbanta on 04/02/17.
*/
import * as types from "../actions/ActionTypes";


export default function logReducer(state = {}, action) {
switch (action.type) {

case types.SOMETHING_HAPPENED_SUCCESSFULLY:
return {
...state,...action.data, somethingHappeningStatus:"successful"
};
case types.SOMETHING_FAILED:
return {
...state,...action.data, somethingHappeningStatus:"failed"
};
default:
return state;
}
}
@@ -0,0 +1,33 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import LoginForm from "./../components/LoginForm";

class LoginScreen extends React.Component {
constructor(props, context) {
super(props, context);
}

render() {
return (
<View style={styles.container}>
<LoginForm />
</View>
);
}
}

const styles = StyleSheet.create({
container: {
display: "flex",
flex: 1,
height: "100%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 16,
paddingVertical: 8,
backgroundColor: "#414141"
}
});

export default LoginScreen;
@@ -0,0 +1,33 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import RegisterForm from "../components/RegisterForm";

class RegisterScreen extends React.Component {
constructor(props, context) {
super(props, context);
}

render() {
return (
<View style={styles.container}>
<RegisterForm />
</View>
);
}
}

const styles = StyleSheet.create({
container: {
display: "flex",
flex: 1,
height: "100%",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 16,
paddingVertical: 8,
backgroundColor: "#414141"
}
});

export default RegisterScreen;
@@ -0,0 +1,42 @@
import React from "react";

import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { linkTo } from "@storybook/addon-links";
import { Logo } from "../components/Logo";
import { Button } from "../components/Button";
import { Input } from "../components/Input";

storiesOf("Logo", module)
.add("with original size", () => <Logo size={"original"} />)
.add("with medium size", () => <Logo size={"medium"} />)
.add("with small size", () => <Logo size={"small"} />)
.add("with big size", () => <Logo size={"big"} />)
.add("with bigger size", () => <Logo size={"bigger"} />);

storiesOf("Button", module)
.add("with text", () => (
<Button onClick={action("clicked")}>Hello Button</Button>
))
.add("with some emoji", () => (
<Button onClick={action("clicked")}>šŸ˜€ šŸ˜Ž šŸ‘ šŸ’Æ</Button>
));

storiesOf("Input", module)
.add("with base style", () => <Input onChangeText={action("changed")} />)
.add("with placeholder", () => (
<Input
placeholder={"This is the placeholder, m8!"}
onChangeText={action("changed")}
/>
))
.add("with some emoji in placeholder", () => (
<Input placeholder={"šŸ˜€ šŸ˜Ž šŸ‘ šŸ’Æ"} onChangeText={action("changed")} />
))
.add("with secureTextEntry", () => (
<Input
placeholder={"šŸ˜€ šŸ˜Ž šŸ‘ šŸ’Æ"}
secureTextEntry={true}
onChangeText={action("changed")}
/>
));
File renamed without changes.

This file was deleted.

This file was deleted.

This file was deleted.

Empty file.
@@ -0,0 +1,4 @@
import * as Routing from "react-router-native";
export default Routing;
export const Router = Routing.NativeRouter;
export const Switch = Routing.Switch;
@@ -0,0 +1,4 @@
import * as Routing from "react-router-native";
export default Routing;
export const Router = Routing.NativeRouter;
export const Switch = Routing.Switch;
@@ -0,0 +1,4 @@
import * as Routing from "react-router-dom";
export default Routing;
export const Router = Routing.BrowserRouter;
export const Switch = Routing.Switch;
@@ -0,0 +1,15 @@
import { Platform } from "react-native";

const RouterPackage =
Platform.OS === "web"
? require("react-router-dom")
: require("react-router-native");

/*
* Remove Platform specific exports :/
* */
export const { Link, Route, Redirect } = RouterPackage;
export const Router =
Platform.OS === "web"
? RouterPackage.BrowserRouter
: RouterPackage.NativeRouter;
Empty file.
@@ -0,0 +1,9 @@
import {createStore, applyMiddleware, compose} from "redux";
import thunk from "redux-thunk";
import rootReducer from "../../reducers/rootReducer";

let initialState = {};
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(rootReducer, initialState, composeEnhancers(applyMiddleware(thunk)));

export default store;

This file was deleted.

This file was deleted.

7,652 yarn.lock

Large diffs are not rendered by default.