mirror of
https://github.com/zoriya/react-native-background-downloader.git
synced 2025-12-05 22:46:11 +00:00
fixed error with progressInterval. corrected types & ts config. removed percent from progress event. changed params to object in all events. updated readme. made onProgress starting on app start
This commit is contained in:
495
.eslintrc
495
.eslintrc
@@ -1,495 +0,0 @@
|
||||
/*
|
||||
* Eko's ESLint JSON Config file (eslint allows JavaScript-style comments in JSON config files).
|
||||
*/
|
||||
|
||||
{
|
||||
// Enable the ESLint recommended rules as a starting point.
|
||||
// These are rules that report common problems, see https://eslint.org/docs/rules/
|
||||
"extends": "eslint:recommended",
|
||||
|
||||
"parser": "babel-eslint",
|
||||
// Specify the envs (an environment defines global variables that are predefined).
|
||||
// See https://eslint.org/docs/user-guide/configuring#specifying-environments
|
||||
"env": {
|
||||
// Browser global variables.
|
||||
"browser": false,
|
||||
|
||||
// Node.js global variables and Node.js scoping.
|
||||
"node": true,
|
||||
|
||||
// CommonJS global variables and CommonJS scoping (use this for browser-only code that uses Browserify/WebPack).
|
||||
"commonjs": true,
|
||||
|
||||
// Globals common to both Node.js and Browser.
|
||||
"shared-node-browser": true,
|
||||
|
||||
// enable all ECMAScript 6 features except for modules (this automatically sets the ecmaVersion parser option to 6).
|
||||
"es6": true,
|
||||
|
||||
// web workers global variables.
|
||||
"worker": true
|
||||
},
|
||||
|
||||
// https://eslint.org/docs/rules
|
||||
"rules": {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Possible Errors https://eslint.org/docs/rules/#possible-errors
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/no-console
|
||||
"no-console": ["error", { "allow": ["error"] }],
|
||||
|
||||
// https://eslint.org/docs/rules/valid-jsdoc
|
||||
// TODO - valid-jsdoc
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Best Practices https://eslint.org/docs/rules/#best-practices
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/accessor-pairs
|
||||
"accessor-pairs": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/array-callback-return
|
||||
"array-callback-return": ["error", { "allowImplicit": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/block-scoped-var
|
||||
"block-scoped-var": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/curly
|
||||
"curly": ["error", "all"],
|
||||
|
||||
// https://eslint.org/docs/rules/default-case
|
||||
"default-case": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/dot-location
|
||||
"dot-location": ["error", "property"],
|
||||
|
||||
// https://eslint.org/docs/rules/dot-notation
|
||||
"dot-notation": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/eqeqeq
|
||||
"eqeqeq": ["error", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/no-alert
|
||||
"no-alert": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-caller
|
||||
"no-caller": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-else-return
|
||||
"no-else-return": ["error", { "allowElseIf": false }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-eq-null
|
||||
"no-eq-null": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-eval
|
||||
"no-eval": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-extra-bind
|
||||
"no-extra-bind": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-fallthrough
|
||||
"no-fallthrough": ["error", { "commentPattern": "fall-?thr(ough|u)" }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-floating-decimal
|
||||
"no-floating-decimal": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-implicit-coercion
|
||||
"no-implicit-coercion": ["error", { "allow": ["!!"] }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-implicit-globals
|
||||
"no-implicit-globals": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-implied-eval
|
||||
"no-implied-eval": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-invalid-this
|
||||
"no-invalid-this": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-iterator
|
||||
"no-iterator": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-labels
|
||||
"no-labels": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-lone-blocks
|
||||
"no-lone-blocks": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-loop-func
|
||||
"no-loop-func": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-magic-numbers
|
||||
"no-magic-numbers": ["error", {
|
||||
"ignore": [
|
||||
0, 1, -1,
|
||||
10, 100, 1000, 10000, 100000, 1000000,
|
||||
1024, 8, 2,
|
||||
24, 60
|
||||
]
|
||||
}],
|
||||
|
||||
// https://eslint.org/docs/rules/no-multi-spaces
|
||||
"no-multi-spaces": ["error", { "ignoreEOLComments": true, "exceptions": {
|
||||
"Property": true,
|
||||
"VariableDeclarator": true,
|
||||
"ImportDeclaration": true
|
||||
}}],
|
||||
|
||||
// https://eslint.org/docs/rules/no-multi-str
|
||||
"no-multi-str": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-new
|
||||
"no-new": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-new-wrappers
|
||||
"no-new-wrappers": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-octal-escape
|
||||
"no-octal-escape": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-proto
|
||||
"no-proto": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-return-assign
|
||||
"no-return-assign": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-return-await
|
||||
"no-return-await": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-script-url
|
||||
"no-script-url": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-self-compare
|
||||
"no-self-compare": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-sequences
|
||||
"no-sequences": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-throw-literal
|
||||
"no-throw-literal": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-unmodified-loop-condition
|
||||
"no-unmodified-loop-condition": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-unused-expressions
|
||||
"no-unused-expressions": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-useless-call
|
||||
"no-useless-call": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-useless-concat
|
||||
"no-useless-concat": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-useless-return
|
||||
"no-useless-return": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-void
|
||||
"no-void": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-with
|
||||
"no-with": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/prefer-promise-reject-errors
|
||||
"prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/radix
|
||||
"radix": ["error", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/require-await
|
||||
"require-await": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/wrap-iife
|
||||
"wrap-iife": ["error", "any"],
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Strict Mode https://eslint.org/docs/rules/#strict-mode
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/strict
|
||||
"strict": ["error", "safe"],
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Variables https://eslint.org/docs/rules/#variables
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/no-shadow
|
||||
"no-shadow": ["error", { "builtinGlobals": true, "hoist": "all", "allow": [] }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-shadow-restricted-names
|
||||
"no-shadow-restricted-names": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-undef-init
|
||||
"no-undef-init": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-use-before-define
|
||||
"no-use-before-define": ["error", { "functions": true, "classes": true, "variables": true }],
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Node.js and CommonJS https://eslint.org/docs/rules/#nodejs-and-commonjs
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/global-require
|
||||
"global-require": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-buffer-constructor
|
||||
"no-buffer-constructor": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-new-require
|
||||
"no-new-require": "error",
|
||||
|
||||
// https://eslint.org/docs/rules/no-path-concat
|
||||
"no-path-concat": "error",
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Stylistic Issues https://eslint.org/docs/rules/#stylistic-issues
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/array-bracket-newline
|
||||
"array-bracket-newline": ["warn", { "multiline": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/array-bracket-spacing
|
||||
"array-bracket-spacing": ["warn", "never"],
|
||||
|
||||
// https://eslint.org/docs/rules/block-spacing
|
||||
"block-spacing": ["warn", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/brace-style
|
||||
"brace-style": ["warn", "1tbs", { "allowSingleLine": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/camelcase
|
||||
"camelcase": ["warn", { "properties": "always" }],
|
||||
|
||||
// https://eslint.org/docs/rules/capitalized-comments
|
||||
"capitalized-comments": ["warn", "always", { "ignoreInlineComments": true, "ignoreConsecutiveComments": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/comma-dangle
|
||||
"comma-dangle": ["warn", "only-multiline"],
|
||||
|
||||
// https://eslint.org/docs/rules/comma-spacing
|
||||
"comma-spacing": ["warn", { "before": false, "after": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/comma-style
|
||||
"comma-style": ["warn", "last"],
|
||||
|
||||
// https://eslint.org/docs/rules/computed-property-spacing
|
||||
"computed-property-spacing": ["warn", "never"],
|
||||
|
||||
// TODO - discuss with TEAM!
|
||||
// https://eslint.org/docs/rules/consistent-this
|
||||
"consistent-this": ["warn", "that", "_this", "self"],
|
||||
|
||||
// https://eslint.org/docs/rules/eol-last
|
||||
"eol-last": ["warn", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/func-call-spacing
|
||||
"func-call-spacing": ["warn", "never"],
|
||||
|
||||
// https://eslint.org/docs/rules/func-name-matching
|
||||
"func-name-matching": ["warn", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/implicit-arrow-linebreak
|
||||
"implicit-arrow-linebreak": ["warn", "beside"],
|
||||
|
||||
// https://eslint.org/docs/rules/indent
|
||||
"indent": ["warn", 4, {
|
||||
"SwitchCase": 1,
|
||||
"FunctionDeclaration": {
|
||||
"parameters": 2,
|
||||
"body": 1
|
||||
},
|
||||
"FunctionExpression": {
|
||||
"parameters": 2,
|
||||
"body": 1
|
||||
},
|
||||
"CallExpression": {
|
||||
"arguments": 1
|
||||
},
|
||||
"ArrayExpression": 1,
|
||||
"ObjectExpression": 1,
|
||||
"ImportDeclaration": 1,
|
||||
"ignoredNodes": [
|
||||
"ConditionalExpression"
|
||||
]
|
||||
}],
|
||||
|
||||
// https://eslint.org/docs/rules/jsx-quotes
|
||||
"jsx-quotes": ["warn", "prefer-double"],
|
||||
|
||||
// https://eslint.org/docs/rules/key-spacing
|
||||
"key-spacing": [
|
||||
"warn",
|
||||
{
|
||||
"singleLine": {
|
||||
"beforeColon": false,
|
||||
"afterColon": true,
|
||||
"mode": "strict"
|
||||
},
|
||||
"multiLine": {
|
||||
"beforeColon": false,
|
||||
"afterColon": true,
|
||||
"mode": "minimum"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// https://eslint.org/docs/rules/keyword-spacing
|
||||
"keyword-spacing": ["warn", { "before": true, "after": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/linebreak-style
|
||||
"linebreak-style": ["warn", "unix"],
|
||||
|
||||
// https://eslint.org/docs/rules/lines-around-comment
|
||||
"lines-around-comment": ["warn", {
|
||||
"beforeBlockComment": true,
|
||||
"afterBlockComment": false,
|
||||
"beforeLineComment": true,
|
||||
"afterLineComment": false,
|
||||
"allowBlockStart": true,
|
||||
"allowBlockEnd": false,
|
||||
"allowClassStart": true,
|
||||
"allowClassEnd": false,
|
||||
"allowObjectStart": true,
|
||||
"allowObjectEnd": false,
|
||||
"allowArrayStart": true,
|
||||
"allowArrayEnd": false
|
||||
}],
|
||||
|
||||
// https://eslint.org/docs/rules/max-len
|
||||
"max-len": ["warn", {
|
||||
"code": 120,
|
||||
"tabWidth": 4,
|
||||
"ignoreUrls": true,
|
||||
"ignoreComments": true
|
||||
}],
|
||||
|
||||
// https://eslint.org/docs/rules/max-lines
|
||||
"max-lines": ["warn", {
|
||||
"max": 500,
|
||||
"skipBlankLines": true,
|
||||
"skipComments": true
|
||||
}],
|
||||
|
||||
// https://eslint.org/docs/rules/max-statements
|
||||
"max-statements": ["warn", 30],
|
||||
|
||||
// https://eslint.org/docs/rules/max-statements-per-line
|
||||
"max-statements-per-line": ["warn", {
|
||||
"max": 1
|
||||
}],
|
||||
|
||||
// https://eslint.org/docs/rules/multiline-ternary
|
||||
"multiline-ternary": ["warn", "always-multiline"],
|
||||
|
||||
// https://eslint.org/docs/rules/new-cap
|
||||
"new-cap": ["warn", { "newIsCap": true, "capIsNew": true, "properties": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/new-parens
|
||||
"new-parens": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/newline-per-chained-call
|
||||
"newline-per-chained-call": ["warn", { "ignoreChainWithDepth": 2 }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-array-constructor
|
||||
"no-array-constructor": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-bitwise
|
||||
"no-bitwise": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-lonely-if
|
||||
"no-lonely-if": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-mixed-operators
|
||||
"no-mixed-operators": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-multi-assign
|
||||
"no-multi-assign": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-multiple-empty-lines
|
||||
"no-multiple-empty-lines": ["warn", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-negated-condition
|
||||
"no-negated-condition": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-new-object
|
||||
"no-new-object": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-tabs
|
||||
"no-tabs": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/no-trailing-spaces
|
||||
"no-trailing-spaces": ["warn", { "skipBlankLines": false, "ignoreComments": false }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-unneeded-ternary
|
||||
"no-unneeded-ternary": ["warn", { "defaultAssignment": false }],
|
||||
|
||||
// https://eslint.org/docs/rules/no-whitespace-before-property
|
||||
"no-whitespace-before-property": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/object-curly-newline
|
||||
"object-curly-newline": ["warn", { "consistent": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/object-curly-spacing
|
||||
"object-curly-spacing": ["warn", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/one-var
|
||||
"one-var": ["error", "never"],
|
||||
|
||||
// https://eslint.org/docs/rules/operator-linebreak
|
||||
"operator-linebreak": ["warn", "after"],
|
||||
|
||||
// https://eslint.org/docs/rules/padded-blocks
|
||||
"padded-blocks": ["warn", "never"],
|
||||
|
||||
// https://eslint.org/docs/rules/quote-props
|
||||
"quote-props": ["warn", "as-needed"],
|
||||
|
||||
// https://eslint.org/docs/rules/quotes
|
||||
"quotes": ["warn", "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/semi
|
||||
"semi": ["warn", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/semi-spacing
|
||||
"semi-spacing": ["warn", { "before": false, "after": true }],
|
||||
|
||||
// https://eslint.org/docs/rules/semi-style
|
||||
"semi-style": ["warn", "last"],
|
||||
|
||||
// https://eslint.org/docs/rules/space-before-blocks
|
||||
"space-before-blocks": ["warn", "always"],
|
||||
|
||||
// https://eslint.org/docs/rules/space-before-function-paren
|
||||
"space-before-function-paren": ["warn", "never"],
|
||||
|
||||
// https://eslint.org/docs/rules/space-in-parens
|
||||
"space-in-parens": ["warn", "never"],
|
||||
|
||||
// https://eslint.org/docs/rules/space-infix-ops
|
||||
"space-infix-ops": "warn",
|
||||
|
||||
// https://eslint.org/docs/rules/space-unary-ops
|
||||
"space-unary-ops": ["warn", { "words": true, "nonwords": false }],
|
||||
|
||||
// https://eslint.org/docs/rules/spaced-comment
|
||||
"spaced-comment": ["warn", "always", { "exceptions": ["-", "/", "=", "*"] }],
|
||||
|
||||
// https://eslint.org/docs/rules/switch-colon-spacing
|
||||
"switch-colon-spacing": ["warn", { "after": true, "before": false }],
|
||||
|
||||
// https://eslint.org/docs/rules/unicode-bom
|
||||
"unicode-bom": ["error", "never"],
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// ECMAScript 6 https://eslint.org/docs/rules/#ecmascript-6
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://eslint.org/docs/rules/arrow-spacing
|
||||
"arrow-spacing": ["warn", { "before": true, "after": true }]
|
||||
|
||||
// TODO - more ES6 rules
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
||||
10
.eslintrc.js
10
.eslintrc.js
@@ -20,6 +20,8 @@ module.exports = {
|
||||
plugins: [
|
||||
'react',
|
||||
'react-hooks',
|
||||
'jest',
|
||||
'@typescript-eslint',
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
@@ -63,9 +65,15 @@ module.exports = {
|
||||
'no-class-assign': 'off',
|
||||
'no-useless-escape': 'off',
|
||||
curly: [2, 'multi', 'consistent'],
|
||||
'react/prop-types': 'off', // TODO: TURN ON AND FIX ALL WARNINGS
|
||||
'react/display-name': 'off',
|
||||
'react-hooks/exhaustive-deps': ['warn', {
|
||||
}],
|
||||
},
|
||||
overrides: [{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['plugin:@typescript-eslint/recommended'],
|
||||
}],
|
||||
globals: {
|
||||
describe: 'readonly',
|
||||
test: 'readonly',
|
||||
|
||||
37
README.md
37
README.md
@@ -111,10 +111,10 @@ let task = download({
|
||||
metadata: {}
|
||||
}).begin(({ expectedBytes, headers }) => {
|
||||
console.log(`Going to download ${expectedBytes} bytes!`)
|
||||
}).progress(percent => {
|
||||
console.log(`Downloaded: ${percent * 100}%`)
|
||||
}).done(() => {
|
||||
console.log('Download is done!')
|
||||
}).progress(({ bytesDownloaded, bytesTotal }) => {
|
||||
console.log(`Downloaded: ${bytesDownloaded / bytesTotal * 100}%`)
|
||||
}).done(({ bytesDownloaded, bytesTotal }) => {
|
||||
console.log('Download is done!', { bytesDownloaded, bytesTotal })
|
||||
|
||||
// PROCESS YOUR STUFF
|
||||
|
||||
@@ -148,10 +148,10 @@ import RNBackgroundDownloader from '@kesha-antonov/react-native-background-downl
|
||||
let lostTasks = await RNBackgroundDownloader.checkForExistingDownloads()
|
||||
for (let task of lostTasks) {
|
||||
console.log(`Task ${task.id} was found!`)
|
||||
task.progress(percent => {
|
||||
console.log(`Downloaded: ${percent * 100}%`)
|
||||
}).done(() => {
|
||||
console.log('Download is done!')
|
||||
task.progress(({ bytesDownloaded, bytesTotal }) => {
|
||||
console.log(`Downloaded: ${bytesDownloaded / bytesTotal * 100}%`)
|
||||
}).done(({ bytesDownloaded, bytesTotal }) => {
|
||||
console.log('Download is done!', { bytesDownloaded, bytesTotal })
|
||||
}).error(error => {
|
||||
console.log('Download canceled due to error: ', error)
|
||||
})
|
||||
@@ -182,10 +182,10 @@ let task = RNBackgroundDownloader.download({
|
||||
}
|
||||
}).begin(({ expectedBytes, headers }) => {
|
||||
console.log(`Going to download ${expectedBytes} bytes!`)
|
||||
}).progress(percent => {
|
||||
console.log(`Downloaded: ${percent * 100}%`)
|
||||
}).done(() => {
|
||||
console.log('Download is done!')
|
||||
}).progress(({ bytesDownloaded, bytesTotal }) => {
|
||||
console.log(`Downloaded: ${bytesDownloaded / bytesTotal * 100}%`)
|
||||
}).done(({ bytesDownloaded, bytesTotal }) => {
|
||||
console.log('Download is done!', { bytesDownloaded, bytesTotal })
|
||||
}).error(error => {
|
||||
console.log('Download canceled due to error: ', error)
|
||||
})
|
||||
@@ -243,7 +243,6 @@ A class representing a download task created by `RNBackgroundDownloader.download
|
||||
| -------------- | ------ | ---------------------------------------------------------------------------------------------------- |
|
||||
| `id` | String | The id you gave the task when calling `RNBackgroundDownloader.download` |
|
||||
| `metadata` | Object | The metadata you gave the task when calling `RNBackgroundDownloader.download` |
|
||||
| `percent` | Number | The current percent of completion of the task between 0 and 1 |
|
||||
| `bytesDownloaded` | Number | The number of bytes currently written by the task |
|
||||
| `bytesTotal` | Number | The number bytes expected to be written by this task or more plainly, the file size being downloaded |
|
||||
|
||||
@@ -304,12 +303,12 @@ Use these methods to stay updated on what's happening with the task.
|
||||
|
||||
All callback methods return the current instance of the `DownloadTask` for chaining.
|
||||
|
||||
| Function | Callback Arguments | Info |
|
||||
| ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `begin` | { expectedBytes, headers } | Called when the first byte is received. 💡: this is good place to check if the device has enough storage space for this download |
|
||||
| `progress` | percent, bytesDownloaded, bytesTotal | Called at max every 1.5s so you can update your progress bar accordingly |
|
||||
| `done` | | Called when the download is done, the file is at the destination you've set |
|
||||
| `error` | error | Called when the download stops due to an error |
|
||||
| Function | Callback Arguments | Info|
|
||||
| ---------- | --------------------------------- | ---- |
|
||||
| `begin` | { expectedBytes, headers } | Called when the first byte is received. 💡: this is good place to check if the device has enough storage space for this download |
|
||||
| `progress` | { bytesDownloaded, bytesTotal } | Called at max every 1.5s so you can update your progress bar accordingly |
|
||||
| `done` | { bytesDownloaded, bytesTotal } | Called when the download is done, the file is at the destination you've set |
|
||||
| `error` | { error, errorCode } | Called when the download stops due to an error |
|
||||
|
||||
### `pause()`
|
||||
Pauses the download
|
||||
|
||||
@@ -19,13 +19,12 @@ public class OnProgress extends Thread {
|
||||
private Cursor cursor;
|
||||
private int lastBytesDownloaded;
|
||||
private int bytesTotal;
|
||||
private int progressInterval = 300;
|
||||
|
||||
private RNBGDTaskConfig config;
|
||||
private DeviceEventManagerModule.RCTDeviceEventEmitter ee;
|
||||
|
||||
public OnProgress(RNBGDTaskConfig config, long downloadId,
|
||||
DeviceEventManagerModule.RCTDeviceEventEmitter ee, Downloader downloader, int progressInterval) {
|
||||
DeviceEventManagerModule.RCTDeviceEventEmitter ee, Downloader downloader) {
|
||||
this.config = config;
|
||||
|
||||
this.downloadId = downloadId;
|
||||
@@ -34,9 +33,6 @@ public class OnProgress extends Thread {
|
||||
|
||||
this.ee = ee;
|
||||
this.downloader = downloader;
|
||||
if (progressInterval > 0) {
|
||||
this.progressInterval = progressInterval;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInterrupt() {
|
||||
@@ -56,7 +52,7 @@ public class OnProgress extends Thread {
|
||||
Log.d("RNBackgroundDownloader", "RNBD: OnProgress-1. downloadId " + downloadId);
|
||||
while (downloadId > 0) {
|
||||
try {
|
||||
Log.d("RNBackgroundDownloader", "RNBD: OnProgress-2. downloadId " + downloadId);
|
||||
Log.d("RNBackgroundDownloader", "RNBD: OnProgress-2. downloadId " + downloadId + " destination " + config.destination);
|
||||
|
||||
cursor = downloader.downloadManager.query(query);
|
||||
|
||||
@@ -77,7 +73,7 @@ public class OnProgress extends Thread {
|
||||
Thread.sleep(1000);
|
||||
} else {
|
||||
Log.d("RNBackgroundDownloader", "RNBD: OnProgress-2.3. downloadId " + downloadId);
|
||||
Thread.sleep(progressInterval);
|
||||
Thread.sleep(config.progressInterval);
|
||||
}
|
||||
|
||||
// get total bytes of the file
|
||||
@@ -101,7 +97,6 @@ public class OnProgress extends Thread {
|
||||
params.putString("id", config.id);
|
||||
params.putInt("bytesDownloaded", (int) lastBytesDownloaded);
|
||||
params.putInt("bytesTotal", (int) bytesTotal);
|
||||
params.putDouble("percent", ((double) lastBytesDownloaded / bytesTotal));
|
||||
|
||||
HashMap<String, WritableMap> progressReports = new HashMap<>();
|
||||
progressReports.put(config.id, params);
|
||||
|
||||
@@ -8,12 +8,14 @@ public class RNBGDTaskConfig implements Serializable {
|
||||
public String destination;
|
||||
public String metadata = "{}";
|
||||
public boolean reportedBegin;
|
||||
public int progressInterval;
|
||||
|
||||
public RNBGDTaskConfig(String id, String url, String destination, String metadata) {
|
||||
public RNBGDTaskConfig(String id, String url, String destination, String metadata, int progressInterval) {
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
this.destination = destination;
|
||||
this.metadata = metadata;
|
||||
this.reportedBegin = false;
|
||||
this.progressInterval = progressInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,8 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("id", config.id);
|
||||
params.putString("location", config.destination);
|
||||
params.putInt("bytesDownloaded", downloadStatus.getInt("bytesDownloaded"));
|
||||
params.putInt("bytesTotal", downloadStatus.getInt("bytesTotal"));
|
||||
|
||||
ee.emit("downloadComplete", params);
|
||||
break;
|
||||
@@ -148,13 +150,20 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
public RNBackgroundDownloaderModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
|
||||
ReadableMap emptyMap = Arguments.createMap();
|
||||
this.initDownloader(emptyMap);
|
||||
loadConfigMap();
|
||||
|
||||
downloader = new Downloader(reactContext);
|
||||
|
||||
IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
|
||||
compatRegisterReceiver(reactContext, downloadReceiver, filter, true);
|
||||
|
||||
// iterate over downloadIdToConfig
|
||||
for(Map.Entry<Long, RNBGDTaskConfig> entry : downloadIdToConfig.entrySet()) {
|
||||
Long downloadId = entry.getKey();
|
||||
RNBGDTaskConfig config = entry.getValue();
|
||||
|
||||
startReportingTasks(downloadId, config);
|
||||
}
|
||||
}
|
||||
|
||||
// TAKEN FROM
|
||||
@@ -220,15 +229,6 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
return constants;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void initDownloader(ReadableMap options) {
|
||||
Log.d(getName(), "RNBD: initDownloader");
|
||||
|
||||
loadConfigMap();
|
||||
|
||||
// TODO. MAYBE REINIT DOWNLOADER
|
||||
}
|
||||
|
||||
private void removeFromMaps(long downloadId) {
|
||||
Log.d(getName(), "RNBD: removeFromMaps");
|
||||
|
||||
@@ -291,7 +291,7 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
return;
|
||||
}
|
||||
|
||||
RNBGDTaskConfig config = new RNBGDTaskConfig(id, url, destination, metadata);
|
||||
RNBGDTaskConfig config = new RNBGDTaskConfig(id, url, destination, metadata, progressInterval);
|
||||
final Request request = new Request(Uri.parse(url));
|
||||
request.setAllowedOverRoaming(isAllowedOverRoaming);
|
||||
request.setAllowedOverMetered(isAllowedOverMetered);
|
||||
@@ -333,52 +333,59 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
return;
|
||||
}
|
||||
|
||||
config.reportedBegin = true;
|
||||
saveConfigMap();
|
||||
startReportingTasks(downloadId, config);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(getName(), "RNBD: download-2 downloadId: " + downloadId);
|
||||
// report begin & progress
|
||||
//
|
||||
// overlaped with thread to not block main thread
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Log.d(getName(), "RNBD: download-3 downloadId: " + downloadId);
|
||||
private void startReportingTasks(Long downloadId, RNBGDTaskConfig config) {
|
||||
Log.d(getName(), "RNBD: startReportingTasks-1 downloadId " + downloadId + " config.id " + config.id);
|
||||
config.reportedBegin = true;
|
||||
downloadIdToConfig.put(downloadId, config);
|
||||
saveConfigMap();
|
||||
|
||||
while (true) {
|
||||
WritableMap downloadStatus = downloader.checkDownloadStatus(downloadId);
|
||||
int status = downloadStatus.getInt("status");
|
||||
Log.d(getName(), "RNBD: startReportingTasks-2 downloadId: " + downloadId);
|
||||
// report begin & progress
|
||||
//
|
||||
// overlaped with thread to not block main thread
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Log.d(getName(), "RNBD: startReportingTasks-3 downloadId: " + downloadId);
|
||||
|
||||
Log.d(getName(), "RNBD: download-3.1 " + status + " downloadId: " + downloadId);
|
||||
while (true) {
|
||||
WritableMap downloadStatus = downloader.checkDownloadStatus(downloadId);
|
||||
int status = downloadStatus.getInt("status");
|
||||
|
||||
if (status == DownloadManager.STATUS_RUNNING) {
|
||||
break;
|
||||
}
|
||||
if (status == DownloadManager.STATUS_FAILED || status == DownloadManager.STATUS_SUCCESSFUL) {
|
||||
Log.d(getName(), "RNBD: download-3.2 " + status + " downloadId: " + downloadId);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
Log.d(getName(), "RNBD: startReportingTasks-3.1 " + status + " downloadId: " + downloadId);
|
||||
|
||||
Thread.sleep(500);
|
||||
if (status == DownloadManager.STATUS_RUNNING) {
|
||||
break;
|
||||
}
|
||||
if (status == DownloadManager.STATUS_FAILED || status == DownloadManager.STATUS_SUCCESSFUL) {
|
||||
Log.d(getName(), "RNBD: startReportingTasks-3.2 " + status + " downloadId: " + downloadId);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
// EMIT BEGIN
|
||||
OnBegin onBeginTh = new OnBegin(config, ee);
|
||||
onBeginTh.start();
|
||||
// wait for onBeginTh to finish
|
||||
onBeginTh.join();
|
||||
|
||||
Log.d(getName(), "RNBD: download-4 downloadId: " + downloadId);
|
||||
OnProgress onProgressTh = new OnProgress(config, downloadId, ee, downloader, progressInterval);
|
||||
onProgressThreads.put(config.id, onProgressTh);
|
||||
onProgressTh.start();
|
||||
Log.d(getName(), "RNBD: download-5 downloadId: " + downloadId);
|
||||
} catch (Exception e) {
|
||||
Thread.sleep(500);
|
||||
}
|
||||
|
||||
// EMIT BEGIN
|
||||
OnBegin onBeginTh = new OnBegin(config, ee);
|
||||
onBeginTh.start();
|
||||
// wait for onBeginTh to finish
|
||||
onBeginTh.join();
|
||||
|
||||
Log.d(getName(), "RNBD: startReportingTasks-4 downloadId: " + downloadId);
|
||||
OnProgress onProgressTh = new OnProgress(config, downloadId, ee, downloader);
|
||||
onProgressThreads.put(config.id, onProgressTh);
|
||||
onProgressTh.start();
|
||||
Log.d(getName(), "RNBD: startReportingTasks-5 downloadId: " + downloadId);
|
||||
} catch (Exception e) {
|
||||
Log.d(getName(), "RNBD: Runnable e: " + e.toString());
|
||||
}
|
||||
}).start();
|
||||
Log.d(getName(), "RNBD: download-6 downloadId: " + downloadId);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
Log.d(getName(), "RNBD: startReportingTasks-6 downloadId: " + downloadId);
|
||||
}
|
||||
|
||||
// TODO: NOT WORKING WITH DownloadManager FOR NOW
|
||||
@@ -453,8 +460,8 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
WritableMap result = downloader.getDownloadStatus(cursor);
|
||||
Long downloadId = Long.parseLong(result.getString("downloadId"));
|
||||
WritableMap downloadStatus = downloader.getDownloadStatus(cursor);
|
||||
Long downloadId = Long.parseLong(downloadStatus.getString("downloadId"));
|
||||
|
||||
if (downloadIdToConfig.containsKey(downloadId)) {
|
||||
Log.d(getName(), "RNBD: checkForExistingDownloads-2");
|
||||
@@ -462,15 +469,9 @@ public class RNBackgroundDownloaderModule extends ReactContextBaseJavaModule {
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("id", config.id);
|
||||
params.putString("metadata", config.metadata);
|
||||
params.putInt("state", stateMap.get(result.getInt("status")));
|
||||
|
||||
int bytesDownloaded = result.getInt("bytesDownloaded");
|
||||
params.putInt("bytesDownloaded", bytesDownloaded);
|
||||
|
||||
int bytesTotal = result.getInt("bytesTotal");
|
||||
params.putInt("bytesTotal", bytesTotal);
|
||||
|
||||
params.putDouble("percent", ((double) bytesDownloaded / bytesTotal));
|
||||
params.putInt("state", stateMap.get(downloadStatus.getInt("status")));
|
||||
params.putInt("bytesDownloaded", downloadStatus.getInt("bytesDownloaded"));
|
||||
params.putInt("bytesTotal", downloadStatus.getInt("bytesTotal"));
|
||||
|
||||
foundIds.pushMap(params);
|
||||
|
||||
|
||||
@@ -1,4 +1,87 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: '@react-native',
|
||||
};
|
||||
env: {
|
||||
es2020: true,
|
||||
jest: true,
|
||||
},
|
||||
parser: '@babel/eslint-parser',
|
||||
extends: [
|
||||
'standard',
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 11,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: [
|
||||
'react',
|
||||
'react-hooks',
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
indent: [
|
||||
'error',
|
||||
2, {
|
||||
SwitchCase: 1,
|
||||
ignoredNodes: [
|
||||
'TemplateLiteral',
|
||||
],
|
||||
},
|
||||
],
|
||||
'template-curly-spacing': 'off',
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix',
|
||||
],
|
||||
quotes: [
|
||||
'error',
|
||||
'single',
|
||||
],
|
||||
semi: [
|
||||
'error',
|
||||
'never',
|
||||
],
|
||||
'comma-dangle': [
|
||||
'error',
|
||||
{
|
||||
arrays: 'always-multiline',
|
||||
objects: 'always-multiline',
|
||||
imports: 'always-multiline',
|
||||
exports: 'never',
|
||||
functions: 'never',
|
||||
},
|
||||
],
|
||||
'no-func-assign': 'off',
|
||||
'no-class-assign': 'off',
|
||||
'no-useless-escape': 'off',
|
||||
curly: [2, 'multi', 'consistent'],
|
||||
'react/prop-types': 'off', // TODO: TURN ON AND FIX ALL WARNINGS
|
||||
'react/display-name': 'off',
|
||||
'react-hooks/exhaustive-deps': ['warn', {
|
||||
additionalHooks: '(useAnimatedStyle|useSharedValue|useAnimatedGestureHandler|useAnimatedScrollHandler|useAnimatedProps|useDerivedValue|useAnimatedRef|useAnimatedReact)',
|
||||
// useAnimatedReaction
|
||||
// USE RULE FUNC/FUNC/DEPS
|
||||
}],
|
||||
},
|
||||
globals: {
|
||||
describe: 'readonly',
|
||||
test: 'readonly',
|
||||
jest: 'readonly',
|
||||
expect: 'readonly',
|
||||
fetch: 'readonly',
|
||||
navigator: 'readonly',
|
||||
__DEV__: 'readonly',
|
||||
XMLHttpRequest: 'readonly',
|
||||
FormData: 'readonly',
|
||||
React$Element: 'readonly',
|
||||
requestAnimationFrame: 'readonly',
|
||||
},
|
||||
}
|
||||
|
||||
105
index.d.ts
vendored
105
index.d.ts
vendored
@@ -11,50 +11,68 @@ export interface DownloadHeaders {
|
||||
|
||||
type SetHeaders = (h: DownloadHeaders) => void;
|
||||
|
||||
export interface TaskInfoObject {
|
||||
id: string;
|
||||
metadata: object | string;
|
||||
|
||||
percent?: number;
|
||||
bytesDownloaded?: number;
|
||||
bytesTotal?: number;
|
||||
|
||||
beginHandler?: Function;
|
||||
progressHandler?: Function;
|
||||
doneHandler?: Function;
|
||||
errorHandler?: Function;
|
||||
}
|
||||
export type TaskInfo = TaskInfoObject;
|
||||
|
||||
export interface BeginHandlerObject {
|
||||
expectedBytes: number;
|
||||
headers: { [key: string]: string };
|
||||
}
|
||||
|
||||
export type BeginHandler = ({
|
||||
expectedBytes,
|
||||
headers,
|
||||
}: BeginHandlerObject) => any;
|
||||
export type ProgressHandler = (
|
||||
percent: number,
|
||||
bytesDownloaded: number,
|
||||
}: BeginHandlerObject) => void;
|
||||
|
||||
export interface ProgressHandlerObject {
|
||||
bytesDownloaded: number
|
||||
bytesTotal: number
|
||||
) => any;
|
||||
export type DoneHandler = () => any;
|
||||
export type ErrorHandler = (error: any, errorCode: any) => any;
|
||||
}
|
||||
export type ProgressHandler = ({
|
||||
bytesDownloaded,
|
||||
bytesTotal,
|
||||
}: ProgressHandlerObject) => void;
|
||||
|
||||
export interface DoneHandlerObject {
|
||||
bytesDownloaded: number
|
||||
bytesTotal: number
|
||||
}
|
||||
export type DoneHandler = ({
|
||||
bytesDownloaded,
|
||||
bytesTotal,
|
||||
}: DoneHandlerObject) => void;
|
||||
|
||||
export interface ErrorHandlerObject {
|
||||
error: string
|
||||
errorCode: number
|
||||
}
|
||||
export type ErrorHandler = ({
|
||||
error,
|
||||
errorCode,
|
||||
}: ErrorHandlerObject) => void;
|
||||
|
||||
export interface TaskInfoObject {
|
||||
id: string;
|
||||
metadata: object | string;
|
||||
|
||||
bytesDownloaded?: number;
|
||||
bytesTotal?: number;
|
||||
|
||||
beginHandler?: BeginHandler;
|
||||
progressHandler?: ProgressHandler;
|
||||
doneHandler?: DoneHandler;
|
||||
errorHandler?: ErrorHandler;
|
||||
}
|
||||
export type TaskInfo = TaskInfoObject;
|
||||
|
||||
export type DownloadTaskState =
|
||||
| "DOWNLOADING"
|
||||
| "PAUSED"
|
||||
| "DONE"
|
||||
| "FAILED"
|
||||
| "STOPPED";
|
||||
| 'DOWNLOADING'
|
||||
| 'PAUSED'
|
||||
| 'DONE'
|
||||
| 'FAILED'
|
||||
| 'STOPPED';
|
||||
|
||||
export interface DownloadTask {
|
||||
constructor: (taskInfo: TaskInfo) => DownloadTask;
|
||||
|
||||
id: string;
|
||||
state: DownloadTaskState;
|
||||
percent: number;
|
||||
bytesDownloaded: number;
|
||||
bytesTotal: number;
|
||||
|
||||
@@ -68,18 +86,14 @@ export interface DownloadTask {
|
||||
_doneHandler: DoneHandler;
|
||||
_errorHandler: ErrorHandler;
|
||||
|
||||
pause: () => any;
|
||||
resume: () => any;
|
||||
stop: () => any;
|
||||
pause: () => void;
|
||||
resume: () => void;
|
||||
stop: () => void;
|
||||
}
|
||||
|
||||
export type CheckForExistingDownloads = () => Promise<DownloadTask[]>;
|
||||
export type EnsureDownloadsAreRunning = () => Promise<void>;
|
||||
|
||||
export interface InitDownloaderOptions {
|
||||
}
|
||||
export type InitDownloader = (options: InitDownloaderOptions) => undefined;
|
||||
|
||||
export interface DownloadOption {
|
||||
id: string;
|
||||
url: string;
|
||||
@@ -88,6 +102,7 @@ export interface DownloadOption {
|
||||
metadata?: object;
|
||||
isAllowedOverRoaming?: boolean;
|
||||
isAllowedOverMetered?: boolean;
|
||||
progressInterval?: number;
|
||||
}
|
||||
|
||||
export type Download = (options: DownloadOption) => DownloadTask;
|
||||
@@ -97,17 +112,15 @@ export interface Directories {
|
||||
documents: string;
|
||||
}
|
||||
|
||||
export const setHeaders: SetHeaders;
|
||||
export const checkForExistingDownloads: CheckForExistingDownloads;
|
||||
export const ensureDownloadsAreRunning: EnsureDownloadsAreRunning;
|
||||
export const initDownloader: InitDownloader;
|
||||
export const download: Download;
|
||||
export const completeHandler: CompleteHandler;
|
||||
export const directories: Directories;
|
||||
export const setHeaders: SetHeaders
|
||||
export const checkForExistingDownloads: CheckForExistingDownloads
|
||||
export const ensureDownloadsAreRunning: EnsureDownloadsAreRunning
|
||||
export const download: Download
|
||||
export const completeHandler: CompleteHandler
|
||||
export const directories: Directories
|
||||
|
||||
export interface RNBackgroundDownloader {
|
||||
setHeaders: SetHeaders;
|
||||
initDownloader: InitDownloader;
|
||||
checkForExistingDownloads: CheckForExistingDownloads;
|
||||
ensureDownloadsAreRunning: EnsureDownloadsAreRunning;
|
||||
download: Download;
|
||||
@@ -115,5 +128,5 @@ export interface RNBackgroundDownloader {
|
||||
directories: Directories;
|
||||
}
|
||||
|
||||
declare const RNBackgroundDownloader: RNBackgroundDownloader;
|
||||
export default RNBackgroundDownloader;
|
||||
declare const RNBackgroundDownloader: RNBackgroundDownloader
|
||||
export default RNBackgroundDownloader
|
||||
|
||||
49
index.ts
49
index.ts
@@ -1,4 +1,4 @@
|
||||
import { NativeModules, NativeEventEmitter, Platform } from 'react-native'
|
||||
import { NativeModules, NativeEventEmitter } from 'react-native'
|
||||
import DownloadTask from './lib/DownloadTask'
|
||||
|
||||
const { RNBackgroundDownloader } = NativeModules
|
||||
@@ -7,50 +7,46 @@ const RNBackgroundDownloaderEmitter = new NativeEventEmitter(RNBackgroundDownloa
|
||||
const tasksMap = new Map()
|
||||
let headers = {}
|
||||
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadBegin', ({ id, expectedBytes, headers }) => {
|
||||
console.log('[RNBackgroundDownloader] downloadBegin', id, expectedBytes, headers)
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadBegin', ({ id, ...rest }) => {
|
||||
console.log('[RNBackgroundDownloader] downloadBegin', id, rest)
|
||||
const task = tasksMap.get(id)
|
||||
task?.onBegin({ expectedBytes, headers })
|
||||
task?.onBegin(rest)
|
||||
})
|
||||
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadProgress', events => {
|
||||
// console.log('[RNBackgroundDownloader] downloadProgress-1', events, tasksMap)
|
||||
for (const event of events) {
|
||||
const task = tasksMap.get(event.id)
|
||||
// console.log('[RNBackgroundDownloader] downloadProgress-2', event.id, task)
|
||||
task?.onProgress(event.percent, event.bytesDownloaded, event.bytesTotal)
|
||||
const { id, ...rest } = event
|
||||
const task = tasksMap.get(id)
|
||||
// console.log('[RNBackgroundDownloader] downloadProgress-2', id, task)
|
||||
task?.onProgress(rest)
|
||||
}
|
||||
})
|
||||
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadComplete', ({ id, location }) => {
|
||||
console.log('[RNBackgroundDownloader] downloadComplete', id, location)
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadComplete', ({ id, ...rest }) => {
|
||||
console.log('[RNBackgroundDownloader] downloadComplete', id, rest)
|
||||
const task = tasksMap.get(id)
|
||||
task?.onDone({ location })
|
||||
task?.onDone(rest)
|
||||
|
||||
tasksMap.delete(id)
|
||||
})
|
||||
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadFailed', event => {
|
||||
console.log('[RNBackgroundDownloader] downloadFailed', event)
|
||||
const task = tasksMap.get(event.id)
|
||||
task?.onError(event.error, event.errorCode)
|
||||
RNBackgroundDownloaderEmitter.addListener('downloadFailed', ({ id, ...rest }) => {
|
||||
console.log('[RNBackgroundDownloader] downloadFailed', id, rest)
|
||||
const task = tasksMap.get(id)
|
||||
task?.onError(rest)
|
||||
|
||||
tasksMap.delete(event.id)
|
||||
tasksMap.delete(id)
|
||||
})
|
||||
|
||||
export function setHeaders(h = {}) {
|
||||
export function setHeaders (h = {}) {
|
||||
if (typeof h !== 'object')
|
||||
throw new Error('[RNBackgroundDownloader] headers must be an object')
|
||||
|
||||
headers = h
|
||||
}
|
||||
|
||||
export function initDownloader(options = {}) {
|
||||
if (Platform.OS === 'android')
|
||||
RNBackgroundDownloader.initDownloader(options)
|
||||
}
|
||||
|
||||
export function checkForExistingDownloads() {
|
||||
export function checkForExistingDownloads () {
|
||||
console.log('[RNBackgroundDownloader] checkForExistingDownloads-1')
|
||||
return RNBackgroundDownloader.checkForExistingDownloads()
|
||||
.then(foundTasks => {
|
||||
@@ -80,7 +76,7 @@ export function checkForExistingDownloads() {
|
||||
})
|
||||
}
|
||||
|
||||
export function ensureDownloadsAreRunning() {
|
||||
export function ensureDownloadsAreRunning () {
|
||||
console.log('[RNBackgroundDownloader] ensureDownloadsAreRunning')
|
||||
return checkForExistingDownloads()
|
||||
.then(tasks => {
|
||||
@@ -92,7 +88,7 @@ export function ensureDownloadsAreRunning() {
|
||||
})
|
||||
}
|
||||
|
||||
export function completeHandler(jobId: string) {
|
||||
export function completeHandler (jobId: string) {
|
||||
if (jobId == null) {
|
||||
console.warn('[RNBackgroundDownloader] completeHandler: jobId is empty')
|
||||
return
|
||||
@@ -109,9 +105,10 @@ type DownloadOptions = {
|
||||
metadata?: object,
|
||||
isAllowedOverRoaming?: boolean,
|
||||
isAllowedOverMetered?: boolean,
|
||||
progressInterval?: number,
|
||||
}
|
||||
|
||||
export function download(options: DownloadOptions) {
|
||||
export function download (options: DownloadOptions) {
|
||||
console.log('[RNBackgroundDownloader] download', options)
|
||||
if (!options.id || !options.url || !options.destination)
|
||||
throw new Error('[RNBackgroundDownloader] id, url and destination are required')
|
||||
@@ -125,6 +122,7 @@ export function download(options: DownloadOptions) {
|
||||
|
||||
if (options.isAllowedOverRoaming == null) options.isAllowedOverRoaming = true
|
||||
if (options.isAllowedOverMetered == null) options.isAllowedOverMetered = true
|
||||
if (options.progressInterval == null) options.progressInterval = 1000
|
||||
|
||||
const task = new DownloadTask({
|
||||
id: options.id,
|
||||
@@ -145,7 +143,6 @@ export const directories = {
|
||||
}
|
||||
|
||||
export default {
|
||||
initDownloader,
|
||||
download,
|
||||
checkForExistingDownloads,
|
||||
ensureDownloadsAreRunning,
|
||||
|
||||
@@ -19,7 +19,6 @@ static CompletionHandler storedCompletionHandler;
|
||||
NSMutableDictionary<NSNumber *, RNBGDTaskConfig *> *taskToConfigMap;
|
||||
NSMutableDictionary<NSString *, NSURLSessionDownloadTask *> *idToTaskMap;
|
||||
NSMutableDictionary<NSString *, NSData *> *idToResumeDataMap;
|
||||
NSMutableDictionary<NSString *, NSNumber *> *idToPercentMap;
|
||||
NSMutableDictionary<NSString *, NSDictionary *> *progressReports;
|
||||
NSDate *lastProgressReport;
|
||||
NSNumber *sharedLock;
|
||||
@@ -63,7 +62,6 @@ RCT_EXPORT_MODULE();
|
||||
}
|
||||
idToTaskMap = [[NSMutableDictionary alloc] init];
|
||||
idToResumeDataMap = [[NSMutableDictionary alloc] init];
|
||||
idToPercentMap = [[NSMutableDictionary alloc] init];
|
||||
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
|
||||
NSString *sessonIdentifier = [bundleIdentifier stringByAppendingString:@".backgrounddownloadtask"];
|
||||
sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessonIdentifier];
|
||||
@@ -149,7 +147,6 @@ RCT_EXPORT_MODULE();
|
||||
|
||||
if (taskConfig) {
|
||||
[idToTaskMap removeObjectForKey:taskConfig.id];
|
||||
[idToPercentMap removeObjectForKey:taskConfig.id];
|
||||
}
|
||||
// TOREMOVE - GIVES ERROR IN JS ON HOT RELOAD
|
||||
// if (taskToConfigMap.count == 0) {
|
||||
@@ -224,7 +221,6 @@ RCT_EXPORT_METHOD(download: (NSDictionary *) options) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[self serialize: taskToConfigMap] forKey:ID_TO_CONFIG_MAP_KEY];
|
||||
|
||||
idToTaskMap[identifier] = task;
|
||||
idToPercentMap[identifier] = @0.0;
|
||||
|
||||
[task resume];
|
||||
lastProgressReport = [[NSDate alloc] init];
|
||||
@@ -280,20 +276,17 @@ RCT_EXPORT_METHOD(checkForExistingDownloads: (RCTPromiseResolveBlock)resolve rej
|
||||
}
|
||||
[task resume];
|
||||
}
|
||||
NSNumber *percent = task.countOfBytesExpectedToReceive > 0 ? [NSNumber numberWithFloat:(float)task.countOfBytesReceived/(float)task.countOfBytesExpectedToReceive] : @0.0;
|
||||
|
||||
[idsFound addObject:@{
|
||||
@"id": taskConfig.id,
|
||||
@"metadata": taskConfig.metadata,
|
||||
@"state": [NSNumber numberWithInt: task.state],
|
||||
@"bytesDownloaded": [NSNumber numberWithLongLong:task.countOfBytesReceived],
|
||||
@"bytesTotal": [NSNumber numberWithLongLong:task.countOfBytesExpectedToReceive],
|
||||
@"percent": percent
|
||||
@"bytesTotal": [NSNumber numberWithLongLong:task.countOfBytesExpectedToReceive]
|
||||
}];
|
||||
taskConfig.reportedBegin = YES;
|
||||
taskToConfigMap[@(task.taskIdentifier)] = taskConfig;
|
||||
idToTaskMap[taskConfig.id] = task;
|
||||
idToPercentMap[taskConfig.id] = percent;
|
||||
} else {
|
||||
[task cancel];
|
||||
}
|
||||
@@ -331,6 +324,7 @@ RCT_EXPORT_METHOD(completeHandler:(nonnull NSString *)jobId
|
||||
if (self.bridge) {
|
||||
if (error == nil) {
|
||||
NSDictionary *responseHeaders = ((NSHTTPURLResponse *)downloadTask.response).allHeaderFields;
|
||||
// TODO: SEND bytesDownloaded AND bytesTotal
|
||||
[self sendEventWithName:@"downloadComplete" body:@{@"id": taskConfig.id, @"headers": responseHeaders, @"location": taskConfig.destination}];
|
||||
} else {
|
||||
[self sendEventWithName:@"downloadFailed" body:@{@"id": taskConfig.id, @"error": [error localizedDescription]}];
|
||||
@@ -363,12 +357,11 @@ RCT_EXPORT_METHOD(completeHandler:(nonnull NSString *)jobId
|
||||
taskCofig.reportedBegin = YES;
|
||||
}
|
||||
|
||||
NSNumber *prevPercent = idToPercentMap[taskCofig.id];
|
||||
NSNumber *percent = [NSNumber numberWithFloat:(float)bytesTotalWritten/(float)bytesTotalExpectedToWrite];
|
||||
if ([percent floatValue] - [prevPercent floatValue] > 0.01f) {
|
||||
progressReports[taskCofig.id] = @{@"id": taskCofig.id, @"bytesDownloaded": [NSNumber numberWithLongLong: bytesTotalWritten], @"bytesTotal": [NSNumber numberWithLongLong: bytesTotalExpectedToWrite], @"percent": percent};
|
||||
idToPercentMap[taskCofig.id] = percent;
|
||||
}
|
||||
progressReports[taskCofig.id] = @{
|
||||
@"id": taskCofig.id,
|
||||
@"bytesDownloaded": [NSNumber numberWithLongLong: bytesTotalWritten],
|
||||
@"bytesTotal": [NSNumber numberWithLongLong: bytesTotalExpectedToWrite]
|
||||
};
|
||||
|
||||
NSDate *now = [[NSDate alloc] init];
|
||||
if ([now timeIntervalSinceDate:lastProgressReport] > 0.25 && progressReports.count > 0) {
|
||||
@@ -376,6 +369,8 @@ RCT_EXPORT_METHOD(completeHandler:(nonnull NSString *)jobId
|
||||
[self sendEventWithName:@"downloadProgress" body:[progressReports allValues]];
|
||||
}
|
||||
lastProgressReport = now;
|
||||
// TODO: SHOULD REMOVE ALL progressReports ?
|
||||
// IS IT ALL SENT?
|
||||
[progressReports removeAllObjects];
|
||||
}
|
||||
}
|
||||
@@ -393,6 +388,7 @@ RCT_EXPORT_METHOD(completeHandler:(nonnull NSString *)jobId
|
||||
return;
|
||||
|
||||
if (self.bridge) {
|
||||
// TODO: SEND error AS IN OBJECT
|
||||
[self sendEventWithName:@"downloadFailed" body:@{@"id": taskCofig.id, @"error": [error localizedDescription]}];
|
||||
}
|
||||
// IF WE CAN'T RESUME TO DOWNLOAD LATER
|
||||
|
||||
@@ -15,13 +15,11 @@ export default class DownloadTask {
|
||||
state = 'PENDING'
|
||||
metadata = {}
|
||||
|
||||
percent = 0
|
||||
bytesDownloaded = 0
|
||||
bytesTotal = 0
|
||||
|
||||
constructor (taskInfo: TaskInfo, originalTask?: TaskInfo) {
|
||||
this.id = taskInfo.id
|
||||
this.percent = taskInfo.percent ?? 0
|
||||
this.bytesDownloaded = taskInfo.bytesDownloaded ?? 0
|
||||
this.bytesTotal = taskInfo.bytesTotal ?? 0
|
||||
|
||||
@@ -61,26 +59,27 @@ export default class DownloadTask {
|
||||
return this
|
||||
}
|
||||
|
||||
onBegin ({ expectedBytes, headers }) {
|
||||
onBegin (params) {
|
||||
this.state = 'DOWNLOADING'
|
||||
this.beginHandler?.({ expectedBytes, headers })
|
||||
this.beginHandler?.(params)
|
||||
}
|
||||
|
||||
onProgress (percent, bytesDownloaded, bytesTotal) {
|
||||
this.percent = percent
|
||||
onProgress ({ bytesDownloaded, bytesTotal }) {
|
||||
this.bytesDownloaded = bytesDownloaded
|
||||
this.bytesTotal = bytesTotal
|
||||
this.progressHandler?.(percent, bytesDownloaded, bytesTotal)
|
||||
this.progressHandler?.({ bytesDownloaded, bytesTotal })
|
||||
}
|
||||
|
||||
onDone ({ location }) {
|
||||
onDone (params) {
|
||||
this.state = 'DONE'
|
||||
this.doneHandler?.({ location })
|
||||
this.bytesDownloaded = params.bytesDownloaded
|
||||
this.bytesTotal = params.bytesTotal
|
||||
this.doneHandler?.(params)
|
||||
}
|
||||
|
||||
onError (error, errorCode) {
|
||||
onError (params) {
|
||||
this.state = 'FAILED'
|
||||
this.errorHandler?.(error, errorCode)
|
||||
this.errorHandler?.(params)
|
||||
}
|
||||
|
||||
pause () {
|
||||
|
||||
34
package.json
34
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kesha-antonov/react-native-background-downloader",
|
||||
"version": "3.0.0-alpha.0",
|
||||
"version": "3.0.0-alpha.1",
|
||||
"description": "A library for React-Native to help you download large files on iOS and Android both in the foreground and most importantly in the background.",
|
||||
"keywords": [
|
||||
"react-native",
|
||||
@@ -15,9 +15,8 @@
|
||||
"homepage": "https://github.com/kesha-antonov/react-native-background-downloader",
|
||||
"license": "Apache-2.0",
|
||||
"author": {
|
||||
"name": "Eko labs",
|
||||
"email": "dev@helloeko.com",
|
||||
"url": "https://developer.helloeko.com"
|
||||
"name": "Eko labs, Kesha Antonov",
|
||||
"email": "innokenty.longway@gmail.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
@@ -56,17 +55,21 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/eslint-parser": "^7.22.15",
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@babel/runtime": "^7.23.2",
|
||||
"@react-native-community/eslint-config": "^3.2.0",
|
||||
"@babel/core": "^7.23.6",
|
||||
"@babel/eslint-parser": "^7.23.3",
|
||||
"@babel/preset-env": "^7.23.6",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@babel/runtime": "^7.23.6",
|
||||
"@react-native/babel-preset": "^0.74.0",
|
||||
"@react-native/eslint-config": "^0.74.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
||||
"@typescript-eslint/parser": "^6.13.1",
|
||||
"babel-jest": "^29.7.0",
|
||||
"eslint": "8.52.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-config-standard-jsx": "^11.0.0",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-n": "^16.2.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-n": "^16.5.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
@@ -77,10 +80,11 @@
|
||||
"lint-staged": ">=15",
|
||||
"metro-react-native-babel-preset": "^0.77.0",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.72.6",
|
||||
"react-native": "0.73.0",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-vector-icons": "^10.0.1",
|
||||
"react-test-renderer": "18.2.0"
|
||||
"react-native-vector-icons": "^10.0.3",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native": ">=0.57.0"
|
||||
|
||||
Reference in New Issue
Block a user