Compare commits

...

22 Commits

Author SHA1 Message Date
Simon Bruder 51c53f2980
Add more options 2021-02-20 11:20:24 +01:00
Simon Bruder 1c1cfb9068
Add nix package expression 2021-02-20 11:19:35 +01:00
MaysWind cc8132bc3a modify style 2021-02-16 13:19:10 +08:00
MaysWind fddc891cd1 update README.md 2021-02-16 12:59:13 +08:00
MaysWind f7d8834110 update date 2021-02-16 12:58:06 +08:00
MaysWind 13b5bc049a bump version to 1.2.1 2021-02-16 12:39:39 +08:00
MaysWind ba8176e150 fix incorrect style in some old browsers 2021-02-16 12:36:16 +08:00
MaysWind 2a3748d2d4 fix cannot load page when some old browsers don't support addEventListener for MediaQueryList (#588) 2021-02-16 11:26:37 +08:00
MaysWind 836b39ed3d bump version to 1.2.0 2021-02-14 19:39:31 +08:00
MaysWind 97b00fc32e fix content height is incorrect sometimes 2021-02-14 19:36:19 +08:00
MaysWind e28e7c5fde modify select style 2021-02-14 16:33:57 +08:00
MaysWind 999b43c3ee add option for swipe gesture 2021-02-14 14:10:14 +08:00
MaysWind 05e0fb6b4f fix typo 2021-02-14 12:21:52 +08:00
MaysWind d153b95fc7 add safearea support 2021-02-14 02:20:51 +08:00
MaysWind aa80ab0350 optimize dark mode 2021-02-13 23:46:11 +08:00
MaysWind d18dabc17a fix code 2021-02-13 23:35:17 +08:00
MaysWind 3d13eb13d8 update third party dependencies 2021-02-13 23:27:53 +08:00
MaysWind 2e9f93557d optimize dark mode 2021-02-13 22:28:39 +08:00
MaysWind 9b312636bc add log 2021-02-11 13:45:58 +08:00
MaysWind 220df6ca49 add option for changing task order by drag-and-drop 2021-02-11 01:18:48 +08:00
MaysWind 5f718894aa support dark theme 2021-02-11 01:05:51 +08:00
MaysWind 2ee8efe40d fix cannot detect the correct language in some os and browser 2021-02-10 17:49:37 +08:00
37 changed files with 13014 additions and 2073 deletions

View File

