├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── contribute.md
│ └── feature_request.md
└── workflows
│ └── main.yml
├── .gitignore
├── .huskyrc
├── .prettierrc
├── .stylelintrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app
├── app.html
├── app.icns
├── classes
│ ├── AppUpdate.js
│ ├── Boot.js
│ └── Storage.js
├── components
│ ├── Breadcrumb
│ │ ├── index.jsx
│ │ └── styles
│ │ │ └── index.js
│ ├── DialogBox
│ │ ├── components
│ │ │ ├── Confirm.jsx
│ │ │ ├── Notification.jsx
│ │ │ ├── ProgressBar.jsx
│ │ │ ├── Selection.jsx
│ │ │ └── TextFieldEdit.jsx
│ │ ├── index.jsx
│ │ └── styles
│ │ │ ├── Confirm.js
│ │ │ ├── Notification.js
│ │ │ ├── ProgressBar.js
│ │ │ ├── Selection.js
│ │ │ └── TextFieldEdit.js
│ ├── LoadingIndicator
│ │ ├── index.jsx
│ │ └── styles
│ │ │ └── index.js
│ └── Snackbars
│ │ ├── components
│ │ └── SnackbarThemeWrapper.jsx
│ │ ├── index.jsx
│ │ └── styles
│ │ ├── SnackbarThemeWrapper.js
│ │ └── index.js
├── constants
│ ├── dom.js
│ ├── env.js
│ ├── index.js
│ ├── keymaps.js
│ ├── meta.js
│ ├── onboarding.js
│ ├── paths.js
│ └── serviceKeys.js
├── containers
│ ├── Alerts
│ │ ├── actions.js
│ │ ├── index.jsx
│ │ └── reducers.js
│ ├── App
│ │ ├── Root.jsx
│ │ ├── actions.js
│ │ ├── components
│ │ │ └── Titlebar.jsx
│ │ ├── index.jsx
│ │ ├── reducers.js
│ │ ├── selectors.js
│ │ └── styles
│ │ │ ├── Titlebar.js
│ │ │ └── index.js
│ ├── AppFeaturesPage
│ │ ├── Loadable.js
│ │ ├── index.jsx
│ │ └── styles
│ │ │ └── index.js
│ ├── AppUpdatePage
│ │ ├── UpdateAvailable
│ │ │ ├── Loadable.js
│ │ │ ├── index.jsx
│ │ │ └── styles
│ │ │ │ ├── index.js
│ │ │ │ └── release-notes.scss
│ │ └── UpdateProgress
│ │ │ ├── Loadable.js
│ │ │ ├── index.jsx
│ │ │ └── styles
│ │ │ └── index.js
│ ├── ErrorBoundary
│ │ ├── components
│ │ │ ├── GenerateErrorReport.jsx
│ │ │ └── GenerateErrorReportBody.jsx
│ │ ├── index.jsx
│ │ └── styles
│ │ │ ├── GenerateErrorReport.js
│ │ │ └── index.js
│ ├── HelpFaqsPage
│ │ ├── Loadable.js
│ │ ├── components
│ │ │ └── HelpPhoneNotRecognized.jsx
│ │ ├── index.jsx
│ │ └── styles
│ │ │ ├── HelpPhoneNotRecognized.js
│ │ │ └── index.js
│ ├── HomePage
│ │ ├── Loadable.js
│ │ ├── actions.js
│ │ ├── components
│ │ │ ├── FileExplorer.jsx
│ │ │ ├── FileExplorerBodyRender.jsx
│ │ │ ├── FileExplorerTableBodyEmptyRender.jsx
│ │ │ ├── FileExplorerTableBodyGridRender.jsx
│ │ │ ├── FileExplorerTableBodyGridWrapperRender.jsx
│ │ │ ├── FileExplorerTableBodyListRender.jsx
│ │ │ ├── FileExplorerTableBodyListWrapperRender.jsx
│ │ │ ├── FileExplorerTableBodyRender.jsx
│ │ │ ├── FileExplorerTableFooterRender.jsx
│ │ │ ├── FileExplorerTableFooterStatusBarRender.jsx
│ │ │ ├── FileExplorerTableHeadRender.jsx
│ │ │ ├── SidebarAreaPaneLists.jsx
│ │ │ ├── ToolbarAreaPane.jsx
│ │ │ └── ToolbarBody.jsx
│ │ ├── index.jsx
│ │ ├── reducers.js
│ │ ├── selectors.js
│ │ └── styles
│ │ │ ├── FileExplorer.js
│ │ │ ├── FileExplorerBodyRender.js
│ │ │ ├── FileExplorerTableBodyEmptyRender.js
│ │ │ ├── FileExplorerTableBodyGridRender.js
│ │ │ ├── FileExplorerTableBodyGridWrapperRender.js
│ │ │ ├── FileExplorerTableBodyListRender.js
│ │ │ ├── FileExplorerTableBodyRender.js
│ │ │ ├── FileExplorerTableFooterRender.js
│ │ │ ├── FileExplorerTableFooterStatusBarRender.js
│ │ │ ├── FileExplorerTableHeadRender.js
│ │ │ ├── SidebarAreaPaneLists.js
│ │ │ ├── ToolbarAreaPane.js
│ │ │ └── index.js
│ ├── KeyboardShortcutsPage
│ │ ├── Loadable.js
│ │ ├── components
│ │ │ ├── KbdRender.jsx
│ │ │ └── KeyboadShortcuts.jsx
│ │ ├── index.jsx
│ │ └── styles
│ │ │ ├── KeyboadShortcuts.js
│ │ │ └── index.js
│ ├── NotFoundPage
│ │ ├── Loadable.js
│ │ ├── index.jsx
│ │ └── styles
│ │ │ └── index.scss
│ ├── Onboarding
│ │ ├── components
│ │ │ ├── Features.jsx
│ │ │ └── WhatsNew.jsx
│ │ ├── index.jsx
│ │ └── styles
│ │ │ ├── Features.js
│ │ │ ├── WhatsNew.js
│ │ │ └── index.js
│ ├── PrivacyPolicyPage
│ │ ├── Loadable.js
│ │ ├── index.jsx
│ │ └── styles
│ │ │ └── index.js
│ ├── ReportBugsPage
│ │ ├── Loadable.js
│ │ ├── index.jsx
│ │ └── styles
│ │ │ └── index.js
│ └── Settings
│ │ ├── actions.js
│ │ ├── components
│ │ ├── SettingsDialog.jsx
│ │ └── SettingsDialogTabContainer.jsx
│ │ ├── index.jsx
│ │ ├── reducers.js
│ │ ├── selectors.js
│ │ └── styles
│ │ └── index.js
├── data
│ └── file-explorer
│ │ ├── controllers
│ │ └── FileExplorerController.js
│ │ ├── data-sources
│ │ ├── FileExplorerKalamDataSource.js
│ │ ├── FileExplorerLegacyDataSource.js
│ │ └── FileExplorerLocalDataSource.js
│ │ └── repositories
│ │ └── FileExplorerRepository.js
├── enums
│ ├── appUpdater.js
│ ├── events.js
│ ├── index.js
│ └── mtpError.js
├── helpers
│ ├── binaries.js
│ ├── bootHelper.js
│ ├── console.js
│ ├── createWindows.js
│ ├── deviceInfo.js
│ ├── fileOps.js
│ ├── identifiers.js
│ ├── logs.js
│ ├── processBufferOutput.js
│ ├── reducerPrefixer.js
│ ├── remoteWindowHelpers.js
│ ├── settings.js
│ ├── storageHelper.js
│ ├── theme.js
│ ├── titlebarDoubleClick.js
│ └── windowHelper.js
├── index.js
├── main.dev.js
├── menu.js
├── public
│ └── images
│ │ ├── FileExplorer
│ │ ├── buymeacoffee-button.png
│ │ ├── files-archive.svg
│ │ ├── folder-blue.svg
│ │ ├── folder-dark.svg
│ │ ├── folder-light.svg
│ │ └── paypal-logo.png
│ │ ├── bug.svg
│ │ ├── file-types
│ │ ├── 7z.svg
│ │ ├── aac.svg
│ │ ├── ai.svg
│ │ ├── archive.svg
│ │ ├── arj.svg
│ │ ├── audio.svg
│ │ ├── avi.svg
│ │ ├── css.svg
│ │ ├── csv.svg
│ │ ├── dbf.svg
│ │ ├── doc.svg
│ │ ├── dwg.svg
│ │ ├── exe.svg
│ │ ├── fit.svg
│ │ ├── fla.svg
│ │ ├── flac.svg
│ │ ├── gif.svg
│ │ ├── html.svg
│ │ ├── iso.svg
│ │ ├── jpg.svg
│ │ ├── js.svg
│ │ ├── json.svg
│ │ ├── mdf.svg
│ │ ├── mp2.svg
│ │ ├── mp3.svg
│ │ ├── mp4.svg
│ │ ├── mxf.svg
│ │ ├── nrg.svg
│ │ ├── pdf.svg
│ │ ├── png.svg
│ │ ├── ppt.svg
│ │ ├── psd.svg
│ │ ├── rar.svg
│ │ ├── rtf.svg
│ │ ├── svg.svg
│ │ ├── text.svg
│ │ ├── tiff.svg
│ │ ├── txt.svg
│ │ ├── unknown.svg
│ │ ├── video.svg
│ │ ├── wav.svg
│ │ ├── wma.svg
│ │ ├── xls.svg
│ │ ├── xml.svg
│ │ └── zip.svg
│ │ ├── help
│ │ ├── allow-data-access.png
│ │ ├── charge-only-permission.png
│ │ ├── full-disk-access-file-picker.jpeg
│ │ ├── full-disk-access.png
│ │ ├── google-drive-not-connecting.png
│ │ ├── macos-directory-access.jpg
│ │ ├── privacy-restricted-folder-access.png
│ │ ├── sleep-setting.jpg
│ │ ├── transfer-media-permission.png
│ │ ├── usb-notification-charging-via-usb.png
│ │ └── usb-notification-transferring-media.png
│ │ ├── no-image.png
│ │ └── toolbar
│ │ └── buymeacoffee.png
├── routing
│ └── index.js
├── services
│ ├── analytics
│ │ ├── googleAnalytics.js
│ │ ├── index.js
│ │ └── mixpanelAnalytics.js
│ ├── ipc-events
│ │ ├── IpcEventHandler.js
│ │ └── IpcEventType.js
│ └── sentry
│ │ └── index.js
├── store
│ ├── configureStore
│ │ ├── dev.js
│ │ ├── index.js
│ │ └── prod.js
│ └── reducers
│ │ ├── index.js
│ │ └── withReducer.js
├── styles
│ ├── js
│ │ ├── index.js
│ │ ├── mixins.js
│ │ └── variables.js
│ └── scss
│ │ ├── app.global.scss
│ │ ├── base
│ │ ├── _base.scss
│ │ ├── _extends.scss
│ │ ├── _mixins.scss
│ │ ├── _variables.scss
│ │ └── mixins
│ │ │ ├── _align-items.scss
│ │ │ ├── _animate-link.scss
│ │ │ ├── _animations.scss
│ │ │ ├── _backface-visibility.scss
│ │ │ ├── _background-cover.scss
│ │ │ ├── _border.scss
│ │ │ ├── _box-model.scss
│ │ │ ├── _box-shadow.scss
│ │ │ ├── _breakpoint.scss
│ │ │ ├── _clearfix.scss
│ │ │ ├── _display.scss
│ │ │ ├── _display_flex.scss
│ │ │ ├── _flex.scss
│ │ │ ├── _hide-text.scss
│ │ │ ├── _horz-vert-center.scss
│ │ │ ├── _hover-focus.scss
│ │ │ ├── _inline-block.scss
│ │ │ ├── _inner-shadow.scss
│ │ │ ├── _keyframes.scss
│ │ │ ├── _linear-gradient-angle.scss
│ │ │ ├── _linear-gradient.scss
│ │ │ ├── _margin-auto.scss
│ │ │ ├── _mediumFont.scss
│ │ │ ├── _min-breakpoint.scss
│ │ │ ├── _opacity.scss
│ │ │ ├── _placeholder.scss
│ │ │ ├── _rem.scss
│ │ │ ├── _replace-text.scss
│ │ │ ├── _retina.scss
│ │ │ ├── _rounded-corners.scss
│ │ │ ├── _single-transform.scss
│ │ │ ├── _text-shadow.scss
│ │ │ ├── _transform.scss
│ │ │ ├── _transitions.scss
│ │ │ ├── _translate.scss
│ │ │ └── _triangles.scss
│ │ └── themes
│ │ ├── fonts.scss
│ │ └── reset.scss
├── templates
│ ├── appFeaturesPage.js
│ ├── fileExplorer.js
│ ├── generateErrorReport.js
│ ├── helpFaqsPage.js
│ ├── keyboardShortcutsPage.js
│ ├── loadProfileError.js
│ ├── menu.js
│ ├── privacyPolicyPage.js
│ └── socialMediaShareBtns.js
├── utils
│ ├── checkIf.js
│ ├── date.js
│ ├── errors.js
│ ├── eventHandling.js
│ ├── files.js
│ ├── funcs.js
│ ├── getPlatform.js
│ ├── gzip.js
│ ├── imgsrc.js
│ ├── isGoogleAndroidFileTransferActive.js
│ ├── isOnline.js
│ ├── isPackaged.js
│ ├── log.js
│ ├── pkginfo.js
│ ├── process.js
│ ├── styleResets.js
│ ├── styles.js
│ └── url.js
└── vendors
│ └── pretty-file-icons
│ ├── LICENSE
│ ├── README.md
│ ├── index.js
│ ├── index.json
│ └── package.json
├── babel.config.js
├── blobs
├── binaries
│ ├── .gitkeep
│ └── libusb_1.0.22_el_capitan_darwin_amd64.tar.gz
└── images
│ ├── file-explorer-bluebg.jpg
│ ├── file-explorer.png
│ ├── file-transfer-bluebg.jpg
│ ├── file-transfer-large.png
│ └── file-transfer.png
├── build
├── entitlements.mac.plist
├── icon.icns
├── icon.ico
├── icon.png
├── icons
│ ├── 1024x1024.png
│ ├── 128x128.png
│ ├── 16x16.png
│ ├── 256x256.png
│ ├── 32x32.png
│ ├── 512x512.png
│ └── 64x64.png
├── mac
│ └── bin
│ │ ├── amd64
│ │ ├── kalam.dylib
│ │ ├── kalam.h
│ │ ├── kalam_debug_report
│ │ └── libusb.dylib
│ │ ├── arm64
│ │ ├── kalam.dylib
│ │ ├── kalam.h
│ │ ├── kalam_debug_report
│ │ └── libusb.dylib
│ │ ├── medieval
│ │ └── amd64
│ │ │ ├── kalam.dylib
│ │ │ ├── kalam.h
│ │ │ ├── kalam_debug_report
│ │ │ └── libusb.dylib
│ │ └── mtp-cli
└── sample.entitlements.mas.plist
├── codemagic.yaml
├── config
├── dev-app-update.yml
└── env
│ ├── env.dev.js
│ ├── env.prod.js
│ └── index.js
├── docs-sources
├── images
│ ├── file-explorer.png
│ └── file-transfer.png
├── index.js
├── styles
│ ├── base
│ │ ├── _base.scss
│ │ └── _themes.scss
│ └── global.scss
├── templates
│ ├── index.html
│ └── privacy.html
├── utils
│ ├── consts.js
│ └── funcs.js
└── webpack
│ ├── webpack.config.base.js
│ ├── webpack.config.dev.js
│ └── webpack.config.prod.js
├── docs
├── CNAME
├── _config.yml
├── bundle
│ ├── file-explorer.1b1a659da61529904113.png
│ ├── file-transfer.e01ae86967cd5e83a375.png
│ ├── index.2a3c7308644dc6b26b7d.css
│ └── index.6845514fce43dda32e49.js
├── favicon.ico
├── google25c4a4597b2b27f3.html
├── index.html
├── privacy.html
├── robots.txt
└── sitemap.xml
├── electron-builder-config.js
├── ffi
└── kalam
│ ├── native
│ ├── .gitignore
│ ├── README.md
│ ├── go.mod
│ ├── go.sum
│ ├── helpers.go
│ ├── kalam.go
│ ├── kalam_debug_report
│ │ └── main.go
│ ├── scripts
│ │ └── build.mjs
│ ├── send_to_js
│ │ ├── constants.go
│ │ ├── enums.go
│ │ ├── errors.go
│ │ ├── helpers.go
│ │ ├── main.go
│ │ └── structs.go
│ ├── structs.go
│ └── utils.go
│ └── src
│ └── Kalam.js
├── internals
└── scripts
│ ├── AfterPack.js
│ ├── CheckBuildExist.js
│ ├── CheckNodeEnv.js
│ ├── CheckPortInUse.js
│ ├── CheckYarn.js
│ ├── Notarize.js
│ ├── OptionalDepsInstall.js
│ ├── preinstall.sh
│ └── semver.js
├── lint-staged.config.js
├── package.json
├── sample.env
├── sample.sentry.properties
├── scripts
└── cicd
│ ├── axios.mjs
│ ├── base.mjs
│ ├── codemagic-publish-builds.mjs
│ ├── codemagic-start-mac-intel-x64-vm.mjs
│ └── constants.mjs
├── sentry-symbols.js
├── webpack
├── config.base.js
├── config.eslint.js
├── config.main.prod.babel.js
├── config.renderer.dev.babel.js
├── config.renderer.dev.dll.babel.js
└── config.renderer.prod.babel.js
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 | .eslintcache
25 |
26 | # Dependency directory
27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
28 | node_modules
29 |
30 | # OSX
31 | .DS_Store
32 |
33 | # flow-typed
34 | flow-typed/npm/*
35 | !flow-typed/npm/module_vx.x.x.js
36 |
37 | # App packaged
38 | release
39 | app/main.prod.js
40 | app/main.prod.js.map
41 | app/renderer.prod.js
42 | app/renderer.prod.js.map
43 | app/style.css
44 | app/style.css.map
45 | dist
46 | dll
47 | main.js
48 | main.js.map
49 | app/vendors
50 |
51 |
52 | .idea
53 | npm-debug.log.*
54 | __snapshots__
55 |
56 | # Package.json
57 | package.json
58 | .travis.yml
59 |
60 | .env*
61 | .idea
62 | vendors
63 | build
64 | docs
65 | .vscode
66 | .github
67 | app/dll
68 | .prettierrc
69 | .stylelintrc
70 | .eslintrc.json
71 |
72 |
73 | package-lock.json
74 | sentry.properties
75 |
76 | app/certs/*.pem
77 | certs/*
78 | todo.txt
79 | *yarn-error.log
80 | eslint-common-rules.txt
81 |
82 | build/entitlements.mas.plist
83 | *embedded.provisionprofile
84 | extras/*
85 | mtp-mock-files/*
86 | resources
87 | tmp/*
88 | *.prod.js
89 | *.js.map
90 | *.js.LICENSE.txt
91 | *.prod.js.LICENSE.txt
92 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom:
2 | - https://paypal.me/ganeshrvel
3 | - https://buymeacoffee.com/ganeshrvel
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | labels: 'bug'
5 |
6 | ---
7 |
8 | **Prerequisites**
9 |
10 | - [ ] Have you reviewed the steps in the following link to see if they address your issue?
11 | - https://github.com/ganeshrvel/openmtp/issues/276
12 |
13 | **Describe the bug**
14 | A clear and concise description of what the bug is.
15 |
16 |
17 | **Attachments**
18 | Include if relevant,
19 | 1. Open your Terminal and run the following code:
20 | ```shell
21 | zip -r -X ~/Desktop/OpenMTP-log.zip "$HOME/Library/Application Support/io.ganeshrvel.openmtp/logs/"
22 | ```
23 | 2. Attach the file *OpenMTP-log.zip* found in your Desktop folder here.
24 |
25 | Or
26 |
27 | 1. Open the App,
28 | 2. Click on Help > Report Bugs.
29 | 3. Generate and send us the bugs report.
30 |
31 | **Screenshots**
32 | If applicable, add screenshots to help explain your problem.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/contribute.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Contribute
3 | about: Open a new issue and contribute to the app.
4 | ---
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: You want something added to the app or code.
4 | labels: 'enhancement'
5 | ---
6 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 | runs-on: macOS-11.00
12 | steps:
13 | - name: Setup build environment
14 | uses: actions/setup-node@v1
15 | with:
16 | node-version: '16.x'
17 | - run: npm install -g cross-env create-dmg
18 | - name: Cloning Git repository
19 | uses: actions/checkout@v1
20 | - name: Attempt to build OpenMTP
21 | run: |
22 | yarn
23 | yarn build
24 | - name: Attempt to generate unsigned macOS app
25 | run: |
26 | export CSC_IDENTITY_AUTO_DISCOVERY=false
27 | yarn package-mac-without-notarize 2>&1 || true
28 | - name: Check if macOS app was generated
29 | run: test -e dist/mac/OpenMTP.app
30 | - name: Attempt to create disk image for generated macOS app
31 | run: |
32 | mkdir dist/dmg
33 | create-dmg dist/mac/OpenMTP.app dist/dmg 2>&1 || true
34 | shasum dist/dmg/* >> dist/dmg/CHECKSUM_SHA256.txt
35 | - name: Upload disk image and checksum as artifact
36 | uses: actions/upload-artifact@v1.0.0
37 | with:
38 | name: 'Disk Image'
39 | path: dist/dmg/
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 | .eslintcache
25 |
26 | # Dependency directory
27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
28 | node_modules/
29 | app/node_modules
30 |
31 | # OSX
32 | .DS_Store
33 |
34 | # flow-typed
35 | flow-typed/npm/*
36 | !flow-typed/npm/module_vx.x.x.js
37 |
38 | # App packaged
39 | release
40 | app/main.prod.js
41 | app/main.prod.js.map
42 | app/renderer.prod.js
43 | app/renderer.prod.js.map
44 | app/style.css
45 | app/style.css.map
46 | dist
47 | dll
48 | main.js
49 | main.js.map
50 |
51 | .idea
52 | npm-debug.log.*
53 | package-lock.json
54 | .env*
55 | sentry.properties
56 |
57 | app/certs/*.pem
58 | certs/*
59 | todo.txt
60 | *yarn-error.log
61 | eslint-common-rules.txt
62 |
63 | build/entitlements.mas.plist
64 | *embedded.provisionprofile
65 | extras/*
66 | mtp-mock-files/*
67 | resources
68 | tmp/*
69 | *.prod.js
70 | *.js.map
71 | *.js.LICENSE.txt
72 | *.prod.js.LICENSE.txt
73 |
--------------------------------------------------------------------------------
/.huskyrc:
--------------------------------------------------------------------------------
1 | {
2 | "hooks": {
3 | "pre-commit": "lint-staged"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [
3 | {
4 | "files": [".prettierrc", ".babelrc", ".eslintrc", ".stylelintrc"],
5 | "options": {
6 | "parser": "json"
7 | }
8 | }
9 | ],
10 | "singleQuote": true
11 | }
12 |
--------------------------------------------------------------------------------
/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard", "stylelint-config-prettier"],
3 | "rules": {
4 | "color-function-notation": null,
5 | "value-no-vendor-prefix": null,
6 | "property-no-vendor-prefix": null,
7 | "font-family-name-quotes": null,
8 | "rule-empty-line-before": null,
9 | "at-rule-no-vendor-prefix": null,
10 | "shorthand-property-no-redundant-values": null,
11 | "selector-class-pattern": null,
12 | "annotation-no-unknown": null,
13 | "value-keyword-case": null,
14 | "function-no-unknown": null,
15 | "selector-no-vendor-prefix": null,
16 | "media-feature-name-no-vendor-prefix": null,
17 | "alpha-value-notation": null,
18 | "at-rule-no-unknown": null,
19 | "import-notation": null,
20 | "no-descending-specificity": null
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to OpenMTP
2 |
3 | Thank you for your interest in contributing to OpenMTP!
4 |
5 | ### How to Contribute
6 | - Create a new issue [here](https://github.com/ganeshrvel/openmtp/issues/new "here").
7 | - Assign yourself as the "Assignees".
8 | - Fork the repo and create your branch from the **master** (important!).
9 | - Make your changes.
10 | - Ensure that the changes pass linting.
11 | - Update the documentation if needed.
12 | - Add short, meaningful commit message that describes the change you made to the code.
13 | - Append the issue URL in the commit message.
14 | - Issue a pull request to the **development** branch.
15 | - Add a reviewer.
16 |
17 | When you submit code changes, your submissions are understood to be under the same [MIT License](https://github.com/ganeshrvel/openmtp/blob/master/LICENSE "MIT License") that covers the project. Feel free to contact the maintainers if that's a concern.
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2010-present Ganesh Rathinavel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/app/app.html:
--------------------------------------------------------------------------------
1 | <!DOCTYPE html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="utf-8">
5 | <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" />
6 | <title>OpenMTP | Android File Transfer for macOS</title>
7 | <script>
8 | (() => {
9 | if (typeof process === "object" && typeof process.env === "object" && typeof process.env.NODE_ENV === "undefined") {
10 | process.env.NODE_ENV = "production";
11 | }
12 |
13 | if (
14 | typeof process !== "object" ||
15 | (typeof process === "object" && !process.env.START_HOT)
16 | ) {
17 | const link = document.createElement("link");
18 | link.rel = "stylesheet";
19 | link.href = "./dist/style.css";
20 | // HACK: Writing the script path should be done with webpack
21 | document.getElementsByTagName("head")[0].appendChild(link);
22 | }
23 | })();
24 | </script>
25 | </head>
26 | <body>
27 | <div id="root"></div>
28 | <script>
29 | if (typeof process === "object") {
30 | const scripts = [];
31 | let PORT;
32 |
33 | if (process.env.NODE_ENV === "development") {
34 | // Dynamically insert the DLL script in development env in the
35 | // renderer process
36 | scripts.push("../dll/renderer.dev.dll.js");
37 |
38 | PORT = require("../config/env").PORT;
39 | }
40 | if (process.env.START_HOT) {
41 | // Dynamically insert the bundled app script in the renderer process
42 | scripts.push(`http://localhost:${PORT}/dist/renderer.dev.js`);
43 | } else {
44 | scripts.push("./dist/renderer.prod.js");
45 | }
46 |
47 | if (scripts.length) {
48 | document.write(
49 | scripts
50 | .map(script => `<script defer src="${script}"><\/script>`)
51 | .join("")
52 | );
53 | }
54 | }
55 | </script>
56 | </body>
57 | </html>
58 |
--------------------------------------------------------------------------------
/app/app.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/app.icns
--------------------------------------------------------------------------------
/app/components/Breadcrumb/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => {
4 | return {
5 | root: {
6 | width: `100%`,
7 | height: `100%`,
8 | },
9 |
10 | rootBreadcrumbs: {
11 | width: `100%`,
12 | height: `100%`,
13 | },
14 |
15 | breadcrumb: {
16 | padding: '10px 15px',
17 | backgroundColor: theme.palette.background.paper,
18 | display: 'flex',
19 | alignItems: 'center',
20 | ...mixins({ theme }).resetUl,
21 | },
22 |
23 | breadcrumbLi: {
24 | display: 'inline-block',
25 | padding: '0 2px 4px 2px',
26 | overflow: 'hidden',
27 | fontSize: 14,
28 | maxWidth: 59,
29 | whiteSpace: 'nowrap',
30 | textOverflow: 'ellipsis',
31 | },
32 |
33 | breadcrumbLiA: {
34 | cursor: `pointer`,
35 | color: theme.palette.secondary.main,
36 | textDecoration: 'none',
37 | [`&.bold`]: {
38 | fontWeight: `bold`,
39 | },
40 | },
41 | breadcrumbSeperator: {
42 | fontSize: 18,
43 | },
44 | };
45 | };
46 |
--------------------------------------------------------------------------------
/app/components/DialogBox/index.jsx:
--------------------------------------------------------------------------------
1 | export { default as Notification } from './components/Notification';
2 | export { default as Confirm } from './components/Confirm';
3 | export { default as TextFieldEdit } from './components/TextFieldEdit';
4 | export { default as Selection } from './components/Selection';
5 | export { default as ProgressBar } from './components/ProgressBar';
6 |
--------------------------------------------------------------------------------
/app/components/DialogBox/styles/Confirm.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | margin: {},
5 | root: {},
6 | btnPositive: {
7 | ...mixins({ theme }).btnPositive,
8 | },
9 | btnNegative: {
10 | ...mixins({ theme }).btnNegative,
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/app/components/DialogBox/styles/Notification.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | margin: {},
5 | root: {},
6 | btnPositive: {
7 | ...mixins({ theme }).btnPositive,
8 | },
9 | btnNegative: {
10 | ...mixins({ theme }).btnNegative,
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/app/components/DialogBox/styles/ProgressBar.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {
3 | flexGrow: 1,
4 | },
5 | dialogFixMultipleProgressPadding: {
6 | marginTop: 35,
7 | },
8 | dialogContentTextTop: {
9 | marginBottom: 10,
10 | fontSize: 14,
11 | },
12 | dialogContentTextBottom: {
13 | marginTop: 10,
14 | fontSize: 14,
15 | },
16 | dialogTitleInnerWrapper: {
17 | alignItems: `center`,
18 | },
19 | helpText: {
20 | float: `right`,
21 | },
22 | titleText: {
23 | float: `left`,
24 | fontSize: 17,
25 | },
26 | bottomText: {
27 | fontSize: 10,
28 | fontWeight: 400,
29 | padding: '0px 0 15px 0',
30 | },
31 | childrenWrapper: {
32 | padding: '0px 0 5px 0',
33 | },
34 | });
35 |
--------------------------------------------------------------------------------
/app/components/DialogBox/styles/Selection.js:
--------------------------------------------------------------------------------
1 | export const styles = (theme) => ({
2 | root: {},
3 | selectedAvatar: {
4 | background: theme.palette.secondary.main,
5 | },
6 | selectedIcon: {
7 | color: '#fff',
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/app/components/DialogBox/styles/TextFieldEdit.js:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 | import TextField from '@material-ui/core/TextField';
3 | import { mixins } from '../../../styles/js';
4 |
5 | export const styles = (theme) => ({
6 | root: {},
7 | dialogContentText: {
8 | marginBottom: 10,
9 | wordBreak: `break-all`,
10 | },
11 | bodyText: {
12 | display: 'block',
13 | },
14 | secondaryText: {
15 | marginBottom: 20,
16 | display: 'block',
17 | },
18 | btnPositive: {
19 | ...mixins({ theme }).btnPositive,
20 | },
21 | btnNegative: {
22 | ...mixins({ theme }).btnNegative,
23 | },
24 | textFieldRoot: {
25 | '& .MuiFormLabel-root.Mui-error.Mui-focused': {
26 | color: '#f44336',
27 | },
28 | '& .MuiFormLabel-root.Mui-focused': {
29 | color: 'unset',
30 | },
31 | },
32 | });
33 |
34 | export const StyledTextField = styled(TextField)`
35 | /* hover (double-ampersand needed for specificity reasons. */
36 | && .MuiInput-underline:hover:before {
37 | border-bottom: 1px solid rgba(0, 0, 0);
38 | }
39 | /* focused */
40 | .MuiInput-underline:after {
41 | border-bottom: 1px solid rgba(0, 0, 0, 0.87);
42 | }
43 | /* focused */
44 | .MuiInputLabel-root.MuiInput-focused {
45 | color: #000;
46 | }
47 | `;
48 |
--------------------------------------------------------------------------------
/app/components/LoadingIndicator/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import CircularProgress from '@material-ui/core/CircularProgress';
4 | import { styles } from './styles';
5 |
6 | function LoadingIndicator(props) {
7 | const { classes: styles } = props;
8 |
9 | return (
10 | <div>
11 | <CircularProgress
12 | color="secondary"
13 | className={styles.progress}
14 | size={50}
15 | />
16 | </div>
17 | );
18 | }
19 |
20 | export default withStyles(styles)(LoadingIndicator);
21 |
--------------------------------------------------------------------------------
/app/components/LoadingIndicator/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {},
3 | progress: {
4 | position: `absolute`,
5 | top: `50%`,
6 | left: `50%`,
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/app/components/Snackbars/components/SnackbarThemeWrapper.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classNames from 'classnames';
3 | import CheckCircleIcon from '@material-ui/icons/CheckCircle';
4 | import ErrorIcon from '@material-ui/icons/Error';
5 | import InfoIcon from '@material-ui/icons/Info';
6 | import Button from '@material-ui/core/Button';
7 | import SnackbarContent from '@material-ui/core/SnackbarContent';
8 | import WarningIcon from '@material-ui/icons/Warning';
9 | import { withStyles } from '@material-ui/core/styles';
10 | import { styles } from '../styles/SnackbarThemeWrapper';
11 |
12 | const variantIcon = {
13 | success: CheckCircleIcon,
14 | warning: WarningIcon,
15 | error: ErrorIcon,
16 | info: InfoIcon,
17 | };
18 |
19 | function SnackbarThemeWrapper(props) {
20 | const { classes: styles, message, onClose, variant, ...other } = props;
21 | const Icon = variantIcon[variant];
22 |
23 | return (
24 | <SnackbarContent
25 | onClick={onClose}
26 | className={classNames(styles[variant], styles.root)}
27 | aria-describedby="client-snackbar"
28 | message={
29 | <span id="client-snackbar" className={styles.message}>
30 | <Icon className={classNames(styles.icon, styles.iconVariant)} />
31 | {message}
32 | </span>
33 | }
34 | action={[
35 | <Button
36 | key={1}
37 | onClick={onClose}
38 | color="primary"
39 | className={styles.closeBtn}
40 | >
41 | Close
42 | </Button>,
43 | ]}
44 | {...other}
45 | />
46 | );
47 | }
48 |
49 | export default withStyles(styles)(SnackbarThemeWrapper);
50 |
--------------------------------------------------------------------------------
/app/components/Snackbars/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import Snackbar from '@material-ui/core/Snackbar';
3 | import { withStyles } from '@material-ui/core/styles';
4 | import SnackbarThemeWrapper from './components/SnackbarThemeWrapper';
5 | import { styles } from './styles';
6 |
7 | class Snackbars extends PureComponent {
8 | constructor(props) {
9 | super(props);
10 | this.snackbarOpen = false;
11 | }
12 |
13 | componentWillMount() {
14 | this.fireSnackbar();
15 | }
16 |
17 | fireSnackbar = () => {
18 | this.snackbarOpen = true;
19 | };
20 |
21 | _handleClose = (event, reason) => {
22 | const { OnSnackBarsCloseAlerts } = this.props;
23 |
24 | if (reason === 'clickaway') {
25 | return;
26 | }
27 |
28 | this.snackbarOpen = false;
29 | OnSnackBarsCloseAlerts();
30 | };
31 |
32 | render() {
33 | const { classes: styles, message, variant, autoHideDuration } = this.props;
34 |
35 | return (
36 | <Snackbar
37 | className={styles.root}
38 | anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
39 | open={this.snackbarOpen}
40 | autoHideDuration={autoHideDuration}
41 | onClose={this._handleClose}
42 | >
43 | <SnackbarThemeWrapper
44 | onClose={this._handleClose}
45 | variant={variant}
46 | message={message}
47 | />
48 | </Snackbar>
49 | );
50 | }
51 | }
52 |
53 | export default withStyles(styles)(Snackbars);
54 |
--------------------------------------------------------------------------------
/app/components/Snackbars/styles/SnackbarThemeWrapper.js:
--------------------------------------------------------------------------------
1 | import green from '@material-ui/core/colors/green';
2 | import amber from '@material-ui/core/colors/amber';
3 |
4 | export const styles = (theme) => ({
5 | success: {
6 | backgroundColor: green[600],
7 | },
8 | error: {
9 | backgroundColor: theme.palette.snackbar.error,
10 | },
11 | info: {
12 | backgroundColor: theme.palette.primary.dark,
13 | },
14 | warning: {
15 | backgroundColor: amber[700],
16 | },
17 | icon: {
18 | fontSize: 25,
19 | color: '#fff',
20 | },
21 | closeBtn: {
22 | color: '#fff',
23 | },
24 | iconVariant: {
25 | opacity: 0.9,
26 | marginRight: 10,
27 | },
28 | message: {
29 | display: 'flex',
30 | alignItems: 'center',
31 | color: '#fff',
32 | fontWeight: 500,
33 | },
34 | root: {
35 | minWidth: 288,
36 | maxWidth: 568,
37 | minHeight: 60,
38 | borderRadius: 15,
39 | flexGrow: `unset`,
40 | cursor: `pointer`,
41 | },
42 | });
43 |
--------------------------------------------------------------------------------
/app/components/Snackbars/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | margin: {
3 | margin: 10,
4 | },
5 | root: {
6 | top: 10,
7 | right: 15,
8 | left: `unset`,
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/app/constants/dom.js:
--------------------------------------------------------------------------------
1 | export const APP_TITLEBAR_DOM_ID = `app-main-titlebar`;
2 |
3 | export const FILE_EXPLORER_BODY_WRAPPER_ID = `file-explorer-body-wrapper`;
4 |
--------------------------------------------------------------------------------
/app/constants/env.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Constants
3 | * Note: Don't import log helper file from utils here
4 | */
5 |
6 | const isDev = process.env.NODE_ENV !== 'production';
7 | const isProd = process.env.NODE_ENV === 'production';
8 | const isDebug = process.env.DEBUG_PROD === 'true';
9 |
10 | const config = {
11 | dev: {
12 | reportToSenty: false,
13 | enableGoogleAnalytics: false,
14 | enableMixpanelAnalytics: false,
15 | disableReactWarnings: true,
16 | allowDevelopmentEnvironment: true,
17 | },
18 | prod: {
19 | reportToSenty: true,
20 | enableGoogleAnalytics: true,
21 | enableMixpanelAnalytics: true,
22 | disableReactWarnings: false,
23 | allowDevelopmentEnvironment: false,
24 | },
25 | debug: {
26 | reportToSenty: true,
27 | enableGoogleAnalytics: true,
28 | enableMixPanelAnalytics: true,
29 | disableReactWarnings: false,
30 | allowDevelopmentEnvironment: true,
31 | },
32 | };
33 |
34 | let _env = 'dev';
35 |
36 | if (isProd) {
37 | _env = 'prod';
38 | } else if (isDebug) {
39 | _env = 'debug';
40 | }
41 |
42 | module.exports.ENV_FLAVOR = config[_env];
43 |
44 | module.exports.IS_DEV = isDev;
45 |
46 | module.exports.IS_PROD = isProd;
47 |
48 | module.exports.DEBUG_PROD = isDebug;
49 |
50 | module.exports.IS_RENDERER = process && process.type === 'renderer';
51 |
--------------------------------------------------------------------------------
/app/constants/meta.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Constants
3 | * Note: Don't import log helper file from utils here
4 | */
5 |
6 | import { pkginfo } from '../utils/pkginfo';
7 |
8 | const {
9 | productName,
10 | description,
11 | name,
12 | author,
13 | version,
14 | repository,
15 | homepage,
16 | bugs,
17 | } = pkginfo;
18 |
19 | export const APP_BUNDLE_ID = 'io.ganeshrvel.openmtp';
20 |
21 | export const APP_NAME = `${productName}`;
22 |
23 | export const APP_VERSION = `${version}`;
24 |
25 | export const AUTHOR_EMAIL = author?.email ?? null;
26 |
27 | export const AUTHOR_NAME = author?.name ?? null;
28 |
29 | export const APP_DESC = `${description}`;
30 |
31 | export const APP_TITLE = `${APP_DESC}`;
32 |
33 | export const APP_IDENTIFIER = `${name}`;
34 |
35 | export const APP_GITHUB_URL = repository?.url
36 | ? repository.url.replace(/^git\+|\.git/g, '')
37 | : null;
38 |
39 | export const APP_GITHUB_RELEASES_URL = `${APP_GITHUB_URL}/releases`;
40 |
41 | export const APP_GITHUB_ISSUES_URL = bugs?.url ?? null;
42 |
43 | export const APP_WEBSITE = `${homepage}`;
44 |
--------------------------------------------------------------------------------
/app/constants/onboarding.js:
--------------------------------------------------------------------------------
1 | // most recently used version number to show the onboarding screen
2 | // search keywords: new, next, update, onboarding
3 | export const latestUpdatePushVersion = '3.2.20';
4 |
--------------------------------------------------------------------------------
/app/constants/serviceKeys.js:
--------------------------------------------------------------------------------
1 | export const SERVICE_KEYS = {
2 | sentryDsn: `https://1f60d05960cc4c10a744bebd19bc2814@o410539.ingest.sentry.io/5544425`,
3 | googleAnalytics: `UA-131227413-1`,
4 | mixpanelAnalytics: `e2ae6803122e622822a5fbf32ff0e5ae`,
5 | };
6 |
--------------------------------------------------------------------------------
/app/containers/Alerts/actions.js:
--------------------------------------------------------------------------------
1 | import prefixer from '../../helpers/reducerPrefixer';
2 |
3 | const prefix = '@@Alerts';
4 | const actionTypesList = ['THROW_ALERT', 'CLEAR_ALERT'];
5 |
6 | export const actionTypes = prefixer(prefix, actionTypesList);
7 |
8 | export function throwAlert(data) {
9 | return {
10 | type: actionTypes.THROW_ALERT,
11 | payload: {
12 | ...data,
13 | },
14 | };
15 | }
16 |
17 | export function clearAlert() {
18 | return {
19 | type: actionTypes.CLEAR_ALERT,
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/app/containers/Alerts/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | import { bindActionCreators } from 'redux';
4 | import { withReducer } from '../../store/reducers/withReducer';
5 | import reducers from './reducers';
6 | import { clearAlert } from './actions';
7 | import Snackbars from '../../components/Snackbars';
8 |
9 | class Alerts extends Component {
10 | _handleClose = () => {
11 | const { actionCreateClearAlert } = this.props;
12 |
13 | actionCreateClearAlert();
14 | };
15 |
16 | render() {
17 | const { Alerts } = this.props;
18 | const { message, variant, autoHideDuration } = Alerts;
19 |
20 | return (
21 | message && (
22 | <Snackbars
23 | OnSnackBarsCloseAlerts={() => this._handleClose()}
24 | message={message}
25 | variant={variant}
26 | autoHideDuration={autoHideDuration}
27 | />
28 | )
29 | );
30 | }
31 | }
32 |
33 | const mapDispatchToProps = (dispatch, __) =>
34 | bindActionCreators(
35 | {
36 | actionCreateClearAlert: () => (_, __) => {
37 | dispatch(clearAlert());
38 | },
39 | },
40 | dispatch
41 | );
42 |
43 | const mapStateToProps = (state, __) => {
44 | return {
45 | Alerts: state.Alerts,
46 | };
47 | };
48 |
49 | export default withReducer(
50 | 'Alerts',
51 | reducers
52 | )(connect(mapStateToProps, mapDispatchToProps)(Alerts));
53 |
--------------------------------------------------------------------------------
/app/containers/Alerts/reducers.js:
--------------------------------------------------------------------------------
1 | import { actionTypes } from './actions';
2 |
3 | export const initialState = {
4 | message: null,
5 | autoHideDuration: 2500, // in ms
6 | variant: `error`,
7 | };
8 |
9 | export default function Alerts(state = initialState, action) {
10 | const { type, payload } = action;
11 |
12 | switch (type) {
13 | case actionTypes.THROW_ALERT:
14 | return {
15 | ...state,
16 | ...payload,
17 | };
18 | case actionTypes.CLEAR_ALERT:
19 | return {
20 | ...state,
21 | ...initialState,
22 | };
23 | default:
24 | return state;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/containers/App/Root.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Provider } from 'react-redux';
3 | import { ConnectedRouter } from 'react-router-redux';
4 | import '../../helpers/console';
5 |
6 | import App from '.';
7 |
8 | export default class Root extends Component {
9 | render() {
10 | const { store, history } = this.props;
11 |
12 | return (
13 | <Provider store={store}>
14 | <ConnectedRouter history={history}>
15 | <App />
16 | </ConnectedRouter>
17 | </Provider>
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/containers/App/actions.js:
--------------------------------------------------------------------------------
1 | import prefixer from '../../helpers/reducerPrefixer';
2 |
3 | const prefix = '@@App';
4 | const actionTypesList = ['REQ_LOAD', 'RES_LOAD', 'FAIL_LOAD'];
5 |
6 | export const actionTypes = prefixer(prefix, actionTypesList);
7 |
8 | export function reqLoadApp() {
9 | return {
10 | type: actionTypes.REQ_LOAD,
11 | };
12 | }
13 |
14 | export function resLoadApp() {
15 | return {
16 | type: actionTypes.RES_LOAD,
17 | };
18 | }
19 |
20 | export function failLoadApp(e) {
21 | return {
22 | type: actionTypes.FAIL_LOAD,
23 | payload: {
24 | error: e,
25 | },
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/app/containers/App/components/Titlebar.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import { styles } from '../styles/Titlebar';
4 | import { toggleWindowSizeOnDoubleClick } from '../../../helpers/titlebarDoubleClick';
5 | import { APP_TITLEBAR_DOM_ID } from '../../../constants/dom';
6 | import { capitalize, isEmpty, niceBytes } from '../../../utils/funcs';
7 | import { getSelectedStorage } from '../../HomePage/actions';
8 | import { getCurrentWindowHash } from '../../../helpers/windowHelper';
9 |
10 | class Titlebar extends PureComponent {
11 | render() {
12 | const { classes: styles, mtpDevice, mtpStoragesList, mtpMode } = this.props;
13 |
14 | const selectedStorage = getSelectedStorage(mtpStoragesList);
15 | const windowHash = getCurrentWindowHash();
16 |
17 | return (
18 | <div
19 | onDoubleClick={() => {
20 | toggleWindowSizeOnDoubleClick();
21 | }}
22 | className={styles.root}
23 | id={APP_TITLEBAR_DOM_ID}
24 | >
25 | {/* Only show the device info. on the main window */}
26 | {windowHash !== '/' ? null : mtpDevice?.isAvailable &&
27 | mtpDevice?.info?.mtpDeviceInfo &&
28 | !isEmpty(selectedStorage?.data?.info) ? (
29 | <span className={styles.deviceInfo}>
30 | <span className={styles.deviceModel}>
31 | {`${mtpDevice?.info?.mtpDeviceInfo?.Model} (${selectedStorage?.data?.name}) - `}
32 | </span>
33 | {`${niceBytes(
34 | parseInt(selectedStorage?.data.info?.FreeSpaceInBytes ?? 0, 10)
35 | )} Free of ${niceBytes(
36 | parseInt(selectedStorage?.data.info?.MaxCapability ?? 0, 10)
37 | )}, ${capitalize(mtpMode)} Mode`}
38 | </span>
39 | ) : (
40 | <span className={styles.deviceInfo}>
41 | {`${capitalize(mtpMode)} Mode`}
42 | </span>
43 | )}
44 | </div>
45 | );
46 | }
47 | }
48 |
49 | export default withStyles(styles)(Titlebar);
50 |
--------------------------------------------------------------------------------
/app/containers/App/reducers.js:
--------------------------------------------------------------------------------
1 | export const initialState = {};
2 |
3 | export default function App(state = initialState, action) {
4 | const { type } = action;
5 |
6 | switch (type) {
7 | default:
8 | return state;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/containers/App/selectors.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 |
3 | import { createSelector } from 'reselect';
4 | import { initialState } from './reducers';
5 |
6 | const make = (state, props) => (state ? state.App : {});
7 |
8 | /* eslint-enable no-unused-vars */
9 |
--------------------------------------------------------------------------------
/app/containers/App/styles/Titlebar.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => {
4 | return {
5 | root: {
6 | width: `100%`,
7 | height: 14,
8 | textAlign: 'center',
9 | ...mixins({ theme }).appDragEnable,
10 | ...mixins({ theme }).center,
11 | },
12 | deviceInfo: {
13 | ...mixins({ theme }).center,
14 | width: `100%`,
15 | textAlign: 'center',
16 | color: theme.palette.lightText1Color,
17 | fontWeight: 'bold',
18 | fontSize: '12px',
19 | },
20 | deviceModel: {
21 | textTransform: 'capitalize',
22 | },
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/app/containers/AppFeaturesPage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/AppFeaturesPage/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import { Helmet } from 'react-helmet';
4 | import { APP_TITLE } from '../../constants/meta';
5 | import { resetOverFlowY } from '../../utils/styleResets';
6 | import { styles } from './styles';
7 | import Features from '../Onboarding/components/Features';
8 | import WhatsNew from '../Onboarding/components/WhatsNew';
9 | import { APP_FEATURES_PAGE_TITLE } from '../../templates/appFeaturesPage';
10 |
11 | class AppFeaturesPage extends Component {
12 | componentWillMount() {
13 | resetOverFlowY();
14 | }
15 |
16 | render() {
17 | const { classes: styles } = this.props;
18 |
19 | return (
20 | <div className={styles.root}>
21 | <Helmet titleTemplate={`%s - ${APP_TITLE}`}>
22 | <title>{APP_FEATURES_PAGE_TITLE}</title>
23 | </Helmet>
24 | <div className={styles.body}>
25 | <Features hideTitle={false} />
26 | <div className={styles.marginDivider} />
27 | <WhatsNew hideTitle={false} />
28 | </div>
29 | </div>
30 | );
31 | }
32 | }
33 |
34 | export default withStyles(styles)(AppFeaturesPage);
35 |
--------------------------------------------------------------------------------
/app/containers/AppFeaturesPage/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {
3 | textAlign: `left`,
4 | padding: '10px 30px 30px 30px',
5 | maxWidth: '800px',
6 | marginRight: 'auto',
7 | marginLeft: 'auto',
8 | overflow: 'auto',
9 | },
10 | heading: {},
11 | body: {},
12 | marginDivider: {
13 | height: 15,
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/app/containers/AppUpdatePage/UpdateAvailable/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/AppUpdatePage/UpdateAvailable/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | root: {
5 | padding: `0 25px 10px 25px`,
6 | },
7 |
8 | loadingText: { padding: 15 },
9 |
10 | title: {
11 | fontWeight: `bold`,
12 | },
13 |
14 | releaseNotes: {
15 | fontWeight: `bold`,
16 | marginTop: 10,
17 | },
18 |
19 | scrollContainer: {
20 | ...mixins({ theme }).center,
21 | marginTop: 5,
22 | border: `1px solid #000`,
23 | background: theme.palette.background.paper,
24 | height: 350,
25 | width: '100%',
26 | padding: 15,
27 | overflowX: 'auto',
28 | overflowY: 'auto',
29 | },
30 |
31 | btnWrapper: {
32 | position: `absolute`,
33 | bottom: 15,
34 | right: 24,
35 | },
36 |
37 | btnPositive: {
38 | ...mixins({ theme }).btnPositive,
39 | margin: `0 0 0 10px`,
40 | },
41 |
42 | btnNegative: {
43 | ...mixins({ theme }).btnNegativeWhite,
44 | },
45 | });
46 |
--------------------------------------------------------------------------------
/app/containers/AppUpdatePage/UpdateAvailable/styles/release-notes.scss:
--------------------------------------------------------------------------------
1 | .releaseNotes {
2 | h1,
3 | h2,
4 | h3,
5 | h4,
6 | h5,
7 | h6,
8 | p,
9 | ul {
10 | margin-top: 0;
11 | margin-bottom: 10px;
12 | line-height: 22px;
13 | }
14 | li {
15 | line-height: 22px;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/containers/AppUpdatePage/UpdateProgress/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/AppUpdatePage/UpdateProgress/index.jsx:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from 'electron';
2 | import React, { Component } from 'react';
3 | import { withStyles } from '@material-ui/core/styles';
4 | import LinearProgress from '@material-ui/core/LinearProgress';
5 | import Typography from '@material-ui/core/Typography';
6 | import { styles } from './styles';
7 |
8 | class ProgressbarPage extends Component {
9 | constructor(props) {
10 | super(props);
11 |
12 | this.initialState = {
13 | progressTitle: `Progress...`,
14 | progressBodyText: `Progress...`,
15 | value: 0,
16 | variant: `indeterminate`,
17 | };
18 |
19 | this.state = {
20 | ...this.initialState,
21 | };
22 | }
23 |
24 | componentWillMount() {
25 | ipcRenderer.on(
26 | 'appUpdatesProgressBarCommunication',
27 | (event, { ...args }) => {
28 | this.setState({ ...args });
29 | }
30 | );
31 | }
32 |
33 | componentWillUnmount() {
34 | ipcRenderer.removeListener('appUpdatesProgressBarCommunication', () => {});
35 | }
36 |
37 | render() {
38 | const { classes: styles } = this.props;
39 | const { progressTitle, progressBodyText, value, variant } = this.state;
40 |
41 | return (
42 | <div className={styles.root}>
43 | <Typography variant="body1" className={styles.progressTitle}>
44 | {progressTitle}
45 | </Typography>
46 | <Typography variant="body1" className={styles.progressBodyText}>
47 | {progressBodyText}
48 | </Typography>
49 | <LinearProgress color="secondary" variant={variant} value={value} />
50 | </div>
51 | );
52 | }
53 | }
54 |
55 | export default withStyles(styles)(ProgressbarPage);
56 |
--------------------------------------------------------------------------------
/app/containers/AppUpdatePage/UpdateProgress/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | root: {
5 | textAlign: `left`,
6 | ...mixins({ theme }).center,
7 | width: 500,
8 | marginTop: 10,
9 | },
10 | progressBodyText: {
11 | marginBottom: 10,
12 | },
13 | progressTitle: {
14 | fontWeight: 'bold',
15 | marginBottom: 10,
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/app/containers/ErrorBoundary/styles/GenerateErrorReport.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | subHeading: {
5 | ...mixins({ theme }).noDrag,
6 | ...mixins({ theme }).noselect,
7 | marginTop: 15,
8 | },
9 | instructions: {
10 | listStyle: `none`,
11 | color: theme.palette.lightText1Color,
12 | lineHeight: '24px',
13 | marginTop: 15,
14 | paddingLeft: 0,
15 | marginBottom: 15,
16 | },
17 | generateLogsBtnWrapper: {},
18 | generateLogsBtn: {
19 | marginTop: 0,
20 | ...mixins({ theme }).btnPositive,
21 | },
22 | emailIdWrapper: {
23 | color: theme.palette.lightText1Color,
24 | marginTop: 15,
25 | },
26 | emailId: {
27 | marginLeft: 16,
28 | fontWeight: `bold`,
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/app/containers/ErrorBoundary/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | root: {
5 | textAlign: `center`,
6 | ...mixins({ theme }).center,
7 | ...mixins({ theme }).absoluteCenter,
8 | },
9 | bugImg: {
10 | ...mixins({ theme }).noDrag,
11 | height: `auto`,
12 | width: 150,
13 | },
14 | headings: {
15 | ...mixins({ theme }).noDrag,
16 | ...mixins({ theme }).noselect,
17 | marginTop: 15,
18 | },
19 | subHeading: {
20 | ...mixins({ theme }).noDrag,
21 | ...mixins({ theme }).noselect,
22 | marginTop: 15,
23 | },
24 | goBackBtn: {
25 | marginTop: 5,
26 | },
27 | });
28 |
--------------------------------------------------------------------------------
/app/containers/HelpFaqsPage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable({ ...props }) {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component {...props} />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/HelpFaqsPage/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import Typography from '@material-ui/core/Typography';
4 | import { connect } from 'react-redux';
5 | import { bindActionCreators } from 'redux';
6 | import { Helmet } from 'react-helmet';
7 | import { APP_TITLE } from '../../constants/meta';
8 | import { resetOverFlowY } from '../../utils/styleResets';
9 | import { styles } from './styles';
10 | import {
11 | FAQS_PAGE_TITLE,
12 | HELP_PHONE_IS_NOT_CONNECTING,
13 | } from '../../templates/helpFaqsPage';
14 | import HelpPhoneNotRecognized from './components/HelpPhoneNotRecognized';
15 |
16 | class FaqsPage extends Component {
17 | componentWillMount() {
18 | resetOverFlowY();
19 | }
20 |
21 | render() {
22 | const { classes: styles, showPhoneNotRecognizedNote } = this.props;
23 |
24 | const title = showPhoneNotRecognizedNote
25 | ? HELP_PHONE_IS_NOT_CONNECTING
26 | : FAQS_PAGE_TITLE;
27 |
28 | return (
29 | <div className={styles.root}>
30 | <Helmet titleTemplate={`%s - ${APP_TITLE}`}>
31 | <title>{title}</title>
32 | </Helmet>
33 | <Typography variant="h5" className={styles.heading}>
34 | {title}
35 | </Typography>
36 | <div className={styles.body}>
37 | <HelpPhoneNotRecognized
38 | showPhoneNotRecognizedNote={showPhoneNotRecognizedNote}
39 | />
40 | </div>
41 | </div>
42 | );
43 | }
44 | }
45 |
46 | const mapDispatchToProps = (dispatch, __) => bindActionCreators({}, dispatch);
47 |
48 | const mapStateToProps = (_, __) => {
49 | return {};
50 | };
51 |
52 | export default connect(
53 | mapStateToProps,
54 | mapDispatchToProps
55 | )(withStyles(styles)(FaqsPage));
56 |
--------------------------------------------------------------------------------
/app/containers/HelpFaqsPage/styles/HelpPhoneNotRecognized.js:
--------------------------------------------------------------------------------
1 | import mixins from '../../../styles/js/mixins';
2 |
3 | export const styles = (theme) => ({
4 | root: {},
5 | expansionRoot: {
6 | background: theme.palette.tableHeaderFooterBgColor,
7 | },
8 | heading: {
9 | fontWeight: 600,
10 | },
11 | imagePlaceholder: {
12 | width: 200,
13 | height: 'auto',
14 | },
15 | imgWrapper: {
16 | ...mixins({ theme }).center,
17 | textAlign: 'center',
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/app/containers/HelpFaqsPage/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {
3 | textAlign: `left`,
4 | padding: '30px 30px 30px 30px',
5 | maxWidth: 950,
6 | marginRight: 'auto',
7 | marginLeft: 'auto',
8 | overflow: 'auto',
9 | },
10 | a: {
11 | fontWeight: `bold`,
12 | },
13 | heading: {},
14 | body: {
15 | paddingTop: 25,
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/app/containers/HomePage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/HomePage/components/FileExplorerTableFooterRender.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import TableFooter from '@material-ui/core/TableFooter';
4 | import { styles } from '../styles/FileExplorerTableFooterRender';
5 | import Breadcrumb from '../../../components/Breadcrumb';
6 | import FileExplorerTableFooterStatusBarRender from './FileExplorerTableFooterStatusBarRender';
7 |
8 | class FileExplorerTableFooterRender extends PureComponent {
9 | render() {
10 | const {
11 | classes: styles,
12 | currentBrowsePath,
13 | deviceType,
14 | onBreadcrumbPathClick,
15 | isStatusBarEnabled,
16 | directoryLists,
17 | fileTransferClipboard,
18 | mtpDevice,
19 | } = this.props;
20 |
21 | return (
22 | <TableFooter component="div" className={styles.tableFooter}>
23 | {isStatusBarEnabled && (
24 | <FileExplorerTableFooterStatusBarRender
25 | directoryLists={directoryLists}
26 | fileTransferClipboard={fileTransferClipboard}
27 | deviceType={deviceType}
28 | mtpDevice={mtpDevice}
29 | />
30 | )}
31 | <Breadcrumb
32 | onBreadcrumbPathClick={onBreadcrumbPathClick}
33 | currentBrowsePath={currentBrowsePath[deviceType]}
34 | deviceType={deviceType}
35 | />
36 | </TableFooter>
37 | );
38 | }
39 | }
40 |
41 | export default withStyles(styles)(FileExplorerTableFooterRender);
42 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorer.js:
--------------------------------------------------------------------------------
1 | export const styles = (theme) => ({
2 | socialMediaShareContainer: {
3 | paddingTop: 5,
4 | },
5 | supportBtnsTitle: {
6 | marginBottom: 10,
7 | fontSize: 12,
8 | fontWeight: 500,
9 | },
10 | supportBtnsTitleNewLine: {
11 | display: 'block',
12 | },
13 | supportBtnsBoldText: {
14 | fontWeight: 'bold',
15 | },
16 | socialMediaShareTitle: {
17 | marginTop: 10,
18 | fontSize: 11,
19 | fontWeight: 500,
20 | },
21 | socialMediaShareBtnsContainer: {
22 | width: '100%',
23 | display: 'flex',
24 | alignItems: 'center',
25 | },
26 | socialMediaBtnWrapper: {
27 | width: 50,
28 | height: 50,
29 | },
30 | socialMediaBtnWrapperForImage: {
31 | padding: `7px !important`,
32 | background: '#fff',
33 | [`&:hover`]: {
34 | background: `rgba(255, 255, 255, 0.85) !important`,
35 | },
36 | },
37 | socialMediaShareBtn: {
38 | height: 22,
39 | width: `22px`,
40 | color: theme.palette.contrastPrimaryMainColor,
41 | },
42 | socialMediaShareBtnImages: {
43 | height: 23,
44 | width: 23,
45 | },
46 | imageBtn: {
47 | padding: `7px !important`,
48 | background: '#fff',
49 | [`&:hover`]: {
50 | background: `rgba(255, 255, 255, 0.85) !important`,
51 | },
52 | },
53 |
54 | supportBtnsContainer: {
55 | width: `100%`,
56 | display: `flex`,
57 | },
58 | supportBtnWrapper: {
59 | width: 'auto',
60 | },
61 | supportBtnWrapperForImage: {
62 | padding: `0px 10px 5px 0 !important`,
63 | },
64 | supportBtnImages: {
65 | width: `100%`,
66 | height: 40,
67 | cursor: 'pointer',
68 |
69 | [`&:hover`]: {
70 | filter: `brightness(0.85)`,
71 | },
72 |
73 | [`&.paypal`]: {
74 | background: `#fff`,
75 | borderRadius: 7,
76 | padding: 7,
77 | },
78 | },
79 | });
80 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerBodyRender.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | root: {
5 | width: '100%',
6 | ...mixins({ theme }).noselect,
7 | },
8 | tableWrapper: {
9 | ...mixins({ theme }).noOutline,
10 | height: `calc(100vh - 120px)`,
11 | overflowY: 'auto',
12 | overflowX: 'auto',
13 | borderBottom: `solid 1px ${theme.palette.fileExplorerThinLineDividerColor}`,
14 | borderLeft: `solid 1px ${theme.palette.fileExplorerThinLineDividerColor}`,
15 | [`&.onHoverDropZone`]: {
16 | backgroundColor: theme.palette.fileDrop,
17 | },
18 | [`&.statusBarActive`]: {
19 | height: `calc(100vh - 150px) !important`,
20 | },
21 | },
22 | });
23 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableBodyEmptyRender.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 | import { tableCellFileExplorerTableRowsRender } from './FileExplorerTableBodyListRender';
3 |
4 | export const styles = (theme) => ({
5 | emptyTableRowWrapper: {},
6 | tableCell: tableCellFileExplorerTableRowsRender,
7 | helpPhoneNotRecognized: {
8 | width: '100%',
9 | ...mixins({ theme }).center,
10 | color: theme.palette.snackbar.error,
11 | fontWeight: 600,
12 | },
13 | noMtp: {
14 | marginTop: 10,
15 | },
16 | instructions: {
17 | marginTop: 5,
18 | lineHeight: `18px`,
19 | paddingLeft: 30,
20 | color: `rgba(0, 0, 0, 0.8)`,
21 | },
22 | nestedPanel: {
23 | paddingLeft: 16,
24 | paddingRight: 16,
25 | },
26 | divider: {
27 | marginTop: 10,
28 | marginBottom: 10,
29 | },
30 | });
31 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableBodyGridRender.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | wrapper: {},
5 | itemWrapper: {
6 | float: `left`,
7 | width: 100,
8 | height: 137,
9 | },
10 | itemCheckBox: {
11 | display: `none`,
12 | },
13 | fileTypeIcon: {
14 | width: 'auto',
15 | height: 80,
16 | },
17 | fileTypeIconWrapper: {
18 | ...mixins({ theme }).center,
19 | paddingTop: 10,
20 | paddingBottom: 10,
21 | textAlign: 'center',
22 | },
23 | itemSelected: {
24 | backgroundColor: 'rgba(41, 121, 255, 0.15) !important',
25 | },
26 | itemFileName: {
27 | wordBreak: `break-all`,
28 | textAlign: `center`,
29 | },
30 | itemFileNameWrapper: {
31 | marginLeft: 12,
32 | marginRight: 12,
33 | marginTop: -8,
34 | textAlign: `center`,
35 | },
36 | });
37 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableBodyGridWrapperRender.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | wrapper: {},
3 | gridTableCell: {
4 | paddingLeft: `5px !important`,
5 | paddingRight: `5px !important`,
6 | border: 0,
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableBodyListRender.js:
--------------------------------------------------------------------------------
1 | export const tableCellFileExplorerTableRowsRender = {
2 | borderBottom: `unset`,
3 | [`&.checkboxCell`]: {
4 | width: 50,
5 | },
6 | [`&.nameCell`]: {
7 | display: 'flex',
8 | alignItems: 'center',
9 | whiteSpace: `nowrap`,
10 | overflow: `hidden`,
11 | textOverflow: `ellipsis`,
12 | },
13 | [`&.sizeCell`]: {
14 | whiteSpace: `nowrap`,
15 | overflow: `hidden`,
16 | textOverflow: `ellipsis`,
17 | width: `auto`,
18 | minWidth: 100,
19 | },
20 | [`&.dateAddedCell`]: {
21 | whiteSpace: `nowrap`,
22 | overflow: `hidden`,
23 | textOverflow: `ellipsis`,
24 | width: `auto`,
25 | minWidth: 100,
26 | paddingRight: 10,
27 | },
28 | };
29 |
30 | export const styles = (_) => {
31 | return {
32 | tableRowSelected: {
33 | backgroundColor: 'rgba(41, 121, 255, 0.15) !important',
34 | },
35 | tableCell: tableCellFileExplorerTableRowsRender,
36 | fileTypeIconWrapper: {
37 | paddingTop: 5,
38 | paddingBottom: 5,
39 | paddingLeft: 2,
40 | textAlign: 'center',
41 | },
42 | fileTypeIcon: {
43 | verticalAlign: `middle`,
44 | height: 20,
45 | width: 'auto',
46 | },
47 | truncate: {
48 | textOverflow: 'ellipsis',
49 | overflow: 'hidden',
50 | maxWidth: 310,
51 | whiteSpace: 'nowrap',
52 | },
53 | };
54 | };
55 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableBodyRender.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | table: {},
3 | });
4 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableFooterRender.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | tableFooter: {
3 | display: 'unset !important',
4 | },
5 | });
6 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableFooterStatusBarRender.js:
--------------------------------------------------------------------------------
1 | export const styles = (theme) => ({
2 | root: {
3 | padding: '5px 15px 0 15px',
4 | width: '100%',
5 | background: theme.palette.tableHeaderFooterBgColor,
6 | height: 30,
7 | textAlign: 'center',
8 | },
9 |
10 | deviceTypeWrapper: {
11 | fontWeight: '500',
12 | color: theme.palette.secondary.main,
13 | marginLeft: 5,
14 | fontSize: 12,
15 | textTransform: 'capitalize',
16 |
17 | [`& span`]: {
18 | color: theme.palette.contrastPrimaryMainColor,
19 | fontWeight: '600',
20 | fontSize: 13,
21 | },
22 | },
23 |
24 | bodyWrapper: {
25 | fontWeight: '500',
26 | color: theme.palette.lightText1Color,
27 | },
28 | });
29 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/FileExplorerTableHeadRender.js:
--------------------------------------------------------------------------------
1 | export const styles = (theme) => ({
2 | tableHeadCell: {
3 | border: `unset`,
4 | backgroundColor: theme.palette.tableHeaderFooterBgColor,
5 | position: 'sticky',
6 | top: 0,
7 | zIndex: 10,
8 | },
9 | });
10 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/SidebarAreaPaneLists.js:
--------------------------------------------------------------------------------
1 | import { variables } from '../../../styles/js';
2 |
3 | export const styles = (_) => {
4 | return {
5 | listsWrapper: {
6 | paddingTop: variables().sizes.sidebarAreaPaddingTop,
7 | width: variables().sizes.sidebarAreaPaneWidth,
8 | },
9 | listsBottom: {
10 | paddingTop: 5,
11 | },
12 | listIcon: {
13 | minWidth: 35,
14 | },
15 | listsCaption: {
16 | padding: `14px 0 0px 20px`,
17 | },
18 | primary: {},
19 | icon: {},
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/app/containers/HomePage/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => {
2 | return {
3 | root: {},
4 | grid: {
5 | width: `100%`,
6 | },
7 | splitPane: {
8 | width: `50%`,
9 | float: `left`,
10 | [`&:after`]: {
11 | content: '""',
12 | display: `table`,
13 | clear: `both`,
14 | },
15 | },
16 | singlePane: {
17 | width: `100% !important`,
18 | },
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/app/containers/KeyboardShortcutsPage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/KeyboardShortcutsPage/components/KbdRender.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { quickHash } from '../../../utils/funcs';
3 | import { fileExplorerKeymaps } from '../../../constants/keymaps';
4 |
5 | export default class KbdRender extends PureComponent {
6 | render() {
7 | const { styles } = this.props;
8 |
9 | return Object.keys(fileExplorerKeymaps).map((a) => {
10 | const item = fileExplorerKeymaps[a];
11 |
12 | return (
13 | <div key={a}>
14 | <div className={styles.kbdWrapper}>
15 | <span className={styles.kbdTitle}>{item.label}</span>
16 | <div className={styles.kbdInnerWrapper}>
17 | {item.keys.map((key, keyIndex) => {
18 | const keySplit = key.split('+');
19 |
20 | return (
21 | <span key={quickHash(key)}>
22 | {keySplit.map((f, fIndex) => {
23 | return (
24 | <span key={quickHash(f)}>
25 | <kbd>{f}</kbd>
26 | {fIndex === keySplit.length - 1 ? null : `+`}
27 | </span>
28 | );
29 | })}
30 | {keyIndex === item.keys.length - 1 ? null : ` or `}
31 | </span>
32 | );
33 | })}
34 | </div>
35 | </div>
36 | </div>
37 | );
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/containers/KeyboardShortcutsPage/components/KeyboadShortcuts.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import { styles } from '../styles/KeyboadShortcuts';
4 | import KbdRender from './KbdRender';
5 |
6 | class KeyboadShortcuts extends PureComponent {
7 | render() {
8 | const { classes: styles } = this.props;
9 |
10 | return (
11 | <div className={styles.root}>
12 | <KbdRender styles={styles} />
13 | </div>
14 | );
15 | }
16 | }
17 |
18 | export default withStyles(styles)(KeyboadShortcuts);
19 |
--------------------------------------------------------------------------------
/app/containers/KeyboardShortcutsPage/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import Typography from '@material-ui/core/Typography';
4 | import { Helmet } from 'react-helmet';
5 | import { APP_TITLE } from '../../constants/meta';
6 | import { resetOverFlowY } from '../../utils/styleResets';
7 | import { styles } from './styles';
8 | import KeyboadShortcuts from './components/KeyboadShortcuts';
9 | import { KEYBOARD_SHORTCUTS_PAGE_TITLE } from '../../templates/keyboardShortcutsPage';
10 |
11 | class KeyboardShortcutsPage extends Component {
12 | componentWillMount() {
13 | resetOverFlowY();
14 | }
15 |
16 | render() {
17 | const { classes: styles } = this.props;
18 |
19 | return (
20 | <div className={styles.root}>
21 | <Helmet titleTemplate={`%s - ${APP_TITLE}`}>
22 | <title>{KEYBOARD_SHORTCUTS_PAGE_TITLE}</title>
23 | </Helmet>
24 | <Typography variant="h6" color="secondary">
25 | Keyboard Shortcuts
26 | </Typography>
27 | <div className={styles.body}>
28 | <KeyboadShortcuts />
29 | </div>
30 | </div>
31 | );
32 | }
33 | }
34 |
35 | export default withStyles(styles)(KeyboardShortcutsPage);
36 |
--------------------------------------------------------------------------------
/app/containers/KeyboardShortcutsPage/styles/KeyboadShortcuts.js:
--------------------------------------------------------------------------------
1 | export const styles = (theme) => ({
2 | root: {},
3 | title: {
4 | fontWeight: `bold`,
5 | },
6 | kbdWrapper: {
7 | paddingBottom: 14,
8 | },
9 | kbdInnerWrapper: {
10 | display: `inline-block`,
11 | },
12 | kbdTitle: {
13 | display: 'block',
14 | color: theme.palette.lightText1Color,
15 | padding: '1px 0 6px 0',
16 | fontSize: 14,
17 | },
18 | });
19 |
--------------------------------------------------------------------------------
/app/containers/KeyboardShortcutsPage/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {
3 | textAlign: `left`,
4 | padding: '0 30px 30px 30px',
5 | maxWidth: '800px',
6 | marginRight: 'auto',
7 | marginLeft: 'auto',
8 | overflow: 'auto',
9 | },
10 | heading: {
11 | fontWeight: 'bold',
12 | },
13 | body: {
14 | marginTop: 10,
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/app/containers/NotFoundPage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/NotFoundPage/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { Helmet } from 'react-helmet';
4 | import { routes } from '../../routing';
5 | import styles from './styles/index.scss';
6 | import { APP_TITLE } from '../../constants/meta';
7 |
8 | export default class NotFound extends Component {
9 | render() {
10 | return (
11 | <Fragment>
12 | <Helmet titleTemplate={`%s - ${APP_TITLE}`}>
13 | <title>Resource not found!</title>
14 | </Helmet>
15 | <div className={styles.container}>
16 | <h1>Resource not found!</h1>
17 | <Link to={routes.Home.path}>Go back</Link>
18 | </div>
19 | </Fragment>
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/containers/NotFoundPage/styles/index.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 500px;
3 | margin-left: auto;
4 | margin-right: auto;
5 | text-align: center;
6 | h2 {
7 | font-size: 2rem;
8 | }
9 | a {
10 | font-size: 1.4rem;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/Onboarding/styles/Features.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {},
3 | title: {
4 | fontWeight: `bold`,
5 | },
6 | });
7 |
--------------------------------------------------------------------------------
/app/containers/Onboarding/styles/WhatsNew.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {},
3 | title: {
4 | fontWeight: `bold`,
5 | },
6 | nestedPanel: {
7 | paddingLeft: 16,
8 | paddingRight: 16,
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/app/containers/Onboarding/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | root: {},
5 | btnPositive: {
6 | ...mixins({ theme }).btnPositive,
7 | },
8 | divider: {
9 | marginBottom: 20,
10 | },
11 | contentBox: {
12 | padding: 25,
13 | background: 'rgba(224, 224, 224, 0.12)',
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/app/containers/PrivacyPolicyPage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/PrivacyPolicyPage/styles/index.js:
--------------------------------------------------------------------------------
1 | export const styles = (_) => ({
2 | root: {
3 | textAlign: `left`,
4 | padding: '30px 30px 30px 30px',
5 | maxWidth: '800px',
6 | marginRight: 'auto',
7 | marginLeft: 'auto',
8 | overflow: 'auto',
9 | },
10 | a: {
11 | fontWeight: `bold`,
12 | },
13 | heading: {},
14 | body: {
15 | lineHeight: `22px`,
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/app/containers/ReportBugsPage/Loadable.js:
--------------------------------------------------------------------------------
1 | import React, { lazy, Suspense } from 'react';
2 | import LoadingIndicator from '../../components/LoadingIndicator';
3 |
4 | const Component = lazy(() => import('.'));
5 |
6 | export default function loadable() {
7 | return (
8 | <Suspense fallback={<LoadingIndicator />}>
9 | <Component />
10 | </Suspense>
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/containers/ReportBugsPage/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { withStyles } from '@material-ui/core/styles';
3 | import { Helmet } from 'react-helmet';
4 | import { connect } from 'react-redux';
5 | import { bindActionCreators } from 'redux';
6 | import GenerateErrorReport from '../ErrorBoundary/components/GenerateErrorReport';
7 | import { APP_TITLE } from '../../constants/meta';
8 | import { styles } from './styles';
9 | import { REPORT_BUGS_PAGE_TITLE } from '../../templates/generateErrorReport';
10 |
11 | class ReportBugsPage extends Component {
12 | render() {
13 | const { classes: styles } = this.props;
14 |
15 | return (
16 | <div className={styles.root}>
17 | <Helmet titleTemplate={`%s - ${APP_TITLE}`}>
18 | <title>{REPORT_BUGS_PAGE_TITLE}</title>
19 | </Helmet>
20 | <GenerateErrorReport isReportBugsPage />
21 | </div>
22 | );
23 | }
24 | }
25 |
26 | const mapDispatchToProps = (dispatch, __) => bindActionCreators({}, dispatch);
27 |
28 | const mapStateToProps = (_, __) => {
29 | return {};
30 | };
31 |
32 | export default connect(
33 | mapStateToProps,
34 | mapDispatchToProps
35 | )(withStyles(styles)(ReportBugsPage));
36 |
--------------------------------------------------------------------------------
/app/containers/ReportBugsPage/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | root: {
5 | textAlign: `center`,
6 | ...mixins({ theme }).center,
7 | width: 500,
8 | marginTop: 7,
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/app/containers/Settings/components/SettingsDialogTabContainer.jsx:
--------------------------------------------------------------------------------
1 | import React, { PureComponent, Fragment } from 'react';
2 |
3 | export default class SettingsDialogTabContainer extends PureComponent {
4 | render() {
5 | const { children } = this.props;
6 |
7 | return <Fragment>{children}</Fragment>;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/containers/Settings/styles/index.js:
--------------------------------------------------------------------------------
1 | import { mixins } from '../../../styles/js';
2 |
3 | export const styles = (theme) => ({
4 | margin: {},
5 | root: {},
6 | fieldset: {
7 | width: `100%`,
8 | },
9 | tabHeadingWrapper: {
10 | borderBottom: `1px solid rgba(0, 123, 255, 0.2)`,
11 | },
12 | tab: {
13 | minWidth: 100,
14 | },
15 | tabContainer: {
16 | paddingTop: 20,
17 | paddingLeft: 15,
18 | height: 390,
19 | overflowX: `auto`,
20 | overflowY: `auto`,
21 | borderBottom: `rgba(0, 122, 245, 0.15) 1px solid`,
22 | },
23 | subtitleMarginFix: {
24 | marginTop: 10,
25 | },
26 | subtitle: {},
27 | fmSettingsStylesFix: {
28 | marginTop: 10,
29 | },
30 | subheading: {
31 | marginBottom: 5,
32 | },
33 | title: {
34 | flex: `0 0 auto`,
35 | margin: 0,
36 | padding: `24px 24px 8px`,
37 | },
38 | switch: {
39 | height: 30,
40 | marginBottom: 7,
41 | },
42 | block: {
43 | marginBottom: 20,
44 | },
45 | onboardingPaper: {
46 | position: `relative`,
47 | padding: 10,
48 | marginTop: 4,
49 | backgroundColor: theme.palette.secondary.main,
50 | },
51 | onboardingPaperArrow: {
52 | fontWeight: `bold`,
53 | content: ' ',
54 | borderBottom: `11px solid ${theme.palette.secondary.main}`,
55 | borderLeft: '8px solid transparent',
56 | borderRight: '8px solid transparent',
57 | position: 'absolute',
58 | top: -10,
59 | left: 2,
60 | },
61 | onboardingPaperBody: {},
62 | onboardingPaperBodyItem: {
63 | color: '#ffffff',
64 | display: 'block',
65 | width: '100%',
66 | fontSize: 13,
67 | fontWeight: 500,
68 | },
69 |
70 | a: {
71 | fontWeight: `bold`,
72 | },
73 | btnPositive: {
74 | ...mixins({ theme }).btnPositive,
75 | },
76 | });
77 |
--------------------------------------------------------------------------------
/app/enums/appUpdater.js:
--------------------------------------------------------------------------------
1 | export const UPDATER_STATUS = {
2 | inactive: 'inactive',
3 | checkInProgress: 'checkInProgress',
4 | updateInProgress: 'updateInProgress',
5 | };
6 |
--------------------------------------------------------------------------------
/app/enums/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {object} DEVICE_TYPE
3 | * @property {string} mtp - MTP Device
4 | * @property {string} local - Local Device
5 | * */
6 | export const DEVICE_TYPE = {
7 | mtp: 'mtp',
8 | local: 'local',
9 | };
10 |
11 | export const MTP_MODE = {
12 | legacy: 'legacy',
13 | kalam: 'kalam',
14 | };
15 |
16 | export const FILE_EXPLORER_VIEW_TYPE = {
17 | grid: 'grid',
18 | list: 'list',
19 | };
20 |
21 | export const APP_THEME_MODE_TYPE = {
22 | light: 'light',
23 | dark: 'dark',
24 | auto: 'auto',
25 | };
26 |
27 | export const FILE_TRANSFER_DIRECTION = {
28 | upload: 'upload',
29 | download: 'download',
30 | };
31 |
32 | export const USB_HOTPLUG_EVENTS = {
33 | attach: 'attach',
34 | detach: 'detach',
35 | };
36 |
--------------------------------------------------------------------------------
/app/enums/mtpError.js:
--------------------------------------------------------------------------------
1 | export const MTP_ERROR = {
2 | ErrorGeneral: 'ErrorGeneral',
3 | ErrorSendObject: 'ErrorSendObject',
4 | ErrorFileObjectRead: 'ErrorFileObjectRead',
5 | ErrorFileTransfer: 'ErrorFileTransfer',
6 | ErrorInvalidPath: 'ErrorInvalidPath',
7 | ErrorLocalFileRead: 'ErrorLocalFileRead',
8 | ErrorFilePermission: 'ErrorFilePermission',
9 | ErrorFileNotFound: 'ErrorFileNotFound',
10 | ErrorListDirectory: 'ErrorListDirectory',
11 | ErrorStorageFull: 'ErrorStorageFull',
12 | ErrorNoStorage: 'ErrorNoStorage',
13 | ErrorStorageInfo: 'ErrorStorageInfo',
14 | ErrorDeviceInfo: 'ErrorDeviceInfo',
15 | ErrorAllowStorageAccess: 'ErrorAllowStorageAccess',
16 | ErrorMultipleDevice: 'ErrorMultipleDevice',
17 | ErrorDeviceLocked: 'ErrorDeviceLocked',
18 | ErrorDeviceSetup: 'ErrorDeviceSetup',
19 | ErrorDeviceChanged: 'ErrorDeviceChanged',
20 | ErrorMtpLockExists: 'ErrorMtpLockExists',
21 | ErrorMtpDetectFailed: 'ErrorMtpDetectFailed',
22 | };
23 |
--------------------------------------------------------------------------------
/app/helpers/bootHelper.js:
--------------------------------------------------------------------------------
1 | import Boot from '../classes/Boot';
2 |
3 | export const bootLoader = new Boot();
4 |
--------------------------------------------------------------------------------
/app/helpers/console.js:
--------------------------------------------------------------------------------
1 | import clp from 'console-log-plus';
2 | import { ENV_FLAVOR } from '../constants/env';
3 |
4 | const { warn } = console;
5 |
6 | function logWarning(...warnings) {
7 | let showWarning = true;
8 |
9 | warnings.forEach((warning) => {
10 | const msg = warning?.toString();
11 |
12 | if (msg.includes('UNSAFE_')) showWarning = false;
13 | else if (msg.includes('SourceMap')) showWarning = false;
14 | else if (msg.includes('DevTools')) showWarning = false;
15 | });
16 |
17 | if (showWarning) {
18 | warn(...warnings);
19 | }
20 | }
21 |
22 | if (ENV_FLAVOR.disableReactWarnings) {
23 | console.warn = logWarning;
24 |
25 | clp({
26 | color: 'orange',
27 | message: `Warning: React depreciation warnings are disabled.\n Edit 'app/helpers/console.js' to enable them`,
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/app/helpers/deviceInfo.js:
--------------------------------------------------------------------------------
1 | import { IS_RENDERER } from '../constants/env';
2 | import { isEmpty } from '../utils/funcs';
3 |
4 | export function getDeviceInfo() {
5 | if (IS_RENDERER) {
6 | // import it here so that the main process doesnt crash
7 | // eslint-disable-next-line global-require
8 | const { store } = require('../store/configureStore');
9 | const state = store?.getState();
10 |
11 | if (isEmpty(state)) {
12 | return {};
13 | }
14 |
15 | const info = state?.Home?.mtpDevice?.info?.mtpDeviceInfo;
16 |
17 | if (isEmpty(info)) {
18 | return {};
19 | }
20 |
21 | const {
22 | StandardVersion,
23 | MTPVersion,
24 | MTPExtension,
25 | Manufacturer,
26 | Model,
27 | DeviceVersion,
28 | } = info;
29 |
30 | return {
31 | StandardVersion,
32 | MTPVersion,
33 | MTPExtension,
34 | Manufacturer,
35 | Model,
36 | DeviceVersion,
37 | };
38 | }
39 |
40 | return {};
41 | }
42 |
--------------------------------------------------------------------------------
/app/helpers/fileOps.js:
--------------------------------------------------------------------------------
1 | import {
2 | existsSync as _existsSync,
3 | writeFile as _writeFileAsync,
4 | appendFile as _appendFileAsync,
5 | readFileSync as _readFileSync,
6 | writeFileSync as _writeFileSync,
7 | } from 'fs';
8 | import { EOL } from 'os';
9 | import mkdirp from 'mkdirp';
10 | import rimraf from 'rimraf';
11 |
12 | export const writeFileAsync = (filePath, text) => {
13 | const options = { mode: 0o755 };
14 |
15 | _writeFileAsync(filePath, text, options, (err) => {
16 | if (err) {
17 | console.error(err, `writeFileAsync`);
18 |
19 | return null;
20 | }
21 | });
22 | };
23 |
24 | export const writeFileSync = (filePath, text) => {
25 | const options = { mode: 0o755 };
26 |
27 | try {
28 | _writeFileSync(filePath, text, options);
29 | } catch (err) {
30 | console.error(err, `writeFileSync`);
31 | }
32 | };
33 |
34 | export const appendFileAsync = (filePath, text) => {
35 | const options = { mode: 0o755 };
36 |
37 | _appendFileAsync(filePath, text + EOL, options, (err) => {
38 | if (err) {
39 | console.error(err, `appendFileAsync`);
40 |
41 | return null;
42 | }
43 | });
44 | };
45 |
46 | export const readFileSync = (filePath) => {
47 | const options = { encoding: 'utf8' };
48 |
49 | return _readFileSync(filePath, options);
50 | };
51 |
52 | export const fileExistsSync = (filePath) => _existsSync(filePath);
53 |
54 | export const createDirSync = async (newFolderPath) => {
55 | await mkdirp.sync(newFolderPath);
56 | };
57 |
58 | export const deleteFilesSync = (filePath) => {
59 | rimraf.sync(filePath);
60 | };
61 |
--------------------------------------------------------------------------------
/app/helpers/identifiers.js:
--------------------------------------------------------------------------------
1 | import { v6 as uuidv6 } from 'uuid';
2 |
3 | import { identifierStorage } from './storageHelper';
4 | import { isEmpty } from '../utils/funcs';
5 |
6 | export function getMachineId() {
7 | try {
8 | const settings = identifierStorage.getItems(['machineId']);
9 |
10 | if (!settings?.machineId || isEmpty(settings?.machineId)) {
11 | const _machineId = uuidv6();
12 |
13 | identifierStorage.setItems({
14 | machineId: _machineId,
15 | });
16 |
17 | return _machineId;
18 | }
19 |
20 | return settings.machineId;
21 | } catch (e) {
22 | console.error(`Unable to find machineId. Error: ${e}`);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/helpers/logs.js:
--------------------------------------------------------------------------------
1 | import { PATHS } from '../constants/paths';
2 | import { undefinedOrNull } from '../utils/funcs';
3 |
4 | /**
5 | * Description - Strip user home directory path from the error before it is sent to sentry
6 | * @param s
7 | * @return {string|string}
8 | */
9 | export const redactHomeDirectory = (s) => {
10 | if (undefinedOrNull(s)) {
11 | return '';
12 | }
13 |
14 | return (
15 | s?.toString()?.replaceAll(new RegExp(PATHS.homeDir, 'ig'), '/Users/user') ??
16 | ''
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/app/helpers/reducerPrefixer.js:
--------------------------------------------------------------------------------
1 | export default (prefix, typesList) => {
2 | return typesList.reduce((result, value) => {
3 | // eslint-disable-next-line no-param-reassign
4 | result[value] = `${prefix}/${value}`;
5 |
6 | return result;
7 | }, {});
8 | };
9 |
--------------------------------------------------------------------------------
/app/helpers/remoteWindowHelpers.js:
--------------------------------------------------------------------------------
1 | import { IS_RENDERER } from '../constants/env';
2 |
3 | export const getRemoteWindow = () => {
4 | let remote;
5 |
6 | if (IS_RENDERER) {
7 | remote = window.require('@electron/remote');
8 | } else {
9 | // eslint-disable-next-line global-require
10 | remote = require('@electron/remote/main');
11 | }
12 |
13 | return remote;
14 | };
15 |
--------------------------------------------------------------------------------
/app/helpers/settings.js:
--------------------------------------------------------------------------------
1 | import { settingsStorage } from './storageHelper';
2 | import { getAppThemeMode } from './theme';
3 | import { isPrereleaseVersion, undefinedOrNull } from '../utils/funcs';
4 | import { initialState } from '../containers/Settings/reducers';
5 | import { checkIf } from '../utils/checkIf';
6 | import { FILE_TRANSFER_DIRECTION } from '../enums';
7 |
8 | export const getAppThemeModeSetting = () => {
9 | const setting = settingsStorage.getItems(['appThemeMode']);
10 |
11 | let value = setting.appThemeMode;
12 |
13 | if (undefinedOrNull(value)) {
14 | value = initialState.appThemeMode;
15 | }
16 |
17 | return getAppThemeMode(value);
18 | };
19 |
20 | export const getMtpModeSetting = () => {
21 | const setting = settingsStorage.getItems(['mtpMode']);
22 |
23 | let value = setting.mtpMode;
24 |
25 | if (undefinedOrNull(value)) {
26 | value = initialState.mtpMode;
27 | }
28 |
29 | return value;
30 | };
31 |
32 | export const getFilesPreprocessingBeforeTransferSetting = ({ direction }) => {
33 | checkIf(direction, 'string');
34 | checkIf(direction, 'inObjectValues', FILE_TRANSFER_DIRECTION);
35 |
36 | const setting = settingsStorage.getItems([
37 | 'filesPreprocessingBeforeTransfer',
38 | ]);
39 |
40 | let value = setting.filesPreprocessingBeforeTransfer
41 | ? setting.filesPreprocessingBeforeTransfer[direction]
42 | : null;
43 |
44 | if (undefinedOrNull(value)) {
45 | value = initialState.filesPreprocessingBeforeTransfer[direction];
46 | }
47 |
48 | checkIf(value, 'boolean');
49 |
50 | return value;
51 | };
52 |
53 | export const getEnablePrereleaseUpdatesSetting = () => {
54 | const setting = settingsStorage.getItems(['enablePrereleaseUpdates']);
55 |
56 | let value = setting.enablePrereleaseUpdates;
57 |
58 | const isPrerelease = isPrereleaseVersion();
59 |
60 | if (isPrerelease) {
61 | return true;
62 | }
63 |
64 | if (undefinedOrNull(value)) {
65 | value = initialState.enablePrereleaseUpdates;
66 | }
67 |
68 | return value;
69 | };
70 |
--------------------------------------------------------------------------------
/app/helpers/storageHelper.js:
--------------------------------------------------------------------------------
1 | import { PATHS } from '../constants/paths';
2 | import Storage from '../classes/Storage';
3 |
4 | const { settingsFile, identifierFile } = PATHS;
5 |
6 | export const identifierStorage = new Storage(identifierFile, true);
7 |
8 | export const settingsStorage = new Storage(settingsFile, false);
9 |
--------------------------------------------------------------------------------
/app/helpers/theme.js:
--------------------------------------------------------------------------------
1 | import { nativeTheme } from 'electron';
2 | import { APP_THEME_MODE_TYPE } from '../enums';
3 | import { undefinedOrNull } from '../utils/funcs';
4 | import { getAppThemeModeSetting } from './settings';
5 | import { getRemoteWindow } from './remoteWindowHelpers';
6 |
7 | const remote = getRemoteWindow();
8 |
9 | // [appThemeModeSettings] is optional
10 | // if [appThemeModeSettings] is not provided then fetch the theme value from the settings
11 | export const getAppThemeMode = (appThemeModeSettings) => {
12 | // compatible with both renderer and main process
13 | const { shouldUseDarkColors } = remote?.nativeTheme ?? nativeTheme ?? {};
14 |
15 | let _appThemeModeSettings = appThemeModeSettings;
16 |
17 | if (undefinedOrNull(_appThemeModeSettings)) {
18 | _appThemeModeSettings = getAppThemeModeSetting();
19 | }
20 |
21 | switch (_appThemeModeSettings) {
22 | case APP_THEME_MODE_TYPE.dark:
23 | return _appThemeModeSettings;
24 |
25 | case APP_THEME_MODE_TYPE.light:
26 | return _appThemeModeSettings;
27 |
28 | default:
29 | if (shouldUseDarkColors) {
30 | return APP_THEME_MODE_TYPE.dark;
31 | }
32 |
33 | return APP_THEME_MODE_TYPE.light;
34 | }
35 | };
36 |
37 | export const getContrastingTheme = (appThemeMode) => {
38 | if (appThemeMode === APP_THEME_MODE_TYPE.dark) {
39 | return APP_THEME_MODE_TYPE.light;
40 | }
41 |
42 | return APP_THEME_MODE_TYPE.dark;
43 | };
44 |
--------------------------------------------------------------------------------
/app/helpers/titlebarDoubleClick.js:
--------------------------------------------------------------------------------
1 | import { getRemoteWindow } from './remoteWindowHelpers';
2 |
3 | const remote = getRemoteWindow();
4 |
5 | export const toggleWindowSizeOnDoubleClick = () => {
6 | const window = remote.getCurrentWindow();
7 |
8 | if (!window.isMaximized()) {
9 | window.maximize();
10 |
11 | return null;
12 | }
13 |
14 | window.unmaximize();
15 | };
16 |
--------------------------------------------------------------------------------
/app/helpers/windowHelper.js:
--------------------------------------------------------------------------------
1 | import { BrowserWindow } from 'electron';
2 | import { urls } from 'nice-utils';
3 | import { getAppThemeMode } from './theme';
4 | import { getCurrentThemePalette } from '../containers/App/styles';
5 | import { undefinedOrNull } from '../utils/funcs';
6 | import { IS_RENDERER } from '../constants/env';
7 | import { getRemoteWindow } from './remoteWindowHelpers';
8 |
9 | const remote = getRemoteWindow();
10 |
11 | export const getMainWindowMainProcess = () => {
12 | const _mainWindow = BrowserWindow.getAllWindows();
13 |
14 | if (typeof _mainWindow === 'undefined' || _mainWindow === null) {
15 | return null;
16 | }
17 |
18 | return BrowserWindow.getAllWindows()[_mainWindow.length - 1];
19 | };
20 |
21 | export const getMainWindowRendererProcess = () => {
22 | const _mainWindow = remote.BrowserWindow.getAllWindows();
23 |
24 | if (typeof _mainWindow === 'undefined' || _mainWindow === null) {
25 | return null;
26 | }
27 |
28 | return remote.BrowserWindow.getAllWindows()[_mainWindow.length - 1];
29 | };
30 |
31 | export const getWindowBackgroundColor = () => {
32 | const appThemeMode = getAppThemeMode();
33 | const { background } = getCurrentThemePalette(appThemeMode);
34 |
35 | return background.paper;
36 | };
37 |
38 | export const getCurrentWindowHash = () => {
39 | if (!IS_RENDERER) {
40 | return null;
41 | }
42 |
43 | const hash = urls().getHash();
44 |
45 | if (undefinedOrNull(hash) || hash === '') {
46 | return '/';
47 | }
48 |
49 | return hash;
50 | };
51 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off */
2 |
3 | import './services/sentry';
4 |
5 | import React from 'react';
6 | import { render } from 'react-dom';
7 | import Root from './containers/App/Root';
8 | import { history, store } from './store/configureStore';
9 | import './styles/scss/app.global.scss';
10 |
11 | const MOUNT_POINT = document.getElementById('root');
12 |
13 | render(<Root store={store} history={history} />, MOUNT_POINT);
14 |
--------------------------------------------------------------------------------
/app/public/images/FileExplorer/buymeacoffee-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/FileExplorer/buymeacoffee-button.png
--------------------------------------------------------------------------------
/app/public/images/FileExplorer/folder-dark.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?>
2 | <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3 | <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4 | viewBox="0 0 408 408" style="enable-background:new 0 0 408 408;" xml:space="preserve">
5 | <g>
6 | <g>
7 | <path d="M332,121.921H184.8l-29.28-34.8c-0.985-1.184-2.461-1.848-4-1.8H32.76C14.628,85.453,0,100.189,0,118.321v214.04
8 | c0.022,18.194,14.766,32.938,32.96,32.96H332c18.194-0.022,32.938-14.766,32.96-32.96v-177.48
9 | C364.938,136.687,350.194,121.943,332,121.921z"/>
10 | </g>
11 | </g>
12 | <g>
13 | <g>
14 | <path d="M375.24,79.281H228l-29.28-34.8c-0.985-1.184-2.461-1.848-4-1.8H76c-16.452,0.027-30.364,12.181-32.6,28.48h108.28
15 | c5.678-0.014,11.069,2.492,14.72,6.84l25,29.72H332c26.005,0.044,47.076,21.115,47.12,47.12v167.52
16 | c16.488-2.057,28.867-16.064,28.88-32.68v-177.48C407.957,94.1,393.34,79.413,375.24,79.281z"/>
17 | </g>
18 | </g>
19 | <g>
20 | </g>
21 | <g>
22 | </g>
23 | <g>
24 | </g>
25 | <g>
26 | </g>
27 | <g>
28 | </g>
29 | <g>
30 | </g>
31 | <g>
32 | </g>
33 | <g>
34 | </g>
35 | <g>
36 | </g>
37 | <g>
38 | </g>
39 | <g>
40 | </g>
41 | <g>
42 | </g>
43 | <g>
44 | </g>
45 | <g>
46 | </g>
47 | <g>
48 | </g>
49 | </svg>
50 |
--------------------------------------------------------------------------------
/app/public/images/FileExplorer/folder-light.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0"?>
2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 408 408" style="enable-background:new 0 0 512 512" xml:space="preserve" class=""><g>
3 | <g xmlns="http://www.w3.org/2000/svg">
4 | <g>
5 | <path d="M332,121.921H184.8l-29.28-34.8c-0.985-1.184-2.461-1.848-4-1.8H32.76C14.628,85.453,0,100.189,0,118.321v214.04 c0.022,18.194,14.766,32.938,32.96,32.96H332c18.194-0.022,32.938-14.766,32.96-32.96v-177.48 C364.938,136.687,350.194,121.943,332,121.921z" fill="#ffffff" data-original="#000000" style=""/>
6 | </g>
7 | </g>
8 | <g xmlns="http://www.w3.org/2000/svg">
9 | <g>
10 | <path d="M375.24,79.281H228l-29.28-34.8c-0.985-1.184-2.461-1.848-4-1.8H76c-16.452,0.027-30.364,12.181-32.6,28.48h108.28 c5.678-0.014,11.069,2.492,14.72,6.84l25,29.72H332c26.005,0.044,47.076,21.115,47.12,47.12v167.52 c16.488-2.057,28.867-16.064,28.88-32.68v-177.48C407.957,94.1,393.34,79.413,375.24,79.281z" fill="#ffffff" data-original="#000000" style=""/>
11 | </g>
12 | </g>
13 | <g xmlns="http://www.w3.org/2000/svg">
14 | </g>
15 | <g xmlns="http://www.w3.org/2000/svg">
16 | </g>
17 | <g xmlns="http://www.w3.org/2000/svg">
18 | </g>
19 | <g xmlns="http://www.w3.org/2000/svg">
20 | </g>
21 | <g xmlns="http://www.w3.org/2000/svg">
22 | </g>
23 | <g xmlns="http://www.w3.org/2000/svg">
24 | </g>
25 | <g xmlns="http://www.w3.org/2000/svg">
26 | </g>
27 | <g xmlns="http://www.w3.org/2000/svg">
28 | </g>
29 | <g xmlns="http://www.w3.org/2000/svg">
30 | </g>
31 | <g xmlns="http://www.w3.org/2000/svg">
32 | </g>
33 | <g xmlns="http://www.w3.org/2000/svg">
34 | </g>
35 | <g xmlns="http://www.w3.org/2000/svg">
36 | </g>
37 | <g xmlns="http://www.w3.org/2000/svg">
38 | </g>
39 | <g xmlns="http://www.w3.org/2000/svg">
40 | </g>
41 | <g xmlns="http://www.w3.org/2000/svg">
42 | </g>
43 | </g></svg>
44 |
--------------------------------------------------------------------------------
/app/public/images/FileExplorer/paypal-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/FileExplorer/paypal-logo.png
--------------------------------------------------------------------------------
/app/public/images/file-types/7z.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#90bae1;fill-opacity:1" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#c8bdb8" d="M28.5,24v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h-2v2h-2v2h2v2h-2v2h2v2h-2v2h2v2h-2v2h2v2 h-4v5c0,2.757,2.243,5,5,5s5-2.243,5-5v-5H28.5z M30.5,29c0,1.654-1.346,3-3,3s-3-1.346-3-3v-3h6V29z"/><path style="fill:#c8bdb8" d="M26.5,30h2c0.552,0,1-0.447,1-1s-0.448-1-1-1h-2c-0.552,0-1,0.447-1,1S25.948,30,26.5,30z"/></g></g><g transform="scale(0.99005755,1.0100423)" style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:13.88808155px;font-family:Allerta;-inkscape-font-specification:Allerta;fill:#fff;fill-opacity:1"><path d="m 22.232274,52.472202 3.47202,-8.666488 -4.353588,0 0,-1.329133 6.279474,0 -3.878897,9.995621 -1.519009,0 z" style="fill:#fff"/><path d="m 29.393316,44.822907 5.818346,0 0,1.315571 -3.933148,4.801153 -0.271251,0.217001 4.204399,0 0,1.31557 -5.818346,0 0,-1.31557 3.933148,-4.801153 0.271251,-0.217001 -4.204399,0 0,-1.315571 z" style="fill:#fff"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/ai.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><path style="fill:#ffc14f" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#fff" d="M20.067,53l3.527-10.063h1.627L28.722,53h-1.695l-0.725-2.092h-3.787L21.776,53H20.067z M22.897,49.801h3.008l-1.49-4.348L22.897,49.801z"/><path style="fill:#fff" d="M32.536,53h-1.668V42.924h1.668V53z"/></g><path style="fill:#c8bdb8" d="M37.5,11v0.461c-3.071,0.968-5.503,3.382-6.502,6.44C30.311,17.346,29.45,17,28.5,17 c-1.859,0-3.411,1.28-3.858,3H21.5v-2h-6v6h6v-2h2.921c-0.336,2.663-1.985,4.978-4.389,6.163C19.364,26.884,18.04,26,16.5,26 c-2.206,0-4,1.794-4,4s1.794,4,4,4c2.146,0,3.888-1.702,3.982-3.825c2.655-1.151,4.647-3.387,5.524-6.073 C26.692,24.655,27.552,25,28.5,25c1.859,0,3.411-1.28,3.858-3H35.5v2h6v-6h-6v2h-2.931c0.379-3.019,2.444-5.514,5.222-6.518 C38.383,14.955,39.818,16,41.5,16c2.206,0,4-1.794,4-4v-1H37.5z M19.5,22h-2v-2h2V22z M16.5,32c-1.103,0-2-0.897-2-2s0.897-2,2-2 s2,0.897,2,2S17.603,32,16.5,32z M37.5,20h2v2h-2V20z M28.5,23c-1.103,0-2-0.897-2-2s0.897-2,2-2s2,0.897,2,2S29.603,23,28.5,23z M41.5,14c-0.723,0-1.353-0.389-1.704-0.964C40.028,13.015,40.262,13,40.5,13h2.731C42.886,13.597,42.239,14,41.5,14z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/archive.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><g><rect x="26.5" y="42" style="fill:#c8bdb8" width="2" height="14"/><polygon style="fill:#c8bdb8" points="30.5,23 30.5,21 28.5,21 28.5,19 26.5,19 26.5,21 24.5,21 24.5,23 26.5,23 26.5,25 24.5,25 24.5,27 26.5,27 26.5,29 24.5,29 24.5,31 26.5,31 26.5,34 28.5,34 28.5,31 30.5,31 30.5,29 28.5,29 28.5,27 30.5,27 30.5,25 28.5,25 28.5,23"/></g><g><rect x="23.5" y="34" style="fill:#cbb292" width="8" height="8"/><path style="fill:#5e5f62" d="M32.5,43h-10V33h10V43z M24.5,41h6v-6h-6V41z"/></g><rect x="23.5" y="36" style="fill:#5e5f62" width="8" height="2"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/audio.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#c8bdb8" d="M 35.67,26.986 C 35.103,26.19 34.37,25.443 33.362,24.635 29.448,21.504 28.605,18.358 28.5,17.897 L 28.5,17 c 0,-0.553 -0.447,-1 -1,-1 -0.553,0 -1,0.447 -1,1 l 0,1 0,8.359 0,9.053 -3.706,0 c -3.882,0 -6.294,1.961 -6.294,5.117 0,3.466 2.24,5.706 5.706,5.706 3.471,0 6.294,-2.823 6.294,-6.294 l 0,-11.473 0.298,0.243 c 0.34,0.336 0.861,0.72 1.521,1.205 2.318,1.709 6.2,4.567 5.224,7.793 C 35.514,37.807 35.5,37.904 35.5,38 c 0,0.43 0.278,0.826 0.71,0.957 0.097,0.029 0.194,0.043 0.29,0.043 0.43,0 0.826,-0.278 0.957,-0.71 C 39.084,32.915 37.035,28.9 35.67,26.986 Z M 26.5,39.941 c 0,2.368 -1.926,4.294 -4.294,4.294 -2.355,0 -3.706,-1.351 -3.706,-3.706 0,-2.576 2.335,-3.117 4.294,-3.117 l 3.706,0 0,2.529 z M 31.505,28.308 C 30.934,27.886 30.44,27.523 30.134,27.227 l -1.634,-1.34 0,-3.473 c 0.827,1.174 1.987,2.483 3.612,3.783 0.858,0.688 1.472,1.308 1.929,1.95 0.716,1.003 1.431,2.339 1.788,3.978 -1.327,-1.61 -3.084,-2.904 -4.324,-3.817 z"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/avi.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#d75e72" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#fff" d="M16.361,53l3.527-10.063h1.627L25.016,53H23.32l-0.725-2.092h-3.787L18.07,53H16.361z M19.191,49.801h3.008l-1.49-4.348L19.191,49.801z"/><path style="fill:#fff" d="M29.828,53.055l-3.131-10.131h1.873l2.338,8.695l2.475-8.695h1.859l-3.281,10.131H29.828z"/><path style="fill:#fff" d="M38.988,53H37.32V42.924h1.668V53z"/></g><polygon style="fill:#c8bdb8" points="23.5,28 23.5,20.954 23.5,14 34.5,21"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/exe.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#9777a8" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#fff" d="M17.082,44.168v3.172h4.211v1.121h-4.211v3.295h4.635V53h-6.303V42.924h6.303v1.244H17.082z"/><path style="fill:#fff" d="M28.58,48.105L31.137,53h-1.9l-1.6-3.801H27.5L25.777,53h-1.9l2.557-4.895l-2.721-5.182h1.873 l1.777,4.102H27.5l1.928-4.102h1.873L28.58,48.105z"/><path style="fill:#fff" d="M35.266,44.168v3.172h4.211v1.121h-4.211v3.295H39.9V53h-6.303V42.924H39.9v1.244H35.266z"/></g><path style="fill:#9777a8" d="M33.5,32c-0.099,0-0.2-0.015-0.299-0.046c-0.527-0.165-0.821-0.726-0.656-1.253l5-16 c0.165-0.527,0.726-0.821,1.253-0.656c0.527,0.165,0.821,0.726,0.656,1.253l-5,16C34.321,31.726,33.926,32,33.5,32z"/><circle style="fill:#9777a8" cx="29" cy="19.5" r="1.5"/><circle style="fill:#9777a8" cx="29" cy="26.5" r="1.5"/><path style="fill:#9777a8" d="M23.5,30h-2c-3.86,0-7-3.14-7-7s3.14-7,7-7h2c0.552,0,1,0.448,1,1s-0.448,1-1,1h-2 c-2.757,0-5,2.243-5,5s2.243,5,5,5h2c0.552,0,1,0.448,1,1S24.052,30,23.5,30z"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/fla.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#ce3c3b" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#fff" d="M17.246,44.168v3.172h4.211v1.121h-4.211V53h-1.668V42.924h6.303v1.244H17.246z"/><path style="fill:#fff" d="M25.299,42.924v8.832h4.635V53h-6.303V42.924H25.299z"/><path style="fill:#fff" d="M31.205,53l3.527-10.063h1.627L39.859,53h-1.695l-0.725-2.092h-3.787L32.914,53H31.205z M34.035,49.801h3.008l-1.49-4.348L34.035,49.801z"/></g><circle style="fill:#c8bdb8" cx="25.5" cy="16" r="2"/><g><path style="fill:#c8bdb8" d="M34.985,13.929l-0.707-0.707C32.201,11.144,29.438,10,26.5,10s-5.701,1.144-7.778,3.222 C16.644,15.299,15.5,18.062,15.5,21s1.144,5.701,3.222,7.778C20.799,30.856,23.562,32,26.5,32s5.701-1.144,7.778-3.222 l0.707-0.707L27.914,21L34.985,13.929z M32.118,28.032C30.528,29.308,28.567,30,26.5,30c-2.404,0-4.664-0.936-6.364-2.636 S17.5,23.404,17.5,21s0.936-4.664,2.636-6.364S24.096,12,26.5,12c2.067,0,4.028,0.692,5.618,1.968L25.086,21L32.118,28.032z"/><path style="fill:#c8bdb8" d="M35.5,20h-3c-0.553,0-1,0.447-1,1s0.447,1,1,1h3c0.553,0,1-0.447,1-1S36.053,20,35.5,20z"/><path style="fill:#c8bdb8" d="M41.5,20h-2c-0.553,0-1,0.447-1,1s0.447,1,1,1h2c0.553,0,1-0.447,1-1S42.053,20,41.5,20z"/></g></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/html.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#ec6630" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#fff" d="M17.455,42.924V53h-1.641v-4.539h-4.361V53H9.785V42.924h1.668v4.416h4.361v-4.416H17.455z"/><path style="fill:#fff" d="M27.107,42.924v1.121H24.1V53h-1.654v-8.955h-3.008v-1.121H27.107z"/><path style="fill:#fff" d="M36.705,42.924h1.668V53h-1.668v-6.932l-2.256,5.605H33l-2.27-5.605V53h-1.668V42.924h1.668 l2.994,6.891L36.705,42.924z"/><path style="fill:#fff" d="M42.57,42.924v8.832h4.635V53h-6.303V42.924H42.57z"/></g><g><path style="fill:#ec6630" d="M23.207,16.293c-0.391-0.391-1.023-0.391-1.414,0l-6,6c-0.391,0.391-0.391,1.023,0,1.414l6,6 C21.988,29.902,22.244,30,22.5,30s0.512-0.098,0.707-0.293c0.391-0.391,0.391-1.023,0-1.414L17.914,23l5.293-5.293 C23.598,17.316,23.598,16.684,23.207,16.293z"/><path style="fill:#ec6630" d="M41.207,22.293l-6-6c-0.391-0.391-1.023-0.391-1.414,0s-0.391,1.023,0,1.414L39.086,23 l-5.293,5.293c-0.391,0.391-0.391,1.023,0,1.414C33.988,29.902,34.244,30,34.5,30s0.512-0.098,0.707-0.293l6-6 C41.598,23.316,41.598,22.684,41.207,22.293z"/></g></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/tiff.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><path style="fill:#556080;fill-opacity:1" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><circle style="fill:#f3d55b" cx="18.931" cy="14.431" r="4.569"/><polygon style="fill:#8d97b3;fill-opacity:1" points="6.5,39 17.5,39 49.5,39 49.5,28 39.5,18.5 29,30 23.517,24.517"/></g><g transform="scale(0.99005755,1.0100423)" style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:13.88808155px;font-family:Allerta;-inkscape-font-specification:Allerta;fill:#fff;fill-opacity:1"><path d="m 21.859303,42.442173 0,1.112131 -2.983768,0 0,8.88349 -1.641072,0 0,-8.88349 -2.983768,0 0,-1.112131 7.608608,0 z" style="fill:#fff"/><path d="m 25.494074,52.437794 -1.654634,0 0,-9.995621 1.654634,0 0,9.995621 z" style="fill:#fff"/><path d="m 29.684912,43.676367 0,3.146519 4.177274,0 0,1.112131 -4.177274,0 0,4.502777 -1.654635,0 0,-9.995621 6.252349,0 0,1.234194 -4.597714,0 z" style="fill:#fff"/><path d="m 37.71396,43.676367 0,3.146519 4.177274,0 0,1.112131 -4.177274,0 0,4.502777 -1.654635,0 0,-9.995621 6.252349,0 0,1.234194 -4.597714,0 z" style="fill:#fff"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/unknown.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#c8bdb8" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><circle style="fill:#fff" cx="18.5" cy="47" r="3"/><circle style="fill:#fff" cx="28.5" cy="47" r="3"/><circle style="fill:#fff" cx="38.5" cy="47" r="3"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/video.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><path style="fill:#c8bdb8" d="M 24.5,40 C 24.334,40 24.169,39.959 24.019,39.877 23.699,39.701 23.5,39.365 23.5,39 l 0,-14 c 0,-0.365 0.199,-0.701 0.519,-0.877 0.321,-0.175 0.71,-0.162 1.019,0.033 l 11,7 C 36.325,31.34 36.5,31.658 36.5,32 c 0,0.342 -0.175,0.66 -0.463,0.844 l -11,7 C 24.874,39.947 24.687,40 24.5,40 Z m 1,-13.179 0,10.357 L 33.637,32 25.5,26.821 Z"/><path style="fill:#c8bdb8" d="m 28.5,47 c -8.271,0 -15,-6.729 -15,-15 0,-8.271 6.729,-15 15,-15 8.271,0 15,6.729 15,15 0,8.271 -6.729,15 -15,15 z m 0,-28 c -7.168,0 -13,5.832 -13,13 0,7.168 5.832,13 13,13 7.168,0 13,-5.832 13,-13 0,-7.168 -5.832,-13 -13,-13 z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/></g></svg>
--------------------------------------------------------------------------------
/app/public/images/file-types/zip.svg:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="iso-8859-1"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 56 56" style="enable-background:new 0 0 56 56" xml:space="preserve"><g><path style="fill:#e9e9e0" d="M36.985,0H7.963C7.155,0,6.5,0.655,6.5,1.926V55c0,0.345,0.655,1,1.463,1h40.074 c0.808,0,1.463-0.655,1.463-1V12.978c0-0.696-0.093-0.92-0.257-1.085L37.607,0.257C37.442,0.093,37.218,0,36.985,0z"/><polygon style="fill:#d9d7ca" points="37.5,0.151 37.5,12 49.349,12"/><path style="fill:#556080" d="M48.037,56H7.963C7.155,56,6.5,55.345,6.5,54.537V39h43v15.537C49.5,55.345,48.845,56,48.037,56z"/><g><path style="fill:#fff" d="M25.266,42.924v1.326l-4.799,7.205l-0.273,0.219h5.072V53h-6.699v-1.326l4.799-7.205l0.287-0.219 h-5.086v-1.326H25.266z"/><path style="fill:#fff" d="M29.271,53h-1.668V42.924h1.668V53z"/><path style="fill:#fff" d="M33.414,53h-1.641V42.924h2.898c0.428,0,0.852,0.068,1.271,0.205 c0.419,0.137,0.795,0.342,1.128,0.615c0.333,0.273,0.602,0.604,0.807,0.991s0.308,0.822,0.308,1.306 c0,0.511-0.087,0.973-0.26,1.388c-0.173,0.415-0.415,0.764-0.725,1.046c-0.31,0.282-0.684,0.501-1.121,0.656 s-0.921,0.232-1.449,0.232h-1.217V53z M33.414,44.168v3.992h1.504c0.2,0,0.398-0.034,0.595-0.103 c0.196-0.068,0.376-0.18,0.54-0.335s0.296-0.371,0.396-0.649c0.1-0.278,0.15-0.622,0.15-1.032c0-0.164-0.023-0.354-0.068-0.567 c-0.046-0.214-0.139-0.419-0.28-0.615c-0.142-0.196-0.34-0.36-0.595-0.492c-0.255-0.132-0.593-0.198-1.012-0.198H33.414z"/></g><g><path style="fill:#c8bdb8" d="M28.5,24v-2h2v-2h-2v-2h2v-2h-2v-2h2v-2h-2v-2h2V8h-2V6h-2v2h-2v2h2v2h-2v2h2v2h-2v2h2v2h-2v2h2v2 h-4v5c0,2.757,2.243,5,5,5s5-2.243,5-5v-5H28.5z M30.5,29c0,1.654-1.346,3-3,3s-3-1.346-3-3v-3h6V29z"/><path style="fill:#c8bdb8" d="M26.5,30h2c0.552,0,1-0.447,1-1s-0.448-1-1-1h-2c-0.552,0-1,0.447-1,1S25.948,30,26.5,30z"/></g></g></svg>
--------------------------------------------------------------------------------
/app/public/images/help/allow-data-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/allow-data-access.png
--------------------------------------------------------------------------------
/app/public/images/help/charge-only-permission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/charge-only-permission.png
--------------------------------------------------------------------------------
/app/public/images/help/full-disk-access-file-picker.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/full-disk-access-file-picker.jpeg
--------------------------------------------------------------------------------
/app/public/images/help/full-disk-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/full-disk-access.png
--------------------------------------------------------------------------------
/app/public/images/help/google-drive-not-connecting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/google-drive-not-connecting.png
--------------------------------------------------------------------------------
/app/public/images/help/macos-directory-access.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/macos-directory-access.jpg
--------------------------------------------------------------------------------
/app/public/images/help/privacy-restricted-folder-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/privacy-restricted-folder-access.png
--------------------------------------------------------------------------------
/app/public/images/help/sleep-setting.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/sleep-setting.jpg
--------------------------------------------------------------------------------
/app/public/images/help/transfer-media-permission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/transfer-media-permission.png
--------------------------------------------------------------------------------
/app/public/images/help/usb-notification-charging-via-usb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/usb-notification-charging-via-usb.png
--------------------------------------------------------------------------------
/app/public/images/help/usb-notification-transferring-media.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/help/usb-notification-transferring-media.png
--------------------------------------------------------------------------------
/app/public/images/no-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/no-image.png
--------------------------------------------------------------------------------
/app/public/images/toolbar/buymeacoffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/app/public/images/toolbar/buymeacoffee.png
--------------------------------------------------------------------------------
/app/services/ipc-events/IpcEventHandler.js:
--------------------------------------------------------------------------------
1 | import { ipcMain } from 'electron';
2 | import { IpcEvents } from './IpcEventType';
3 | import {
4 | faqsWindow,
5 | helpPhoneNotConnectingWindow,
6 | privacyPolicyWindow,
7 | reportBugsWindow,
8 | } from '../../helpers/createWindows';
9 |
10 | export default class IpcEventService {
11 | static shared = new IpcEventService();
12 |
13 | start() {
14 | this.#init();
15 | }
16 |
17 | #init = () => {
18 | // todo move all create window methods to IpcEventService and all window create methods from renderer should be event-driven (aka via IpcEventService). The main process windows could be directly invoked.
19 | // This is done to avoid issues with 'electron/remote' (in the packaged builds the electron/remote enable doesn't work)
20 |
21 | ipcMain.on(IpcEvents.OPEN_FAQS_WINDOW, (_, __) => {
22 | faqsWindow(false);
23 | });
24 | ipcMain.on(IpcEvents.OPEN_HELP_PHONE_NOT_CONNECTING_WINDOW, (_, __) => {
25 | helpPhoneNotConnectingWindow(false);
26 | });
27 | ipcMain.on(IpcEvents.OPEN_HELP_PRIVACY_POLICY_WINDOW, (_, __) => {
28 | privacyPolicyWindow(false);
29 | });
30 |
31 | ipcMain.on(IpcEvents.REPORT_BUGS_DISPOSE_MTP_REPLY, (_, args) => {
32 | reportBugsWindow(false, false)?.send(
33 | IpcEvents.REPORT_BUGS_DISPOSE_MTP_REPLY_FROM_MAIN,
34 | args
35 | );
36 | });
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/app/services/ipc-events/IpcEventType.js:
--------------------------------------------------------------------------------
1 | export class IpcEvents {
2 | static OPEN_FAQS_WINDOW = 'ipc.window.faqs';
3 |
4 | static OPEN_HELP_PHONE_NOT_CONNECTING_WINDOW =
5 | 'ipc.window.helpPhoneNotConnecting';
6 |
7 | static OPEN_HELP_PRIVACY_POLICY_WINDOW = 'ipc.window.privacyPolicy';
8 |
9 | static OPEN_KEYBOARD_SHORTCUTS_WINDOW = 'ipc.window.keyboardShortcuts';
10 |
11 | static REPORT_BUGS_DISPOSE_MTP = 'ipc.reportBugsDisposeMtp';
12 |
13 | static REPORT_BUGS_DISPOSE_MTP_REPLY = 'ipc.reportBugsDisposeMtpReply';
14 |
15 | static REPORT_BUGS_DISPOSE_MTP_REPLY_FROM_MAIN =
16 | 'ipc.reportBugsDisposeMtpReply.fromMain';
17 |
18 | static USB_HOTPLUG = 'ipc.usbHotplug';
19 | }
20 |
--------------------------------------------------------------------------------
/app/services/sentry/index.js:
--------------------------------------------------------------------------------
1 | import * as Sentry from '@sentry/electron';
2 | import { ENV_FLAVOR } from '../../constants/env';
3 | import { SERVICE_KEYS } from '../../constants/serviceKeys';
4 | import { getDeviceInfo } from '../../helpers/deviceInfo';
5 | import { isEmpty } from '../../utils/funcs';
6 | import { pkginfo } from '../../utils/pkginfo';
7 | import { checkIf } from '../../utils/checkIf';
8 | import { MTP_MODE } from '../../enums';
9 | import { getMachineId } from '../../helpers/identifiers';
10 |
11 | class SentryService {
12 | constructor() {
13 | if (!ENV_FLAVOR.reportToSenty) {
14 | return;
15 | }
16 |
17 | this.init();
18 | }
19 |
20 | async init() {
21 | Sentry.init({
22 | dsn: SERVICE_KEYS.sentryDsn,
23 | // disabled native crash reporting to respect user's privacy
24 | enableNative: false,
25 | release: pkginfo.version,
26 | });
27 |
28 | this.machineId = getMachineId();
29 | }
30 |
31 | async report({ error, title, mtpMode }) {
32 | checkIf(mtpMode, 'inObjectValues', MTP_MODE);
33 |
34 | if (!ENV_FLAVOR.reportToSenty) {
35 | return;
36 | }
37 |
38 | const deviceInfo = getDeviceInfo();
39 |
40 | Sentry.configureScope((scope) => {
41 | if (!isEmpty(deviceInfo)) {
42 | Object.keys(deviceInfo).forEach((a) => {
43 | const item = deviceInfo[a];
44 |
45 | scope.setExtra(a, item);
46 | });
47 | }
48 |
49 | if (!isEmpty(title)) {
50 | scope.setExtra('error title', title);
51 | }
52 |
53 | scope.setExtra('MTP Mode', mtpMode);
54 |
55 | // this is a hashed value (sha-256)
56 | scope.setUser({ id: this.machineId });
57 |
58 | Sentry.captureException(error);
59 | });
60 | }
61 | }
62 |
63 | export const sentryService = new SentryService();
64 |
--------------------------------------------------------------------------------
/app/store/configureStore/dev.js:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off */
2 | /* eslint-disable import/no-import-module-exports */
3 |
4 | import { createStore, applyMiddleware, compose } from 'redux';
5 | import thunk from 'redux-thunk';
6 | import { createHashHistory } from 'history';
7 | import { routerMiddleware } from 'react-router-redux';
8 | import { createLogger } from 'redux-logger';
9 | import rootReducer from '../reducers';
10 |
11 | const history = createHashHistory();
12 |
13 | const configureStore = (initialState) => {
14 | // Redux Configuration
15 | const middleware = [];
16 | const enhancers = [];
17 |
18 | // Thunk Middleware
19 | middleware.push(thunk);
20 |
21 | // Logging Middleware
22 | const logger = createLogger({
23 | level: 'info',
24 | collapsed: true,
25 | });
26 |
27 | // Skip redux logs in console during the tests
28 | if (process.env.NODE_ENV !== 'test') {
29 | middleware.push(logger);
30 | }
31 |
32 | // Router Middleware
33 | const router = routerMiddleware(history);
34 |
35 | middleware.push(router);
36 |
37 | // If Redux DevTools Extension is installed use it, otherwise use Redux compose
38 | const composeEnhancers =
39 | window && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
40 | ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
41 | : compose;
42 |
43 | // Apply Middleware & Compose Enhancers
44 | enhancers.push(applyMiddleware(...middleware));
45 | const enhancer = composeEnhancers(...enhancers);
46 |
47 | // Create Store
48 | const store = createStore(rootReducer(), initialState, enhancer);
49 |
50 | store.asyncReducers = {};
51 | store.injectReducer = (key, reducer) => {
52 | store.asyncReducers[key] = reducer;
53 | store.replaceReducer(rootReducer(store.asyncReducers));
54 |
55 | return store;
56 | };
57 |
58 | if (module.hot) {
59 | module.hot.accept('../reducers', () =>
60 | store.replaceReducer(require('../reducers').default)
61 | );
62 | }
63 |
64 | return store;
65 | };
66 |
67 | export default { configureStore, history };
68 |
--------------------------------------------------------------------------------
/app/store/configureStore/index.js:
--------------------------------------------------------------------------------
1 | import configureStoreDev from './dev';
2 | import configureStoreProd from './prod';
3 | import { IS_PROD } from '../../constants/env';
4 |
5 | const selectedConfigureStore = IS_PROD ? configureStoreProd : configureStoreDev;
6 |
7 | const { configureStore } = selectedConfigureStore;
8 |
9 | export const { history } = selectedConfigureStore;
10 |
11 | export const store = configureStore();
12 |
--------------------------------------------------------------------------------
/app/store/configureStore/prod.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | import thunk from 'redux-thunk';
3 | import { createHashHistory } from 'history';
4 | import { routerMiddleware } from 'react-router-redux';
5 | import rootReducer from '../reducers';
6 |
7 | const history = createHashHistory();
8 | const router = routerMiddleware(history);
9 | const enhancer = applyMiddleware(thunk, router);
10 |
11 | const configureStore = (initialState) => {
12 | const store = createStore(rootReducer(), initialState, enhancer);
13 |
14 | store.asyncReducers = {};
15 | store.injectReducer = (key, reducer) => {
16 | store.asyncReducers[key] = reducer;
17 | store.replaceReducer(rootReducer(store.asyncReducers));
18 |
19 | return store;
20 | };
21 |
22 | return store;
23 | };
24 |
25 | export default { configureStore, history };
26 |
--------------------------------------------------------------------------------
/app/store/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import { routerReducer as router } from 'react-router-redux';
3 | import Alerts from '../../containers/Alerts/reducers';
4 | import Settings from '../../containers/Settings/reducers';
5 |
6 | const rootReducer = (asyncReducers) =>
7 | combineReducers({
8 | Alerts,
9 | Settings,
10 | router,
11 | ...asyncReducers,
12 | });
13 |
14 | export default rootReducer;
15 |
--------------------------------------------------------------------------------
/app/store/reducers/withReducer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { object } from 'prop-types';
3 |
4 | /* eslint-disable */
5 | const withReducer = (key, reducer) => (WrappedComponent) => {
6 | const Extended = (props, context) => {
7 | context.store.injectReducer(key, reducer);
8 | return <WrappedComponent {...props} />;
9 | };
10 |
11 | Extended.contextTypes = {
12 | store: object,
13 | };
14 |
15 | return Extended;
16 | };
17 |
18 | /* eslint-enable */
19 | export { withReducer };
20 |
--------------------------------------------------------------------------------
/app/styles/js/index.js:
--------------------------------------------------------------------------------
1 | export { default as variables } from './variables';
2 | export { default as mixins } from './mixins';
3 |
--------------------------------------------------------------------------------
/app/styles/js/variables.js:
--------------------------------------------------------------------------------
1 | // common styling variable object which can be imported by components
2 | export default (_) => {
3 | return {
4 | sizes: {
5 | toolbarHeight: 64,
6 | sidebarAreaPaneWidth: 300,
7 | sidebarAreaPaddingTop: 40,
8 | regularFontSize: 14,
9 | },
10 | // styles: {
11 | // bgColor: APP_THEME_COLOR_VAR.bgColor,
12 | // primaryColor: {
13 | // main: APP_THEME_COLOR_VAR.primaryMainColor,
14 | // },
15 | // secondaryColor: {
16 | // main: APP_THEME_COLOR_VAR.secondaryMainColor,
17 | // },
18 | // background: {
19 | // paper: APP_THEME_COLOR_VAR.paperBgColor,
20 | // },
21 | // icons: {
22 | // navbarRegular: APP_THEME_COLOR_VAR.contrastPrimaryMainColor,
23 | // disabled: APP_THEME_COLOR_VAR.disabledBgColor,
24 | // },
25 | // nativeSystemColor: APP_THEME_COLOR_VAR.nativeSystemColor,
26 | // tableHeaderFooterBgColor: APP_THEME_COLOR_VAR.tableHeaderFooterBgColor,
27 | // fileExplorerThinLineDividerColor:
28 | // APP_THEME_COLOR_VAR.fileExplorerThinLineDividerColor,
29 | // lightText1Color: APP_THEME_COLOR_VAR.lightText1Color,
30 | // },
31 | };
32 | };
33 |
--------------------------------------------------------------------------------
/app/styles/scss/app.global.scss:
--------------------------------------------------------------------------------
1 | @import './themes/fonts';
2 | @import './base/base';
3 | @import './themes/reset';
4 |
--------------------------------------------------------------------------------
/app/styles/scss/base/_base.scss:
--------------------------------------------------------------------------------
1 | //Base
2 | @import 'variables';
3 | @import 'mixins';
4 | @import 'extends';
5 |
--------------------------------------------------------------------------------
/app/styles/scss/base/_extends.scss:
--------------------------------------------------------------------------------
1 | %marginAuto {
2 | @include margin-auto();
3 | }
4 |
5 | %clearfix {
6 | @include clearfix();
7 | }
8 |
9 | %inlineBlock {
10 | @include inline-block();
11 | }
12 |
13 | %hideText {
14 | @include hide-text();
15 | }
16 |
--------------------------------------------------------------------------------
/app/styles/scss/base/_variables.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 | // Font Sizes
3 | // ----------------------------------------------------------------------
4 | $regularSize: 14;
5 |
6 | // ----------------------------------------------------------------------
7 | // Font Families
8 | // ----------------------------------------------------------------------
9 | $roboto: 'Roboto', sans-serif;
10 |
11 | // ----------------------------------------------------------------------
12 | // styles
13 | // ----------------------------------------------------------------------
14 |
15 | $appBgColor: var(--app-bg-color) !default;
16 |
17 | $appSecondaryColor: var(--app-secondary-main-color) !default;
18 |
19 | $nativeSystemColor: var(--app-native-system-color) !default;
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_align-items.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | // Flex Align Items
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | @mixin align-items($value) {
8 | -webkit-box-align: $value;
9 | -moz-box-align: $value;
10 | -ms-flex-align: $value;
11 | -webkit-align-items: $value;
12 | align-items: $value;
13 | }
14 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_animate-link.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Animated link that has a fade-in underline
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include animate-link($screenGreen, $gothamMedium, 14);
14 |
15 | @mixin animate-link($color, $font, $fontSize) {
16 | font-family: $font;
17 |
18 | @include single-transition(border, 0.2s, ease-in-out, 0);
19 |
20 | text-decoration: none;
21 | color: $color;
22 | border-bottom: 1px solid transparent;
23 |
24 | @include rem('font-size', $fontSize);
25 |
26 | &:focus,
27 | &:hover {
28 | border-color: $color;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_animations.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Animations
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include animation('slide-down 5s 3');
14 |
15 | @mixin animation($str) {
16 | -webkit-animation: #{$str};
17 | -moz-animation: #{$str};
18 | -ms-animation: #{$str};
19 | -o-animation: #{$str};
20 | animation: #{$str};
21 | }
22 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_backface-visibility.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Backface-visibility
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include backface-visibility("hidden");
14 |
15 | @mixin backface-visibility($value) {
16 | -webkit-backface-visibility: $value;
17 | -moz-backface-visibility: $value;
18 | backface-visibility: $value;
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_background-cover.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Background cover
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include background-cover();
14 |
15 | @mixin background-cover() {
16 | -webkit-background-size: cover;
17 | -moz-background-size: cover;
18 | -o-background-size: cover;
19 | background-size: cover;
20 | }
21 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_border.scss:
--------------------------------------------------------------------------------
1 | @mixin border-radius($value) {
2 | -moz-border-radius: $value;
3 | -webkit-border-radius: $value;
4 | border-radius: $value;
5 | }
6 |
7 | @mixin border($value) {
8 | border: $value;
9 | }
10 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_box-model.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Box Model
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | @mixin box-sizing($box-model) {
14 | -webkit-box-sizing: $box-model;
15 | -moz-box-sizing: $box-model;
16 | box-sizing: $box-model;
17 | }
18 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_box-shadow.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Box Shadow
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include box-shadow(1px, 2px, 2px, 2px, #000);
14 |
15 | @mixin box-shadow(
16 | $hoff: false,
17 | $voff: false,
18 | $blur: false,
19 | $spread: false,
20 | $color: false
21 | ) {
22 | -webkit-box-shadow: $hoff $voff $blur $spread $color;
23 | -moz-box-shadow: $hoff $voff $blur $spread $color;
24 | box-shadow: $hoff $voff $blur $spread $color;
25 | }
26 |
27 | @mixin box-shadow-1($value) {
28 | -webkit-box-shadow: $value;
29 | -moz-box-shadow: $value;
30 | box-shadow: $value;
31 | }
32 |
33 | @mixin box-shadow-2($value1, $value2, $value3) {
34 | -webkit-box-shadow: $value1, $value2, $value3;
35 | -moz-box-shadow: $value1, $value2, $value3;
36 | box-shadow: $value1, $value2, $value3;
37 | }
38 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_breakpoint.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Media Query Breakpoints
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example @include breakpoint(940) { width:80%; }
14 |
15 | @mixin breakpoint($size) {
16 | @media only screen and (max-width: $size + px) {
17 | @content;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_clearfix.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Clearfix after element
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include clearfix();
14 |
15 | @mixin clearfix() {
16 | & {
17 | *zoom: 1;
18 | }
19 | &::before,
20 | &::after {
21 | content: '';
22 | display: table;
23 | }
24 | &::after {
25 | clear: both;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_display.scss:
--------------------------------------------------------------------------------
1 | @mixin display($value) {
2 | display: $value;
3 | }
4 |
5 | @mixin display-none($important) {
6 | @if $important {
7 | $important: !important;
8 | }
9 |
10 | display: none $important;
11 | }
12 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_display_flex.scss:
--------------------------------------------------------------------------------
1 | @mixin display_flex() {
2 | display: -webkit-box;
3 | display: -moz-box;
4 | display: -ms-flexbox;
5 | display: -webkit-flex;
6 | display: flex;
7 | }
8 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_hide-text.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Hide Text
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include hide-text();
14 |
15 | @mixin hide-text() {
16 | position: relative;
17 | text-indent: -99999px;
18 | display: inline-block;
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_horz-vert-center.scss:
--------------------------------------------------------------------------------
1 | // example: @include horz-vert-center();
2 |
3 | @mixin horz-vert-center($alignItem: true) {
4 | display: flex;
5 | justify-content: center;
6 | flex-direction: column;
7 | @if $alignItem {
8 | align-items: center;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_hover-focus.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // -----------------------------------------------------------------------
8 |
9 | // Hover and Focus
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example @include hoverFocus('text-decoration', 'none');
14 |
15 | @mixin hoverFocus($property, $value) {
16 | &:hover,
17 | &:focus {
18 | #{$property}: $value;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_inline-block.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Display inline block cross browser
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include inline-block();
14 |
15 | /* stylelint-disable declaration-block-no-duplicate-properties */
16 |
17 | @mixin inline-block() {
18 | display: -moz-inline-stack;
19 | display: inline-block;
20 | vertical-align: top;
21 | zoom: 1;
22 | *display: inline;
23 | }
24 |
25 | /* stylelint-enable declaration-block-no-duplicate-properties */
26 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_inner-shadow.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Inner Shadow
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include inner-shadow(1px, 2px, 2px, #000);
14 |
15 | @mixin inner-shadow($hoff: false, $voff: false, $blur: false, $color: false) {
16 | -webkit-box-shadow: inset $hoff $voff $blur $color;
17 | -moz-box-shadow: inset $hoff $voff $blur $color;
18 | box-shadow: inset $hoff $voff $blur $color;
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_keyframes.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Keyframes
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include keyframes(slide-down) {0%{ opacity:1; } 90%{ opacity:0; }}
14 |
15 | @mixin keyframes($animation-name) {
16 | @-webkit-keyframes #{$animation-name} {
17 | @content;
18 | }
19 | @-moz-keyframes #{$animation-name} {
20 | @content;
21 | }
22 | @-ms-keyframes #{$animation-name} {
23 | @content;
24 | }
25 | @-o-keyframes #{$animation-name} {
26 | @content;
27 | }
28 | @keyframes #{$animation-name} {
29 | @content;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_linear-gradient-angle.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Linear Gradient angle
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include linear-gradient(-10, #cccccc, #333333);
14 |
15 | @mixin linear-gradient($angle, $colorStart, $colorStop) {
16 | background: #{$colorStart}; /* Old browsers */
17 | background: -moz-linear-gradient(
18 | $angle,
19 | #{$colorStart} 0%,
20 | #{$colorStop} 100%
21 | ); /* FF3.6+ */
22 |
23 | background: -webkit-gradient(
24 | linear,
25 | left bottom,
26 | right top,
27 | color-stop(0%, #{$colorStart}),
28 | color-stop(100%, #{$colorStop})
29 | ); /* Chrome,Safari4+ */
30 |
31 | background: -webkit-linear-gradient(
32 | 45deg,
33 | #{$colorStart} 0%,
34 | #{$colorStop} 100%
35 | ); /* Chrome10+,Safari5.1+ */
36 |
37 | background: -o-linear-gradient(
38 | 45deg,
39 | #{$colorStart} 0%,
40 | #{$colorStop} 100%
41 | ); /* Opera 11.10+ */
42 |
43 | background: -ms-linear-gradient(
44 | 45deg,
45 | #{$colorStart} 0%,
46 | #{$colorStop} 100%
47 | ); /* IE10+ */
48 |
49 | background: linear-gradient(
50 | 45deg,
51 | #{$colorStart} 0%,
52 | #{$colorStop} 100%
53 | ); /* W3C */
54 |
55 | filter: progid:dximagetransform.microsoft.gradient( startColorstr='#{$colorStart}', endColorstr='#{$colorStop}',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
56 | }
57 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_linear-gradient.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // -----------------------------------------------------------------------
8 |
9 | // Linear Gradients
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include linearGradient(#cccccc, #333333);
14 |
15 | @mixin linearGradient($top, $bottom) {
16 | background: #{$top}; /* Old browsers */
17 | background: -moz-linear-gradient(
18 | top,
19 | #{$top} 0%,
20 | #{$bottom} 100%
21 | ); /* FF3.6+ */
22 |
23 | background: -webkit-gradient(
24 | linear,
25 | left top,
26 | left bottom,
27 | color-stop(0%, #{$top}),
28 | color-stop(100%, #{$bottom})
29 | ); /* Chrome,Safari4+ */
30 |
31 | background: -webkit-linear-gradient(
32 | top,
33 | #{$top} 0%,
34 | #{$bottom} 100%
35 | ); /* Chrome10+,Safari5.1+ */
36 |
37 | background: -o-linear-gradient(
38 | top,
39 | #{$top} 0%,
40 | #{$bottom} 100%
41 | ); /* Opera 11.10+ */
42 |
43 | background: -ms-linear-gradient(top, #{$top} 0%, #{$bottom} 100%); /* IE10+ */
44 | background: linear-gradient(to bottom, #{$top} 0%, #{$bottom} 100%); /* W3C */
45 | filter: progid:dximagetransform.microsoft.gradient( startColorstr='#{$top}', endColorstr='#{$bottom}', GradientType=0 ); /* IE6-9 */
46 | }
47 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_margin-auto.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Margin auto
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include margin-auto();
14 |
15 | @mixin margin-auto() {
16 | margin-left: auto;
17 | margin-right: auto;
18 | }
19 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_mediumFont.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | // Medium Font
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | // example @include medium-font();
8 |
9 | @mixin medium-font() {
10 | font-weight: bold;
11 | letter-spacing: 0.4px;
12 | }
13 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_min-breakpoint.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Media Query Breakpoints
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example @include min-breakpoint(940) { width:80%; }
14 |
15 | @mixin min-breakpoint($size) {
16 | @media only screen and (min-width: $size + px) {
17 | @content;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_opacity.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // -----------------------------------------------------------------------
8 |
9 | // Opacity
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | @mixin opacity($opacity) {
14 | opacity: $opacity;
15 | $opacity-ie: $opacity * 100;
16 |
17 | filter: alpha(opacity=$opacity-ie); //IE8
18 | }
19 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_placeholder.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Change placeholder text color
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include placeholder-color(#333);
14 |
15 | @mixin placeholder-color($color) {
16 | &.placeholder {
17 | color: $color;
18 | }
19 |
20 | &:-moz-placeholder {
21 | color: $color;
22 | }
23 |
24 | &::-webkit-input-placeholder {
25 | color: $color;
26 | }
27 |
28 | &:-ms-input-placeholder {
29 | color: $color;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_rem.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // REM Units with PX fallback
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include rem("margin", 10, 5, 10, 5);
14 | // example: @include rem("font-size", 14);
15 |
16 | @mixin rem($property, $values...) {
17 | $n: length($values);
18 | $i: 1;
19 |
20 | $pxlist: ();
21 | $remlist: ();
22 |
23 | @while $i <= $n {
24 | $itemVal: (nth($values, $i));
25 | @if $itemVal != 'auto' {
26 | $pxlist: append($pxlist, $itemVal + px);
27 | //$remlist: append($remlist, ($itemVal / 10) + rem); // Use this if you've set HTML font size value to 62.5%
28 | $remlist: append($remlist, ($itemVal / 16) + rem);
29 | } @else {
30 | $pxlist: append($pxlist, auto);
31 | $remlist: append($remlist, auto);
32 | }
33 |
34 | $i: $i + 1;
35 | }
36 |
37 | #{$property}: $pxlist;
38 | #{$property}: $remlist;
39 | }
40 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_replace-text.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Replace text
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include replace-text();
14 |
15 | /* stylelint-disable font-family-no-missing-generic-family-keyword */
16 |
17 | @mixin replace-text() {
18 | border: 0;
19 | color: transparent;
20 | font: 0/0 a;
21 | text-shadow: none;
22 | }
23 |
24 | /* stylelint-enable font-family-no-missing-generic-family-keyword */
25 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_retina.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // -----------------------------------------------------------------------
8 |
9 | // Retina Images
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include retina("logo2x.png", 100, 50);
14 |
15 | /* stylelint-disable media-feature-name-no-unknown */
16 |
17 | @mixin retina($image, $width, $height) {
18 | @media (min--moz-device-pixel-ratio: 1.3),
19 | (-o-min-device-pixel-ratio: 2.6/2),
20 | (-webkit-min-device-pixel-ratio: 1.3),
21 | (min-device-pixel-ratio: 1.3),
22 | (min-resolution: 1.3dppx) {
23 | background-image: url('#{$image}');
24 | background-size: $width + px $height + px;
25 | //background-size: $width / 10 + rem $height / 10 + rem; // Use this if you've set HTML font size value to 62.5%
26 | background-size: $width / 16 + rem $height / 16 + rem;
27 | }
28 | }
29 |
30 | /* stylelint-enable media-feature-name-no-unknown */
31 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_single-transform.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Single Transform
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include flat-button($greyBlue, white, 5px 15px);
14 |
15 | @mixin single-transform($deg) {
16 | -ms-transform: rotate($deg);
17 | -webkit-transform: rotate($deg);
18 | transform: rotate($deg);
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_text-shadow.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Text Shadow
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include single-text-shadow(1px, 2px, 2px, #000);
14 |
15 | @mixin single-text-shadow(
16 | $hoff: false,
17 | $voff: false,
18 | $blur: false,
19 | $color: false
20 | ) {
21 | text-shadow: $hoff $voff $blur $color;
22 | }
23 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_transform.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Transform
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include transform("origin", 0, 0);
14 |
15 | @mixin transform($type, $values...) {
16 | $n: length($values);
17 | $i: 1;
18 |
19 | $originVal: ();
20 |
21 | @while $i <= $n {
22 | $itemVal: (nth($values, $i));
23 | @if $type == 'rotate' or $type == 'rotateY' or $type == 'rotateX' {
24 | $originVal: append($originVal, $itemVal + deg);
25 | } @else {
26 | $originVal: append($originVal, $itemVal + px);
27 | }
28 |
29 | $i: $i + 1;
30 | }
31 |
32 | -webkit-transform: #{$type }($originVal);
33 | -moz-transform: #{$type }($originVal);
34 | transform: #{$type }($originVal);
35 | }
36 |
37 | @mixin transform-1($values) {
38 | -webkit-transform: $values;
39 | -ms-transform: $values;
40 | transform: $values;
41 | }
42 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_transitions.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Transitions
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include single-transition(background, 1s, ease-in-out, 0);
14 |
15 | @mixin single-transition($property, $duration, $timing-function, $delay) {
16 | -webkit-transition: $property $duration $timing-function $delay;
17 | -moz-transition: $property $duration $timing-function $delay;
18 | -o-transition: $property $duration $timing-function $delay;
19 | transition: $property $duration $timing-function $delay;
20 | }
21 |
22 | // example: @include double-transition(background, 1s, ease-in-out, 0, opacity, .1s, ease-in-out, 0);
23 |
24 | @mixin double-transition(
25 | $property1,
26 | $duration1,
27 | $timing-function1,
28 | $delay1,
29 | $property2,
30 | $duration2,
31 | $timing-function2,
32 | $delay2
33 | ) {
34 | -webkit-transition: $property1 $duration1 $timing-function1 $delay1,
35 | $property2 $duration2 $timing-function2 $delay2;
36 | -moz-transition: $property1 $duration1 $timing-function1 $delay1,
37 | $property2 $duration2 $timing-function2 $delay2;
38 | -o-transition: $property1 $duration1 $timing-function1 $delay1,
39 | $property2 $duration2 $timing-function2 $delay2;
40 | transition: $property1 $duration1 $timing-function1 $delay1,
41 | $property2 $duration2 $timing-function2 $delay2;
42 | }
43 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_translate.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Translate
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include translate(0);
14 |
15 | @mixin translate($value) {
16 | -webkit-transform: translateZ($value);
17 | -moz-transform: translateZ($value);
18 | -ms-transform: translateZ($value);
19 | -o-transform: translateZ($value);
20 | transform: translateZ($value);
21 | }
22 |
--------------------------------------------------------------------------------
/app/styles/scss/base/mixins/_triangles.scss:
--------------------------------------------------------------------------------
1 | //------ SASS Useful Mixins ---------------------------------------------
2 |
3 | // by Ryan Burgess
4 | // https://github.com/ryanburgess/SASS-Useful-Mixins
5 | // MIT © Ryan Burgess
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | // Arrows / Triangles
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | // example: @include arrow("left", #cccccc, 10);
14 |
15 | /* stylelint-disable declaration-block-no-duplicate-properties */
16 |
17 | @mixin arrow($direction, $color, $size) {
18 | $pxSize: $size + px;
19 | $remSize: ($size / 10) + rem;
20 |
21 | width: 0;
22 | height: 0;
23 |
24 | @if $direction == 'left' {
25 | border-top: $pxSize solid transparent;
26 | border-right: $pxSize solid $color;
27 | border-bottom: $pxSize solid transparent;
28 | border-top: $remSize solid transparent;
29 | border-right: $remSize solid $color;
30 | border-bottom: $remSize solid transparent;
31 | } @else if $direction == 'right' {
32 | border-top: $pxSize solid transparent;
33 | border-bottom: $pxSize solid transparent;
34 | border-left: $pxSize solid $color;
35 | border-top: $remSize solid transparent;
36 | border-bottom: $remSize solid transparent;
37 | border-left: $remSize solid $color;
38 | } @else if $direction == 'up' {
39 | border-left: $pxSize solid transparent;
40 | border-right: $pxSize solid transparent;
41 | border-bottom: $pxSize solid $color;
42 | border-left: $remSize solid transparent;
43 | border-right: $remSize solid transparent;
44 | border-bottom: $remSize solid $color;
45 | } @else if $direction == 'down' {
46 | border-left: $pxSize solid transparent;
47 | border-right: $pxSize solid transparent;
48 | border-top: $pxSize solid $color;
49 | border-left: $remSize solid transparent;
50 | border-right: $remSize solid transparent;
51 | border-top: $remSize solid $color;
52 | }
53 | }
54 |
55 | /* stylelint-enable declaration-block-no-duplicate-properties */
56 |
--------------------------------------------------------------------------------
/app/styles/scss/themes/fonts.scss:
--------------------------------------------------------------------------------
1 | @import '~roboto-fontface/css/roboto/roboto-fontface.css';
2 |
--------------------------------------------------------------------------------
/app/styles/scss/themes/reset.scss:
--------------------------------------------------------------------------------
1 | body {
2 | width: 100%;
3 | background-color: var(--app-bg-color) !important;
4 | @include rem('font-size', $regularSize);
5 |
6 | font-family: $roboto;
7 | overflow-x: hidden;
8 | overflow-y: hidden;
9 | }
10 |
11 | a {
12 | cursor: pointer;
13 | color: $appSecondaryColor;
14 | }
15 |
16 | *::-webkit-scrollbar-track {
17 | -webkit-box-shadow: inset 0 0 3px rgba(0, 0, 0, 0);
18 | border-radius: 0;
19 | background-color: var(--app-bg-color);
20 | }
21 |
22 | *::-webkit-scrollbar {
23 | width: 8px;
24 | height: 8px;
25 | opacity: 1;
26 | transition: background-color 0.3s;
27 | }
28 |
29 | *::-webkit-scrollbar-thumb:hover {
30 | background-color: #135ba1;
31 | }
32 |
33 | *::-webkit-scrollbar-thumb {
34 | border-radius: 0;
35 | -webkit-box-shadow: inset 0 0 3px rgba(0, 0, 0, 0);
36 | background-color: #1976d2;
37 | }
38 |
39 | kbd {
40 | display: inline-block;
41 | margin: 0 0.1em;
42 | padding: 0.1em 0.6em;
43 | font-size: 14px;
44 | font-weight: bold;
45 | line-height: 1.4;
46 | color: #242729;
47 | text-shadow: 0 1px 0 #fff;
48 | background-color: #e1e3e5;
49 | border: 1px solid #adb3b9;
50 | border-radius: 3px;
51 | box-shadow: 0 1px 0 rgba(12, 13, 14, 0.2), 0 0 0 2px #fff inset;
52 | white-space: nowrap;
53 | }
54 |
--------------------------------------------------------------------------------
/app/templates/appFeaturesPage.js:
--------------------------------------------------------------------------------
1 | export const APP_FEATURES_PAGE_TITLE = `New Features and Updates`;
2 |
--------------------------------------------------------------------------------
/app/templates/fileExplorer.js:
--------------------------------------------------------------------------------
1 | export const helpPhoneNotConnecting = `FAQs - My phone is not connecting!`;
2 |
3 | export const buyMeACoffeeText = `Buy me a Coffee (UPI, PayPal, Credit/Debit Cards, Internet Banking)`;
4 |
5 | export const supportUsingPayPal = `Support us via PayPal`;
6 |
--------------------------------------------------------------------------------
/app/templates/generateErrorReport.js:
--------------------------------------------------------------------------------
1 | import { APP_NAME, APP_VERSION, AUTHOR_EMAIL } from '../constants/meta';
2 |
3 | const subject = `Error Logs for ${APP_NAME} | Version: ${APP_VERSION}`;
4 | const body = subject;
5 |
6 | export const mailTo = `mailto:${AUTHOR_EMAIL}?Subject=${subject}&Body=${body}.`;
7 |
8 | export const mailToInstructions = (zippedLogFileBaseName) =>
9 | `%0D%0A %0D%0A Attach the generated error report file "${zippedLogFileBaseName}" (which is found in your Desktop folder) along with this email.`;
10 |
11 | export const reportGenerateError = `Error report generation failed. Try again!`;
12 |
13 | export const REPORT_BUGS_PAGE_TITLE = `Report Bugs`;
14 |
--------------------------------------------------------------------------------
/app/templates/helpFaqsPage.js:
--------------------------------------------------------------------------------
1 | export const HELP_PHONE_IS_NOT_CONNECTING = `Help - My Phone is not connecting`;
2 |
3 | export const FAQS_PAGE_TITLE = `Help - FAQs`;
4 |
--------------------------------------------------------------------------------
/app/templates/keyboardShortcutsPage.js:
--------------------------------------------------------------------------------
1 | export const KEYBOARD_SHORTCUTS_PAGE_TITLE = `Keyboard Shortcuts`;
2 |
--------------------------------------------------------------------------------
/app/templates/loadProfileError.js:
--------------------------------------------------------------------------------
1 | import { APP_NAME, APP_VERSION, AUTHOR_EMAIL } from '../constants/meta';
2 |
3 | export const loadProfileErrorHtml = `
4 | <html lang="en-gb">
5 | <body>
6 | <h3>Unable to load profile files. Please restart the app. </h3>
7 | <p>Write to the developer if the problem persists.</p>
8 | <a href="mailto:${AUTHOR_EMAIL}?Subject=Unable to load profile files&Body=${APP_NAME} - ${APP_VERSION}">${AUTHOR_EMAIL}</a>
9 | </body>
10 | </html>
11 | `;
12 |
--------------------------------------------------------------------------------
/app/templates/menu.js:
--------------------------------------------------------------------------------
1 | import { APP_NAME, APP_WEBSITE } from '../constants/meta';
2 |
3 | const inviteViaEmailSubject = `Android File Transfer for macOS - OpenMTP`;
4 |
5 | const inviteViaEmailBody = `Tired of using expensive, outdated, bug heavy, Android File Transfer apps for macOS? %0D%0A Download "${APP_NAME}" - The Most Advanced Android File Transfer App for macOS from ${APP_WEBSITE} for free. %0D%0A It's Safe, Transparent, Open-Source and FREE for a lifetime!`;
6 |
7 | export const inviteViaEmail = `mailto:?Subject=${inviteViaEmailSubject}&Body=${inviteViaEmailBody}`;
8 |
--------------------------------------------------------------------------------
/app/templates/privacyPolicyPage.js:
--------------------------------------------------------------------------------
1 | export const PRIVACY_POLICY_PAGE_TITLE = `Privacy Policy`;
2 |
--------------------------------------------------------------------------------
/app/templates/socialMediaShareBtns.js:
--------------------------------------------------------------------------------
1 | import { APP_DESC, APP_NAME, APP_WEBSITE } from '../constants/meta';
2 |
3 | const twitterShareText = `Tired of using expensive, outdated, bug heavy, Android File Transfer apps for macOS?
4 |
5 | Get "${APP_DESC}" by @ganeshrvel.
6 | It's Safe, Transparent, Open-Source and FREE for a lifetime!
7 |
8 | `;
9 |
10 | export const twitterShareUrl = `http://twitter.com/share?text=${encodeURIComponent(
11 | twitterShareText
12 | )}&hashtags=${APP_NAME},AndroidFileTransfer,macOS&url=${APP_WEBSITE}`;
13 |
14 | export const fbShareUrl = `http://www.facebook.com/sharer/sharer.php?u=${APP_WEBSITE}`;
15 |
16 | const redditShareText = `Tired of using expensive, outdated, bug heavy, Android File Transfer apps for macOS? Get "${APP_DESC}" by /u/ganeshrnet. It's Safe, Transparent, Open-Source and FREE for a lifetime!`;
17 |
18 | export const redditShareUrl = `http://www.reddit.com/submit?url=${APP_WEBSITE}&title=${encodeURIComponent(
19 | redditShareText
20 | )}`;
21 |
--------------------------------------------------------------------------------
/app/utils/date.js:
--------------------------------------------------------------------------------
1 | import dayjs from 'dayjs';
2 | import advancedFormat from 'dayjs/plugin/advancedFormat';
3 |
4 | dayjs.extend(advancedFormat);
5 |
6 | export const yearMonthNow = ({ monthInletters = false }) => {
7 | let monthFormat = `MM`;
8 |
9 | if (monthInletters) {
10 | monthFormat = `MMM`;
11 | }
12 |
13 | return dayjs().format(`YYYY-${monthFormat}`);
14 | };
15 |
16 | export const dateTimeUnixTimestampNow = ({ monthInletters = false }) => {
17 | let monthFormat = `MM`;
18 |
19 | if (monthInletters) {
20 | monthFormat = `MMM`;
21 | }
22 |
23 | return dayjs().format(`YYYY-${monthFormat}-DD HH:mm:ss (x)`);
24 | };
25 |
26 | export const dateNow = ({ monthInletters = false }) => {
27 | let monthFormat = `MM`;
28 |
29 | if (monthInletters) {
30 | monthFormat = `MMM`;
31 | }
32 |
33 | return dayjs().format(`YYYY-${monthFormat}-DD`);
34 | };
35 |
36 | export const unixTimestampNow = () => {
37 | return dayjs().format(`x`);
38 | };
39 |
40 | export const msToTime = (milliseconds) => {
41 | const hours = milliseconds / (1000 * 60 * 60);
42 | const absoluteHours = Math.floor(hours);
43 | const h = absoluteHours > 9 ? absoluteHours : `0${absoluteHours}`;
44 |
45 | const minutes = (hours - absoluteHours) * 60;
46 | const absoluteMinutes = Math.floor(minutes);
47 | const m = absoluteMinutes > 9 ? absoluteMinutes : `0${absoluteMinutes}`;
48 |
49 | const seconds = (minutes - absoluteMinutes) * 60;
50 | const absoluteSeconds = Math.floor(seconds);
51 | const s = absoluteSeconds > 9 ? absoluteSeconds : `0${absoluteSeconds}`;
52 |
53 | return `${h}:${m}:${s}`;
54 | };
55 |
56 | export const daysDiff = (startDate, endDate) => {
57 | const start = dayjs(startDate, 'YYYY-MM-DD');
58 | const end = dayjs(endDate, 'YYYY-MM-DD');
59 |
60 | return start.diff(end, 'day');
61 | };
62 |
63 | export const appDateFormat = (dateTime) => {
64 | return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss');
65 | };
66 |
--------------------------------------------------------------------------------
/app/utils/errors.js:
--------------------------------------------------------------------------------
1 | export function getError(error) {
2 | if (isConsoleError(error)) {
3 | return error.message;
4 | }
5 |
6 | return error;
7 | }
8 |
9 | export function isConsoleError(e) {
10 | return e && e.stack;
11 | }
12 |
--------------------------------------------------------------------------------
/app/utils/eventHandling.js:
--------------------------------------------------------------------------------
1 | import EventEmitter from 'events';
2 | import util from 'util';
3 |
4 | export default function EmitAppEvents() {
5 | EventEmitter.call(this);
6 | }
7 |
8 | util.inherits(EmitAppEvents, EventEmitter);
9 |
10 | export const appEvents = new EmitAppEvents();
11 |
--------------------------------------------------------------------------------
/app/utils/files.js:
--------------------------------------------------------------------------------
1 | import { join, parse } from 'path';
2 | import { homedir as homedirOs } from 'os';
3 | import { APP_BUNDLE_ID } from '../constants/meta';
4 |
5 | const homeDir = homedirOs();
6 |
7 | export const getAppDataPath = () => {
8 | switch (process.platform) {
9 | case 'darwin':
10 | return join(homeDir, 'Library', 'Application Support', APP_BUNDLE_ID);
11 |
12 | case 'win32':
13 | return join(process.env.APPDATA, APP_BUNDLE_ID);
14 |
15 | case 'linux':
16 | return join(homeDir, APP_BUNDLE_ID);
17 |
18 | default: {
19 | process.exit(1);
20 | }
21 | }
22 | };
23 |
24 | export const pathUp = (filePath) => {
25 | return filePath.replace(/\/$/, '').replace(/\/[^/]+$/, '') || '/';
26 | };
27 |
28 | export const sanitizePath = (filePath) => {
29 | return filePath.replace(/\/\/+/g, '/');
30 | };
31 |
32 | export const baseName = (filePath) => {
33 | if (typeof filePath === 'undefined' || filePath === null) {
34 | return null;
35 | }
36 |
37 | const parsedPath = pathInfo(filePath);
38 |
39 | return parsedPath !== null ? parsedPath.base : null;
40 | };
41 |
42 | export const getExtension = (fileName, isFolder) => {
43 | if (isFolder) {
44 | return null;
45 | }
46 |
47 | const parsedPath = pathInfo(fileName);
48 |
49 | return parsedPath !== null ? parsedPath.ext : null;
50 | };
51 |
52 | export const pathInfo = (filePath) => {
53 | return parse(filePath);
54 | };
55 |
--------------------------------------------------------------------------------
/app/utils/getPlatform.js:
--------------------------------------------------------------------------------
1 | import { platform, release } from 'os';
2 | import macosVersion from 'macos-version';
3 | import { OS_ARCH_TYPE } from '../constants';
4 |
5 | export const getPlatform = () => {
6 | switch (platform()) {
7 | case 'aix':
8 | case 'freebsd':
9 | case 'linux':
10 | case 'openbsd':
11 | case 'android':
12 | return 'linux';
13 | case 'darwin':
14 | case 'sunos':
15 | return 'mac';
16 | case 'win32':
17 | return 'win';
18 | default:
19 | return null;
20 | }
21 | };
22 |
23 | // these are currently supported system architectures for binaries
24 | export const getBinariesSupportedSystemArchitecture = () => {
25 | if (process.arch === 'arm64') {
26 | return OS_ARCH_TYPE.arm64;
27 | }
28 |
29 | return OS_ARCH_TYPE.amd64;
30 | };
31 |
32 | export const getOsVersion = () => {
33 | if (macosVersion.isMacOS) {
34 | return macosVersion();
35 | }
36 |
37 | return release();
38 | };
39 |
--------------------------------------------------------------------------------
/app/utils/gzip.js:
--------------------------------------------------------------------------------
1 | import { createGzip } from 'zlib';
2 | import { createReadStream, createWriteStream } from 'fs';
3 | import { log } from './log';
4 |
5 | export const compressFile = async (_input, _output) => {
6 | try {
7 | await new Promise((resolve, reject) => {
8 | const stream = createReadStream(_input);
9 |
10 | stream
11 | .pipe(createGzip())
12 | .pipe(createWriteStream(_output))
13 | .on('finish', () => resolve(true))
14 | .on('error', (err) => {
15 | reject(err);
16 | });
17 | });
18 |
19 | return true;
20 | } catch (e) {
21 | log.error(e, `gzip -> compressFile`);
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/app/utils/imgsrc.js:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off, prefer-template: off */
2 |
3 | /**
4 | * handle image import into the program.
5 | * default path: ../public/images/
6 | * @param filePath
7 | * @param returnNoImageFound (optional)
8 | * @returns {*}
9 | */
10 | export const imgsrc = (filePath, returnNoImageFound = true) => {
11 | try {
12 | return require('../public/images/' + filePath).default;
13 | } catch (e) {
14 | if (!returnNoImageFound) {
15 | return null;
16 | }
17 |
18 | return require('../public/images/no-image.png').default;
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/app/utils/isGoogleAndroidFileTransferActive.js:
--------------------------------------------------------------------------------
1 | import { isProcessRunning } from './process';
2 |
3 | export const isGoogleAndroidFileTransferActive = async () => {
4 | const isAftRunning = await isProcessRunning('Android File transfer.app');
5 | const isAftAgentRunning = await isProcessRunning(
6 | 'Android File Transfer Agent.app'
7 | );
8 |
9 | return isAftRunning && isAftAgentRunning;
10 | };
11 |
--------------------------------------------------------------------------------
/app/utils/isOnline.js:
--------------------------------------------------------------------------------
1 | import dns from 'dns';
2 | import { log } from './log';
3 |
4 | export const isConnected = () => {
5 | try {
6 | return new Promise((resolve) => {
7 | dns.lookup('github.com', (err) => {
8 | if (err && err.code === 'ENOTFOUND') {
9 | resolve(false);
10 |
11 | return null;
12 | }
13 |
14 | resolve(true);
15 | });
16 | });
17 | } catch (e) {
18 | log.error(e, `isOnline -> isConnected`);
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/app/utils/isPackaged.js:
--------------------------------------------------------------------------------
1 | import { isPackaged as _isPackaged } from 'electron-is-packaged';
2 |
3 | export const isPackaged = _isPackaged;
4 |
--------------------------------------------------------------------------------
/app/utils/pkginfo.js:
--------------------------------------------------------------------------------
1 | import { join } from 'path';
2 | import { readFileSync } from 'fs';
3 | import { rootPath } from 'electron-root-path';
4 |
5 | let _pkginfo = {};
6 |
7 | // eslint-disable-next-line no-undef
8 | if (typeof PKG_INFO !== 'undefined' && PKG_INFO !== null) {
9 | // eslint-disable-next-line no-undef
10 | _pkginfo = PKG_INFO;
11 | } else {
12 | /* This is a fallback incase the webpack DefinePlugin modules hasn't been initialized yet. */
13 | /* Developement mode only */
14 | _pkginfo = JSON.parse(
15 | readFileSync(join(rootPath, 'package.json'), { encoding: 'utf8' })
16 | );
17 | }
18 |
19 | export const pkginfo = _pkginfo;
20 |
--------------------------------------------------------------------------------
/app/utils/process.js:
--------------------------------------------------------------------------------
1 | import { spawn } from 'child_process';
2 | import { checkIf } from './checkIf';
3 | import { log } from './log';
4 |
5 | // this is to prevent grep from appearing in the pslist and thus polluting the output
6 | const queryToRegex = (str) => {
7 | if (typeof str === 'undefined' || str === null) {
8 | return '';
9 | }
10 |
11 | if (str.trim() === '') {
12 | return '';
13 | }
14 |
15 | str.replace(str.charAt(0), `[${str.charAt(0)}]`);
16 | };
17 |
18 | export const isProcessRunning = (query) => {
19 | checkIf(query, 'string');
20 |
21 | return new Promise((resolve) => {
22 | let stdout = '';
23 | let stderr;
24 |
25 | const child = spawn('ps', ['aux']);
26 | const grep = spawn('grep', [`"${queryToRegex(query)}"`]);
27 |
28 | child.stdout.pipe(grep.stdin);
29 |
30 | child.stdout.on('data', (data) => {
31 | stdout += data;
32 | });
33 |
34 | child.stderr.on('data', (data) => {
35 | stderr = data;
36 | });
37 |
38 | child.on('exit', (code) => {
39 | if (code > 1 && stderr) {
40 | log.error(stderr, 'isProcessRunning -> exit');
41 |
42 | return resolve(false);
43 | }
44 |
45 | return resolve(
46 | (stdout ?? '')?.toLowerCase().indexOf(query?.toLowerCase()) > -1
47 | );
48 | });
49 | }).catch((e) => {
50 | log.error(e, 'isProcessRunning -> err');
51 |
52 | return Promise.resolve(false);
53 | });
54 | };
55 |
--------------------------------------------------------------------------------
/app/utils/styleResets.js:
--------------------------------------------------------------------------------
1 | export const resetOverFlowY = () => {
2 | if (typeof document !== 'undefined' && document) {
3 | document.body.style.overflowY = 'auto';
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/app/utils/styles.js:
--------------------------------------------------------------------------------
1 | import { isString } from './funcs';
2 |
3 | export const setStyle = (selector, styles) => {
4 | let elem;
5 |
6 | if (isString(selector)) {
7 | elem = document.querySelector(selector);
8 | } else {
9 | elem = selector;
10 | }
11 |
12 | if (!elem) {
13 | return;
14 | }
15 |
16 | let styleString = '';
17 |
18 | Object.keys(styles).map((a) => {
19 | const item = styles[a];
20 |
21 | styleString += `${a}:${item};`;
22 |
23 | return a;
24 | });
25 |
26 | elem.setAttribute('style', styleString);
27 | };
28 |
--------------------------------------------------------------------------------
/app/utils/url.js:
--------------------------------------------------------------------------------
1 | import { shell } from 'electron';
2 |
3 | export const openExternalUrl = (url, events = null) => {
4 | if (events) {
5 | events.preventDefault();
6 | }
7 |
8 | shell.openExternal(url);
9 | };
10 |
--------------------------------------------------------------------------------
/app/vendors/pretty-file-icons/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Unknown
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/vendors/pretty-file-icons/README.md:
--------------------------------------------------------------------------------
1 | # Pretty File Icons
2 |
3 | Pretty colorful icons for files (in svg format).
4 |
5 | Icon pack author: [Madebyoliver](http://www.flaticon.com/authors/madebyoliver).
6 | Icons are published as-is and under the licence by [flaticon.com](http://flaticon.com).
7 | Licence for everything except icons is MIT.
8 |
9 | See [index.json](index.json) for available icons list. Live preview is
10 | available [here](https://kravets-levko.github.io/pretty-file-icons/preview.html).
11 |
12 | ## Usage
13 |
14 | Just download image files and use them. Also, this package is available on NPM:
15 | ```
16 | npm install pretty-file-icons
17 | ```
18 |
19 | In addition, this package contains mapping for some file extensions - see the
20 | [index.json](index.json) file. Also, it can be used in javascript applications
21 | to retrieve icon names by file name:
22 | ```javascript
23 | var prettyFileIcons = require('pretty-file-icons');
24 |
25 | console.log(prettyFileIcons.getIcon('test.csv'));
26 | console.log(prettyFileIcons.getIcon('test.csv', 'svg'));
27 | console.log(prettyFileIcons.getIcon('.test', 'svg'));
28 |
29 | // Prints:
30 | // csv
31 | // csv.svg
32 | // unknown.svg
33 | ```
34 |
35 | ## Preview:
36 |
37 | 
38 |
--------------------------------------------------------------------------------
/app/vendors/pretty-file-icons/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 |
5 | var extensions = require('./index.json');
6 | var unknown = extensions[''];
7 |
8 | function isString(value) {
9 | return (typeof value === 'string') ||
10 | (Object.prototype.toString.call(value) === '[object String]');
11 | }
12 |
13 | function getIcon(filename, type) {
14 | // Extract extension from the filename
15 | var ext = isString(filename) ? path.extname(filename).toLowerCase() : '';
16 |
17 | // Validate type - it should be 'svg' or '.svg'
18 | type = isString(type) ? type.toLowerCase() : '';
19 | if (type.charAt(0) === '.') {
20 | type = type.substr(1, type.length);
21 | }
22 | if (['svg'].indexOf(type) >= 0) {
23 | type = '.' + type;
24 | } else {
25 | type = '';
26 | }
27 |
28 | return (extensions[ext] || unknown) + type;
29 | }
30 |
31 | module.exports.getIcon = getIcon;
32 |
33 | module.exports.unknown = unknown;
34 | module.exports.extensions = extensions;
35 |
--------------------------------------------------------------------------------
/app/vendors/pretty-file-icons/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "": "unknown",
3 | "audio": "audio",
4 | "video": "video",
5 | "text": "text",
6 | "archive": "archive",
7 |
8 | ".jpg": "jpg",
9 | ".jpe": "jpg",
10 | ".jpeg": "jpg",
11 | ".jfif": "jpg",
12 | ".png": "png",
13 | ".gif": "gif",
14 | ".tiff": "tiff",
15 | ".svg": "svg",
16 | ".psd": "psd",
17 | ".ai": "ai",
18 | ".dwg": "dwg",
19 |
20 | ".iso": "iso",
21 | ".mdf": "mdf",
22 | ".nrg": "nrg",
23 |
24 | ".zip": "zip",
25 | ".7z": "7z",
26 | ".7zip": "7z",
27 | ".arj": "arj",
28 | ".rar": "rar",
29 | ".gz": "archive",
30 | ".gzip": "archive",
31 | ".bz2": "archive",
32 | ".bzip2": "archive",
33 | ".tar": "archive",
34 |
35 | ".xls": "xls",
36 | ".doc": "doc",
37 | ".pdf": "pdf",
38 | ".ppt": "ppt",
39 | ".rtf": "rtf",
40 | ".txt": "txt",
41 | ".md": "text",
42 | ".markdown": "text",
43 |
44 | ".avi": "avi",
45 | ".mp2": "mp2",
46 | ".mp3": "mp3",
47 | ".mp4": "mp4",
48 | ".fla": "fla",
49 | ".mxf": "mxf",
50 | ".wav": "wav",
51 | ".wma": "wma",
52 | ".aac": "aac",
53 | ".flac": "flac",
54 |
55 | ".css": "css",
56 | ".csv": "csv",
57 | ".html": "html",
58 | ".json": "json",
59 | ".js": "js",
60 | ".xml": "xml",
61 |
62 | ".dbf": "dbf",
63 | ".exe": "exe",
64 | ".fit": "fit"
65 | }
66 |
--------------------------------------------------------------------------------
/app/vendors/pretty-file-icons/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pretty-file-icons",
3 | "version": "2.2.1",
4 | "description": "Pretty colorful icons for files (in svg format).",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "xdg-open preview.html",
8 | "optimize": "svgo --config=./.svgo.yml --folder=./svg"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/kravets-levko/pretty-file-icons.git"
13 | },
14 | "keywords": [
15 | "file extensions",
16 | "file types",
17 | "file",
18 | "types",
19 | "extensions",
20 | "file icons",
21 | "icons",
22 | "svg icons",
23 | "vector icons",
24 | "colorful icons"
25 | ],
26 | "author": "Unknown",
27 | "license": "MIT",
28 | "bugs": {
29 | "url": "https://github.com/kravets-levko/pretty-file-icons/issues"
30 | },
31 | "contributors": [
32 | {
33 | "name": "Levko Kravets",
34 | "email": "levko.ne@gmail.com"
35 | }
36 | ],
37 | "devDependencies": {
38 | "svgo": "^0.7.2"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/blobs/binaries/.gitkeep:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/blobs/binaries/libusb_1.0.22_el_capitan_darwin_amd64.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/blobs/binaries/libusb_1.0.22_el_capitan_darwin_amd64.tar.gz
--------------------------------------------------------------------------------
/blobs/images/file-explorer-bluebg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/blobs/images/file-explorer-bluebg.jpg
--------------------------------------------------------------------------------
/blobs/images/file-explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/blobs/images/file-explorer.png
--------------------------------------------------------------------------------
/blobs/images/file-transfer-bluebg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/blobs/images/file-transfer-bluebg.jpg
--------------------------------------------------------------------------------
/blobs/images/file-transfer-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/blobs/images/file-transfer-large.png
--------------------------------------------------------------------------------
/blobs/images/file-transfer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/blobs/images/file-transfer.png
--------------------------------------------------------------------------------
/build/entitlements.mac.plist:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 | <plist version="1.0">
4 | <dict>
5 | <key>com.apple.security.cs.allow-dyld-environment-variables</key>
6 | <true/>
7 | <key>com.apple.security.cs.disable-library-validation</key>
8 | <true/>
9 | <key>com.apple.security.cs.allow-jit</key>
10 | <true/>
11 | <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
12 | <true/>
13 | <key>com.apple.security.files.user-selected.read-only</key>
14 | <true/>
15 | <key>com.apple.security.files.user-selected.read-write</key>
16 | <true/>
17 | <key>com.apple.security.personal-information.photos-library</key>
18 | <true/>
19 | <key>com.apple.security.network.server</key>
20 | <true/>
21 | <key>com.apple.security.network.client</key>
22 | <true/>
23 | </dict>
24 | </plist>
25 |
--------------------------------------------------------------------------------
/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icon.icns
--------------------------------------------------------------------------------
/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icon.ico
--------------------------------------------------------------------------------
/build/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icon.png
--------------------------------------------------------------------------------
/build/icons/1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/1024x1024.png
--------------------------------------------------------------------------------
/build/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/128x128.png
--------------------------------------------------------------------------------
/build/icons/16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/16x16.png
--------------------------------------------------------------------------------
/build/icons/256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/256x256.png
--------------------------------------------------------------------------------
/build/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/32x32.png
--------------------------------------------------------------------------------
/build/icons/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/512x512.png
--------------------------------------------------------------------------------
/build/icons/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/icons/64x64.png
--------------------------------------------------------------------------------
/build/mac/bin/amd64/kalam.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/amd64/kalam.dylib
--------------------------------------------------------------------------------
/build/mac/bin/amd64/kalam_debug_report:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/amd64/kalam_debug_report
--------------------------------------------------------------------------------
/build/mac/bin/amd64/libusb.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/amd64/libusb.dylib
--------------------------------------------------------------------------------
/build/mac/bin/arm64/kalam.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/arm64/kalam.dylib
--------------------------------------------------------------------------------
/build/mac/bin/arm64/kalam_debug_report:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/arm64/kalam_debug_report
--------------------------------------------------------------------------------
/build/mac/bin/arm64/libusb.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/arm64/libusb.dylib
--------------------------------------------------------------------------------
/build/mac/bin/medieval/amd64/kalam.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/medieval/amd64/kalam.dylib
--------------------------------------------------------------------------------
/build/mac/bin/medieval/amd64/kalam_debug_report:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/medieval/amd64/kalam_debug_report
--------------------------------------------------------------------------------
/build/mac/bin/medieval/amd64/libusb.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/medieval/amd64/libusb.dylib
--------------------------------------------------------------------------------
/build/mac/bin/mtp-cli:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/build/mac/bin/mtp-cli
--------------------------------------------------------------------------------
/build/sample.entitlements.mas.plist:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 | <plist version="1.0">
4 | <dict>
5 | <key>com.apple.security.app-sandbox</key>
6 | <true/>
7 | <key>com.apple.security.application-groups</key>
8 | <string><TEAM_ID>.<BUNDLE_ID></string>
9 | <key>com.apple.security.network.client</key>
10 | <true/>
11 | <key>com.apple.security.device.usb</key>
12 | <true/>
13 | <key>com.apple.security.files.user-selected.read-write</key>
14 | <true/>
15 | <key>com.apple.security.files.user-selected.read-only</key>
16 | <true/>
17 | <key>com.apple.security.files.downloads.read-write</key>
18 | <true/>
19 | <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
20 | <true/>
21 | </dict>
22 | </plist>
23 |
24 |
--------------------------------------------------------------------------------
/config/dev-app-update.yml:
--------------------------------------------------------------------------------
1 | owner: ganeshrvel
2 | repo: openmtp-testflight # use openmtp for testing the live release
3 | provider: github
4 | private: false
5 |
--------------------------------------------------------------------------------
/config/env/env.dev.js:
--------------------------------------------------------------------------------
1 | module.exports.PORT = 4642;
2 |
--------------------------------------------------------------------------------
/config/env/env.prod.js:
--------------------------------------------------------------------------------
1 | module.exports.PORT = 4642;
2 |
--------------------------------------------------------------------------------
/config/env/index.js:
--------------------------------------------------------------------------------
1 | /* eslint prefer-destructuring: ["error", {AssignmentExpression: {array: true}}] */
2 | const IS_PROD = require('../../app/constants/env').IS_PROD;
3 |
4 | const PORT_PROD = require('./env.prod').PORT;
5 |
6 | const PORT_DEV = require('./env.dev').PORT;
7 |
8 | module.exports.PORT = process.env.PORT || IS_PROD ? PORT_PROD : PORT_DEV;
9 |
--------------------------------------------------------------------------------
/docs-sources/images/file-explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/docs-sources/images/file-explorer.png
--------------------------------------------------------------------------------
/docs-sources/images/file-transfer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/docs-sources/images/file-transfer.png
--------------------------------------------------------------------------------
/docs-sources/styles/base/_base.scss:
--------------------------------------------------------------------------------
1 | @import '../../../app/styles/scss/base/base';
2 | @import 'themes';
3 |
--------------------------------------------------------------------------------
/docs-sources/styles/base/_themes.scss:
--------------------------------------------------------------------------------
1 | @import '~normalize.css/normalize.css';
2 | @import '~milligram/dist/milligram.min.css';
3 |
--------------------------------------------------------------------------------
/docs-sources/utils/consts.js:
--------------------------------------------------------------------------------
1 | export const ALLOWED_GITHUB_FETCH_STATUSES = [200, 403, 404];
2 |
3 | export const APP_GITHUB_URL = `https://github.com/ganeshrvel/openmtp`;
4 |
5 | export const APP_GITHUB_API_URL = `https://api.github.com/repos/ganeshrvel/openmtp/releases/latest`;
6 |
--------------------------------------------------------------------------------
/docs-sources/webpack/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 |
3 | const PORT = 4644;
4 |
5 | module.exports = {
6 | devtool: 'inline-source-map',
7 | devServer: {
8 | port: PORT,
9 | compress: true,
10 | hot: true,
11 | // writeToDisk: true,
12 | },
13 | plugins: [
14 | new webpack.HotModuleReplacementPlugin({
15 | multiStep: false,
16 | }),
17 | ],
18 | module: {
19 | rules: [
20 | {
21 | test: /\.(scss|css|sass)$/,
22 | use: [
23 | {
24 | loader: 'style-loader',
25 | },
26 | {
27 | loader: 'css-loader',
28 | },
29 | {
30 | loader: 'sass-loader',
31 | },
32 | ],
33 | },
34 | ],
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/docs-sources/webpack/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
4 | const TerserPlugin = require('terser-webpack-plugin');
5 | const webpack = require('webpack');
6 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
7 |
8 | const buildPath = path.join(__dirname, '..', '..', 'docs');
9 |
10 | module.exports = {
11 | plugins: [
12 | new webpack.ProgressPlugin(),
13 | new CleanWebpackPlugin({
14 | dry: false,
15 | verbose: true,
16 | cleanOnceBeforeBuildPatterns: [`${buildPath}/bundle/*`],
17 | }),
18 | new MiniCssExtractPlugin({
19 | filename: 'bundle/[name].[contenthash].css',
20 | }),
21 | ],
22 | optimization: {
23 | minimizer: [
24 | new TerserPlugin({
25 | parallel: true,
26 | terserOptions: {
27 | sourceMap: true,
28 | mangle: true,
29 | output: {
30 | beautify: false,
31 | },
32 | },
33 | }),
34 | new OptimizeCSSAssetsPlugin({}),
35 | ],
36 | },
37 | module: {
38 | rules: [
39 | {
40 | test: /\.s?(a|c)ss$/,
41 | use: [
42 | MiniCssExtractPlugin.loader,
43 | {
44 | loader: 'css-loader',
45 | options: {
46 | modules: true,
47 | sourceMap: true,
48 | importLoaders: 1,
49 | },
50 | },
51 | 'sass-loader',
52 | ],
53 | include: /\.module\.s?(c|a)ss$/,
54 | },
55 | {
56 | test: /\.s?(a|c)ss$/,
57 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
58 | exclude: /\.module\.s?(c|a)ss$/,
59 | },
60 | ],
61 | },
62 | };
63 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | openmtp.ganeshrvel.com
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-slate
--------------------------------------------------------------------------------
/docs/bundle/file-explorer.1b1a659da61529904113.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/docs/bundle/file-explorer.1b1a659da61529904113.png
--------------------------------------------------------------------------------
/docs/bundle/file-transfer.e01ae86967cd5e83a375.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/docs/bundle/file-transfer.e01ae86967cd5e83a375.png
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ganeshrvel/openmtp/546d7f24fee324a990d69cc569891e9e4b80ea5e/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/google25c4a4597b2b27f3.html:
--------------------------------------------------------------------------------
1 | google-site-verification: google25c4a4597b2b27f3.html
--------------------------------------------------------------------------------
/docs/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 | Disallow: /styles/
4 | Disallow: /images/
5 | Disallow: /bundle/
6 |
--------------------------------------------------------------------------------
/docs/sitemap.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <urlset
3 | xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
4 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 | xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
6 | http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
7 |
8 |
9 | <url>
10 | <loc>https://ganeshrvel.github.io/openmtp/</loc>
11 | <lastmod>2019-01-20T09:10:27+00:00</lastmod>
12 | <priority>1.00</priority>
13 | </url>
14 | <url>
15 | <loc>https://ganeshrvel.github.io/openmtp/privacy.html</loc>
16 | <lastmod>2019-01-20T09:10:27+00:00</lastmod>
17 | <priority>0.80</priority>
18 | </url>
19 |
20 |
21 | </urlset>
--------------------------------------------------------------------------------
/ffi/kalam/native/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/ffi/kalam/native/go.mod:
--------------------------------------------------------------------------------
1 | module kalam
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/ganeshrvel/go-mtpfs v1.0.4-0.20240426083057-1c3302b3c476
7 | github.com/ganeshrvel/go-mtpx v0.0.0-20240426092756-18f12db021cc
8 | github.com/json-iterator/go v1.1.12
9 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
10 | )
11 |
12 | ///##### Upgrade a package
13 | //go get github.com/<org-name>/<package-name>@<git-commit-hash>
14 |
15 | //example: go get github.com/ganeshrvel/go-mtpfs@<git-commit-hash>
16 | //example: go get github.com/ganeshrvel/go-mtpx@<git-commit-hash>
17 |
18 | ///##### Use a local package
19 | // replace github.com/ganeshrvel/go-mtpfs vxxxxxx-xxxxxxxxxx
20 | // with ../go-mtpfs
21 |
--------------------------------------------------------------------------------
/ffi/kalam/native/kalam_debug_report/main.go:
--------------------------------------------------------------------------------
1 | // +build !go1.17
2 |
3 | package main
4 |
5 | import (
6 | "github.com/ganeshrvel/go-mtpx"
7 | "log"
8 | )
9 |
10 | func main() {
11 | log.Println("======================================================")
12 | log.Println("start kalam debug log")
13 | log.Printf("------------------------------------------------------\n")
14 |
15 | dev, err := mtpx.Initialize(mtpx.Init{DebugMode: true})
16 | if err != nil {
17 | log.Printf("error initializing: %+v\n", err)
18 |
19 | log.Printf("\n")
20 | log.Println("end kalam debug log")
21 | log.Println("======================================================")
22 |
23 | return
24 | }
25 | log.Printf("\n------------------------------------------------------\n\n")
26 |
27 | info, err := mtpx.FetchDeviceInfo(dev)
28 | if err != nil {
29 | log.Printf("error fetching device info: %+v\n", err)
30 | }
31 | log.Printf("\n------------------------------------------------------\n\n")
32 |
33 | log.Printf("Storage: %+v\n", info)
34 | log.Printf("\n------------------------------------------------------\n\n")
35 |
36 | storages, err := mtpx.FetchStorages(dev)
37 | if err != nil {
38 | log.Printf("error fetching storages info: %+v\n", err)
39 | }
40 | log.Printf("Storage: %+v\n", storages)
41 | log.Printf("\n------------------------------------------------------\n\n")
42 |
43 | mtpx.Dispose(dev)
44 |
45 | log.Printf("\n\n")
46 | log.Println("end kalam debug log")
47 | log.Println("======================================================")
48 | }
49 |
--------------------------------------------------------------------------------
/ffi/kalam/native/send_to_js/constants.go:
--------------------------------------------------------------------------------
1 | package send_to_js
2 |
3 | const DateTimeFormat = "2006-01-02T15:04:05.000Z"
4 |
--------------------------------------------------------------------------------
/ffi/kalam/native/send_to_js/enums.go:
--------------------------------------------------------------------------------
1 | package send_to_js
2 |
3 | const (
4 | ErrorMtpDetectFailed ErrorType = "ErrorMtpDetectFailed"
5 | ErrorMtpLockExists ErrorType = "ErrorMtpLockExists"
6 | ErrorDeviceChanged ErrorType = "ErrorDeviceChanged"
7 | ErrorDeviceSetup ErrorType = "ErrorDeviceSetup"
8 | ErrorMultipleDevice ErrorType = "ErrorMultipleDevice"
9 | ErrorAllowStorageAccess ErrorType = "ErrorAllowStorageAccess"
10 | ErrorDeviceLocked ErrorType = "ErrorDeviceLocked"
11 | ErrorDeviceInfo ErrorType = "ErrorDeviceInfo"
12 | ErrorStorageInfo ErrorType = "ErrorStorageInfo"
13 | ErrorNoStorage ErrorType = "ErrorNoStorage"
14 | ErrorStorageFull ErrorType = "ErrorStorageFull"
15 | ErrorListDirectory ErrorType = "ErrorListDirectory"
16 | ErrorFileNotFound ErrorType = "ErrorFileNotFound"
17 | ErrorFilePermission ErrorType = "ErrorFilePermission"
18 | ErrorLocalFileRead ErrorType = "ErrorLocalFileRead"
19 | ErrorInvalidPath ErrorType = "ErrorInvalidPath"
20 | ErrorFileTransfer ErrorType = "ErrorFileTransfer"
21 | ErrorFileObjectRead ErrorType = "ErrorFileObjectRead"
22 | ErrorSendObject ErrorType = "ErrorSendObject"
23 | ErrorGeneral ErrorType = "ErrorGeneral"
24 | )
25 |
--------------------------------------------------------------------------------
/ffi/kalam/native/send_to_js/errors.go:
--------------------------------------------------------------------------------
1 | package send_to_js
2 |
3 | type MtpDetectFailedError struct {
4 | error
5 | }
6 |
7 | type MtpChangedError struct {
8 | error
9 | }
10 |
--------------------------------------------------------------------------------
/ffi/kalam/native/structs.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/ganeshrvel/go-mtpfs/mtp"
5 | "github.com/ganeshrvel/go-mtpx"
6 | "os"
7 | )
8 |
9 | type verifyMtpSessionMode struct {
10 | skipDeviceChangeCheck bool
11 | }
12 |
13 | type deviceContainer struct {
14 | dev *mtp.Device
15 | deviceInfo *mtp.DeviceInfo
16 | locked bool
17 | }
18 |
19 | type MakeDirectoryInput struct {
20 | StorageId uint32 `json:"storageId"`
21 | FullPath string `json:"fullPath"`
22 | }
23 |
24 | type FileExistsInput struct {
25 | StorageId uint32 `json:"storageId"`
26 | Files []string `json:"Files"`
27 | }
28 |
29 | type DeleteFileInput struct {
30 | StorageId uint32 `json:"storageId"`
31 | Files []string `json:"Files"`
32 | }
33 |
34 | type RenameFileInput struct {
35 | StorageId uint32 `json:"storageId"`
36 | FullPath string `json:"fullPath"`
37 | NewFileName string `json:"newFileName"`
38 | }
39 |
40 | type WalkInput struct {
41 | StorageId uint32 `json:"storageId"`
42 | FullPath string `json:"fullPath"`
43 | Recursive bool `json:"recursive"`
44 | SkipDisallowedFiles bool `json:"skipDisallowedFiles"`
45 | SkipHiddenFiles bool `json:"skipHiddenFiles"`
46 | }
47 |
48 | type UploadFilesInput struct {
49 | StorageId uint32 `json:"storageId"`
50 | Sources []string `json:"sources"`
51 | Destination string `json:"destination"`
52 | PreprocessFiles bool `json:"preprocessFiles"`
53 | }
54 |
55 | type DownloadFilesInput struct {
56 | StorageId uint32 `json:"storageId"`
57 | Sources []string `json:"sources"`
58 | Destination string `json:"destination"`
59 | PreprocessFiles bool `json:"preprocessFiles"`
60 | }
61 |
62 | type UploadPreprocessContainer struct {
63 | fi *os.FileInfo
64 | fullPath string
65 | }
66 |
67 | type DownloadPreprocessContainer struct {
68 | fi *mtpx.FileInfo
69 | }
70 |
71 | type ProgressContainer struct {
72 | pInfo *mtpx.ProgressInfo
73 | }
74 |
--------------------------------------------------------------------------------
/ffi/kalam/native/utils.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 | )
6 |
7 | func isDirLocal(name string) bool {
8 | if fi, err := os.Stat(name); err == nil {
9 | if fi.Mode().IsDir() {
10 | return true
11 | }
12 | }
13 | return false
14 | }
15 |
16 | func existsLocal(filename string) bool {
17 | _, err := os.Stat(filename)
18 |
19 | return !os.IsNotExist(err)
20 | }
21 |
--------------------------------------------------------------------------------
/internals/scripts/AfterPack.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const glob = require('glob');
3 | const fs = require('fs-extra');
4 |
5 | exports.default = async (context) => {
6 | // clean the unnecessary locales from packed app
7 | const lprojRegEx = /(en)\.lproj/g;
8 | const APP_NAME = context.packager.appInfo.productFilename;
9 | const APP_OUT_DIR = context.appOutDir;
10 | const PLATFORM = context.packager.platform.name;
11 |
12 | const cwd = path.join(`${APP_OUT_DIR}`, `${APP_NAME}.app/Contents/Resources`);
13 | const lproj = glob.sync('*.lproj', { cwd });
14 | const _promises = [];
15 |
16 | switch (PLATFORM) {
17 | case 'mac':
18 | lproj.forEach((dir) => {
19 | if (!lprojRegEx.test(dir)) {
20 | _promises.push(fs.remove(path.join(cwd, dir)));
21 | }
22 | });
23 |
24 | break;
25 | default:
26 | break;
27 | }
28 |
29 | return _promises;
30 | };
31 |
--------------------------------------------------------------------------------
/internals/scripts/CheckBuildExist.js:
--------------------------------------------------------------------------------
1 | // Check if the renderer and main bundles are built
2 | import path from 'path';
3 | import chalk from 'chalk';
4 | import fs from 'fs';
5 |
6 | function CheckBuildExist() {
7 | const mainPath = path.join(__dirname, '..', '..', 'app', 'main.prod.js');
8 | const rendererPath = path.join(
9 | __dirname,
10 | '..',
11 | '..',
12 | 'app',
13 | 'dist',
14 | 'renderer.prod.js'
15 | );
16 |
17 | if (!fs.existsSync(mainPath)) {
18 | throw new Error(
19 | chalk.whiteBright.bgRed.bold(
20 | 'The main process is not built yet. Build it by running "yarn build-main"'
21 | )
22 | );
23 | }
24 |
25 | if (!fs.existsSync(rendererPath)) {
26 | throw new Error(
27 | chalk.whiteBright.bgRed.bold(
28 | 'The renderer process is not built yet. Build it by running "yarn build-renderer"'
29 | )
30 | );
31 | }
32 | }
33 |
34 | CheckBuildExist();
35 |
--------------------------------------------------------------------------------
/internals/scripts/CheckNodeEnv.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 |
3 | export default function CheckNodeEnv(expectedEnv) {
4 | if (!expectedEnv) {
5 | throw new Error('"expectedEnv" not set');
6 | }
7 |
8 | if (process.env.NODE_ENV !== expectedEnv) {
9 | console.info(
10 | chalk.whiteBright.bgRed.bold(
11 | `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
12 | )
13 | );
14 | process.exit(2);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/internals/scripts/CheckPortInUse.js:
--------------------------------------------------------------------------------
1 | import chalk from 'chalk';
2 | import detectPort from 'detect-port';
3 | import { PORT } from '../../config/env';
4 |
5 | (function CheckPortInUse() {
6 | const _port = PORT.toString();
7 |
8 | detectPort(_port, (err, availablePort) => {
9 | if (_port !== String(availablePort)) {
10 | throw new Error(
11 | chalk.whiteBright.bgRed.bold(
12 | // eslint-disable-next-line prefer-template
13 | 'Port "' +
14 | _port +
15 | '" on "localhost" is already in use. Please use another port.'
16 | )
17 | );
18 | } else {
19 | process.exit(0);
20 | }
21 | });
22 | })();
23 |
--------------------------------------------------------------------------------
/internals/scripts/CheckYarn.js:
--------------------------------------------------------------------------------
1 | const { execSync } = require('child_process');
2 | const { semverSatisfies } = require('./semver');
3 |
4 | const requiredVersionRange = '>=6.x <=8.16.0';
5 |
6 | try {
7 | const npmVersion = execSync('npm -v').toString().trim();
8 |
9 | if (!semverSatisfies(npmVersion, requiredVersionRange)) {
10 | console.error(
11 | `Error: This project requires npm version ${requiredVersionRange}. You have version ${npmVersion}.\nPlease downgrade your npm, this is due to a bug in node-gyp. Github issue: https://github.com/ganeshrvel/openmtp/issues/367.\ncommand: npm install -g npm@8.16.0`
12 | );
13 | process.exit(1);
14 | }
15 |
16 | console.info(`Using compatible npm version: ${npmVersion}`);
17 | } catch (error) {
18 | console.error('Error checking npm version:', error);
19 |
20 | process.exit(1);
21 | }
22 |
23 | if (!/yarn\.js$/.test(process.env.npm_execpath || '')) {
24 | console.warn(
25 | "\u001b[33mYou don't seem to be using yarn. This could produce unexpected results.\u001b[39m"
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/internals/scripts/Notarize.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const { notarize: electronNotarize } = require('@electron/notarize');
6 | const electronBuilderConfig = require('../../electron-builder-config');
7 |
8 | const electronBuilderData = electronBuilderConfig();
9 |
10 | const { ELECTRON_NOTARIZE } = process.env;
11 |
12 | exports.default = async (context) => {
13 | const { electronPlatformName, appOutDir } = context;
14 |
15 | if (ELECTRON_NOTARIZE === 'NO') {
16 | return;
17 | }
18 |
19 | if (electronPlatformName !== 'darwin') {
20 | return;
21 | }
22 |
23 | const appBundleId = electronBuilderData.appId;
24 | const appName = context.packager.appInfo.productFilename;
25 | const appPath = path.join(appOutDir, `${appName}.app`);
26 | const appleId = process.env.APPLEID;
27 | const appleIdPassword = process.env.APPLE_APP_SPECIFIC_PASSWORD;
28 | const appleTeamId = process.env.APPLE_TEAM_ID;
29 |
30 | if (!fs.existsSync(appPath)) {
31 | throw new Error(`Cannot find application at: ${appPath}`);
32 | }
33 |
34 | console.info(`Notarizing ${appBundleId} found at ${appPath}`);
35 |
36 | // eslint-disable-next-line no-return-await
37 | return await electronNotarize({
38 | appBundleId,
39 | appPath,
40 | appleId,
41 | appleIdPassword,
42 | teamId: appleTeamId,
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/internals/scripts/OptionalDepsInstall.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const saveFile = require('fs').writeFileSync;
3 |
4 | const pkgJsonPath = path.join(
5 | `${require.main.paths[0].split('node_modules')[0]}`,
6 | '../../',
7 | 'package.json'
8 | );
9 |
10 | const json = require(pkgJsonPath);
11 |
12 | // json.dependencies['node-mac-permissions'] = '^2.2.1';
13 |
14 | saveFile(pkgJsonPath, JSON.stringify(json, null, 2));
15 |
--------------------------------------------------------------------------------
/internals/scripts/preinstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/zsh
2 |
3 | node ./internals/scripts/CheckYarn.js
4 |
--------------------------------------------------------------------------------
/internals/scripts/semver.js:
--------------------------------------------------------------------------------
1 | exports.semverSatisfies = (version, range) => {
2 | const [gtOp, gtVersion] = gtSemver(range);
3 | const [ltOp, ltVersion] = ltSemver(range);
4 | const versionParts = version.split('.').map(Number);
5 | const gtVersionParts = gtVersion.split('.').map(Number);
6 | const ltVersionParts = ltVersion.split('.').map(Number);
7 |
8 | // eslint-disable-next-line no-plusplus
9 | for (let i = 0; i < 3; i++) {
10 | const vp = versionParts[i] || 0;
11 | const gtvp = gtVersionParts[i] || 0;
12 | const ltvp = ltVersionParts[i] || 0;
13 |
14 | if (vp > ltvp || (vp === ltvp && ltOp === '<')) {
15 | return false;
16 | }
17 |
18 | if (vp < gtvp || (vp === gtvp && gtOp === '>')) {
19 | return false;
20 | }
21 | }
22 |
23 | return true;
24 | };
25 |
26 | const gtSemver = (range) => {
27 | const gtPattern = />=?\s*(\d+(?:\.\d+(?:\.\d+)?)?)/.exec(range);
28 |
29 | return gtPattern ? ['>=', gtPattern[1]] : ['>=', '0.0.0'];
30 | };
31 |
32 | const ltSemver = (range) => {
33 | const ltPattern = /<=?\s*(\d+(?:\.\d+(?:\.\d+)?)?)/.exec(range);
34 |
35 | return ltPattern ? ['<=', ltPattern[1]] : ['<=', '9999.9999.9999'];
36 | };
37 |
--------------------------------------------------------------------------------
/lint-staged.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | '*.{js,jsx,mjs}': ['yarn lint', 'yarn postlint-fix', 'git add'],
3 | '{*.json,.{babelrc,eslintrc,prettierrc,stylelintrc}}': [
4 | 'prettier --ignore-path .eslintignore --parser json --write',
5 | 'git add',
6 | ],
7 | '*.{css,scss}': ['yarn lint-styles', 'yarn postlint-styles-fix', 'git add'],
8 | '*.{html,md,yml}': [
9 | 'prettier --ignore-path .eslintignore --single-quote --write',
10 | 'git add',
11 | ],
12 | '*.{js,jsx,mjs,ts,tsx,css,scss,html,md,yml}': ['git add'],
13 | };
14 |
--------------------------------------------------------------------------------
/sample.env:
--------------------------------------------------------------------------------
1 | APPLEID="<value>"
2 | APPLE_APP_SPECIFIC_PASSWORD="<value>"
3 | APPLE_TEAM_ID="<value>"
4 |
--------------------------------------------------------------------------------
/sample.sentry.properties:
--------------------------------------------------------------------------------
1 | defaults.url=https://sentry.io/
2 | defaults.org=<org>
3 | defaults.project=<project>
4 | auth.token=<token>
5 |
--------------------------------------------------------------------------------
/scripts/cicd/axios.mjs:
--------------------------------------------------------------------------------
1 | import process from 'process';
2 | import axiosPackage from 'axios';
3 |
4 | import { CODEMAGIC_BASE_URL } from './constants.mjs';
5 |
6 | export const axios = axiosPackage.create({
7 | baseURL: CODEMAGIC_BASE_URL,
8 | });
9 |
10 | axios.defaults.headers.common['Content-Type'] = 'application/json';
11 | axios.defaults.headers.common['x-auth-token'] =
12 | process.env.CODEMAGIC_AUTH_TOKEN_ID;
13 | axios.defaults.timeout = 15000;
14 |
--------------------------------------------------------------------------------
/scripts/cicd/base.mjs:
--------------------------------------------------------------------------------
1 | import 'zx/globals';
2 |
3 | require('dotenv').config();
4 |
5 | process.env.FORCE_COLOR = 3;
6 | $.shell = '/bin/zsh';
7 |
8 | await
export LANG=en_US.UTF-8`;
9 | await
export LC_ALL=en_US.UTF-8`;
10 |
--------------------------------------------------------------------------------
/scripts/cicd/codemagic-start-mac-intel-x64-vm.mjs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env zx
2 |
3 | import 'zx/globals';
4 | import process from 'process';
5 | import './base.mjs';
6 | import { IS_PROD_WORKFLOW } from './constants.mjs';
7 | import { axios } from './axios.mjs';
8 |
9 | let workflowId;
10 | if (IS_PROD_WORKFLOW) {
11 | workflowId = process.env.CODEMAGIC_INTEL_X64_WORKFLOW_ID_PROD;
12 | } else {
13 | workflowId = process.env.CODEMAGIC_INTEL_X64_WORKFLOW_ID_DEV;
14 | }
15 |
16 | // starting a new codemagic `macos-intel-x64-build` instance
17 | console.info(`starting a new CodeMagic 'macos-intel-x64-build' instance...\n`);
18 | try {
19 | await axios.post('/builds', {
20 | appId: `${process.env.CODEMAGIC_PUBLISH_PROJECT_ID}`,
21 | workflowId,
22 | branch: `${process.env.CM_BRANCH}`,
23 | environment: {
24 | variables: {
25 | CM_ARTIFACT_LINKS_M1_ARM64: process.env.CM_ARTIFACT_LINKS,
26 | },
27 | },
28 | });
29 | } catch (e) {
30 | throw new Error(
31 | `starting a new CodeMagic 'macos-intel-x64-build' instance failed: ${e}`
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/scripts/cicd/constants.mjs:
--------------------------------------------------------------------------------
1 | import process from 'process';
2 | import './base.mjs';
3 |
4 | export const { WORKFLOW_ENV } = process.env;
5 |
6 | export const WORKFLOW_ENV_DEV = 'dev';
7 | export const WORKFLOW_ENV_PROD = 'prod';
8 |
9 | export const IS_DEV_WORKFLOW = WORKFLOW_ENV === WORKFLOW_ENV_DEV;
10 | export const IS_PROD_WORKFLOW = WORKFLOW_ENV === WORKFLOW_ENV_PROD;
11 |
12 | export const CODEMAGIC_BASE_URL = `https://api.codemagic.io`;
13 |
--------------------------------------------------------------------------------
/webpack/config.base.js:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off */
2 |
3 | /**
4 | * Base webpack config used across other specific configs
5 | */
6 |
7 | import { join } from 'path';
8 | import webpack from 'webpack';
9 | import { rootPath } from 'electron-root-path';
10 | import { PATHS } from '../app/constants/paths';
11 |
12 | const pkg = require(join(rootPath, 'package.json'));
13 |
14 | export default {
15 | externals: [...Object.keys(pkg.dependencies || {})],
16 |
17 | module: {
18 | rules: [
19 | {
20 | test: /\.(js|jsx)?$/,
21 | exclude: /node_modules/,
22 | use: {
23 | loader: 'babel-loader',
24 | options: {
25 | cacheDirectory: true,
26 | },
27 | },
28 | },
29 | ],
30 | },
31 |
32 | output: {
33 | path: PATHS.app,
34 | // https://github.com/webpack/webpack/issues/1114
35 | libraryTarget: 'commonjs2',
36 | },
37 |
38 | /**
39 | * Determine the array of extensions that should be used to resolve modules.
40 | */
41 | resolve: {
42 | extensions: ['.js', '.jsx', '.json'],
43 | modules: [PATHS.nodeModules],
44 | },
45 |
46 | plugins: [
47 | // new webpack.IgnorePlugin({ resourceRegExp: /^(node-mac-permissions)$/u }),
48 |
49 | new webpack.EnvironmentPlugin({
50 | NODE_ENV: 'production',
51 | }),
52 |
53 | new webpack.DefinePlugin({
54 | PKG_INFO: {
55 | productName: JSON.stringify(pkg.productName),
56 | description: JSON.stringify(pkg.description),
57 | name: JSON.stringify(pkg.name),
58 | author: JSON.stringify(pkg.author),
59 | version: JSON.stringify(pkg.version),
60 | repository: JSON.stringify(pkg.repository),
61 | homepage: JSON.stringify(pkg.homepage),
62 | bugs: JSON.stringify(pkg.bugs),
63 | },
64 | }),
65 | ],
66 | };
67 |
--------------------------------------------------------------------------------
/webpack/config.eslint.js:
--------------------------------------------------------------------------------
1 | /* eslint import/no-unresolved: off, import/no-self-import: off */
2 | require('@babel/register');
3 |
4 | module.exports = require('./config.renderer.dev.babel').default;
5 |
--------------------------------------------------------------------------------
/webpack/config.renderer.dev.dll.babel.js:
--------------------------------------------------------------------------------
1 | /* eslint global-require: off, */
2 |
3 | /**
4 | * Builds the DLL for development electron renderer process
5 | */
6 |
7 | import webpack from 'webpack';
8 | import path from 'path';
9 | import merge from 'webpack-merge';
10 | import baseConfig from './config.base';
11 | import { PATHS } from '../app/constants/paths';
12 | import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
13 |
14 | const pkg = require('../package.json');
15 |
16 | const dll = path.join(PATHS.root, 'dll');
17 |
18 | CheckNodeEnv('development');
19 |
20 | export default merge(baseConfig, {
21 | context: PATHS.root,
22 | devtool: 'eval',
23 | mode: 'development',
24 | target: 'electron-renderer',
25 | externals: ['fsevents', 'crypto-browserify'],
26 |
27 | /**
28 | * Use `module` from `config.renderer.dev.babel.js`
29 | */
30 | module: require('./config.renderer.dev.babel').default.module,
31 |
32 | entry: {
33 | renderer: Object.keys(pkg.dependencies || {}),
34 | },
35 |
36 | output: {
37 | library: 'renderer',
38 | path: dll,
39 | filename: '[name].dev.dll.js',
40 | libraryTarget: 'var',
41 | },
42 |
43 | plugins: [
44 | new webpack.DllPlugin({
45 | path: path.join(dll, '[name].json'),
46 | name: '[name]',
47 | }),
48 |
49 | /**
50 | * Create global constants which can be configured at compile time.
51 | *
52 | * Useful for allowing different behaviour between development builds and
53 | * release builds
54 | *
55 | * NODE_ENV should be production so that modules do not perform certain
56 | * development checks
57 | */
58 | new webpack.EnvironmentPlugin({
59 | NODE_ENV: 'development',
60 | }),
61 |
62 | new webpack.LoaderOptionsPlugin({
63 | debug: true,
64 | options: {
65 | context: PATHS.app,
66 | output: {
67 | path: dll,
68 | },
69 | },
70 | }),
71 | ],
72 | });
73 |
--------------------------------------------------------------------------------