@ -2,7 +2,7 @@ version: 2
defaults: &defaults
docker:
- image: circleci/node:6.14-browsers
- image: circleci/node:10.23-browsers
working_directory: ~/AriaNg
jobs:

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2016-2020 MaysWind (i@mayswind.net)
Copyright (c) 2016-2021 MaysWind (i@mayswind.net)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -19,12 +19,13 @@ AriaNg is a modern web frontend making [aria2](https://github.com/aria2/aria2) e
* Tree view for multi-directory task
* Download / upload speed chart for aria2 or single task
* Full support for aria2 settings
4. Url command line api support
5. Download finished notification
6. Multi-languages support
7. Multi aria2 RPC host support
8. Exporting and Importing settings support
9. Less bandwidth usage, only requesting incremental data
4. Dark theme
5. Url command line api support
6. Download finished notification
7. Multi-languages support
8. Multi aria2 RPC host support
9. Exporting and Importing settings support
10. Less bandwidth usage, only requesting incremental data
## Screenshots
#### Desktop

17
build-dependencies.nix Normal file
View File

@ -0,0 +1,17 @@
# This file has been generated by node2nix 1.8.0. Do not edit!
{pkgs ? import <nixpkgs> {
inherit system;
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-10_x"}:
let
nodeEnv = import ./node-env.nix {
inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile;
inherit nodejs;
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
};
in
import ./node-packages.nix {
inherit (pkgs) fetchurl fetchgit;
inherit nodeEnv;
}

21
default.nix Normal file
View File

@ -0,0 +1,21 @@
{ pkgs ? import <nixpkgs> { } }:
let
nodeDependencies = (pkgs.callPackage ./build-dependencies.nix { inherit pkgs; }).shell.nodeDependencies;
in
pkgs.stdenvNoCC.mkDerivation rec {
pname = "AriaNg";
version = "1.1.7";
src = ./.;
buildPhase = ''
ln -s ${nodeDependencies}/lib/node_modules ./node_modules
# shebang uses nodejs-12_x?
${pkgs.nodejs-10_x}/bin/node ${nodeDependencies}/bin/gulp clean build
'';
installPhase = ''
cp -r dist $out
'';
}

View File

@ -48,7 +48,7 @@ gulp.task('process-langs', ['prepare-langs'], function () {
gulp.task('prepare-styles', function () {
return gulp.src([
'src/styles/**/*.css'
]).pipe($.autoprefixer({browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']}))
]).pipe($.autoprefixer())
.pipe(gulp.dest('.tmp/styles'))
.pipe(reload({stream: true}));
});

542
node-env.nix Normal file
View File

@ -0,0 +1,542 @@
# This file originates from node2nix
{stdenv, nodejs, python2, utillinux, libtool, runCommand, writeTextFile}:
let
python = if nodejs ? python then nodejs.python else python2;
# Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
tarWrapper = runCommand "tarWrapper" {} ''
mkdir -p $out/bin
cat > $out/bin/tar <<EOF
#! ${stdenv.shell} -e
$(type -p tar) "\$@" --warning=no-unknown-keyword --delay-directory-restore
EOF
chmod +x $out/bin/tar
'';
# Function that generates a TGZ file from a NPM project
buildNodeSourceDist =
{ name, version, src, ... }:
stdenv.mkDerivation {
name = "node-tarball-${name}-${version}";
inherit src;
buildInputs = [ nodejs ];
buildPhase = ''
export HOME=$TMPDIR
tgzFile=$(npm pack | tail -n 1) # Hooks to the pack command will add output (https://docs.npmjs.com/misc/scripts)
'';
installPhase = ''
mkdir -p $out/tarballs
mv $tgzFile $out/tarballs
mkdir -p $out/nix-support
echo "file source-dist $out/tarballs/$tgzFile" >> $out/nix-support/hydra-build-products
'';
};
includeDependencies = {dependencies}:
stdenv.lib.optionalString (dependencies != [])
(stdenv.lib.concatMapStrings (dependency:
''
# Bundle the dependencies of the package
mkdir -p node_modules
cd node_modules
# Only include dependencies if they don't exist. They may also be bundled in the package.
if [ ! -e "${dependency.name}" ]
then
${composePackage dependency}
fi
cd ..
''
) dependencies);
# Recursively composes the dependencies of a package
composePackage = { name, packageName, src, dependencies ? [], ... }@args:
builtins.addErrorContext "while evaluating node package '${packageName}'" ''
DIR=$(pwd)
cd $TMPDIR
unpackFile ${src}
# Make the base dir in which the target dependency resides first
mkdir -p "$(dirname "$DIR/${packageName}")"
if [ -f "${src}" ]
then
# Figure out what directory has been unpacked
packageDir="$(find . -maxdepth 1 -type d | tail -1)"
# Restore write permissions to make building work
find "$packageDir" -type d -exec chmod u+x {} \;
chmod -R u+w "$packageDir"
# Move the extracted tarball into the output folder
mv "$packageDir" "$DIR/${packageName}"
elif [ -d "${src}" ]
then
# Get a stripped name (without hash) of the source directory.
# On old nixpkgs it's already set internally.
if [ -z "$strippedName" ]
then
strippedName="$(stripHash ${src})"
fi
# Restore write permissions to make building work
chmod -R u+w "$strippedName"
# Move the extracted directory into the output folder
mv "$strippedName" "$DIR/${packageName}"
fi
# Unset the stripped name to not confuse the next unpack step
unset strippedName
# Include the dependencies of the package
cd "$DIR/${packageName}"
${includeDependencies { inherit dependencies; }}
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
'';
pinpointDependencies = {dependencies, production}:
let
pinpointDependenciesFromPackageJSON = writeTextFile {
name = "pinpointDependencies.js";
text = ''
var fs = require('fs');
var path = require('path');
function resolveDependencyVersion(location, name) {
if(location == process.env['NIX_STORE']) {
return null;
} else {
var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
if(fs.existsSync(dependencyPackageJSON)) {
var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
if(dependencyPackageObj.name == name) {
return dependencyPackageObj.version;
}
} else {
return resolveDependencyVersion(path.resolve(location, ".."), name);
}
}
}
function replaceDependencies(dependencies) {
if(typeof dependencies == "object" && dependencies !== null) {
for(var dependency in dependencies) {
var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
if(resolvedVersion === null) {
process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
} else {
dependencies[dependency] = resolvedVersion;
}
}
}
}
/* Read the package.json configuration */
var packageObj = JSON.parse(fs.readFileSync('./package.json'));
/* Pinpoint all dependencies */
replaceDependencies(packageObj.dependencies);
if(process.argv[2] == "development") {
replaceDependencies(packageObj.devDependencies);
}
replaceDependencies(packageObj.optionalDependencies);
/* Write the fixed package.json file */
fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
'';
};
in
''
node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
${stdenv.lib.optionalString (dependencies != [])
''
if [ -d node_modules ]
then
cd node_modules
${stdenv.lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
cd ..
fi
''}
'';
# Recursively traverses all dependencies of a package and pinpoints all
# dependencies in the package.json file to the versions that are actually
# being used.
pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
''
if [ -d "${packageName}" ]
then
cd "${packageName}"
${pinpointDependencies { inherit dependencies production; }}
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
fi
'';
# Extract the Node.js source code which is used to compile packages with
# native bindings
nodeSources = runCommand "node-sources" {} ''
tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
mv node-* $out
'';
# Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
addIntegrityFieldsScript = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
function augmentDependencies(baseDir, dependencies) {
for(var dependencyName in dependencies) {
var dependency = dependencies[dependencyName];
// Open package.json and augment metadata fields
var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
var packageJSONPath = path.join(packageJSONDir, "package.json");
if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
console.log("Adding metadata fields to: "+packageJSONPath);
var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
if(dependency.integrity) {
packageObj["_integrity"] = dependency.integrity;
} else {
packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
}
if(dependency.resolved) {
packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided
} else {
packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
}
if(dependency.from !== undefined) { // Adopt from property if one has been provided
packageObj["_from"] = dependency.from;
}
fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
}
// Augment transitive dependencies
if(dependency.dependencies !== undefined) {
augmentDependencies(packageJSONDir, dependency.dependencies);
}
}
}
if(fs.existsSync("./package-lock.json")) {
var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
if(packageLock.lockfileVersion !== 1) {
process.stderr.write("Sorry, I only understand lock file version 1!\n");
process.exit(1);
}
if(packageLock.dependencies !== undefined) {
augmentDependencies(".", packageLock.dependencies);
}
}
'';
};
# Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
reconstructPackageLock = writeTextFile {
name = "addintegrityfields.js";
text = ''
var fs = require('fs');
var path = require('path');
var packageObj = JSON.parse(fs.readFileSync("package.json"));
var lockObj = {
name: packageObj.name,
version: packageObj.version,
lockfileVersion: 1,
requires: true,
dependencies: {}
};
function augmentPackageJSON(filePath, dependencies) {
var packageJSON = path.join(filePath, "package.json");
if(fs.existsSync(packageJSON)) {
var packageObj = JSON.parse(fs.readFileSync(packageJSON));
dependencies[packageObj.name] = {
version: packageObj.version,
integrity: "sha1-000000000000000000000000000=",
dependencies: {}
};
processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
}
}
function processDependencies(dir, dependencies) {
if(fs.existsSync(dir)) {
var files = fs.readdirSync(dir);
files.forEach(function(entry) {
var filePath = path.join(dir, entry);
var stats = fs.statSync(filePath);
if(stats.isDirectory()) {
if(entry.substr(0, 1) == "@") {
// When we encounter a namespace folder, augment all packages belonging to the scope
var pkgFiles = fs.readdirSync(filePath);
pkgFiles.forEach(function(entry) {
if(stats.isDirectory()) {
var pkgFilePath = path.join(filePath, entry);
augmentPackageJSON(pkgFilePath, dependencies);
}
});
} else {
augmentPackageJSON(filePath, dependencies);
}
}
});
}
}
processDependencies("node_modules", lockObj.dependencies);
fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
'';
};
prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}:
let
forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
in
''
# Pinpoint the versions of all dependencies to the ones that are actually being used
echo "pinpointing versions of dependencies..."
source $pinpointDependenciesScriptPath
# Patch the shebangs of the bundled modules to prevent them from
# calling executables outside the Nix store as much as possible
patchShebangs .
# Deploy the Node.js package by running npm install. Since the
# dependencies have been provided already by ourselves, it should not
# attempt to install them again, which is good, because we want to make
# it Nix's responsibility. If it needs to install any dependencies
# anyway (e.g. because the dependency parameters are
# incomplete/incorrect), it fails.
#
# The other responsibilities of NPM are kept -- version checks, build
# steps, postprocessing etc.
export HOME=$TMPDIR
cd "${packageName}"
runHook preRebuild
${stdenv.lib.optionalString bypassCache ''
${stdenv.lib.optionalString reconstructLock ''
if [ -f package-lock.json ]
then
echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!"
echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!"
rm package-lock.json
else
echo "No package-lock.json file found, reconstructing..."
fi
node ${reconstructPackageLock}
''}
node ${addIntegrityFieldsScript}
''}
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
if [ "''${dontNpmInstall-}" != "1" ]
then
# NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
rm -f npm-shrinkwrap.json
npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
fi
'';
# Builds and composes an NPM package including all its dependencies
buildNodePackage =
{ name
, packageName
, version
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, preRebuild ? ""
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" ];
in
stdenv.mkDerivation ({
name = "node_${name}-${version}";
buildInputs = [ tarWrapper python nodejs ]
++ stdenv.lib.optional (stdenv.isLinux) utillinux
++ stdenv.lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit nodejs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall preRebuild unpackPhase buildPhase;
compositionScript = composePackage args;
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
installPhase = ''
# Create and enter a root node_modules/ folder
mkdir -p $out/lib/node_modules
cd $out/lib/node_modules
# Compose the package and all its dependencies
source $compositionScriptPath
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Create symlink to the deployed executable folder, if applicable
if [ -d "$out/lib/node_modules/.bin" ]
then
ln -s $out/lib/node_modules/.bin $out/bin
fi
# Create symlinks to the deployed manual page folders, if applicable
if [ -d "$out/lib/node_modules/${packageName}/man" ]
then
mkdir -p $out/share
for dir in "$out/lib/node_modules/${packageName}/man/"*
do
mkdir -p $out/share/man/$(basename "$dir")
for page in "$dir"/*
do
ln -s $page $out/share/man/$(basename "$dir")
done
done
fi
# Run post install hook, if provided
runHook postInstall
'';
} // extraArgs);
# Builds a development shell
buildNodeShell =
{ name
, packageName
, version
, src
, dependencies ? []
, buildInputs ? []
, production ? true
, npmFlags ? ""
, dontNpmInstall ? false
, bypassCache ? false
, reconstructLock ? false
, dontStrip ? true
, unpackPhase ? "true"
, buildPhase ? "true"
, ... }@args:
let
extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
nodeDependencies = stdenv.mkDerivation ({
name = "node-dependencies-${name}-${version}";
buildInputs = [ tarWrapper python nodejs ]
++ stdenv.lib.optional (stdenv.isLinux) utillinux
++ stdenv.lib.optional (stdenv.isDarwin) libtool
++ buildInputs;
inherit dontStrip; # Stripping may fail a build for some package deployments
inherit dontNpmInstall unpackPhase buildPhase;
includeScript = includeDependencies { inherit dependencies; };
pinpointDependenciesScript = pinpointDependenciesOfPackage args;
passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
installPhase = ''
mkdir -p $out/${packageName}
cd $out/${packageName}
source $includeScriptPath
# Create fake package.json to make the npm commands work properly
cp ${src}/package.json .
chmod 644 package.json
${stdenv.lib.optionalString bypassCache ''
if [ -f ${src}/package-lock.json ]
then
cp ${src}/package-lock.json .
fi
''}
# Go to the parent folder to make sure that all packages are pinpointed
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }}
# Expose the executables that were installed
cd ..
${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
mv ${packageName} lib
ln -s $out/lib/node_modules/.bin $out/bin
'';
} // extraArgs);
in
stdenv.mkDerivation {
name = "node-shell-${name}-${version}";
buildInputs = [ python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
buildCommand = ''
mkdir -p $out/bin
cat > $out/bin/shell <<EOF
#! ${stdenv.shell} -e
$shellHook
exec ${stdenv.shell}
EOF
chmod +x $out/bin/shell
'';
# Provide the dependencies in a development shell through the NODE_PATH environment variable
inherit nodeDependencies;
shellHook = stdenv.lib.optionalString (dependencies != []) ''
export NODE_PATH=${nodeDependencies}/lib/node_modules
export PATH="${nodeDependencies}/bin:$PATH"
'';
};
in
{
buildNodeSourceDist = stdenv.lib.makeOverridable buildNodeSourceDist;
buildNodePackage = stdenv.lib.makeOverridable buildNodePackage;
buildNodeShell = stdenv.lib.makeOverridable buildNodeShell;
}

10529
node-packages.nix Normal file

File diff suppressed because it is too large Load Diff

3017
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,54 +4,54 @@
"node": ">=6"
},
"dependencies": {
"jquery": "3.4.1",
"bootstrap": "3.4.1",
"moment": "2.24.0",
"moment-timezone": "0.5.28",
"echarts": "3.8.5",
"font-awesome": "^4.7.0",
"admin-lte": "2.4.18",
"sweetalert": "^1.1.3",
"awesome-bootstrap-checkbox": "^0.3.7",
"jquery-slimscroll": "^1.3.8",
"bootstrap-contextmenu": "^1.0.0",
"natural-compare": "1.4.0",
"angular": "1.6.10",
"angular-route": "1.6.10",
"angular-sanitize": "1.6.10",
"angular-touch": "1.6.10",
"angular-messages": "1.6.10",
"angular-cookies": "1.6.10",
"angular-animate": "1.6.10",
"angular-translate": "^2.18.2",
"angular-moment": "1.3.0",
"angular-websocket": "^2.0.1",
"angular-local-storage": "^0.7.1",
"angular-ui-notification": "^0.3.6",
"angular-bittorrent-peerid": "^1.3.2",
"angular-busy": "^4.1.4",
"angular-promise-buttons": "^0.1.23",
"angular-sweetalert": "^1.1.2",
"angular-utf8-base64": "^0.0.5",
"angular-clipboard": "^1.7.0",
"angular-cookies": "1.6.10",
"angular-input-dropdown": "git://github.com/mayswind/angular-input-dropdown.git#68670e39816698b3eb98c0e740a0efe77d5fbdd1",
"angularjs-dragula": "^2.0.0"
"angular-local-storage": "^0.7.1",
"angular-messages": "1.6.10",
"angular-moment": "1.3.0",
"angular-promise-buttons": "^0.1.23",
"angular-route": "1.6.10",
"angular-sanitize": "1.6.10",
"angular-sweetalert": "^1.1.2",
"angular-touch": "1.6.10",
"angular-translate": "^2.18.4",
"angular-ui-notification": "^0.3.6",
"angular-utf8-base64": "^0.0.5",
"angular-websocket": "^2.0.1",
"angularjs-dragula": "^2.0.0",
"awesome-bootstrap-checkbox": "^0.3.7",
"bootstrap": "3.4.1",
"bootstrap-contextmenu": "^1.0.0",
"echarts": "3.8.5",
"font-awesome": "^4.7.0",
"jquery": "3.4.1",
"jquery-slimscroll": "^1.3.8",
"moment": "2.24.0",
"moment-timezone": "0.5.28",
"natural-compare": "1.4.0",
"sweetalert": "^1.1.3"
},
"devDependencies": {
"browser-sync": "^2.26.3",
"del": "^4.1.0",
"browser-sync": "^2.26.14",
"del": "^4.1.1",
"eslint-config-angular": "^0.5.0",
"eslint-plugin-angular": "^3.3.0",
"git-rev-sync": "^1.12.0",
"gulp": "^3.9.1",
"gulp-angular-templatecache": "^2.2.6",
"gulp-autoprefixer": "^6.0.0",
"gulp-angular-templatecache": "^2.2.7",
"gulp-autoprefixer": "^6.1.0",
"gulp-cssnano": "^2.1.3",
"gulp-eslint": "^4.0.2",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^2.0.2",
"gulp-inject-version": "^1.0.1",
"gulp-load-plugins": "^1.5.0",
"gulp-load-plugins": "^1.6.0",
"gulp-manifest": "^0.1.1",
"gulp-plumber": "^1.2.1",
"gulp-replace": "^1.0.0",
@ -63,16 +63,22 @@
"gulp-uglify": "^3.0.2",
"gulp-useref": "^3.1.6",
"gulp-util": "^3.0.8",
"nice-try": "^2.0.0",
"natives": "^1.1.6",
"nice-try": "^2.1.0",
"uglify-save-license": "^0.4.1"
},
"name": "ariang",
"description": "AriaNg, a modern web frontend making aria2 easier to use.",
"version": "1.1.7",
"version": "1.2.1",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 0"
},
"browsers": [
"> 1%",
"last 2 versions",
"Firefox ESR"
],
"repository": {
"type": "git",
"url": "git+https://github.com/mayswind/AriaNg.git"

View File

@ -4,11 +4,11 @@
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui" name="viewport">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-title" content="AriaNg"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="apple-mobile-web-app-status-bar-style" content="default"/>
<meta name="msapplication-TileColor" content="#3c4852">
<meta name="msapplication-TileImage" content="tileicon.png">
<meta name="description" content="AriaNg, a modern web frontend making aria2 easier to use.">
@ -43,6 +43,7 @@
<link rel="stylesheet" href="styles/controls/chart.css"/>
<link rel="stylesheet" href="styles/controls/angular-promise-buttons.css"/>
<link rel="stylesheet" href="styles/theme/default.css">
<link rel="stylesheet" href="styles/theme/default-dark.css">
<!-- endbuild -->
</head>
<body class="hold-transition skin-aria-ng sidebar-mini fixed">
@ -282,7 +283,8 @@
</div>
<div class="pull-right ng-cloak" ng-if="globalStatusContext.isEnabled">
<a class="global-status" title="{{('Click to pin' | translate)}}" ng-pop-chart ng-data="globalStatusContext.data"
<a class="global-status" title="{{('Click to pin' | translate)}}"
ng-pop-chart ng-data="globalStatusContext.data" ng-theme="currentTheme"
ng-container="body" ng-placement="top" ng-trigger="click hover" ng-popover-class="global-status-chart">
<span class="realtime-speed">
<i class="icon-download fa fa-arrow-down"></i>

View File

@ -147,6 +147,10 @@ Download Completed=下载完成
BT Download Completed=BT 下载完成
Download Error=下载出错
Language=语言
Theme=主题
Light=浅色
Dark=深色
Follow system settings=跟随系统设置
Debug Mode=调试模式
Page Title=页面标题
Preview=预览
@ -171,6 +175,8 @@ Add New RPC Setting=添加新 RPC 设置
Are you sure you want to remove rpc setting "{{rpcName}}"?=您是否要删除 RPC 设置 "{{rpcName}}"?
Updating Global Stat Interval=全局状态更新间隔
Updating Task Information Interval=任务信息更新间隔
Swipe Gesture=滑动手势
Change Tasks Order by Drag-and-drop=拖拽任务排序
Action After Creating New Tasks=创建新任务后执行操作
Navigate to Task List Page=转到任务列表页面
Navigate to Task Detail Page=转到任务详情页面

View File

@ -147,6 +147,10 @@ Download Completed=下載完成
BT Download Completed=BT 下載完成
Download Error=下載出錯
Language=語言
Theme=主題
Light=淺色
Dark=深色
Follow system settings=跟隨系统設定
Debug Mode=偵錯模式
Page Title=頁面標題
Preview=預覽
@ -171,6 +175,8 @@ Add New RPC Setting=加入新 RPC 設定
Are you sure you want to remove rpc setting "{{rpcName}}"?=您是否要刪除 RPC 設定 "{{rpcName}}"?
Updating Global Stat Interval=全域狀態更新間隔
Updating Task Information Interval=工作資訊更新間隔
Swipe Gesture=滑動手勢
Change Tasks Order by Drag-and-drop=拖拽工作排序
Action After Creating New Tasks=建立新工作後執行操作
Navigate to Task List Page=轉到工作清單頁面
Navigate to Task Detail Page=轉到工作詳情頁面

View File

@ -1035,7 +1035,19 @@
{
key: 'force-save',
category: 'global'
}
},
{
key: 'bt-seed-unverified',
category: 'bittorrent'
},
{
key: 'check-integrity',
category: 'bittorrent'
},
{
key: 'pause-metadata',
category: 'bittorrent'
},
]
});
}());

View File

@ -23,6 +23,7 @@
cachedDebugLogsLimit: 100
}).constant('ariaNgDefaultOptions', {
language: 'en',
theme: 'light',
title: '${downspeed}, ${upspeed} - ${title}',
titleRefreshInterval: 5000,
browserNotification: false,
@ -36,6 +37,8 @@
extendRpcServers: [],
globalStatRefreshInterval: 1000,
downloadTaskRefreshInterval: 1000,
swipeGesture: true,
dragAndDropTasks: true,
rpcListDisplayOrder: 'recentlyUsed',
afterCreatingNewTask: 'task-list',
removeOldTaskAfterRetrying: false,

View File

@ -151,6 +151,10 @@
'BT Download Completed': 'BT Download Completed',
'Download Error': 'Download Error',
'Language': 'Language',
'Theme': 'Theme',
'Light': 'Light',
'Dark': 'Dark',
'Follow system settings': 'Follow system settings',
'Debug Mode': 'Debug Mode',
'Page Title': 'Page Title',
'Preview': 'Preview',
@ -175,6 +179,8 @@
'Are you sure you want to remove rpc setting "{{rpcName}}"?': 'Are you sure you want to remove rpc setting "{{rpcName}}"?',
'Updating Global Stat Interval': 'Updating Global Stat Interval',
'Updating Task Information Interval': 'Updating Task Information Interval',
'Swipe Gesture': 'Swipe Gesture',
'Change Tasks Order by Drag-and-drop': 'Change Tasks Order by Drag-and-drop',
'Action After Creating New Tasks': 'Action After Creating New Tasks',
'Navigate to Task List Page': 'Navigate to Task List Page',
'Navigate to Task Detail Page': 'Navigate to Task Detail Page',

View File

@ -79,6 +79,10 @@
};
$scope.isSupportDragTask = function () {
if (!ariaNgSettingService.getDragAndDropTasks()) {
return false;
}
var displayOrder = ariaNgCommonService.parseOrderType(ariaNgSettingService.getDisplayOrder());
return location === 'waiting' && displayOrder.type === 'default';

View File

@ -93,7 +93,7 @@
$scope.context.currentTab = tabName;
};
$rootScope.swipeActions.extentLeftSwipe = function () {
$rootScope.swipeActions.extendLeftSwipe = function () {
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
if (tabIndex < tabOrders.length - 1) {
@ -104,7 +104,7 @@
}
};
$rootScope.swipeActions.extentRightSwipe = function () {
$rootScope.swipeActions.extendRightSwipe = function () {
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
if (tabIndex > 0) {

View File

@ -56,6 +56,7 @@
sessionSettings: ariaNgSettingService.getAllSessionOptions(),
rpcSettings: ariaNgSettingService.getAllRpcSettings(),
isSupportBlob: ariaNgFileService.isSupportBlob(),
isSupportDarkMode: ariaNgSettingService.isBrowserSupportDarkMode(),
importSettings: null,
exportSettings: null,
exportSettingsCopied: false
@ -92,7 +93,7 @@
$scope.context.titlePreview = getFinalTitle();
};
$rootScope.swipeActions.extentLeftSwipe = function () {
$rootScope.swipeActions.extendLeftSwipe = function () {
var tabIndex = -1;
if (!$scope.isCurrentGlobalTab()) {
@ -107,7 +108,7 @@
}
};
$rootScope.swipeActions.extentRightSwipe = function () {
$rootScope.swipeActions.extendRightSwipe = function () {
var tabIndex = -1;
if (!$scope.isCurrentGlobalTab()) {
@ -138,6 +139,11 @@
$scope.updateTitlePreview();
};
$scope.setTheme = function (value) {
ariaNgSettingService.setTheme(value);
$rootScope.setTheme(value);
};
$scope.setDebugMode = function (value) {
ariaNgSettingService.setDebugMode(value);
};
@ -179,6 +185,14 @@
ariaNgSettingService.setRPCListDisplayOrder(value);
};
$scope.setSwipeGesture = function (value) {
ariaNgSettingService.setSwipeGesture(value);
};
$scope.setDragAndDropTasks = function (value) {
ariaNgSettingService.setDragAndDropTasks(value);
};
$scope.setAfterCreatingNewTask = function (value) {
ariaNgSettingService.setAfterCreatingNewTask(value);
};

View File

@ -218,7 +218,7 @@
$scope.context.currentTab = tabName;
};
$rootScope.swipeActions.extentLeftSwipe = function () {
$rootScope.swipeActions.extendLeftSwipe = function () {
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
if (tabIndex < tabOrders.length - 1) {
@ -229,7 +229,7 @@
}
};
$rootScope.swipeActions.extentRightSwipe = function () {
$rootScope.swipeActions.extendRightSwipe = function () {
var tabIndex = tabOrders.indexOf($scope.context.currentTab);
if (tabIndex > 0) {

View File

@ -11,6 +11,10 @@
$(window, '.wrapper').resize(function () {
fixContentWrapperHeight();
setInterval(function(){
fixContentWrapperHeight();
}, 1);
});
fixContentWrapperHeight();

View File

@ -22,6 +22,43 @@
return false;
};
var setLightTheme = function () {
$rootScope.currentTheme = 'light';
angular.element('body').removeClass('theme-dark');
};
var setDarkTheme = function () {
$rootScope.currentTheme = 'dark';
angular.element('body').addClass('theme-dark');
};
var setThemeBySystemSettings = function () {
if (!ariaNgSettingService.isBrowserSupportDarkMode()) {
setLightTheme();
return;
}
var matchPreferColorScheme = $window.matchMedia('(prefers-color-scheme: dark)');
ariaNgLogService.info('[root.setThemeBySystemSettings] system uses ' + (matchPreferColorScheme.matches ? 'dark' : 'light') + ' theme');
if (matchPreferColorScheme.matches) {
setDarkTheme();
} else {
setLightTheme();
}
};
var initTheme = function () {
if (ariaNgSettingService.getTheme() === 'system') {
setThemeBySystemSettings();
} else if (ariaNgSettingService.getTheme() === 'dark') {
setDarkTheme();
} else {
setLightTheme();
}
};
var initCheck = function () {
var browserFeatures = ariaNgSettingService.getBrowserFeatures();
@ -90,6 +127,8 @@
return angular.element('body').hasClass('sidebar-open');
};
$rootScope.currentTheme = 'light';
$rootScope.searchContext = {
text: ''
};
@ -306,19 +345,27 @@
$rootScope.swipeActions = {
leftSwipe: function () {
if (!ariaNgSettingService.getSwipeGesture()) {
return;
}
if (isSidebarShowInSmallScreen()) {
hideSidebar();
return;
}
if (!this.extentLeftSwipe ||
(angular.isFunction(this.extentLeftSwipe) && !this.extentLeftSwipe())) {
if (!this.extendLeftSwipe ||
(angular.isFunction(this.extendLeftSwipe) && !this.extendLeftSwipe())) {
hideSidebar();
}
},
rightSwipe: function () {
if (!this.extentRightSwipe ||
(angular.isFunction(this.extentRightSwipe) && !this.extentRightSwipe())) {
if (!ariaNgSettingService.getSwipeGesture()) {
return;
}
if (!this.extendRightSwipe ||
(angular.isFunction(this.extendRightSwipe) && !this.extendRightSwipe())) {
showSidebar();
}
}
@ -328,6 +375,16 @@
$window.location.reload();
};
$rootScope.setTheme = function (theme) {
if (theme === 'system') {
setThemeBySystemSettings();
} else if (theme === 'dark') {
setDarkTheme();
} else {
setLightTheme();
}
};
ariaNgSettingService.onApplicationCacheUpdated(function () {
ariaNgLocalizationService.notifyInPage('', 'Application cache has been updated, please reload the page for the changes to take effect.', {
delay: false,
@ -381,8 +438,8 @@
$rootScope.loadPromise = null;
delete $rootScope.swipeActions.extentLeftSwipe;
delete $rootScope.swipeActions.extentRightSwipe;
delete $rootScope.swipeActions.extendLeftSwipe;
delete $rootScope.swipeActions.extendRightSwipe;
if (angular.isArray($rootScope.taskContext.list) && $rootScope.taskContext.list.length > 0) {
$rootScope.taskContext.list.length = 0;
@ -402,6 +459,22 @@
$document.unbind('keypress');
});
if (ariaNgSettingService.isBrowserSupportDarkMode()) {
var matchPreferColorScheme = $window.matchMedia('(prefers-color-scheme: dark)');
matchPreferColorScheme.addEventListener('change', function (e) {
ariaNgLogService.info('[root] system switches to ' + (e.matches ? 'dark' : 'light') + ' theme');
if (ariaNgSettingService.getTheme() === 'system') {
if (e.matches) {
setDarkTheme();
} else {
setLightTheme();
}
}
});
}
initTheme();
initCheck();
initNavbar();
}]);

View File

@ -6,12 +6,11 @@
restrict: 'E',
template: '<div></div>',
scope: {
options: '=ngData'
options: '=ngData',
theme: '=ngTheme'
},
link: function (scope, element, attrs) {
var options = {
ngTheme: 'default'
};
var options = {};
angular.extend(options, attrs);
@ -22,7 +21,7 @@
var height = parseInt(attrs.height) || parentHeight || 200;
wrapper.css('height', height + 'px');
var chart = echarts.init(wrapper[0], chartTheme.get(options.ngTheme));
var chart = echarts.init(wrapper[0], chartTheme.get(scope.theme));
var setOptions = function (value) {
chart.setOption(value);
@ -50,11 +49,11 @@
return {
restrict: 'A',
scope: {
options: '=ngData'
options: '=ngData',
theme: '=ngTheme'
},
link: function (scope, element, attrs) {
var options = {
ngTheme: 'default',
ngPopoverClass: '',
ngContainer: 'body',
ngTrigger: 'click',
@ -83,7 +82,7 @@
var height = parseInt(attrs.height) || parentHeight || 200;
wrapper.css('height', height + 'px');
chart = echarts.init(wrapper[0], chartTheme.get(options.ngTheme));
chart = echarts.init(wrapper[0], chartTheme.get(scope.theme));
}).on('hide.bs.popover', function () {
if (chart && !chart.isDisposed()) {
chart.dispose();
@ -105,14 +104,19 @@
}, true);
}
};
}]).factory('chartTheme', ['chartDefaultTheme', function (chartDefaultTheme) {
}]).factory('chartTheme', ['chartDefaultTheme', 'chartDarkTheme', function (chartDefaultTheme, chartDarkTheme) {
var themes = {
defaultTheme: chartDefaultTheme
defaultTheme: chartDefaultTheme,
darkTheme: chartDarkTheme,
};
return {
get: function (name) {
return themes[name + 'Theme'] ? themes[name + 'Theme'] : {};
if (name !== 'default' && themes[name + 'Theme']) {
return angular.extend({}, themes.defaultTheme, themes[name + 'Theme']);
} else {
return themes.defaultTheme;
}
}
};
}]).factory('chartDefaultTheme', function () {
@ -196,5 +200,63 @@
},
animationDuration: 500
};
}).factory('chartDarkTheme', function () {
return {
tooltip: {
show: true,
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
axisPointer: {
type: 'line',
lineStyle: {
color: '#ddd',
type: 'dashed',
width: 1
},
crossStyle: {
color: '#ddd',
width: 1
},
shadowStyle: {
color: 'rgba(200,200,200,0.2)'
}
}
},
categoryAxis: {
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
lineStyle: {
color: '#333'
}
}
},
valueAxis: {
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: true,
textStyle: {
color: '#eee',
}
},
splitLine: {
lineStyle: {
color: '#333'
}
},
splitArea: {
show: false
}
}
};
});
}());

View File

@ -13,6 +13,11 @@
})();
var browserSupportStorage = browserFeatures.localStroage || browserFeatures.cookies;
var browserSupportAppCache = !!$window.applicationCache;
var browserSupportMatchMedia = !!$window.matchMedia;
var browserSupportDarkMode = browserSupportMatchMedia
&& $window.matchMedia('(prefers-color-scheme: dark)')
&& $window.matchMedia('(prefers-color-scheme: dark)').media !== 'not all'
&& angular.isFunction($window.matchMedia('(prefers-color-scheme: dark)').addEventListener);
var onAppCacheUpdatedCallbacks = [];
var onFirstVisitCallbacks = [];
@ -60,6 +65,10 @@
continue;
}
if (langName.toLowerCase() === alias.toLowerCase()) {
return langName;
}
var language = ariaNgLanguages[langName];
var aliases = language.aliases;
@ -68,7 +77,7 @@
}
for (var i = 0; i < aliases.length; i++) {
if (aliases[i] === alias) {
if (aliases[i].toLowerCase() === alias.toLowerCase()) {
return langName;
}
}
@ -81,6 +90,7 @@
var browserLang = $window.navigator.browserLanguage ? $window.navigator.browserLanguage : $window.navigator.language;
if (!browserLang) {
ariaNgLogService.info('[ariaNgSettingService] cannot get browser language, use default language');
return ariaNgDefaultOptions.language;
}
@ -94,10 +104,25 @@
}
}
if (!ariaNgLanguages[browserLang] && browserLang.split('-').length > 1) { // maybe language-script-region
var langParts = browserLang.split('-');
browserLang = langParts[0] + '-' + langParts[1];
if (!ariaNgLanguages[browserLang]) {
var languageName = getLanguageNameFromAlias(browserLang);
if (languageName) {
browserLang = languageName;
}
}
}
if (!ariaNgLanguages[browserLang]) {
ariaNgLogService.info('[ariaNgSettingService] browser language \"' + browserLang + '\" not support, use default language');
return ariaNgDefaultOptions.language;
}
ariaNgLogService.info('[ariaNgSettingService] use browser language \"' + browserLang + '\" as current language');
return browserLang;
};
@ -215,6 +240,9 @@
isBrowserSupportApplicationCache: function () {
return browserSupportAppCache;
},
isBrowserSupportDarkMode: function () {
return browserSupportDarkMode;
},
getBrowserFeatures: function () {
return browserFeatures;
},
@ -326,6 +354,13 @@
setOption('language', value);
return true;
},
getTheme: function () {
return getOption('theme');
},
setTheme: function (value) {
setOption('theme', value);
return true;
},
isEnableDebugMode: function () {
return sessionSettings.debugMode;
},
@ -363,6 +398,18 @@
setDownloadTaskRefreshInterval: function (value) {
setOption('downloadTaskRefreshInterval', Math.max(parseInt(value), 0));
},
getSwipeGesture: function () {
return getOption('swipeGesture');
},
setSwipeGesture: function (value) {
setOption('swipeGesture', value);
},
getDragAndDropTasks: function () {
return getOption('dragAndDropTasks');
},
setDragAndDropTasks: function (value) {
setOption('dragAndDropTasks', value);
},
getRPCListDisplayOrder: function () {
return getOption('rpcListDisplayOrder');
},

View File

@ -101,7 +101,7 @@
}
.btn-spinner:not(:required) {
margin-left: -22px;
margin-left: -17px;
opacity: 0;
transition: 0.4s margin ease-out, 0.2s opacity ease-out;
}

View File

@ -4,11 +4,26 @@
margin-right: 15px;
}
@media screen and (orientation: landscape) {
.content > .new-task-table,
.tab-pane > .new-task-table {
margin-right: calc(15px + env(safe-area-inset-right));
}
}
.new-task-table > div.row {
padding-top: 8px;
padding-bottom: 8px;
}
@media screen and (orientation: landscape) {
.content > .new-task-table > div.row,
.tab-pane > .new-task-table > div.row {
margin-right: calc(-1 * calc(15px + env(safe-area-inset-right)));
padding-right: env(safe-area-inset-right);
}
}
.new-task-table > div.row:first-child {
border-top: inherit;
}

View File

@ -13,12 +13,24 @@
line-height: 11px;
}
@media screen and (orientation: landscape) {
.tab-pane > .piece-map {
padding-right: calc(2px + env(safe-area-inset-right));
}
}
.piece-legends {
text-align: center;
margin-top: 4px;
margin-bottom: 4px;
}
@media screen and (orientation: landscape) {
.tab-pane > .piece-legends {
padding-right: env(safe-area-inset-right);
}
}
.piece-legend {
display: inline-block;
margin-right: 4px;

View File

@ -4,6 +4,13 @@
margin-right: 15px;
}
@media screen and (orientation: landscape) {
.content > .settings-table,
.tab-pane > .settings-table {
margin-right: calc(15px + env(safe-area-inset-right));
}
}
.settings-table .settings-table-title {
font-size: 12px;
padding-top: 4px;
@ -20,6 +27,14 @@
border-top: 1px solid #ddd;
}
@media screen and (orientation: landscape) {
.content > .settings-table > div.row,
.tab-pane > .settings-table > div.row {
margin-right: calc(-1 * calc(15px + env(safe-area-inset-right)));
padding-right: env(safe-area-inset-right);
}
}
.settings-table > div.row:first-child {
border-top: inherit;
}

View File

@ -4,6 +4,13 @@
margin-right: 15px;
}
@media screen and (orientation: landscape) {
.content > .task-table,
.tab-pane > .task-table {
margin-right: calc(15px + env(safe-area-inset-right));
}
}
.task-table .task-table-title {
font-size: 12px;
padding-top: 4px;
@ -22,6 +29,14 @@
cursor: -webkit-grab;
}
@media screen and (orientation: landscape) {
.content > .task-table div.row,
.tab-pane > .task-table div.row {
margin-right: calc(-1 * calc(15px + env(safe-area-inset-right)));
padding-right: env(safe-area-inset-right);
}
}
.task-table > .task-table-body > div.row {
padding-top: 8px;
padding-bottom: 8px;

View File

@ -18,6 +18,23 @@ body {
user-select: none;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23555555%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E') !important;
background-repeat: no-repeat, repeat !important;
background-position: right 0.7em top 50%, 0 0 !important;
background-size: 0.65em auto, 100% !important;
border: none;
border-radius: 0;
padding: 0 0 0 0.35em;
}
select::-ms-expand {
display: none;
}
td {
vertical-align: middle !important;
}
@ -88,6 +105,26 @@ td {
z-index: 1010;
}
.main-sidebar .sidebar-menu > li.treeview > ul.treeview-menu > li > a {
padding: 6px 5px 6px 41px;
}
@supports (padding-left: max(15px, 0px)) {
@media screen and (orientation: landscape) {
.main-sidebar ul.sidebar-menu > li.header {
padding-left: max(15px, env(safe-area-inset-left));
}
.main-sidebar ul.sidebar-menu > li > a {
padding-left: max(15px, env(safe-area-inset-left));
}
.main-sidebar ul.sidebar-menu > li.treeview > ul.treeview-menu > li > a {
padding-left: max(41px, calc(26px + env(safe-area-inset-left)));
}
}
}
.content-wrapper {
min-height: calc(100vh - 48px);
}
@ -100,6 +137,12 @@ td {
overflow-y: scroll;
}
@media screen and (orientation: portrait) {
.main-footer {
padding-bottom: calc(15px + env(safe-area-inset-bottom));
}
}
.main-footer > .navbar {
margin-bottom: 0;
min-height: inherit;

View File

@ -3,6 +3,11 @@
margin-left: 4px;
}
.btn-sm.promise-btn-style {
padding-top: 6px;
padding-bottom: 6px;
}
.progress-bar {
-webkit-transition: initial !important;
-moz-transition: initial !important;

View File

@ -0,0 +1,417 @@
/* skin-aria-ng core */
.theme-dark.skin-aria-ng {
color: #eee;
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng select {
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23cccccc%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E') !important;
}
.theme-dark.skin-aria-ng .cg-busy-backdrop {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .btn-default {
color: #eee;
border-color: #3f3f3f;
background-color: #333;
}
.theme-dark.skin-aria-ng .btn-default:hover,
.theme-dark.skin-aria-ng .btn-default:active,
.theme-dark.skin-aria-ng .btn-default.hover {
color: #fff;
background-color: #444;
}
.theme-dark.skin-aria-ng .close {
color: #eee;
}
.theme-dark.skin-aria-ng pre {
background-color: #121212;
border-color: #666;
color: #eee;
}
.theme-dark.skin-aria-ng .form-control {
background-color: #121212;
border-color: #666;
color: #eee;
}
.theme-dark.skin-aria-ng .form-control:focus {
border-color: #5399e8;
}
.theme-dark.skin-aria-ng .form-control[disabled],
.theme-dark.skin-aria-ng .form-control[readonly],
.theme-dark.skin-aria-ng fieldset[disabled] .form-control {
background-color: #333;
}
.theme-dark.skin-aria-ng .input-group-addon {
color: #eee;
border-color: #666;
background-color: #333;
}
.theme-dark.skin-aria-ng .input-group.input-group-multiple > .input-group-addon:first-child,
.theme-dark.skin-aria-ng .input-group.input-group-multiple > .input-group-addon-container:first-child {
border-color: #666;
}
.theme-dark.skin-aria-ng .progress {
background-color: #444;
}
.theme-dark.skin-aria-ng .nav-tabs-custom {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs {
border-color: #333;
}
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li > a {
color: #ddd;
}
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li.active > a,
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li.active:hover > a {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li > a:hover,
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li > a:active,
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li.active > a {
color: #208fe5;
}
.theme-dark.skin-aria-ng .nav-tabs-custom > .nav-tabs > li.divider {
border-color: #666;
}
.theme-dark.skin-aria-ng .nav-tabs-custom>.tab-content {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .popover {
background-color: #1a1a1a;
border-color: rgba(0, 0, 0, 0.6);
}
.theme-dark.skin-aria-ng .popover.top .arrow:after {
border-top-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .popover.right .arrow:after {
border-right-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .popover.bottom .arrow:after {
border-bottom-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .popover.left .arrow:after {
border-left-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .modal-header {
border-color: #333;
}
.theme-dark.skin-aria-ng .modal-content {
background-color: #1a1a1a;
border-color: rgba(0, 0, 0, 0.6);
}
.theme-dark.skin-aria-ng .modal-footer {
border-color: #333;
}
.theme-dark.skin-aria-ng .dropdown-menu {
background-color: #1a1a1a;
border-color: #333;
}
.theme-dark.skin-aria-ng .dropdown-menu > li > a {
color: #eee;
}
.theme-dark.skin-aria-ng .dropdown-menu > li > a:hover {
color: #fff;
background-color: #333;
}
.theme-dark.skin-aria-ng .dropdown-menu > li.dropdown-submenu:hover {
background-color: #333;
}
.theme-dark.skin-aria-ng .dropdown-menu > .divider {
background-color: #666;
}
.theme-dark.skin-aria-ng .sweet-overlay {
background-color: rgba(0, 0, 0, 0.6);
}
.theme-dark.skin-aria-ng .sweet-alert {
background-color: #222;
}
.theme-dark.skin-aria-ng .sweet-alert h2,
.theme-dark.skin-aria-ng .sweet-alert p {
color: #ddd;
}
.theme-dark.skin-aria-ng .sweet-alert .sa-icon.sa-success::before,
.theme-dark.skin-aria-ng .sweet-alert .sa-icon.sa-success::after,
.theme-dark.skin-aria-ng .sweet-alert .sa-icon.sa-success .sa-fix {
background-color: #222;
}
.theme-dark.skin-aria-ng .main-header .navbar {
background-color: #121212;
border-color: #333;
}
.theme-dark.skin-aria-ng .main-header .navbar .nav > li > a {
color: #eee;
}
.theme-dark.skin-aria-ng .main-header .navbar .nav > li > a:hover,
.theme-dark.skin-aria-ng .main-header .navbar .nav > li > a:active,
.theme-dark.skin-aria-ng .main-header .navbar .nav > li > a:focus,
.theme-dark.skin-aria-ng .main-header .navbar .nav .open > a,
.theme-dark.skin-aria-ng .main-header .navbar .nav .open > a:hover,
.theme-dark.skin-aria-ng .main-header .navbar .nav .open > a:focus,
.theme-dark.skin-aria-ng .main-header .navbar .nav > .active > a {
color: #0080ff;
background-color: transparent;
}
.theme-dark.skin-aria-ng .main-header .navbar .nav > li > a:active,
.theme-dark.skin-aria-ng .main-header .navbar .nav .open > a,
.theme-dark.skin-aria-ng .main-header .navbar .nav .open > a:hover,
.theme-dark.skin-aria-ng .main-header .navbar .nav .open > a:focus {
background-color: #444;
}
.theme-dark.skin-aria-ng .main-header .navbar .nav > li.disabled > a {
color: #8f8f8f !important;
}
.theme-dark.skin-aria-ng .main-header .navbar .nav > li.divider {
border-color: #666;
}
.theme-dark.skin-aria-ng .main-header .logo {
background-color: #282828;
border-color: #222;
}
.theme-dark.skin-aria-ng .main-header .logo .dropdown-menu > li.active > a {
color: #eee;
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .main-header .logo .dropdown-menu > li.active:hover > a {
color: #fff;
background-color: #333;
}
.theme-dark.skin-aria-ng .wrapper,
.theme-dark.skin-aria-ng .main-sidebar,
.theme-dark.skin-aria-ng .left-side {
background-color: #282828;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.header {
color: #ccc;
background-color: #3c3c3c;
}
.theme-dark.skin-aria-ng .sidebar-menu > li:hover > a {
color: #fff;
background-color: #444;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.active > a {
color: #5399e8;
background-color: #333;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview:hover > a {
color: #fff;
background-color: #282828;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview.active > a,
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview.active:hover > a {
color: #5399e8;
background-color: #282828;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview > a:hover {
color: #fff;
background-color: #444;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview > ul.treeview-menu {
background-color: #282828;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview > ul.treeview-menu > li > a {
color: #eee;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview > ul.treeview-menu > li > a:hover {
color: #fff;
background-color: #444;
}
.theme-dark.skin-aria-ng .sidebar-menu > li.treeview > ul.treeview-menu > li.active > a {
color: #5399e8;
background-color: #333;
}
.theme-dark.skin-aria-ng .sidebar a {
color: #eee;
}
.theme-dark.skin-aria-ng .content-wrapper, .theme-dark.right-side {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .main-footer {
background-color: #1a1a1a;
border-color: #383838;
}
.theme-dark.skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li > a {
color: #eee;
}
.theme-dark.skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li > a:hover,
.theme-dark.skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li > a:active,
.theme-dark.skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li > a:focus,
.theme-dark.skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li.open > a {
color: #0080ff;
background: none;
}
.theme-dark.skin-aria-ng .main-footer > .navbar > .navbar-toolbar > .nav > li.divider {
border-color: #666;
}
.theme-dark.skin-aria-ng .global-status {
color: #eee;
}
.theme-dark.skin-aria-ng input::-webkit-input-placeholder,
.theme-dark.skin-aria-ng input:-moz-placeholder,
.theme-dark.skin-aria-ng input::-moz-placeholder,
.theme-dark.skin-aria-ng input:-ms-input-placeholder {
color: #aaa;
}
.theme-dark.skin-aria-ng select.placeholder {
color: #aaa;
}
/* angular-input-dropdown */
.theme-dark.skin-aria-ng .input-dropdown ul > li {
background-color: #121212;
}
.theme-dark.skin-aria-ng .input-dropdown ul > li.active {
background-color: #333;
}
/* cg-busy */
.theme-dark.skin-aria-ng .cg-busy-default-sign {
color: #eee;
border-color: #666;
background-color: #444;
text-shadow: 0 1px 1px #000;
}
.theme-dark.skin-aria-ng .cg-busy-default-text {
color: #eee;
}
.theme-dark.skin-aria-ng .cg-busy-default-spinner div {
background-color: #eee;
}
/* scrollbar */
.theme-dark.skin-aria-ng ::-webkit-scrollbar-thumb {
background-color: #3c4144;
}
/* piece-bar / piece-map */
.theme-dark.skin-aria-ng .piece-map .piece,
.theme-dark.skin-aria-ng .piece-legend > .piece {
background-color: #242424;
border-color: #3c3d3e;
}
.theme-dark.skin-aria-ng .piece-map .piece.piece-completed,
.theme-dark.skin-aria-ng .piece-legend > .piece.piece-completed {
background-color: #b8dd69;
border-color: #b8dd69;
}
/* task-table */
.theme-dark.skin-aria-ng .task-table {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .task-table .task-table-title a {
color: #eee;
}
.theme-dark.skin-aria-ng .task-table > .task-table-body > div.row {
border-color: #333;
}
.theme-dark.skin-aria-ng .task-table > .task-table-body > div.row:nth-of-type(odd) {
background-color: #262626;
}
.theme-dark.skin-aria-ng .task-table > .task-table-body > div.row:hover {
background-color: #2a2a2a;
}
.theme-dark.skin-aria-ng .task-table .progress span.progress-lower {
color: #eee;
}
/* settings-table */
.theme-dark.skin-aria-ng .settings-table {
background-color: #1a1a1a;
}
.theme-dark.skin-aria-ng .settings-table > div.row {
border-color: #333;
}
.theme-dark.skin-aria-ng .settings-table.striped > div.row:nth-of-type(odd) {
background-color: #202020;
}
.theme-dark.skin-aria-ng .settings-table.hoverable > div.row:hover {
background-color: #242424;
}
.theme-dark.skin-aria-ng .settings-table.hoverable > div.row:nth-of-type(odd).no-hover:hover {
background-color: #202020;
}
/* new-task-table */
.theme-dark.skin-aria-ng .new-task-table {
background-color: #1a1a1a;
}

View File

@ -162,7 +162,6 @@
.skin-aria-ng .sidebar-menu > li.treeview > ul.treeview-menu > li > a {
color: #8aa4af;
padding: 6px 5px 6px 41px;
}
.skin-aria-ng .sidebar-menu > li.treeview > ul.treeview-menu > li > a:hover {

View File

@ -38,6 +38,19 @@
</select>
</div>
</div>
<div class="row">
<div class="setting-key setting-key-without-desc col-sm-4">
<span translate>Theme</span>
</div>
<div class="setting-value col-sm-8">
<select class="form-control" style="width: 100%;" ng-model="context.settings.theme"
ng-change="setTheme(context.settings.theme)">
<option value="light" translate>Light</option>
<option value="dark" translate>Dark</option>
<option ng-if="context.isSupportDarkMode" value="system" translate>Follow system settings</option>
</select>
</div>
</div>
<div class="row" ng-if="context.showDebugMode">
<div class="setting-key setting-key-without-desc col-sm-4">
<span translate>Debug Mode</span>
@ -122,6 +135,28 @@
</select>
</div>
</div>
<div class="row">
<div class="setting-key setting-key-without-desc col-sm-4">
<span translate>Swipe Gesture</span>
</div>
<div class="setting-value col-sm-8">
<select class="form-control" style="width: 100%;" ng-model="context.settings.swipeGesture"
ng-change="setSwipeGesture(context.settings.swipeGesture)"
ng-options="option.value as (option.name | translate) for option in context.trueFalseOptions">
</select>
</div>
</div>
<div class="row">
<div class="setting-key setting-key-without-desc col-sm-4">
<span translate>Change Tasks Order by Drag-and-drop</span>
</div>
<div class="setting-value col-sm-8">
<select class="form-control" style="width: 100%;" ng-model="context.settings.dragAndDropTasks"
ng-change="setDragAndDropTasks(context.settings.dragAndDropTasks)"
ng-options="option.value as (option.name | translate) for option in context.trueFalseOptions">
</select>
</div>
</div>
<div class="row">
<div class="setting-key setting-key-without-desc col-sm-4">
<span translate>RPC List Display Order</span>

View File

@ -43,12 +43,8 @@
<span translate>Operations</span>
</div>
<div class="setting-value col-sm-8">
<button class="btn btn-sm btn-primary" ng-click="saveSession()" promise-btn>
<span translate>Save Session</span>
</button>
<button class="btn btn-sm btn-danger" ng-click="shutdown()">
<span translate>Shutdown Aria2</span>
</button>
<button class="btn btn-sm btn-primary" ng-click="saveSession()" promise-btn><span translate>Save Session</span></button>
<button class="btn btn-sm btn-danger promise-btn-style" ng-click="shutdown()"><span translate>Shutdown Aria2</span></button>
</div>
</div>
</div>

View File

@ -160,7 +160,7 @@
<div class="row no-hover no-background" ng-if="context.isEnableSpeedChart && task && task.status === 'active'">
<div class="col-sm-12">
<div class="task-status-chart-wrapper">
<ng-chart ng-data="context.statusData" height="200"></ng-chart>
<ng-chart ng-data="context.statusData" ng-theme="currentTheme" height="200"></ng-chart>
</div>
</div>
</div>

7
update.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p nodePackages.node2nix
node2nix \
-d \
--nodejs-10 \
-c AriaNg.nix \
-l package-lock.json