From 8edd13a083f13e466e4bbd39f21a832df2b35804 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 13 Jan 2023 09:32:26 +0100 Subject: [PATCH 01/76] Update dependencies --- package.json | 2 +- qortal-ui-core/package.json | 17 +- .../login-view/create-account-section.js | 14 +- .../random-sentence-generator.js | 160 ++++++++++++++++++ .../functional-components/verb-past-tense.js | 36 ++++ .../src/functional-components/wordlists.js | 27 +++ qortal-ui-plugins/package.json | 16 +- 7 files changed, 247 insertions(+), 25 deletions(-) create mode 100644 qortal-ui-core/src/functional-components/random-sentence-generator.js create mode 100644 qortal-ui-core/src/functional-components/verb-past-tense.js create mode 100644 qortal-ui-core/src/functional-components/wordlists.js diff --git a/package.json b/package.json index 67893cef..f1e5a6b9 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "os-locale": "3.0.0" }, "devDependencies": { - "electron": "22.0.0", + "electron": "22.0.2", "electron-builder": "23.6.0", "electron-packager": "17.1.1", "@electron/notarize": "1.2.3", diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index d5b00b64..d52b6ab0 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -58,23 +58,22 @@ "@rollup/plugin-commonjs": "24.0.0", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.2.1", - "@vaadin/button": "23.3.2", - "@vaadin/grid": "23.3.2", - "@vaadin/icons": "23.3.2", - "@vaadin/password-field": "23.3.2", - "@vaadin/tooltip": "23.3.2", + "@rollup/plugin-terser": "0.3.0", + "@vaadin/button": "23.3.3", + "@vaadin/grid": "23.3.3", + "@vaadin/icons": "23.3.3", + "@vaadin/password-field": "23.3.3", + "@vaadin/tooltip": "23.3.3", "asmcrypto.js": "2.3.2", "bcryptjs": "2.4.3", "epml": "0.3.3", "file-saver": "2.0.5", - "lit": "2.5.0", + "lit": "2.6.1", "lit-translate": "2.0.1", "pwa-helpers": "0.9.1", - "random-sentence-generator": "0.0.8", "redux": "4.2.0", "redux-thunk": "2.4.2", - "rollup": "3.9.1", + "rollup": "3.10.0", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0" diff --git a/qortal-ui-core/src/components/login-view/create-account-section.js b/qortal-ui-core/src/components/login-view/create-account-section.js index b285118f..48c27985 100644 --- a/qortal-ui-core/src/components/login-view/create-account-section.js +++ b/qortal-ui-core/src/components/login-view/create-account-section.js @@ -4,11 +4,13 @@ import { store } from '../../store.js' import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate' import { createWallet } from '../../../../qortal-ui-crypto/api/createWallet.js' -import FileSaver from 'file-saver' import { doLogin, doLogout, doSelectAddress } from '../../redux/app/app-actions.js' import { doStoreWallet } from '../../redux/user/user-actions.js' import { checkApiKey } from '../../apiKeyUtils.js' +import FileSaver from 'file-saver' +import ripple from '../../functional-components/loading-ripple.js' import snackbar from '../../functional-components/snackbar.js' +import '../../functional-components/random-sentence-generator.js' import '@material/mwc-button' import '@material/mwc-checkbox' import '@material/mwc-textfield' @@ -22,8 +24,6 @@ import '@polymer/paper-input/paper-input.js' import '@polymer/paper-tooltip/paper-tooltip.js' import '@vaadin/text-field/vaadin-text-field.js' import '@vaadin/password-field/vaadin-password-field.js' -import 'random-sentence-generator' -import ripple from '../../functional-components/loading-ripple.js' let lastPassword = '' @@ -393,17 +393,17 @@ class CreateAccountSection extends connect(store)(LitElement) {
diff --git a/qortal-ui-core/src/functional-components/random-sentence-generator.js b/qortal-ui-core/src/functional-components/random-sentence-generator.js new file mode 100644 index 00000000..b9482fb5 --- /dev/null +++ b/qortal-ui-core/src/functional-components/random-sentence-generator.js @@ -0,0 +1,160 @@ +// Author: irontiga + +'use strict' +import { LitElement, html, css } from 'lit' +import * as WORDLISTS from './wordlists.js' + +class RandomSentenceGenerator extends LitElement { + static get properties() { + return { + template: { + type: String, + attribute: 'template' + }, + parsedString: { + type: String + }, + fetchedWordlistCount: { + type: Number, + value: 0 + }, + capitalize: { + type: Boolean + }, + partsOfSpeechMap: { + type: Object + }, + templateEntropy: { + type: Number, + reflect: true, + attribute: 'template-entropy' + }, + maxWordLength: { + type: Number, + attribute: 'max-word-length' + } + } + } + + constructor() { + super() + this.template = 'adjective noun verb adverb.' + this.maxWordLength = 0 + this.parsedString = '' + this.fetchedWordlistCount = 0 + this.capitalize = true + this.partsOfSpeechMap = { + 'noun': 'nouns', + 'adverb': 'adverbs', + 'adv': 'adverbs', + 'verb': 'verbs', + 'interjection': 'interjections', + 'adjective': 'adjectives', + 'adj': 'adjectives', + 'verbed': 'verbed' + } + this.partsOfSpeech = Object.keys(this.partsOfSpeechMap) + this._wordlists = WORDLISTS + } + + updated(changedProperties) { + let regen = false + if (changedProperties.has('template')) { + regen = true + } + if (changedProperties.has('maxWordLength')) { + console.dir(this.maxWordLength) + if (this.maxWordLength) { + const wl = { ...this._wordlists } + for (const partOfSpeech in this._wordlists) { + console.log(this._wordlists[partOfSpeech]) + if (Array.isArray(this._wordlists[partOfSpeech])) { + wl[partOfSpeech] = this._wordlists[partOfSpeech].filter(word => word.length <= this.maxWordLength) + } + } + this._wordlists = wl + } + regen = true + } + if (regen) this.generate() + } + + _RNG(entropy) { + if (entropy > 1074) { + throw new Error('Javascript can not handle that much entropy!') + } + let randNum = 0 + const crypto = window.crypto || window.msCrypto + + if (crypto) { + const entropy256 = Math.ceil(entropy / 8) + + let buffer = new Uint8Array(entropy256) + crypto.getRandomValues(buffer) + + randNum = buffer.reduce((num, value) => { + return num * value + }, 1) / Math.pow(256, entropy256) + } else { + console.warn('Secure RNG not found. Using Math.random') + randNum = Math.random() + } + return randNum + } + + setRNG(fn) { + this._RNG = fn + } + + _captitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1) + } + + getWord(partOfSpeech) { + const words = this._wordlists[this.partsOfSpeechMap[partOfSpeech]] + const requiredEntropy = Math.log(words.length) / Math.log(2) + const index = this._RNG(requiredEntropy) * words.length + + return { + word: words[Math.round(index)], + entropy: words.length + } + } + + generate() { + this.parsedString = this.parse(this.template) + } + + parse(template) { + const split = template.split(/[\s]/g) + let entropy = 1 + const final = split.map(word => { + const lower = word.toLowerCase() + + this.partsOfSpeech.some(partOfSpeech => { + const partOfSpeechIndex = lower.indexOf(partOfSpeech) // Check it exists + const nextChar = word.charAt(partOfSpeech.length) + + if (partOfSpeechIndex === 0 && !(nextChar && (nextChar.match(/[a-zA-Z]/g) != null))) { + const replacement = this.getWord(partOfSpeech) + word = replacement.word + word.slice(partOfSpeech.length) // Append the rest of the "word" (punctuation) + entropy = entropy * replacement.entropy + return true + } + }) + return word + }) + this.templateEntropy = Math.floor(Math.log(entropy) / Math.log(8)) + return final.join(' ') + } + + render() { + return html` + ${this.parsedString} + ` + } +} + +customElements.define('random-sentence-generator', RandomSentenceGenerator) + +export default RandomSentenceGenerator diff --git a/qortal-ui-core/src/functional-components/verb-past-tense.js b/qortal-ui-core/src/functional-components/verb-past-tense.js new file mode 100644 index 00000000..198e80e9 --- /dev/null +++ b/qortal-ui-core/src/functional-components/verb-past-tense.js @@ -0,0 +1,36 @@ +// Sourced from https://gist.github.com/letsgetrandy/1e05a68ea74ba6736eb5 + +export const EXCEPTIONS = { + 'are': 'were', + 'eat': 'ate', + 'go': 'went', + 'have': 'had', + 'inherit': 'inherited', + 'is': 'was', + 'run': 'ran', + 'sit': 'sat', + 'visit': 'visited' +} + +export const getPastTense = (verb, exceptions = EXCEPTIONS) => { + if (exceptions[verb]) { + return exceptions[verb] + } + if ((/e$/i).test(verb)) { + return verb + 'd' + } + if ((/[aeiou]c$/i).test(verb)) { + return verb + 'ked' + } + // for american english only + if ((/el$/i).test(verb)) { + return verb + 'ed' + } + if ((/[aeio][aeiou][dlmnprst]$/).test(verb)) { + return verb + 'ed' + } + if ((/[aeiou][bdglmnprst]$/i).test(verb)) { + return verb.replace(/(.+[aeiou])([bdglmnprst])/, '$1$2$2ed') + } + return verb + 'ed' +} diff --git a/qortal-ui-core/src/functional-components/wordlists.js b/qortal-ui-core/src/functional-components/wordlists.js new file mode 100644 index 00000000..903889a7 --- /dev/null +++ b/qortal-ui-core/src/functional-components/wordlists.js @@ -0,0 +1,27 @@ +import { getPastTense } from './verb-past-tense.js' + +export const verbs = [ + 'abase', 'abate', 'abduct', 'abet', 'abhor', 'abide', 'abjure', 'ablate', 'abort', 'abound', 'abseil', 'absorb', 'abuse', 'abut', 'accede', 'accent', 'accept', 'access', 'accord', 'accost', 'accrue', 'accuse', 'ache', 'acquit', 'act', 'adapt', 'add', 'addict', 'addle', 'adduce', 'adhere', 'adjoin', 'adjust', 'admire', 'admit', 'adopt', 'adore', 'adorn', 'advert', 'advise', 'aerate', 'affect', 'affirm', 'affix', 'afford', 'age', 'agree', 'aid', 'aim', 'alarm', 'alert', 'alight', 'align', 'allay', 'allege', 'allot', 'allow', 'alloy', 'allure', 'ally', 'alter', 'amass', 'amaze', 'amble', 'ambush', 'amend', 'amount', 'amuse', 'anger', 'angle', 'anneal', 'annex', 'annoy', 'annul', 'anoint', 'answer', 'ape', 'appeal', 'appear', 'append', 'apply', 'arc', 'arch', 'argue', 'arise', 'arm', 'array', 'arrest', 'arrive', 'arrow', 'ascend', 'ask', 'aspire', 'assail', 'assay', 'assent', 'assert', 'assess', 'assign', 'assist', 'assort', 'assume', 'assure', 'atone', 'attach', 'attack', 'attain', 'attend', 'attest', 'attire', 'attune', 'audit', 'augur', 'author', 'avail', 'avenge', 'aver', 'avert', 'avoid', 'await', 'awake', 'awaken', 'award', 'awe', 'babble', 'back', 'badge', 'badger', 'baffle', 'bag', 'bail', 'bait', 'bake', 'bald', 'bale', 'ball', 'ballot', 'ban', 'band', 'bandy', 'bang', 'banish', 'bank', 'banter', 'bar', 'barb', 'barber', 'bard', 'bare', 'barge', 'bark', 'barn', 'barrel', 'barter', 'base', 'bash', 'bask', 'baste', 'bat', 'batch', 'bathe', 'batten', 'batter', 'battle', 'bawl', 'bay', 'be', 'beach', 'beacon', 'bead', 'beam', 'bean', 'bear', 'beard', 'beat', 'become', 'bed', 'beef', 'beep', 'beetle', 'befall', 'befit', 'beg', 'beget', 'beggar', 'begin', 'behave', 'behead', 'behold', 'belay', 'belch', 'belie', 'bell', 'bellow', 'belly', 'belong', 'belt', 'bemoan', 'bench', 'bend', 'berate', 'berry', 'beset', 'best', 'bestir', 'bestow', 'bet', 'betide', 'betray', 'better', 'bevel', 'bewail', 'beware', 'bias', 'bib', 'bicker', 'bid', 'bide', 'bilge', 'bill', 'billet', 'billow', 'bin', 'bind', 'birdie', 'birth', 'bisect', 'bit', 'bite', 'bitter', 'black', 'blame', 'blanch', 'blank', 'blare', 'blast', 'blaze', 'bleach', 'bleat', 'bleed', 'bleep', 'blench', 'blend', 'bless', 'blight', 'blind', 'blink', 'blip', 'bliss', 'blitz', 'bloat', 'blob', 'blood', 'bloody', 'bloom', 'blot', 'blotch', 'blow', 'blue', 'bluff', 'blunt', 'blur', 'blurb', 'blurt', 'blush', 'board', 'boast', 'bob', 'bode', 'body', 'bog', 'bogey', 'boggle', 'boil', 'bolt', 'bomb', 'bond', 'bone', 'bonnet', 'boo', 'book', 'boom', 'boost', 'boot', 'booze', 'bop', 'bore', 'borrow', 'boss', 'botch', 'bother', 'bottle', 'bottom', 'bounce', 'bound', 'bout', 'bow', 'bowel', 'bowl', 'box', 'brace', 'brag', 'braid', 'braise', 'brake', 'branch', 'brand', 'brave', 'brawl', 'bray', 'breach', 'bread', 'break', 'breed', 'breeze', 'brew', 'bribe', 'brick', 'bridge', 'bridle', 'brief', 'brim', 'brine', 'bring', 'broach', 'broil', 'bronze', 'brook', 'brown', 'browse', 'bruise', 'brush', 'bubble', 'buck', 'bucket', 'buckle', 'bud', 'budge', 'budget', 'buffet', 'bug', 'bugle', 'build', 'bulge', 'bulk', 'bull', 'bully', 'bumble', 'bump', 'bunch', 'bundle', 'bung', 'bungle', 'bunk', 'bunker', 'buoy', 'burble', 'burden', 'burgle', 'burn', 'burp', 'burr', 'burrow', 'burst', 'bury', 'bus', 'bush', 'busk', 'bust', 'bustle', 'busy', 'butt', 'button', 'buy', 'buzz', 'bypass', 'cab', 'cabal', 'cabin', 'cable', 'cache', 'cackle', 'cadge', 'cage', 'cajole', 'cake', 'call', 'calm', 'calve', 'camber', 'camp', 'can', 'canal', 'cancel', 'candle', 'candy', 'cane', 'cannon', 'canoe', 'canopy', 'cant', 'canter', 'cap', 'caper', 'card', 'care', 'career', 'caress', 'carol', 'carp', 'carpet', 'carry', 'cart', 'carve', 'case', 'cash', 'cast', 'castle', 'cat', 'catch', 'cater', 'caucus', 'cause', 'cave', 'cavern', 'cease', 'cede', 'cellar', 'cement', 'censor', 'chafe', 'chain', 'chair', 'chalk', 'champ', 'chance', 'change', 'chant', 'chap', 'char', 'charge', 'charm', 'chart', 'chase', 'chat', 'cheat', 'check', 'cheep', 'cheer', 'chew', 'chide', 'chill', 'chime', 'chin', 'chink', 'chip', 'chirp', 'chisel', 'chock', 'choir', 'choke', 'choose', 'chop', 'chord', 'chorus', 'chrome', 'chuck', 'chuff', 'chug', 'chum', 'chunk', 'churn', 'chute', 'cinder', 'cipher', 'circle', 'cite', 'clad', 'claim', 'clam', 'clamp', 'clang', 'clank', 'clap', 'clash', 'clasp', 'class', 'claw', 'clean', 'clear', 'cleat', 'cleave', 'clench', 'clerk', 'click', 'climax', 'climb', 'clinch', 'cling', 'clink', 'clip', 'clique', 'cloak', 'clock', 'clog', 'clone', 'close', 'closet', 'clot', 'cloud', 'clout', 'clown', 'club', 'cluck', 'clue', 'clump', 'clutch', 'coach', 'coal', 'coast', 'coat', 'coax', 'cobble', 'cobweb', 'cockle', 'cocoon', 'coddle', 'code', 'codify', 'coerce', 'coffer', 'coffin', 'cog', 'cohere', 'coil', 'coin', 'coke', 'collar', 'comb', 'combat', 'come', 'commit', 'compel', 'comply', 'con', 'concur', 'cone', 'confer', 'convey', 'convoy', 'cook', 'cool', 'cope', 'copper', 'copy', 'cord', 'cordon', 'core', 'cork', 'corn', 'corner', 'corral', 'cosset', 'cost', 'cotton', 'couch', 'cough', 'count', 'couple', 'course', 'court', 'cover', 'covet', 'cowl', 'cox', 'crab', 'crack', 'cradle', 'craft', 'cram', 'cramp', 'crane', 'crank', 'crash', 'crate', 'crater', 'crave', 'crawl', 'crayon', 'craze', 'creak', 'cream', 'crease', 'create', 'credit', 'creed', 'creep', 'crest', 'crew', 'crib', 'crick', 'crimp', 'cringe', 'crisp', 'croak', 'crook', 'croon', 'crop', 'cross', 'crouch', 'crowd', 'crown', 'cruise', 'crunch', 'crush', 'crust', 'crutch', 'cry', 'cube', 'cuckoo', 'cuddle', 'cudgel', 'cue', 'cuff', 'cull', 'cup', 'curb', 'curd', 'curdle', 'cure', 'curl', 'curry', 'curse', 'curve', 'cuss', 'cut', 'cycle', 'dab', 'dabble', 'dagger', 'dally', 'dam', 'damage', 'damn', 'damp', 'dampen', 'dance', 'dangle', 'dapple', 'dare', 'darken', 'darn', 'dart', 'dash', 'date', 'daub', 'daunt', 'dawdle', 'daze', 'dazzle', 'deaden', 'deafen', 'deal', 'debar', 'debase', 'debate', 'debit', 'debug', 'debut', 'decamp', 'decant', 'decay', 'decide', 'deck', 'decode', 'decoy', 'decree', 'decry', 'deduce', 'deduct', 'deem', 'deepen', 'deface', 'defame', 'defeat', 'defect', 'defend', 'defer', 'defile', 'define', 'deform', 'defray', 'defuse', 'defy', 'deify', 'deign', 'delay', 'delete', 'delude', 'deluge', 'delve', 'demand', 'demean', 'demise', 'demote', 'demur', 'den', 'denote', 'dent', 'denude', 'deny', 'depart', 'depend', 'depict', 'deploy', 'deport', 'depose', 'depute', 'derail', 'deride', 'derive', 'desert', 'design', 'desire', 'desist', 'detach', 'detail', 'detain', 'detect', 'deter', 'detest', 'detour', 'devil', 'devise', 'devote', 'devour', 'dial', 'diaper', 'dice', 'die', 'diet', 'differ', 'dig', 'digest', 'dilate', 'dilute', 'dim', 'dimple', 'din', 'dine', 'dint', 'dip', 'direct', 'disarm', 'disc', 'disco', 'dish', 'dismay', 'disown', 'dispel', 'disuse', 'ditch', 'dither', 'dive', 'divert', 'divest', 'divide', 'divine', 'dizzy', 'do', 'dock', 'docket', 'doctor', 'dodge', 'dog', 'dole', 'doll', 'dolly', 'dome', 'donate', 'doodle', 'doom', 'dope', 'dose', 'dot', 'dote', 'double', 'doubt', 'douse', 'dowel', 'down', 'dowse', 'doze', 'drab', 'draft', 'drag', 'drain', 'drape', 'draw', 'drawl', 'dray', 'dread', 'dream', 'dredge', 'drench', 'dress', 'drift', 'drill', 'drink', 'drip', 'drive', 'drivel', 'drone', 'drool', 'droop', 'drop', 'drown', 'drowse', 'drudge', 'drug', 'drum', 'dry', 'dub', 'duck', 'duel', 'duet', 'dull', 'dumb', 'dummy', 'dump', 'dun', 'dupe', 'dust', 'dwarf', 'dwell', 'dye', 'ear', 'earn', 'ease', 'eat', 'ebb', 'echo', 'eddy', 'edge', 'edify', 'edit', 'efface', 'egg', 'egress', 'eject', 'elapse', 'elate', 'elbow', 'elect', 'elicit', 'elide', 'elope', 'elude', 'embalm', 'embark', 'embed', 'embody', 'emboss', 'emerge', 'emit', 'employ', 'empty', 'enable', 'enact', 'enamel', 'encamp', 'encase', 'encode', 'encore', 'end', 'endear', 'endow', 'endure', 'enfold', 'engage', 'engulf', 'enjoin', 'enjoy', 'enlist', 'enrage', 'enrich', 'ensue', 'ensure', 'entail', 'enter', 'entice', 'entomb', 'entrap', 'envy', 'equal', 'equate', 'equip', 'erase', 'erect', 'erode', 'err', 'erupt', 'escape', 'eschew', 'escort', 'escrow', 'essay', 'esteem', 'etch', 'evade', 'evict', 'evince', 'evoke', 'evolve', 'exact', 'exalt', 'exceed', 'excel', 'except', 'excess', 'excise', 'excite', 'excuse', 'exempt', 'exert', 'exeunt', 'exhale', 'exhort', 'exhume', 'exile', 'exist', 'expand', 'expect', 'expel', 'expend', 'expire', 'export', 'expose', 'extend', 'extol', 'extort', 'exude', 'exult', 'eye', 'fable', 'face', 'facet', 'factor', 'fade', 'fail', 'faint', 'fair', 'fake', 'fall', 'falter', 'fame', 'fan', 'fancy', 'farce', 'fare', 'farm', 'fast', 'fasten', 'fat', 'fate', 'father', 'fathom', 'fatten', 'fault', 'fawn', 'fear', 'feast', 'fee', 'feed', 'feel', 'feign', 'fell', 'fence', 'fend', 'ferret', 'ferry', 'fester', 'fetch', 'fettle', 'feud', 'fever', 'fib', 'fiddle', 'fidget', 'field', 'fife', 'fight', 'figure', 'file', 'fill', 'fillet', 'fillip', 'film', 'filter', 'fin', 'find', 'fine', 'finger', 'finish', 'fire', 'firm', 'fish', 'fit', 'fitter', 'fix', 'fizz', 'fizzle', 'flack', 'flag', 'flail', 'flake', 'flame', 'flank', 'flap', 'flare', 'flash', 'flat', 'flaunt', 'flaw', 'flay', 'flee', 'fleece', 'fleet', 'flesh', 'flex', 'flick', 'flight', 'flinch', 'fling', 'flint', 'flip', 'flit', 'float', 'flock', 'flog', 'flood', 'floor', 'flop', 'floss', 'flour', 'flout', 'flow', 'flower', 'fluff', 'flurry', 'flush', 'flute', 'flux', 'fly', 'foal', 'foam', 'fob', 'focus', 'fodder', 'fog', 'foil', 'foist', 'fold', 'folio', 'follow', 'foment', 'fondle', 'fool', 'foot', 'forage', 'foray', 'forbid', 'force', 'ford', 'forego', 'forest', 'forge', 'forget', 'fork', 'form', 'format', 'foster', 'foul', 'found', 'fowl', 'fox', 'frame', 'frank', 'fray', 'freak', 'free', 'freeze', 'frenzy', 'fresh', 'fret', 'friend', 'fright', 'frill', 'fringe', 'frisk', 'frock', 'frog', 'frolic', 'front', 'frost', 'froth', 'frown', 'fruit', 'fry', 'fudge', 'fuel', 'full', 'fumble', 'fume', 'fun', 'fund', 'funk', 'funnel', 'fur', 'furrow', 'fuse', 'fuss', 'fuzz', 'gabble', 'gad', 'gaff', 'gag', 'gaggle', 'gain', 'gait', 'gall', 'gallop', 'gamble', 'gambol', 'game', 'gang', 'gap', 'gape', 'garage', 'garble', 'garden', 'gargle', 'garner', 'garter', 'gas', 'gash', 'gasp', 'gate', 'gather', 'gauge', 'gavel', 'gaze', 'gear', 'gel', 'gem', 'gender', 'gentle', 'get', 'ghost', 'gibber', 'gibbet', 'giddy', 'gift', 'gig', 'giggle', 'gimlet', 'gin', 'ginger', 'gird', 'girdle', 'girth', 'give', 'glad', 'glance', 'glare', 'glass', 'glaze', 'gleam', 'glean', 'glide', 'glint', 'gloat', 'globe', 'gloom', 'glory', 'gloss', 'glove', 'glow', 'glower', 'glue', 'glut', 'gnarl', 'gnash', 'gnaw', 'go', 'goad', 'gobble', 'golf', 'gong', 'goose', 'gore', 'gorge', 'gossip', 'gouge', 'govern', 'gown', 'grab', 'grace', 'grade', 'graft', 'grain', 'grant', 'graph', 'grasp', 'grass', 'grate', 'grave', 'gravel', 'graze', 'grease', 'green', 'greet', 'grey', 'grieve', 'grill', 'grin', 'grind', 'grip', 'gripe', 'grit', 'groan', 'groin', 'groom', 'groove', 'grope', 'gross', 'grouch', 'ground', 'group', 'grouse', 'grout', 'grovel', 'grow', 'growl', 'grub', 'grudge', 'grunt', 'guard', 'guess', 'guest', 'guffaw', 'guide', 'guilt', 'guise', 'gulf', 'gull', 'gully', 'gulp', 'gum', 'gun', 'gurgle', 'gush', 'gust', 'gut', 'gutter', 'guy', 'guzzle', 'gyrate', 'habit', 'hack', 'haft', 'haggle', 'hail', 'hale', 'hallo', 'halo', 'halt', 'halter', 'halve', 'ham', 'hammer', 'hamper', 'hand', 'handle', 'hang', 'hanker', 'happen', 'harass', 'harden', 'hark', 'harm', 'harp', 'harrow', 'harry', 'hash', 'hasp', 'hassle', 'haste', 'hasten', 'hat', 'hatch', 'hate', 'haul', 'haunt', 'have', 'haven', 'havoc', 'hawk', 'hay', 'hazard', 'haze', 'head', 'heal', 'heap', 'hear', 'heart', 'heat', 'heave', 'heckle', 'hector', 'hedge', 'heed', 'heel', 'heft', 'hell', 'hello', 'helm', 'help', 'hem', 'herald', 'herd', 'hew', 'hex', 'hiccup', 'hide', 'hijack', 'hike', 'hill', 'hilt', 'hinder', 'hinge', 'hint', 'hip', 'hiss', 'hit', 'hitch', 'hive', 'hoard', 'hoax', 'hob', 'hobble', 'hock', 'hoe', 'hog', 'hoist', 'hold', 'hole', 'hollow', 'home', 'hone', 'honey', 'honk', 'hood', 'hoof', 'hook', 'hoop', 'hoot', 'hop', 'hope', 'horde', 'horn', 'hose', 'host', 'hostel', 'hound', 'house', 'hovel', 'hover', 'howl', 'huddle', 'huff', 'hug', 'hulk', 'hull', 'hum', 'humble', 'humbug', 'hump', 'hunch', 'hunger', 'hunt', 'hurdle', 'hurl', 'hurrah', 'hurry', 'hurt', 'hurtle', 'hush', 'husk', 'hustle', 'hymn', 'hyphen', 'ice', 'id', 'idle', 'ignite', 'ignore', 'image', 'imbibe', 'imbue', 'imp', 'impact', 'impair', 'impale', 'impart', 'impede', 'impel', 'imply', 'import', 'impose', 'impugn', 'impute', 'inch', 'incite', 'incur', 'indent', 'index', 'indict', 'induce', 'induct', 'infect', 'infer', 'infest', 'infix', 'inform', 'infuse', 'ingest', 'inhale', 'inject', 'injure', 'ink', 'inlay', 'inlet', 'input', 'insert', 'inset', 'insist', 'insult', 'insure', 'intend', 'inter', 'intern', 'intone', 'inure', 'invade', 'invent', 'invert', 'invest', 'invite', 'invoke', 'ionize', 'iris', 'iron', 'island', 'isle', 'issue', 'itch', 'item', 'jab', 'jabber', 'jack', 'jade', 'jag', 'jail', 'jam', 'jangle', 'jape', 'jar', 'jargon', 'jaunt', 'jaw', 'jazz', 'jeer', 'jelly', 'jerk', 'jest', 'jet', 'jetty', 'jewel', 'jib', 'jibe', 'jig', 'jigsaw', 'jilt', 'jingle', 'jinx', 'jitter', 'jive', 'job', 'jockey', 'jog', 'join', 'joint', 'joke', 'jolly', 'jolt', 'jostle', 'jot', 'joust', 'joy', 'judge', 'jug', 'juggle', 'juice', 'jumble', 'jump', 'junk', 'junket', 'just', 'jut', 'kayak', 'keel', 'keen', 'keep', 'ken', 'kennel', 'kernel', 'key', 'kick', 'kid', 'kidnap', 'kill', 'kiln', 'kilt', 'kindle', 'king', 'kink', 'kipper', 'kiss', 'kit', 'kite', 'kitten', 'knead', 'knee', 'kneel', 'knell', 'knife', 'knight', 'knit', 'knock', 'knoll', 'knot', 'know', 'kosher', 'kowtow', 'laager', 'label', 'lace', 'lack', 'lackey', 'ladle', 'lag', 'lame', 'lament', 'lance', 'land', 'lap', 'lapse', 'lard', 'lark', 'lash', 'lasso', 'last', 'latch', 'lathe', 'lather', 'laud', 'laugh', 'launch', 'laurel', 'lavish', 'law', 'lay', 'layer', 'laze', 'lazy', 'leach', 'lead', 'leaf', 'league', 'leak', 'lean', 'leap', 'learn', 'lease', 'leash', 'leave', 'leaven', 'lecher', 'leech', 'leer', 'leg', 'lend', 'lesion', 'lessen', 'lesson', 'let', 'letter', 'level', 'lever', 'levy', 'libel', 'lichen', 'lick', 'lid', 'lie', 'lift', 'light', 'like', 'liken', 'lilt', 'limb', 'limber', 'lime', 'limit', 'limp', 'line', 'linger', 'link', 'lip', 'liquor', 'lisp', 'list', 'listen', 'litter', 'live', 'liven', 'load', 'loaf', 'loam', 'loan', 'loathe', 'lob', 'lobby', 'local', 'locate', 'lock', 'lodge', 'loft', 'log', 'loiter', 'loll', 'long', 'look', 'loom', 'loop', 'loose', 'loosen', 'loot', 'lop', 'lope', 'lord', 'lose', 'lot', 'loth', 'lounge', 'louse', 'lout', 'love', 'lower', 'luck', 'lug', 'lull', 'lumber', 'lump', 'lunch', 'lunge', 'lurch', 'lure', 'lurk', 'lust', 'lute', 'lynch', 'mace', 'mad', 'madden', 'mail', 'maim', 'major', 'make', 'malign', 'malt', 'man', 'manage', 'mangle', 'mantle', 'manure', 'map', 'mar', 'marble', 'march', 'margin', 'mark', 'market', 'marl', 'maroon', 'marry', 'martyr', 'marvel', 'mash', 'mask', 'mason', 'mass', 'mast', 'master', 'mat', 'match', 'mate', 'matte', 'matter', 'mature', 'maul', 'maze', 'mean', 'medal', 'meddle', 'meet', 'meld', 'mellow', 'melt', 'menace', 'mend', 'mentor', 'merge', 'merit', 'mesh', 'mess', 'metal', 'meter', 'mew', 'mildew', 'milk', 'mill', 'mimic', 'mince', 'mind', 'mine', 'mingle', 'minor', 'mint', 'minute', 'mire', 'mirror', 'miscue', 'misfit', 'mislay', 'miss', 'mist', 'misuse', 'mitre', 'mix', 'moan', 'mob', 'mock', 'model', 'modem', 'modify', 'molest', 'molten', 'monger', 'monkey', 'moon', 'moor', 'moot', 'mop', 'mope', 'morph', 'morsel', 'mortar', 'mosaic', 'moss', 'mother', 'motion', 'motive', 'motor', 'mould', 'mound', 'mount', 'mourn', 'mouse', 'mousse', 'mouth', 'move', 'mow', 'muck', 'mud', 'muddle', 'muddy', 'muff', 'muffle', 'mug', 'mulch', 'mull', 'mumble', 'mummy', 'munch', 'murder', 'murmur', 'muscle', 'muse', 'mush', 'must', 'muster', 'mutate', 'mute', 'mutiny', 'mutter', 'muzzle', 'nag', 'nail', 'name', 'nap', 'narrow', 'near', 'neaten', 'neck', 'need', 'needle', 'negate', 'neigh', 'nerve', 'nest', 'nestle', 'net', 'nettle', 'neuter', 'nibble', 'niche', 'nick', 'nickel', 'niggle', 'nigh', 'nip', 'nod', 'noise', 'noodle', 'noose', 'nose', 'notch', 'note', 'notice', 'notify', 'nudge', 'null', 'numb', 'number', 'nurse', 'nut', 'nuzzle', 'oar', 'obey', 'object', 'oblige', 'obtain', 'occult', 'occupy', 'occur', 'off', 'offend', 'offer', 'ogle', 'oh', 'oil', 'omen', 'omit', 'ooze', 'open', 'opiate', 'oppose', 'opt', 'option', 'orb', 'orbit', 'ordain', 'order', 'orient', 'orphan', 'oust', 'out', 'outbid', 'outdo', 'outfit', 'outlaw', 'outlay', 'output', 'outrun', 'outwit', 'over', 'overdo', 'owe', 'own', 'oyster', 'pace', 'pacify', 'pack', 'packet', 'pad', 'paddle', 'page', 'pain', 'paint', 'pair', 'pal', 'pale', 'pall', 'pallet', 'palm', 'palsy', 'pamper', 'pan', 'pander', 'panel', 'panic', 'pant', 'paper', 'par', 'parade', 'parcel', 'parch', 'pardon', 'pare', 'parent', 'park', 'parley', 'parody', 'parole', 'parrot', 'parry', 'parse', 'part', 'party', 'pass', 'paste', 'pastor', 'pat', 'patch', 'patent', 'patrol', 'patter', 'pause', 'pave', 'paw', 'pawn', 'pay', 'peace', 'peach', 'peak', 'peal', 'pearl', 'pebble', 'peck', 'pedal', 'peddle', 'peek', 'peel', 'peep', 'peer', 'peg', 'pellet', 'pelt', 'pen', 'pencil', 'people', 'pepper', 'perch', 'peril', 'perish', 'perk', 'perm', 'permit', 'peruse', 'pester', 'pestle', 'pet', 'phase', 'phone', 'phrase', 'pi', 'pick', 'picket', 'pickle', 'picnic', 'pie', 'piece', 'pierce', 'piffle', 'pig', 'pike', 'pile', 'pilfer', 'pill', 'pillar', 'pillow', 'pilot', 'pimp', 'pin', 'pinch', 'pine', 'ping', 'pinion', 'pink', 'pip', 'pipe', 'pique', 'pirate', 'pistol', 'pit', 'pitch', 'pith', 'pity', 'pivot', 'place', 'plague', 'plait', 'plan', 'plane', 'plank', 'plant', 'plat', 'plate', 'play', 'plead', 'please', 'pleat', 'pledge', 'plight', 'plod', 'plop', 'plot', 'plough', 'pluck', 'plug', 'plumb', 'plume', 'plump', 'plunge', 'ply', 'poach', 'pocket', 'pod', 'point', 'poise', 'poison', 'poke', 'pole', 'police', 'polish', 'polka', 'poll', 'pollen', 'pomade', 'pond', 'ponder', 'pony', 'pool', 'pop', 'pore', 'port', 'pose', 'posit', 'post', 'pot', 'potter', 'pouch', 'pounce', 'pound', 'pour', 'pout', 'powder', 'power', 'praise', 'prance', 'prank', 'prawn', 'pray', 'preach', 'preen', 'prefab', 'prefix', 'preset', 'press', 'pretty', 'prey', 'price', 'prick', 'pride', 'priest', 'prim', 'prime', 'print', 'prize', 'probe', 'prod', 'profit', 'prompt', 'prong', 'proof', 'prop', 'propel', 'prose', 'prove', 'prowl', 'prune', 'pry', 'pucker', 'puddle', 'puff', 'pug', 'puke', 'pull', 'pulp', 'pulse', 'pumice', 'pummel', 'pump', 'pun', 'punch', 'punish', 'punt', 'pup', 'purge', 'purify', 'purl', 'purple', 'purr', 'purse', 'pursue', 'push', 'put', 'putt', 'putter', 'putty', 'puzzle', 'quack', 'quaff', 'quake', 'quarry', 'quash', 'quaver', 'queen', 'queer', 'quell', 'quench', 'query', 'quest', 'queue', 'quiet', 'quill', 'quilt', 'quip', 'quit', 'quiver', 'quiz', 'quote', 'rabble', 'race', 'rack', 'racket', 'radio', 'raffle', 'raft', 'rag', 'rage', 'raid', 'rail', 'rain', 'raise', 'rake', 'rally', 'ram', 'ramble', 'ramify', 'ramp', 'ramrod', 'ranch', 'range', 'rank', 'rankle', 'ransom', 'rant', 'rap', 'rasp', 'rat', 'rate', 'ratify', 'ration', 'rattle', 'ravage', 'rave', 'ravel', 'raven', 'ravish', 'ray', 'raze', 'reach', 'react', 'read', 'ready', 'really', 'ream', 'reap', 'rear', 'reason', 'rebate', 'rebel', 'rebind', 'rebook', 'rebuff', 'rebuke', 'rebut', 'recall', 'recant', 'recap', 'recast', 'recede', 'recess', 'recite', 'reckon', 'recode', 'recoil', 'record', 'recur', 'redden', 'redeem', 'redial', 'redo', 'redraw', 'reduce', 'reed', 'reef', 'reek', 'reel', 'reeve', 'refer', 'refile', 'refill', 'refine', 'refit', 'reflex', 'reform', 'refuel', 'refuge', 'refund', 'refuse', 'refute', 'regain', 'regale', 'regard', 'regret', 'rehash', 'reheat', 'reify', 'reign', 'reject', 'rejoin', 'relate', 'relax', 'relay', 'relent', 'relink', 'relish', 'relive', 'rely', 'remain', 'remake', 'remand', 'remap', 'remark', 'remedy', 'remind', 'remit', 'remove', 'rename', 'rend', 'render', 'renege', 'renew', 'rent', 'reopen', 'repack', 'repair', 'repast', 'repay', 'repeal', 'repeat', 'repel', 'repent', 'repine', 'replay', 'reply', 'report', 'repose', 'repute', 'reread', 'rerun', 'rescue', 'resell', 'resend', 'resent', 'reset', 'reshow', 'reside', 'resign', 'resin', 'resist', 'resit', 'resort', 'rest', 'result', 'resume', 'retail', 'retain', 'retake', 'retard', 'retch', 'retell', 'retest', 'retire', 'retort', 'retry', 'retune', 'return', 'retype', 'reuse', 'revamp', 'reveal', 'revel', 'revere', 'revert', 'review', 'revile', 'revive', 'revoke', 'revolt', 'reward', 'rewind', 'reword', 'rework', 'rhyme', 'rib', 'ribbon', 'rice', 'rid', 'riddle', 'ride', 'ridge', 'riff', 'rifle', 'rift', 'rig', 'right', 'rim', 'rime', 'ring', 'rinse', 'riot', 'rip', 'ripen', 'ripple', 'rise', 'risk', 'rival', 'rivet', 'roach', 'roam', 'roar', 'roast', 'rob', 'robe', 'rock', 'rocket', 'rogue', 'roll', 'romp', 'roof', 'rook', 'room', 'roost', 'root', 'rope', 'rosin', 'rot', 'rotate', 'rouge', 'rough', 'round', 'rouse', 'rout', 'route', 'rove', 'row', 'rub', 'ruck', 'rue', 'ruff', 'ruffle', 'ruin', 'rule', 'rumble', 'rumple', 'run', 'rush', 'rust', 'rustle', 'rut', 'sack', 'sadden', 'saddle', 'safari', 'sag', 'sail', 'saint', 'sallow', 'salt', 'salute', 'sample', 'sand', 'sandal', 'sap', 'sash', 'sauce', 'sauna', 'savage', 'save', 'saw', 'say', 'scab', 'scald', 'scale', 'scalp', 'scan', 'scant', 'scape', 'scar', 'scare', 'scarf', 'scathe', 'scent', 'scheme', 'school', 'scoff', 'scold', 'scoop', 'scoot', 'scope', 'scorch', 'score', 'scorn', 'scotch', 'scour', 'scout', 'scowl', 'scrap', 'scrape', 'scrawl', 'scream', 'screen', 'screw', 'scribe', 'script', 'scroll', 'scrub', 'scrum', 'scuba', 'scud', 'scuff', 'scull', 'sculpt', 'scum', 'scurry', 'scythe', 'seal', 'seam', 'sear', 'search', 'season', 'seat', 'secede', 'second', 'sector', 'secure', 'sedate', 'seduce', 'see', 'seed', 'seek', 'seem', 'seep', 'seethe', 'seize', 'select', 'sell', 'send', 'sense', 'serge', 'serve', 'set', 'settle', 'sever', 'sew', 'shack', 'shade', 'shadow', 'shaft', 'shag', 'shake', 'sham', 'shame', 'shank', 'shape', 'share', 'shark', 'sharp', 'shave', 'shear', 'shed', 'sheer', 'shell', 'shelve', 'shield', 'shift', 'shin', 'shine', 'ship', 'shirk', 'shiver', 'shoal', 'shock', 'shoe', 'shoo', 'shoot', 'shop', 'short', 'shot', 'shout', 'shove', 'shovel', 'show', 'shower', 'shred', 'shriek', 'shrill', 'shrimp', 'shrine', 'shrink', 'shroud', 'shrug', 'shun', 'shunt', 'shut', 'shy', 'sicken', 'sickly', 'side', 'sidle', 'siege', 'sieve', 'sift', 'sigh', 'sight', 'sign', 'signal', 'signet', 'silk', 'silo', 'silt', 'silver', 'simmer', 'simper', 'simple', 'sin', 'sinew', 'sing', 'single', 'sink', 'sip', 'siphon', 'sire', 'sit', 'site', 'size', 'sizzle', 'skate', 'sketch', 'skew', 'skewer', 'ski', 'skid', 'skim', 'skimp', 'skin', 'skip', 'skirl', 'skirt', 'skulk', 'skunk', 'sky', 'slab', 'slack', 'slag', 'slake', 'slam', 'slang', 'slant', 'slap', 'slash', 'slat', 'slate', 'slave', 'slaver', 'slay', 'sleaze', 'sled', 'sledge', 'sleek', 'sleep', 'sleet', 'sleeve', 'sleigh', 'sleuth', 'slice', 'slick', 'slide', 'slight', 'slim', 'slime', 'sling', 'slink', 'slip', 'slit', 'sliver', 'slog', 'slop', 'slope', 'slosh', 'slot', 'slouch', 'slough', 'slow', 'slug', 'sluice', 'slum', 'slump', 'slur', 'slurp', 'slurry', 'slush', 'smack', 'smart', 'smash', 'smear', 'smell', 'smelt', 'smile', 'smirk', 'smite', 'smock', 'smoke', 'smooth', 'smudge', 'smut', 'snack', 'snag', 'snake', 'snap', 'snare', 'snarl', 'snatch', 'sneak', 'sneer', 'sneeze', 'snick', 'sniff', 'snip', 'snipe', 'snivel', 'snoop', 'snooze', 'snore', 'snort', 'snow', 'snub', 'snuff', 'snug', 'soak', 'soap', 'soar', 'sob', 'sober', 'sock', 'socket', 'sodden', 'soften', 'soil', 'solace', 'solder', 'sole', 'solo', 'solve', 'soot', 'soothe', 'sop', 'sorrow', 'sort', 'sortie', 'sound', 'soup', 'sour', 'source', 'south', 'sow', 'space', 'spade', 'span', 'spank', 'spar', 'spare', 'spark', 'spat', 'spawn', 'speak', 'spear', 'speck', 'speed', 'spell', 'spend', 'spew', 'sphere', 'spice', 'spike', 'spill', 'spin', 'spiral', 'spire', 'spirit', 'spit', 'spite', 'splash', 'splice', 'splint', 'split', 'spoil', 'spoke', 'sponge', 'spoof', 'spool', 'spoon', 'spoor', 'spore', 'sport', 'spot', 'spout', 'sprain', 'sprawl', 'spray', 'spread', 'sprig', 'spring', 'sprint', 'sprout', 'spruce', 'spud', 'spume', 'spur', 'spurn', 'spurt', 'spy', 'squad', 'squall', 'square', 'squash', 'squat', 'squawk', 'squeak', 'squeal', 'squib', 'squint', 'squire', 'squirm', 'squirt', 'stab', 'stable', 'stack', 'staff', 'stag', 'stage', 'stain', 'stake', 'stale', 'stalk', 'stall', 'stamp', 'stand', 'staple', 'star', 'starch', 'stare', 'start', 'starve', 'state', 'stave', 'stay', 'stead', 'steal', 'steam', 'steel', 'steep', 'steer', 'stem', 'step', 'stet', 'stew', 'stick', 'stiff', 'stifle', 'still', 'stilt', 'sting', 'stink', 'stint', 'stir', 'stitch', 'stock', 'stomp', 'stone', 'stooge', 'stool', 'stoop', 'stop', 'store', 'storm', 'story', 'stow', 'strafe', 'strain', 'strand', 'strap', 'stray', 'streak', 'stream', 'stress', 'strew', 'stride', 'strike', 'string', 'strip', 'stripe', 'strive', 'stroke', 'stroll', 'strop', 'strum', 'strut', 'stub', 'stucco', 'stud', 'study', 'stuff', 'stump', 'stun', 'stunt', 'sturdy', 'sty', 'style', 'stymie', 'subdue', 'submit', 'suck', 'sucker', 'suckle', 'suds', 'sue', 'suede', 'suffer', 'suffix', 'sugar', 'suit', 'sulk', 'sully', 'sum', 'summer', 'summit', 'summon', 'sun', 'suntan', 'sup', 'supple', 'supply', 'surf', 'surge', 'survey', 'suture', 'swab', 'swamp', 'swap', 'swarm', 'swat', 'swathe', 'sway', 'swear', 'sweat', 'sweep', 'swell', 'swerve', 'swill', 'swim', 'swing', 'swipe', 'swirl', 'swish', 'switch', 'swivel', 'swoon', 'swoop', 'swop', 'symbol', 'syrup', 'tab', 'tabby', 'table', 'taboo', 'tack', 'tackle', 'tag', 'tail', 'tailor', 'taint', 'take', 'talk', 'tallow', 'tally', 'tame', 'tamp', 'tamper', 'tan', 'tangle', 'tango', 'tank', 'tap', 'tape', 'taper', 'tar', 'target', 'tariff', 'tarry', 'tart', 'task', 'tassel', 'taste', 'tattle', 'tattoo', 'taunt', 'tax', 'taxi', 'teach', 'team', 'tear', 'tease', 'tee', 'teem', 'teeter', 'teethe', 'telex', 'tell', 'temper', 'tempt', 'tenant', 'tend', 'tender', 'tenon', 'tense', 'tent', 'tenure', 'term', 'test', 'tether', 'thank', 'thatch', 'thaw', 'thieve', 'thin', 'think', 'thirst', 'thorn', 'thou', 'thrall', 'thrash', 'thread', 'threat', 'thresh', 'thrill', 'thrive', 'throat', 'throb', 'throne', 'throng', 'throw', 'thrum', 'thrust', 'thud', 'thumb', 'thump', 'thwack', 'thwart', 'tick', 'ticket', 'tickle', 'tide', 'tidy', 'tie', 'tier', 'tile', 'till', 'tiller', 'tilt', 'timber', 'time', 'tin', 'tinge', 'tingle', 'tinker', 'tinkle', 'tinsel', 'tint', 'tip', 'tipple', 'tiptoe', 'tire', 'tissue', 'tithe', 'title', 'titter', 'toady', 'toast', 'toddle', 'toe', 'toggle', 'toil', 'token', 'toll', 'tomb', 'tomcat', 'tone', 'tongue', 'tool', 'toot', 'tooth', 'tootle', 'top', 'topple', 'torch', 'torque', 'toss', 'tot', 'total', 'totter', 'touch', 'tough', 'tour', 'tout', 'tow', 'towel', 'tower', 'toy', 'trace', 'track', 'trade', 'trail', 'train', 'tram', 'tramp', 'trance', 'trap', 'trash', 'travel', 'trawl', 'tread', 'treat', 'treble', 'tree', 'trek', 'trench', 'trend', 'triage', 'trice', 'trick', 'trill', 'trim', 'trip', 'triple', 'troll', 'troop', 'trot', 'troupe', 'trowel', 'truant', 'truck', 'trudge', 'true', 'truss', 'trust', 'try', 'tub', 'tube', 'tuck', 'tucker', 'tuft', 'tug', 'tumble', 'tun', 'tune', 'tunnel', 'turf', 'turn', 'turtle', 'tusk', 'tussle', 'tutor', 'twang', 'tweak', 'tweet', 'twig', 'twill', 'twin', 'twine', 'twinge', 'twirl', 'twist', 'twitch', 'type', 'typify', 'umpire', 'unable', 'unbend', 'unbolt', 'unclog', 'uncoil', 'undo', 'unfit', 'unfold', 'unfurl', 'unhand', 'unify', 'unite', 'unjam', 'unlace', 'unlink', 'unload', 'unlock', 'unmask', 'unpack', 'unpick', 'unplug', 'unroll', 'unseal', 'unseat', 'untie', 'unveil', 'unwind', 'unwrap', 'unzip', 'up', 'update', 'uphold', 'uplift', 'upload', 'uproot', 'upset', 'upturn', 'urge', 'use', 'usher', 'usurp', 'utter', 'vacate', 'vacuum', 'valet', 'value', 'valve', 'vamp', 'vanish', 'vary', 'vat', 'vault', 'vector', 'veer', 'veil', 'vein', 'vend', 'veneer', 'vent', 'verge', 'verify', 'verse', 'vest', 'vet', 'veto', 'vex', 'vial', 'vice', 'video', 'vie', 'view', 'vilify', 'visa', 'vision', 'visit', 'visor', 'voice', 'void', 'volley', 'vomit', 'voodoo', 'vote', 'vouch', 'vow', 'voyage', 'wad', 'waddle', 'wade', 'wafer', 'waffle', 'waft', 'wag', 'wager', 'waggle', 'wagon', 'wail', 'wait', 'waive', 'wake', 'waken', 'walk', 'wall', 'wallow', 'waltz', 'wan', 'wander', 'wane', 'want', 'wanton', 'war', 'warble', 'ward', 'warm', 'warn', 'warp', 'wash', 'waste', 'watch', 'water', 'wattle', 'wave', 'waver', 'wax', 'waylay', 'weaken', 'wean', 'weapon', 'wear', 'weary', 'weasel', 'weave', 'web', 'wed', 'wedge', 'weed', 'weep', 'weigh', 'weight', 'weld', 'well', 'welt', 'welter', 'wench', 'wend', 'wet', 'whack', 'whale', 'wharf', 'wheel', 'wheeze', 'whelp', 'whet', 'whiff', 'while', 'whine', 'whinny', 'whip', 'whir', 'whirl', 'whirr', 'whisk', 'white', 'whiten', 'whizz', 'whoop', 'whoosh', 'wick', 'widen', 'widow', 'wield', 'wig', 'wiggle', 'wild', 'wile', 'will', 'wilt', 'wimple', 'win', 'wince', 'winch', 'wind', 'window', 'wine', 'wing', 'wink', 'winnow', 'winter', 'wipe', 'wire', 'wish', 'wisp', 'wit', 'witch', 'wither', 'wobble', 'wolf', 'wonder', 'wont', 'woo', 'wood', 'word', 'work', 'worm', 'worry', 'worsen', 'worst', 'wound', 'wow', 'wrack', 'wrap', 'wreak', 'wreath', 'wreck', 'wrench', 'wrest', 'wring', 'write', 'writhe', 'wrong', 'x-ray', 'xerox', 'yacht', 'yak', 'yap', 'yard', 'yaw', 'yawn', 'yearn', 'yeast', 'yell', 'yellow', 'yelp', 'yen', 'yes', 'yield', 'yo-yo', 'yodel', 'yoke', 'zero', 'zigzag', 'zinc', 'zip', 'zipper', 'zone', 'zoom' +] +export const nouns = [ + 'abacus', 'abbey', 'abroad', 'abuse', 'access', 'acid', 'act', 'action', 'actor', 'ad', 'adult', 'advice', 'affair', 'affect', 'age', 'agency', 'agenda', 'agent', 'aglet', 'aid', 'air', 'airbag', 'airbus', 'alarm', 'alb', 'alcove', 'alder', 'alibi', 'alley', 'alloy', 'almond', 'alpaca', 'alpha', 'alto', 'amount', 'analog', 'anger', 'angle', 'angora', 'animal', 'anime', 'ankle', 'anklet', 'annual', 'anorak', 'answer', 'ant', 'antler', 'ape', 'appeal', 'apple', 'apron', 'apse', 'arch', 'archer', 'area', 'arm', 'armor', 'army', 'arrow', 'art', 'ascot', 'ash', 'ashram', 'aside', 'ask', 'aspect', 'assist', 'atom', 'atrium', 'attack', 'attic', 'aunt', 'author', 'avenue', 'award', 'babe', 'baboon', 'baby', 'back', 'bacon', 'bad', 'badge', 'badger', 'bag', 'bagel', 'bail', 'bait', 'bake', 'baker', 'bakery', 'ball', 'ballet', 'bamboo', 'banana', 'band', 'bangle', 'banjo', 'bank', 'banker', 'baobab', 'bar', 'barber', 'barge', 'barium', 'barn', 'base', 'basin', 'basis', 'basket', 'bass', 'bat', 'bath', 'bather', 'batter', 'battle', 'bay', 'bayou', 'beach', 'bead', 'beak', 'beam', 'bean', 'beanie', 'bear', 'beard', 'beast', 'beat', 'beauty', 'beaver', 'bed', 'bee', 'beech', 'beef', 'beer', 'beet', 'beetle', 'beggar', 'behest', 'being', 'belfry', 'belief', 'bell', 'belly', 'belt', 'bench', 'bend', 'bengal', 'beret', 'berry', 'bet', 'beyond', 'bid', 'bidet', 'big', 'bijou', 'bike', 'bikini', 'bill', 'bin', 'birch', 'bird', 'birth', 'bit', 'bite', 'bitter', 'black', 'blade', 'blame', 'blank', 'blazer', 'blight', 'blind', 'block', 'blood', 'bloom', 'blouse', 'blow', 'blue', 'boar', 'board', 'boat', 'bobcat', 'body', 'bog', 'bolero', 'bolt', 'bomb', 'bomber', 'bone', 'bongo', 'bonnet', 'bonsai', 'bonus', 'book', 'boot', 'bootee', 'bootie', 'boots', 'booty', 'border', 'bore', 'bosom', 'boss', 'botany', 'bother', 'bottle', 'bottom', 'bough', 'bow', 'bower', 'bowl', 'bowler', 'bowtie', 'box', 'boxer', 'boy', 'bra', 'brace', 'brain', 'brake', 'branch', 'brand', 'brandy', 'brass', 'brave', 'bread', 'break', 'breast', 'breath', 'breeze', 'brick', 'bridge', 'brief', 'briefs', 'broad', 'broker', 'brome', 'bronco', 'bronze', 'brooch', 'brood', 'brook', 'broom', 'brow', 'brown', 'brush', 'bubble', 'bucket', 'buckle', 'bud', 'buddy', 'budget', 'buffer', 'buffet', 'bug', 'buggy', 'bugle', 'bulb', 'bull', 'bullet', 'bumper', 'bun', 'bunch', 'burn', 'burst', 'bus', 'bush', 'bust', 'bustle', 'butane', 'butter', 'button', 'buy', 'buyer', 'cabana', 'cabin', 'cable', 'cacao', 'cactus', 'caddy', 'cadet', 'cafe', 'caftan', 'cake', 'calf', 'calico', 'call', 'calm', 'camel', 'cameo', 'camera', 'camp', 'can', 'canal', 'cancel', 'cancer', 'candle', 'candy', 'cane', 'cannon', 'canoe', 'canon', 'canopy', 'canvas', 'cap', 'cape', 'capon', 'car', 'carbon', 'card', 'care', 'career', 'cargo', 'carol', 'carp', 'carpet', 'carrot', 'carry', 'cart', 'case', 'cash', 'casino', 'cast', 'castle', 'cat', 'catch', 'catsup', 'cattle', 'cause', 'cave', 'cd', 'celery', 'cell', 'cellar', 'cello', 'cement', 'census', 'cent', 'center', 'cereal', 'chafe', 'chain', 'chair', 'chaise', 'chalet', 'chalk', 'chance', 'change', 'chaos', 'chap', 'chapel', 'chard', 'charge', 'charm', 'chart', 'check', 'cheek', 'chef', 'cheque', 'cherry', 'chess', 'chest', 'chick', 'chief', 'child', 'chill', 'chime', 'chin', 'chino', 'chip', 'chive', 'choice', 'choker', 'chop', 'chord', 'chrome', 'chub', 'chug', 'church', 'churn', 'cicada', 'cinema', 'circle', 'cirrus', 'city', 'claim', 'clam', 'clank', 'clasp', 'class', 'clause', 'clave', 'cleat', 'clef', 'cleric', 'clerk', 'click', 'client', 'cliff', 'climb', 'clip', 'cloak', 'clock', 'clogs', 'close', 'closet', 'cloth', 'cloud', 'cloudy', 'clove', 'clover', 'club', 'clue', 'clutch', 'coach', 'coal', 'coast', 'coat', 'cob', 'cobweb', 'cocoa', 'cod', 'code', 'codon', 'coffee', 'coffin', 'coil', 'coin', 'coke', 'cold', 'collar', 'colon', 'colony', 'color', 'colt', 'column', 'comb', 'combat', 'comic', 'comma', 'common', 'condor', 'cone', 'conga', 'congo', 'consul', 'cook', 'cookie', 'cope', 'copper', 'copy', 'cord', 'cork', 'corn', 'corner', 'cornet', 'corral', 'cost', 'cot', 'cotton', 'couch', 'cougar', 'cough', 'count', 'county', 'couple', 'course', 'court', 'cousin', 'cover', 'cow', 'cowboy', 'crab', 'crack', 'cradle', 'craft', 'crash', 'crate', 'cravat', 'craw', 'crayon', 'crazy', 'cream', 'creche', 'credit', 'creek', 'crest', 'crew', 'crib', 'crime', 'crocus', 'crook', 'crop', 'cross', 'crotch', 'croup', 'crow', 'crowd', 'crown', 'crude', 'crush', 'cry', 'cub', 'cuckoo', 'cup', 'cupola', 'curio', 'curl', 'curler', 'cursor', 'curve', 'cut', 'cutlet', 'cycle', 'cymbal', 'cynic', 'cyst', 'dad', 'dagger', 'dahlia', 'daisy', 'damage', 'dame', 'dance', 'dancer', 'danger', 'daniel', 'dare', 'dark', 'dart', 'dash', 'data', 'date', 'david', 'day', 'daybed', 'dead', 'deal', 'dealer', 'dear', 'death', 'debate', 'debt', 'debtor', 'decade', 'deck', 'deep', 'deer', 'degree', 'delay', 'delete', 'demand', 'demur', 'den', 'denim', 'depth', 'deputy', 'derby', 'desert', 'design', 'desire', 'desk', 'detail', 'device', 'devil', 'dew', 'dhow', 'diadem', 'dibble', 'dickey', 'diet', 'dig', 'digger', 'dill', 'dime', 'dimple', 'diner', 'dinghy', 'dinner', 'dirndl', 'dirt', 'disco', 'dish', 'dishes', 'disk', 'divan', 'diver', 'divide', 'diving', 'dock', 'doctor', 'doe', 'dog', 'doll', 'dollar', 'dolman', 'domain', 'donkey', 'door', 'dory', 'dot', 'double', 'doubt', 'draft', 'drag', 'dragon', 'drain', 'drake', 'drama', 'draw', 'drawer', 'dream', 'dress', 'drill', 'drink', 'drive', 'driver', 'drop', 'drug', 'drum', 'drunk', 'dry', 'dryer', 'duck', 'dud', 'due', 'duffel', 'dugout', 'dump', 'dust', 'duster', 'duty', 'dwarf', 'dynamo', 'eagle', 'ear', 'earth', 'ease', 'easel', 'east', 'eat', 'eave', 'e-book', 'eddy', 'edge', 'edger', 'editor', 'edward', 'eel', 'effect', 'effort', 'egg', 'eggnog', 'eight', 'elbow', 'elixir', 'elk', 'elm', 'emery', 'employ', 'emu', 'end', 'enemy', 'energy', 'engine', 'enigma', 'entry', 'envy', 'epee', 'epoch', 'eponym', 'epoxy', 'equal', 'era', 'error', 'escape', 'ese', 'essay', 'estate', 'ethics', 'europe', 'event', 'exam', 'excuse', 'exile', 'exit', 'expert', 'extent', 'eye', 'eyelid', 'face', 'facet', 'fact', 'factor', 'fail', 'fairy', 'faith', 'fall', 'fame', 'family', 'fan', 'fang', 'fanny', 'farm', 'farmer', 'fascia', 'fat', 'father', 'faucet', 'fault', 'fawn', 'fax', 'fear', 'feast', 'fedora', 'fee', 'feed', 'feel', 'feet', 'felony', 'female', 'fen', 'fence', 'fender', 'ferry', 'few', 'fiber', 'fibre', 'fiddle', 'field', 'fifth', 'fight', 'figure', 'file', 'fill', 'filly', 'film', 'filth', 'final', 'find', 'fine', 'finger', 'finish', 'fir', 'fire', 'fish', 'fix', 'flag', 'flame', 'flare', 'flash', 'flat', 'flavor', 'flax', 'fleck', 'fleece', 'flesh', 'flight', 'flock', 'flood', 'floor', 'flour', 'flow', 'flower', 'flu', 'fluke', 'flute', 'fly', 'foam', 'fob', 'focus', 'fog', 'fold', 'folder', 'fondue', 'font', 'food', 'foot', 'foray', 'force', 'forest', 'fork', 'form', 'formal', 'format', 'former', 'fort', 'forum', 'fowl', 'fox', 'frame', 'freeze', 'freon', 'fresco', 'fridge', 'friend', 'fringe', 'frock', 'frog', 'front', 'frost', 'frown', 'fruit', 'fuel', 'full', 'fun', 'funny', 'fur', 'futon', 'future', 'gaffer', 'gain', 'gale', 'galley', 'gallon', 'galn', 'game', 'gander', 'gap', 'garage', 'garb', 'garden', 'garlic', 'garter', 'gas', 'gate', 'gather', 'gauge', 'gazebo', 'gear', 'geese', 'gem', 'gender', 'gene', 'george', 'gerbil', 'geyser', 'ghost', 'giant', 'gift', 'girdle', 'girl', 'git', 'give', 'glad', 'gland', 'glass', 'glen', 'glider', 'glove', 'gloves', 'glue', 'glut', 'go', 'goal', 'goat', 'god', 'gold', 'golf', 'gong', 'good', 'goodie', 'goose', 'gopher', 'gossip', 'gown', 'grab', 'grade', 'grain', 'gram', 'grand', 'granny', 'grape', 'graph', 'grass', 'gray', 'grease', 'great', 'greek', 'green', 'grey', 'grief', 'grill', 'grip', 'grit', 'ground', 'group', 'grouse', 'growth', 'guard', 'guess', 'guest', 'guide', 'guilt', 'guilty', 'guitar', 'gum', 'gun', 'gutter', 'guy', 'gym', 'gyro', 'habit', 'hail', 'hair', 'half', 'hall', 'hamaki', 'hammer', 'hand', 'handle', 'hang', 'harbor', 'harm', 'harp', 'hat', 'hatbox', 'hate', 'hatred', 'haunt', 'hawk', 'hay', 'head', 'health', 'heart', 'hearth', 'heat', 'heater', 'heaven', 'heavy', 'hedge', 'heel', 'height', 'helen', 'helium', 'hell', 'hello', 'helmet', 'helo', 'help', 'hemp', 'hen', 'herb', 'heron', 'heyday', 'hide', 'high', 'hill', 'hip', 'hire', 'hit', 'hive', 'hobbit', 'hobby', 'hockey', 'hoe', 'hog', 'hold', 'hole', 'home', 'honey', 'hood', 'hoof', 'hook', 'hope', 'hops', 'horn', 'hornet', 'horror', 'horse', 'hose', 'host', 'hostel', 'hot', 'hotel', 'hour', 'house', 'hovel', 'hub', 'hubcap', 'hugger', 'human', 'humor', 'humour', 'hunger', 'hunt', 'hurry', 'hurt', 'hut', 'hutch', 'hyena', 'ice', 'icicle', 'icon', 'idea', 'ideal', 'if', 'igloo', 'image', 'impact', 'inbox', 'inch', 'income', 'index', 'injury', 'ink', 'inlay', 'inn', 'input', 'insect', 'inside', 'invite', 'iris', 'iron', 'irony', 'island', 'issue', 'it', 'item', 'jackal', 'jacket', 'jaguar', 'jail', 'jam', 'james', 'jar', 'jaw', 'jeans', 'jeep', 'jeff', 'jelly', 'jet', 'jewel', 'jiffy', 'job', 'jockey', 'joey', 'join', 'joint', 'joke', 'jot', 'joy', 'judge', 'judo', 'juice', 'jumbo', 'jump', 'jumper', 'junior', 'junk', 'junker', 'junket', 'jury', 'jute', 'kale', 'karate', 'karen', 'kayak', 'kazoo', 'keep', 'kendo', 'ketch', 'kettle', 'key', 'kick', 'kid', 'kidney', 'kill', 'kilt', 'kimono', 'kind', 'king', 'kiosk', 'kiss', 'kite', 'kitten', 'kitty', 'klomps', 'knee', 'knife', 'knight', 'knot', 'koala', 'lab', 'labour', 'lace', 'lack', 'ladder', 'lady', 'lake', 'lamb', 'lamp', 'lan', 'lanai', 'land', 'lap', 'lapdog', 'laptop', 'larch', 'larder', 'lark', 'latex', 'lathe', 'latte', 'laugh', 'lava', 'law', 'lawn', 'lawyer', 'lay', 'layer', 'lead', 'leader', 'leaf', 'league', 'leaker', 'leash', 'leave', 'leaver', 'leek', 'leg', 'legal', 'legume', 'lei', 'lemon', 'lemur', 'length', 'lentil', 'lesson', 'let', 'letter', 'level', 'lever', 'lie', 'lier', 'life', 'lift', 'light', 'lilac', 'lily', 'limit', 'limo', 'line', 'linen', 'liner', 'link', 'lion', 'lip', 'liquid', 'liquor', 'lisa', 'list', 'listen', 'litter', 'liver', 'living', 'lizard', 'llama', 'load', 'loaf', 'loafer', 'loan', 'local', 'lock', 'locker', 'locket', 'locust', 'loft', 'log', 'loggia', 'logic', 'long', 'look', 'loss', 'lot', 'lotion', 'lounge', 'lout', 'love', 'low', 'luck', 'lumber', 'lunch', 'lung', 'lunge', 'lute', 'lycra', 'lye', 'lynx', 'lyre', 'lyric', 'magic', 'maid', 'maiden', 'mail', 'main', 'major', 'make', 'makeup', 'male', 'mall', 'mallet', 'mambo', 'man', 'maniac', 'manner', 'manor', 'mantel', 'mantle', 'mantua', 'manx', 'many', 'map', 'maple', 'maraca', 'marble', 'mare', 'margin', 'mark', 'market', 'marsh', 'mask', 'mass', 'master', 'mat', 'match', 'mate', 'math', 'matter', 'maybe', 'mayor', 'meal', 'meat', 'media', 'medium', 'meet', 'melody', 'member', 'memory', 'men', 'menu', 'mess', 'metal', 'meteor', 'meter', 'method', 'metro', 'mice', 'middle', 'midi', 'might', 'mile', 'milk', 'mime', 'mimosa', 'mind', 'mine', 'mini', 'minion', 'minor', 'mint', 'minute', 'mirror', 'misfit', 'miss', 'mist', 'mister', 'miter', 'mitten', 'mix', 'mixer', 'moat', 'mobile', 'mocha', 'mode', 'model', 'modem', 'mole', 'mom', 'moment', 'money', 'monger', 'monkey', 'month', 'mood', 'moon', 'mop', 'morsel', 'mosque', 'most', 'motel', 'moth', 'mother', 'motion', 'motor', 'mound', 'mouse', 'mouser', 'mousse', 'mouth', 'mouton', 'move', 'mover', 'movie', 'mower', 'mud', 'mug', 'mukluk', 'mule', 'muscle', 'museum', 'music', 'mutt', 'n', 'nail', 'name', 'naming', 'napkin', 'nasty', 'nation', 'native', 'nature', 'neat', 'neck', 'need', 'needle', 'neon', 'nephew', 'nerve', 'nest', 'net', 'news', 'nexus', 'nicety', 'niche', 'nickel', 'niece', 'night', 'nobody', 'node', 'noise', 'noodle', 'normal', 'norse', 'north', 'nose', 'note', 'notice', 'notify', 'nougat', 'novel', 'nudge', 'number', 'nurse', 'nut', 'nylon', 'oak', 'oar', 'oasis', 'obi', 'object', 'oboe', 'ocean', 'ocelot', 'octave', 'octavo', 'octet', 'oeuvre', 'offer', 'office', 'oil', 'okra', 'oldie', 'olive', 'omega', 'omelet', 'one', 'onion', 'open', 'opera', 'opium', 'option', 'orange', 'orator', 'orchid', 'order', 'organ', 'osprey', 'other', 'others', 'ott', 'otter', 'ounce', 'outfit', 'outlay', 'output', 'outset', 'oval', 'ovary', 'oven', 'owl', 'owner', 'ox', 'oxen', 'oxford', 'oxygen', 'oyster', 'pace', 'pack', 'packet', 'pad', 'paddle', 'page', 'pagoda', 'pail', 'pain', 'paint', 'pair', 'pajama', 'palm', 'pan', 'panda', 'panic', 'pansy', 'pantry', 'pants', 'panty', 'paper', 'parade', 'parcel', 'pard', 'parent', 'park', 'parka', 'parrot', 'part', 'party', 'pass', 'past', 'pasta', 'paste', 'pastor', 'pastry', 'patch', 'path', 'patina', 'patio', 'patrol', 'pause', 'paw', 'pay', 'payee', 'pea', 'peace', 'peach', 'peak', 'peanut', 'pear', 'pearl', 'pedal', 'peen', 'peer', 'pelt', 'pen', 'pencil', 'peony', 'people', 'pepper', 'perch', 'period', 'permit', 'perp', 'person', 'pest', 'pet', 'petal', 'pew', 'pha', 'phase', 'phone', 'photo', 'phrase', 'piano', 'pick', 'pickax', 'picket', 'pickle', 'pie', 'piece', 'pier', 'piety', 'pig', 'pigeon', 'pike', 'pile', 'pillow', 'pilot', 'pimp', 'pimple', 'pin', 'pine', 'ping', 'pink', 'pinkie', 'pint', 'pinto', 'pipe', 'piracy', 'piss', 'pitch', 'pith', 'pizza', 'place', 'plain', 'plan', 'plane', 'planet', 'plant', 'plate', 'play', 'player', 'plenty', 'plier', 'plot', 'plough', 'plover', 'plow', 'plume', 'pocket', 'poem', 'poet', 'poetry', 'point', 'poison', 'pole', 'police', 'policy', 'polish', 'polo', 'pompom', 'poncho', 'pond', 'pony', 'poof', 'pool', 'pop', 'poppy', 'porch', 'port', 'porter', 'post', 'poster', 'pot', 'potato', 'potty', 'pouch', 'pound', 'powder', 'power', 'press', 'price', 'pride', 'priest', 'prince', 'print', 'prior', 'prison', 'prize', 'profit', 'prompt', 'proof', 'prose', 'prow', 'pruner', 'public', 'puddle', 'puffin', 'pull', 'pulley', 'puma', 'pump', 'punch', 'pupa', 'pupil', 'puppy', 'purple', 'purse', 'push', 'pusher', 'put', 'pvc', 'pyjama', 'quail', 'quart', 'quartz', 'queen', 'quiet', 'quill', 'quilt', 'quince', 'quit', 'quiver', 'quote', 'rabbi', 'rabbit', 'race', 'racer', 'racing', 'racism', 'racist', 'rack', 'radar', 'radio', 'radish', 'raffle', 'raft', 'rag', 'rage', 'rail', 'rain', 'raise', 'rake', 'ram', 'ramie', 'ranch', 'random', 'range', 'rank', 'rat', 'rate', 'ratio', 'raven', 'raw', 'ray', 'rayon', 'reach', 'read', 'reamer', 'rear', 'reason', 'recess', 'recipe', 'record', 'red', 'reef', 'refund', 'refuse', 'region', 'regret', 'reject', 'relief', 'relish', 'remote', 'remove', 'rent', 'repair', 'repeat', 'reply', 'report', 'resale', 'resist', 'resort', 'rest', 'result', 'retina', 'return', 'reveal', 'review', 'reward', 'rhyme', 'rhythm', 'rice', 'rich', 'riddle', 'ride', 'rider', 'ridge', 'rifle', 'right', 'rim', 'ring', 'rip', 'ripple', 'rise', 'riser', 'risk', 'river', 'road', 'roast', 'robe', 'robin', 'rock', 'rocker', 'rocket', 'rod', 'role', 'roll', 'roller', 'roof', 'room', 'root', 'rope', 'rose', 'rotate', 'rough', 'round', 'route', 'router', 'row', 'royal', 'rub', 'rubber', 'rubric', 'ruckus', 'ruffle', 'rugby', 'ruin', 'rule', 'rum', 'run', 'runner', 'rush', 'ruth', 'ry', 'sabre', 'sack', 'sad', 'saddle', 'safe', 'safety', 'sage', 'sail', 'sailor', 'salad', 'salary', 'sale', 'salmon', 'salon', 'saloon', 'salt', 'sampan', 'sample', 'sand', 'sari', 'sarong', 'sash', 'satin', 'satire', 'sauce', 'save', 'saving', 'savior', 'saw', 'scale', 'scarf', 'scene', 'scent', 'scheme', 'school', 'score', 'scorn', 'scow', 'screen', 'screw', 'scrim', 'scrip', 'script', 'sea', 'seal', 'search', 'season', 'seat', 'second', 'secret', 'sector', 'secure', 'seed', 'seeder', 'select', 'self', 'sell', 'senior', 'sense', 'sepal', 'series', 'serve', 'server', 'set', 'sewer', 'sex', 'shack', 'shade', 'shadow', 'shake', 'shaker', 'shame', 'shanty', 'shape', 'share', 'shark', 'sharon', 'shawl', 'she', 'shears', 'sheath', 'shed', 'sheep', 'sheet', 'shelf', 'shell', 'sherry', 'shield', 'shift', 'shin', 'shine', 'ship', 'shirt', 'shoat', 'shock', 'shoe', 'shoes', 'shofar', 'shoot', 'shop', 'shore', 'shorts', 'shot', 'shovel', 'show', 'shower', 'shred', 'shrimp', 'shrine', 'sick', 'side', 'siding', 'sign', 'signal', 'signet', 'signup', 'silica', 'silk', 'sill', 'silly', 'silo', 'silver', 'simple', 'sing', 'singer', 'single', 'sink', 'sir', 'sister', 'sitar', 'site', 'size', 'skate', 'skiing', 'skill', 'skin', 'skirt', 'skull', 'skunk', 'sky', 'slash', 'slave', 'sled', 'sledge', 'sleep', 'sleet', 'sleuth', 'slice', 'slide', 'slider', 'slime', 'slip', 'slope', 'sloth', 'smash', 'smell', 'smile', 'smock', 'smog', 'smoke', 'snail', 'snake', 'sneeze', 'snob', 'snorer', 'snow', 'soap', 'soccer', 'sock', 'socks', 'soda', 'sofa', 'soft', 'soil', 'solid', 'son', 'song', 'sonnet', 'soot', 'sorbet', 'sorrow', 'sort', 'sound', 'soup', 'source', 'south', 'sow', 'soy', 'space', 'spade', 'spank', 'spare', 'spark', 'spasm', 'spear', 'speech', 'speed', 'spell', 'spend', 'sphere', 'sphynx', 'spider', 'spike', 'spine', 'spiral', 'spirit', 'spite', 'spleen', 'split', 'sponge', 'spoon', 'sport', 'spot', 'spray', 'spread', 'spring', 'sprout', 'spruce', 'spume', 'spur', 'spy', 'square', 'squash', 'squid', 'stable', 'stack', 'staff', 'stag', 'stage', 'stain', 'stair', 'stamen', 'stamp', 'stance', 'stand', 'star', 'start', 'state', 'status', 'stay', 'steak', 'steal', 'steam', 'steel', 'stem', 'step', 'steps', 'stew', 'stick', 'still', 'stitch', 'stock', 'stole', 'stone', 'stool', 'stop', 'store', 'storey', 'storm', 'story', 'stove', 'strain', 'strait', 'strap', 'straw', 'stream', 'street', 'stress', 'strike', 'string', 'strip', 'stroke', 'stud', 'studio', 'study', 'stuff', 'stupid', 'style', 'stylus', 'suburb', 'subway', 'suck', 'suede', 'sugar', 'suit', 'sultan', 'summer', 'sun', 'sunday', 'supply', 'survey', 'sushi', 'SUV', 'swamp', 'swan', 'swath', 'sweat', 'sweats', 'sweet', 'sweets', 'swell', 'swim', 'swing', 'swiss', 'switch', 'swivel', 'sword', 'synod', 'syrup', 'system', 'tabby', 'table', 'tackle', 'tail', 'tailor', 'tale', 'talk', 'tam', 'tandem', 'tank', 'tanker', 'tap', 'tard', 'target', 'task', 'tassel', 'taste', 'tatami', 'tattoo', 'tavern', 'tax', 'taxi', 'tea', 'teach', 'team', 'tear', 'teen', 'teeth', 'tell', 'teller', 'temp', 'temper', 'temple', 'tempo', 'tennis', 'tenor', 'tent', 'tepee', 'term', 'test', 'text', 'thanks', 'thaw', 'theism', 'theme', 'theory', 'thigh', 'thing', 'thirst', 'thomas', 'thong', 'thongs', 'thorn', 'thread', 'thrill', 'throat', 'throne', 'thrush', 'thumb', 'tiara', 'tic', 'ticket', 'tie', 'tiger', 'tight', 'tights', 'tile', 'till', 'timber', 'time', 'timer', 'tin', 'tinkle', 'tip', 'tire', 'tissue', 'title', 'toad', 'toast', 'today', 'toe', 'toga', 'togs', 'toilet', 'tom', 'tomato', 'ton', 'tone', 'tongue', 'tool', 'toot', 'tooth', 'top', 'topic', 'toque', 'torso', 'tosser', 'total', 'tote', 'touch', 'tough', 'tour', 'towel', 'tower', 'town', 'toy', 'track', 'trade', 'trail', 'train', 'tram', 'tramp', 'trash', 'travel', 'tray', 'treat', 'tree', 'tremor', 'trench', 'trial', 'tribe', 'trick', 'trim', 'trip', 'tripod', 'trout', 'trove', 'trowel', 'truck', 'trunk', 'trust', 'truth', 'try', 'tub', 'tuba', 'tube', 'tulip', 'tummy', 'tuna', 'tune', 'tunic', 'tunnel', 'turban', 'turn', 'turnip', 'turret', 'turtle', 'tussle', 'tutu', 'tuxedo', 'tv', 'twig', 'twine', 'twist', 'two', 'type', 'tyvek', 'uncle', 'union', 'unique', 'unit', 'unity', 'upper', 'urn', 'usage', 'use', 'user', 'usher', 'usual', 'vacuum', 'valley', 'value', 'van', 'vane', 'vanity', 'vase', 'vast', 'vault', 'veal', 'veil', 'vein', 'veldt', 'vellum', 'velvet', 'venom', 'verse', 'verve', 'vessel', 'vest', 'vibe', 'video', 'view', 'villa', 'vinyl', 'viola', 'violet', 'violin', 'virtue', 'virus', 'vise', 'vision', 'visit', 'visor', 'visual', 'vixen', 'voice', 'volume', 'voyage', 'wad', 'wafer', 'waffle', 'waist', 'wait', 'waiter', 'wake', 'walk', 'walker', 'wall', 'wallet', 'walnut', 'walrus', 'wampum', 'war', 'warden', 'warmth', 'wash', 'washer', 'wasp', 'waste', 'watch', 'water', 'wave', 'wax', 'way', 'wealth', 'weapon', 'wear', 'weasel', 'web', 'wedge', 'weed', 'weeder', 'week', 'weight', 'weird', 'well', 'west', 'whale', 'wharf', 'wheat', 'wheel', 'while', 'whip', 'white', 'whole', 'whorl', 'width', 'wife', 'will', 'willow', 'win', 'wind', 'window', 'wine', 'wing', 'winner', 'winter', 'wire', 'wisdom', 'wish', 'witch', 'wolf', 'wombat', 'women', 'wonder', 'wood', 'wool', 'woolen', 'word', 'work', 'worker', 'world', 'worm', 'worry', 'worth', 'worthy', 'wound', 'wrap', 'wren', 'wrench', 'wrist', 'writer', 'wrong', 'yacht', 'yak', 'yam', 'yard', 'yarn', 'yawl', 'year', 'yeast', 'yellow', 'yew', 'yin', 'yoga', 'yogurt', 'yoke', 'you', 'young', 'youth', 'yurt', 'zebra', 'zephyr', 'zinc', 'zipper', 'zither', 'zone', 'zoo' +] +export const adverbs = [ + 'ably', 'acidly', 'airily', 'ally', 'amply', 'apply', 'aptly', 'archly', 'avidly', 'badly', 'baldly', 'barely', 'basely', 'belly', 'bodily', 'boldly', 'bubbly', 'bully', 'burly', 'busily', 'calmly', 'chilly', 'coldly', 'comely', 'comply', 'coolly', 'cosily', 'costly', 'coyly', 'cuddly', 'curly', 'curtly', 'daily', 'dally', 'damply', 'darkly', 'deadly', 'dearly', 'deeply', 'deftly', 'dimly', 'direly', 'doily', 'dolly', 'doubly', 'dourly', 'drily', 'dryly', 'dually', 'dully', 'duly', 'dumbly', 'early', 'easily', 'edgily', 'eerily', 'evenly', 'evilly', 'fairly', 'family', 'feebly', 'fiddly', 'filly', 'finely', 'firmly', 'fitly', 'flatly', 'fly', 'folly', 'fondly', 'foully', 'freely', 'frilly', 'fully', 'gadfly', 'gaily', 'gamely', 'gangly', 'gently', 'giggly', 'gladly', 'glibly', 'glumly', 'godly', 'golly', 'goodly', 'googly', 'grimly', 'grisly', 'gully', 'hardly', 'hazily', 'highly', 'hilly', 'holly', 'holy', 'homely', 'homily', 'hotly', 'hourly', 'hugely', 'humbly', 'icily', 'idly', 'imply', 'jangly', 'jelly', 'jokily', 'jolly', 'justly', 'keenly', 'kindly', 'kingly', 'lamely', 'lastly', 'lately', 'lazily', 'likely', 'lily', 'limply', 'lively', 'lolly', 'lonely', 'lordly', 'loudly', 'lovely', 'lowly', 'madly', 'mainly', 'manly', 'mayfly', 'mealy', 'meanly', 'measly', 'meekly', 'merely', 'mildly', 'mostly', 'mutely', 'namely', 'nearly', 'neatly', 'newly', 'nicely', 'nimbly', 'nobly', 'nosily', 'numbly', 'oddly', 'oily', 'only', 'openly', 'orally', 'overly', 'palely', 'partly', 'pearly', 'pebbly', 'pertly', 'pimply', 'ply', 'poorly', 'portly', 'primly', 'purely', 'rally', 'rarely', 'rashly', 'really', 'rely', 'reply', 'richly', 'ripely', 'rosily', 'rudely', 'sadly', 'safely', 'sagely', 'sally', 'sanely', 'scaly', 'seemly', 'shyly', 'sickly', 'silly', 'simply', 'singly', 'slily', 'slowly', 'sly', 'slyly', 'smelly', 'smugly', 'snugly', 'softly', 'solely', 'sorely', 'sourly', 'stably', 'steely', 'subtly', 'sully', 'supply', 'surely', 'surly', 'tally', 'tamely', 'tartly', 'tautly', 'termly', 'thinly', 'tidily', 'timely', 'tingly', 'tinkly', 'triply', 'truly', 'ugly', 'unduly', 'unholy', 'unruly', 'vainly', 'vastly', 'viably', 'vilely', 'waggly', 'wanly', 'warily', 'warmly', 'wavily', 'weakly', 'weekly', 'wetly', 'wholly', 'widely', 'wifely', 'wildly', 'wily', 'wisely', 'wobbly', 'woolly', 'wryly', 'yearly' +] +export const interjections = [ + 'aha', 'ahem', 'ahh', 'ahoy', 'alas', 'arg', 'aw', 'bam', 'bingo', 'blah', 'boo', 'bravo', 'brrr', 'cheers', 'dang', 'drat', 'darn', 'duh', 'eek', 'eh', 'encore', 'eureka', 'gee', 'golly', 'gosh', 'haha', 'hello', 'hey', 'hmm', 'huh', 'humph', 'hurray', 'oh', 'oh my', 'oops', 'ouch', 'ow', 'phew', 'phooey', 'pooh', 'pow', 'rats', 'shh', 'shoo', 'thanks', 'there', 'uh-huh', 'uh-oh', 'ugh', 'wahoo', 'well', 'whoa', 'whoops', 'wow', 'yeah', 'yes', 'yikes', 'yippee', 'yo', 'yuck' +] +export const adjectives = [ + 'abject', 'abrupt', 'absent', 'absurd', 'active', 'acute', 'adept', 'adroit', 'aerial', 'agile', 'airy', 'alert', 'aloof', 'amoral', 'amused', 'angry', 'apt', 'arch', 'ardent', 'artful', 'august', 'aural', 'avowed', 'awful', 'bad', 'banal', 'basic', 'bawdy', 'benign', 'bitter', 'bland', 'blank', 'bleak', 'blind', 'blithe', 'blunt', 'boyish', 'brave', 'breezy', 'brief', 'bright', 'broad', 'broken', 'busy', 'cagy', 'cm', 'candid', 'canny', 'carnal', 'casual', 'catty', 'caudal', 'chaste', 'cheeky', 'clear', 'clever', 'clinic', 'clumsy', 'coarse', 'cocky', 'cogent', 'cold', 'conic', 'coward', 'coy', 'cozy', 'crass', 'craven', 'crazy', 'creepy', 'crude', 'curt', 'cute', 'cynic', 'dainty', 'dark', 'dazed', 'dear', 'decent', 'deep', 'deft', 'demure', 'dense', 'dim', 'dire', 'dismal', 'dizzy', 'dogged', 'droll', 'dry', 'dull', 'eager', 'easy', 'eerie', 'equal', 'erect', 'erotic', 'ethic', 'even', 'evil', 'exact', 'exotic', 'faint', 'false', 'famous', 'fatal', 'faulty', 'feeble', 'firm', 'fishy', 'fixed', 'flabby', 'flashy', 'flat', 'fleet', 'flimsy', 'floppy', 'fluent', 'fluid', 'fond', 'foul', 'frail', 'frank', 'free', 'fresh', 'frisky', 'frugal', 'funny', 'fussy', 'futile', 'fuzzy', 'game', 'garish', 'gauche', 'gaudy', 'gawky', 'genial', 'gent', 'glad', 'glib', 'glum', 'grand', 'grave', 'great', 'greedy', 'grimy', 'groggy', 'gross', 'guilty', 'happy', 'hardy', 'harsh', 'hasty', 'hazy', 'heated', 'hectic', 'heroic', 'hoarse', 'honest', 'hot', 'huge', 'humane', 'humble', 'hungry', 'husky', 'icy', 'inept', 'insane', 'ireful', 'ironic', 'jaded', 'jaunty', 'jerky', 'jocose', 'joking', 'jolly', 'jovial', 'joyful', 'juicy', 'just', 'keen', 'lame', 'lavish', 'lax', 'lazy', 'lewd', 'light', 'limp', 'livid', 'logic', 'loose', 'loud', 'loving', 'loyal', 'lubber', 'lucid', 'lucky', 'lurid', 'lusty', 'mad', 'magic', 'manful', 'marked', 'mature', 'meager', 'mean', 'meek', 'menial', 'merry', 'messy', 'metric', 'mighty', 'mild', 'minute', 'miser', 'modest', 'moist', 'moody', 'moral', 'morbid', 'murky', 'music', 'mute', 'naive', 'naked', 'narrow', 'nasty', 'neat', 'nice', 'nimble', 'noble', 'noisy', 'normal', 'nosy', 'numb', 'oafish', 'opaque', 'pert', 'pesky', 'physic', 'pious', 'pithy', 'placid', 'plain', 'poetic', 'polite', 'poor', 'prim', 'prissy', 'proper', 'proud', 'public', 'pure', 'quaint', 'queer', 'quick', 'quiet', 'rabid', 'racy', 'raging', 'rakish', 'random', 'rank', 'rapid', 'rapt', 'rare', 'rash', 'raving', 'ready', 'regal', 'remote', 'rich', 'right', 'rigid', 'ripe', 'ritual', 'robust', 'rosy', 'rough', 'royal', 'rude', 'rueful', 'rugged', 'sad', 'safe', 'sane', 'saucy', 'savage', 'scant', 'secret', 'secure', 'sedate', 'serene', 'severe', 'sexy', 'sexual', 'shaky', 'sharp', 'shoddy', 'showy', 'shrewd', 'shy', 'silent', 'simple', 'skimpy', 'slack', 'sleazy', 'sleek', 'slick', 'slight', 'slow', 'smart', 'smooth', 'smug', 'snooty', 'snug', 'sober', 'soft', 'soggy', 'solemn', 'somber', 'sordid', 'sore', 'sound', 'sour', 'spry', 'square', 'staid', 'stark', 'static', 'steady', 'stern', 'stiff', 'stingy', 'stoic', 'stolid', 'stormy', 'stout', 'strict', 'strong', 'stuffy', 'stupid', 'suave', 'subtle', 'sudden', 'sudden', 'sulky', 'sullen', 'superb', 'supp', 'sure', 'swanky', 'swift', 'tacit', 'tacky', 'tame', 'tardy', 'tart', 'taut', 'tense', 'tepid', 'terse', 'testy', 'thick', 'thin', 'tidy', 'tight', 'timid', 'tonal', 'tough', 'tragic', 'trim', 'trite', 'true', 'trying', 'turgid', 'uneasy', 'unique', 'unkind', 'unsafe', 'urgent', 'useful', 'vague', 'vain', 'vexed', 'visual', 'vital', 'vivid', 'vocal', 'vulgar', 'wan', 'wanton', 'warm', 'weak', 'weird', 'wicked', 'wide', 'wild', 'wise', 'witty', 'woeful', 'wrong', 'wry' +] +export const verbed = new Proxy(verbs, { + get: (arr, prop) => { + // Check it's not a property + if (!(prop in [])) { + return getPastTense(arr[prop]) + } else { + return arr[prop] + } + } +}) diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index ad9f149a..4a0c754e 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -46,19 +46,19 @@ "@rollup/plugin-commonjs": "24.0.0", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.2.1", - "@vaadin/avatar": "23.3.2", - "@vaadin/button": "23.3.2", - "@vaadin/grid": "23.3.2", - "@vaadin/icons": "23.3.2", - "@vaadin/tooltip": "23.3.2", + "@rollup/plugin-terser": "0.3.0", + "@vaadin/avatar": "23.3.3", + "@vaadin/button": "23.3.3", + "@vaadin/grid": "23.3.3", + "@vaadin/icons": "23.3.3", + "@vaadin/tooltip": "23.3.3", "epml": "0.3.3", "file-saver": "2.0.5", "highcharts": "10.3.2", "html-escaper": "3.0.3", - "lit": "2.5.0", + "lit": "2.6.1", "lit-translate": "2.0.1", - "rollup": "3.9.1", + "rollup": "3.10.0", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2" }, From b6f567c5842616dffa891660d2763b0875e1cff0 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 13 Jan 2023 09:52:14 +0100 Subject: [PATCH 02/76] Cleanup code and preparation for chat reference --- qortal-ui-crypto/api.js | 6 +- qortal-ui-crypto/api/PhraseWallet.js | 334 +++++++++--------- qortal-ui-crypto/api/api.js | 4 - .../api/bitcoin/AltcoinHDWallet.js | 152 ++++---- qortal-ui-crypto/api/constants.js | 283 +++++++-------- qortal-ui-crypto/api/createTransaction.js | 24 +- qortal-ui-crypto/api/createWallet.js | 40 +-- qortal-ui-crypto/api/decryptStoredWallet.js | 32 +- qortal-ui-crypto/api/kdf.js | 64 ++-- qortal-ui-crypto/api/registerUsername.js | 45 +-- qortal-ui-crypto/api/storeWallet.js | 46 ++- qortal-ui-crypto/api/tradeRequest.js | 181 +++++----- .../api/transactions/AirdropTransaction.js | 69 ++-- .../api/transactions/DelegationTransaction.js | 41 +-- .../api/transactions/MessageTransaction.js | 136 +++---- .../api/transactions/PaymentTransaction.js | 121 +++---- .../api/transactions/PublicizeTransaction.js | 36 +- .../api/transactions/TransactionBase.js | 249 ++++++------- .../transactions/TransferPrivsTransaction.js | 52 +-- .../transactions/arbitrary/signArbitrary.js | 43 ++- .../api/transactions/arbitraryV3.js | 67 ++-- .../api/transactions/chat/ChatBase.js | 196 ++++------ .../api/transactions/chat/ChatTransaction.js | 125 ++++--- .../transactions/chat/GroupChatTransaction.js | 93 +++-- .../transactions/chat/decryptChatMessage.js | 27 +- .../api/transactions/chat/signChat.js | 51 ++- .../groups/AddGroupAdminTransaction.js | 88 ++--- .../groups/CancelGroupBanTransaction.js | 88 ++--- .../groups/CancelGroupInviteTransaction.js | 100 +++--- .../groups/CreateGroupTransaction.js | 164 ++++----- .../groups/GroupBanTransaction.js | 112 +++--- .../groups/GroupInviteTransaction.js | 98 ++--- .../groups/GroupKickTransaction.js | 102 +++--- .../groups/JoinGroupTransaction.js | 98 +++-- .../groups/LeaveGroupTransaction.js | 96 +++-- .../groups/RemoveGroupAdminTransaction.js | 88 ++--- .../transactions/names/BuyNameTransacion.js | 114 +++--- .../names/CancelSellNameTransacion.js | 78 ++-- .../names/RegisterNameTransaction.js | 94 ++--- .../transactions/names/SellNameTransacion.js | 104 +++--- .../api/transactions/registerName_dnsthing.js | 65 ++-- .../RemoveRewardShareTransaction.js | 88 ++--- .../reward-share/RewardShareTransaction.js | 115 +++--- .../tradebot/TradeBotCreateRequest.js | 106 +++--- .../tradebot/TradeBotRespondRequest.js | 56 ++- .../tradebot/signTradeBotTransaction.js | 43 +-- .../tradeoffer/DeleteTradeOffer.js | 46 ++- .../tradeoffer/cancelAllOffers.js | 35 +- .../api/transactions/transactions.js | 44 +-- .../api/wallet/base58PublicKeyToAddress.js | 9 +- .../api/wallet/publicKeyToAddress.js | 42 ++- .../api/wallet/validateAddress.js | 12 +- qortal-ui-crypto/config.js | 35 +- .../plugins/core/components/ChatModals.js | 1 + .../plugins/core/components/ChatPage.js | 2 + .../core/components/ChatWelcomePage.js | 1 + .../plugins/core/components/NameMenu.js | 1 + .../core/messaging/q-chat/q-chat.src.js | 1 + 58 files changed, 2197 insertions(+), 2446 deletions(-) diff --git a/qortal-ui-crypto/api.js b/qortal-ui-crypto/api.js index b2cfad3c..cc81dc9e 100644 --- a/qortal-ui-crypto/api.js +++ b/qortal-ui-crypto/api.js @@ -2,9 +2,8 @@ import { Sha256 } from 'asmcrypto.js' import Base58 from './api/deps/Base58' import { base58PublicKeyToAddress } from './api/wallet/base58PublicKeyToAddress' import { validateAddress } from './api/wallet/validateAddress' -import { decryptChatMessage } from './api/transactions/chat/decryptChatMessage'; -import _ from 'lodash'; - +import { decryptChatMessage } from './api/transactions/chat/decryptChatMessage' +import _ from 'lodash' window.Sha256 = Sha256 window.Base58 = Base58 @@ -14,7 +13,6 @@ window.validateAddress = validateAddress window.decryptChatMessage = decryptChatMessage export { initApi, store } from './api_deps.js' - export * from './api/deps/deps.js' export * from './api/api.js' export * from './api/registerUsername.js' diff --git a/qortal-ui-crypto/api/PhraseWallet.js b/qortal-ui-crypto/api/PhraseWallet.js index 64baa02b..41818a28 100644 --- a/qortal-ui-crypto/api/PhraseWallet.js +++ b/qortal-ui-crypto/api/PhraseWallet.js @@ -1,7 +1,7 @@ /* Copyright 2017-2018 @ irontiga and vbcs (original developer) */ -'use strict'; +'use strict' import Base58 from './deps/Base58.js' import { Sha256, Sha512 } from 'asmcrypto.js' import nacl from './deps/nacl-fast.js' @@ -10,200 +10,200 @@ import utils from './deps/utils.js' import { generateSaveWalletData } from './storeWallet.js' import publicKeyToAddress from './wallet/publicKeyToAddress.js' -import AltcoinHDWallet from "./bitcoin/AltcoinHDWallet"; +import AltcoinHDWallet from "./bitcoin/AltcoinHDWallet" export default class PhraseWallet { - constructor(seed, walletVersion) { + constructor(seed, walletVersion) { - this._walletVersion = walletVersion || 2 - this.seed = seed + this._walletVersion = walletVersion || 2 + this.seed = seed - this.savedSeedData = {} - this.hasBeenSaved = false - } + this.savedSeedData = {} + this.hasBeenSaved = false + } - set seed(seed) { - this._byteSeed = seed - this._base58Seed = Base58.encode(seed) + set seed(seed) { + this._byteSeed = seed + this._base58Seed = Base58.encode(seed) - this._addresses = [] + this._addresses = [] - this.genAddress(0) - } + this.genAddress(0) + } - getAddress(nonce) { - return this._addresses[nonce] - } + getAddress(nonce) { + return this._addresses[nonce] + } - get addresses() { - return this._addresses - } + get addresses() { + return this._addresses + } - get addressIDs() { - return this._addresses.map(addr => { - return addr.address - }) - } + get addressIDs() { + return this._addresses.map(addr => { + return addr.address + }) + } - get seed() { - return this._byteSeed - } + get seed() { + return this._byteSeed + } - addressExists(nonce) { - return this._addresses[nonce] != undefined - } + addressExists(nonce) { + return this._addresses[nonce] != undefined + } - _genAddressSeed(seed) { - let newSeed = new Sha512().process(seed).finish().result - newSeed = new Sha512().process(utils.appendBuffer(newSeed, seed)).finish().result - return newSeed - } + _genAddressSeed(seed) { + let newSeed = new Sha512().process(seed).finish().result + newSeed = new Sha512().process(utils.appendBuffer(newSeed, seed)).finish().result + return newSeed + } - genAddress(nonce) { - if (nonce >= this._addresses.length) { - this._addresses.length = nonce + 1 - } + genAddress(nonce) { + if (nonce >= this._addresses.length) { + this._addresses.length = nonce + 1 + } - if (this.addressExists(nonce)) { - return this.addresses[nonce] - } + if (this.addressExists(nonce)) { + return this.addresses[nonce] + } - const nonceBytes = utils.int32ToBytes(nonce) + const nonceBytes = utils.int32ToBytes(nonce) - let addrSeed = new Uint8Array() - addrSeed = utils.appendBuffer(addrSeed, nonceBytes) - addrSeed = utils.appendBuffer(addrSeed, this._byteSeed) - addrSeed = utils.appendBuffer(addrSeed, nonceBytes) + let addrSeed = new Uint8Array() + addrSeed = utils.appendBuffer(addrSeed, nonceBytes) + addrSeed = utils.appendBuffer(addrSeed, this._byteSeed) + addrSeed = utils.appendBuffer(addrSeed, nonceBytes) - if (this._walletVersion == 1) { - addrSeed = new Sha256().process( - new Sha256() - .process(addrSeed) - .finish() - .result - ).finish().result + if (this._walletVersion == 1) { + addrSeed = new Sha256().process( + new Sha256() + .process(addrSeed) + .finish() + .result + ).finish().result - addrSeed = this._byteSeed - } else { - addrSeed = this._genAddressSeed(addrSeed).slice(0, 32) - } + addrSeed = this._byteSeed + } else { + addrSeed = this._genAddressSeed(addrSeed).slice(0, 32) + } - const addrKeyPair = nacl.sign.keyPair.fromSeed(new Uint8Array(addrSeed)); + const addrKeyPair = nacl.sign.keyPair.fromSeed(new Uint8Array(addrSeed)); - const address = publicKeyToAddress(addrKeyPair.publicKey); - const qoraAddress = publicKeyToAddress(addrKeyPair.publicKey, true); + const address = publicKeyToAddress(addrKeyPair.publicKey); + const qoraAddress = publicKeyToAddress(addrKeyPair.publicKey, true); - // Create Bitcoin HD Wallet - const btcSeed = [...addrSeed]; - const btcWallet = new AltcoinHDWallet({ - mainnet: { - private: 0x0488ADE4, - public: 0x0488B21E, - prefix: 0 - }, - testnet: { - private: 0x04358394, - public: 0x043587CF, - prefix: 0x6F - } - }).createWallet(new Uint8Array(btcSeed), false); + // Create Bitcoin HD Wallet + const btcSeed = [...addrSeed]; + const btcWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x0488ADE4, + public: 0x0488B21E, + prefix: 0 + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: 0x6F + } + }).createWallet(new Uint8Array(btcSeed), false); - // Create Litecoin HD Wallet - const ltcSeed = [...addrSeed]; - const ltcWallet = new AltcoinHDWallet({ - mainnet: { - private: 0x0488ADE4, - public: 0x0488B21E, - prefix: 0x30 - }, - testnet: { - private: 0x04358394, - public: 0x043587CF, - prefix: 0x6F - } - }).createWallet(new Uint8Array(ltcSeed), false, 'LTC'); + // Create Litecoin HD Wallet + const ltcSeed = [...addrSeed]; + const ltcWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x0488ADE4, + public: 0x0488B21E, + prefix: 0x30 + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: 0x6F + } + }).createWallet(new Uint8Array(ltcSeed), false, 'LTC'); - // Create Dogecoin HD Wallet - const dogeSeed = [...addrSeed]; - const dogeWallet = new AltcoinHDWallet({ - mainnet: { - private: 0x02FAC398, - public: 0x02FACAFD, - prefix: 0x1E - }, - testnet: { - private: 0x04358394, - public: 0x043587CF, - prefix: 0x71 - } - }).createWallet(new Uint8Array(dogeSeed), false, 'DOGE'); + // Create Dogecoin HD Wallet + const dogeSeed = [...addrSeed]; + const dogeWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x02FAC398, + public: 0x02FACAFD, + prefix: 0x1E + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: 0x71 + } + }).createWallet(new Uint8Array(dogeSeed), false, 'DOGE'); - // Create Digibyte HD Wallet - const dgbSeed = [...addrSeed]; - const dgbWallet = new AltcoinHDWallet({ - mainnet: { - private: 0x0488ADE4, - public: 0x0488B21E, - prefix: 0x1E - }, - testnet: { - private: 0x04358394, - public: 0x043587CF, - prefix: 0x7E - } - }).createWallet(new Uint8Array(dgbSeed), false, 'DGB'); + // Create Digibyte HD Wallet + const dgbSeed = [...addrSeed]; + const dgbWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x0488ADE4, + public: 0x0488B21E, + prefix: 0x1E + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: 0x7E + } + }).createWallet(new Uint8Array(dgbSeed), false, 'DGB'); // Create Ravencoin HD Wallet - const rvnSeed = [...addrSeed]; - const rvnWallet = new AltcoinHDWallet({ - mainnet: { - private: 0x0488ADE4, - public: 0x0488B21E, - prefix: 0x3C - }, - testnet: { - private: 0x04358394, - public: 0x043587CF, - prefix: 0x6F - } - }).createWallet(new Uint8Array(rvnSeed), false, 'RVN'); + const rvnSeed = [...addrSeed]; + const rvnWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x0488ADE4, + public: 0x0488B21E, + prefix: 0x3C + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: 0x6F + } + }).createWallet(new Uint8Array(rvnSeed), false, 'RVN'); - // Create Pirate Chain HD Wallet - const arrrSeed = [...addrSeed]; - const arrrWallet = new AltcoinHDWallet({ - mainnet: { - private: 0x0488ADE4, - public: 0x0488B21E, - prefix: [0x16, 0x9A] - }, - testnet: { - private: 0x04358394, - public: 0x043587CF, - prefix: [0x14, 0x51] - } - }).createWallet(new Uint8Array(arrrSeed), false, 'ARRR'); + // Create Pirate Chain HD Wallet + const arrrSeed = [...addrSeed]; + const arrrWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x0488ADE4, + public: 0x0488B21E, + prefix: [0x16, 0x9A] + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: [0x14, 0x51] + } + }).createWallet(new Uint8Array(arrrSeed), false, 'ARRR'); - this._addresses[nonce] = { - address, - btcWallet, - ltcWallet, - dogeWallet, - dgbWallet, - rvnWallet, - arrrWallet, - qoraAddress, - keyPair: { - publicKey: addrKeyPair.publicKey, - privateKey: addrKeyPair.secretKey - }, - base58PublicKey: Base58.encode(addrKeyPair.publicKey), - seed: addrSeed, - nonce: nonce - } - return this._addresses[nonce] - } + this._addresses[nonce] = { + address, + btcWallet, + ltcWallet, + dogeWallet, + dgbWallet, + rvnWallet, + arrrWallet, + qoraAddress, + keyPair: { + publicKey: addrKeyPair.publicKey, + privateKey: addrKeyPair.secretKey + }, + base58PublicKey: Base58.encode(addrKeyPair.publicKey), + seed: addrSeed, + nonce: nonce + } + return this._addresses[nonce] + } - generateSaveWalletData(...args) { - return generateSaveWalletData(this, ...args) - } + generateSaveWalletData(...args) { + return generateSaveWalletData(this, ...args) + } } diff --git a/qortal-ui-crypto/api/api.js b/qortal-ui-crypto/api/api.js index bf40d58a..98da919b 100644 --- a/qortal-ui-crypto/api/api.js +++ b/qortal-ui-crypto/api/api.js @@ -1,9 +1,5 @@ export { request } from './fetch-request.js' - export { transactionTypes as transactions } from './transactions/transactions.js' - export { processTransaction, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js' - export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn, sendArrr } from './tradeRequest.js' - export { cancelAllOffers } from './transactions/trade-portal/tradeoffer/cancelAllOffers.js' diff --git a/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js b/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js index 0d416d54..421d19fb 100644 --- a/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js +++ b/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js @@ -1,11 +1,10 @@ 'use strict'; import Base58 from '../deps/Base58.js' import { Sha256, Sha512 } from 'asmcrypto.js' -import jsSHA from "jssha"; +import jsSHA from 'jssha' import RIPEMD160 from '../deps/ripemd160.js' import utils from '../deps/utils.js' -import { EllipticCurve, BigInteger } from './ecbn.js'; - +import { EllipticCurve, BigInteger } from './ecbn.js' export default class AltcoinHDWallet { @@ -101,14 +100,10 @@ export default class AltcoinHDWallet { this._tmasterPublicKey = '' - - - /** * Child Keys Derivation from the Parent Keys */ - /** * Child Private Key - 32 bytes */ @@ -145,13 +140,10 @@ export default class AltcoinHDWallet { this.xPublicChildKey = '' - - /** * Grand Child Keys Derivation from the Child Keys */ - /** * Grand Child Private Key - 32 bytes */ @@ -200,7 +192,6 @@ export default class AltcoinHDWallet { this._tlitecoinLegacyAddress = '' - /** * Wallet - Wallet Object (keys...) */ @@ -250,76 +241,69 @@ export default class AltcoinHDWallet { generateSeedHash(seed, isBIP44, indicator = null) { - - let buffer; + let buffer if (isBIP44) { buffer = utils.appendBuffer(seed.reverse(), utils.int32ToBytes(indicator)) } else { if(indicator !== null) { - const indicatorString = utils.stringtoUTF8Array(indicator); - buffer = utils.appendBuffer(seed.reverse(), indicatorString); + const indicatorString = utils.stringtoUTF8Array(indicator) + buffer = utils.appendBuffer(seed.reverse(), indicatorString) } else { - buffer = seed.reverse(); + buffer = seed.reverse() } } - const _reverseSeedHash = new Sha256().process(buffer).finish().result; - this.seedHash = new Sha512().process(utils.appendBuffer(seed, _reverseSeedHash)).finish().result; + const _reverseSeedHash = new Sha256().process(buffer).finish().result + this.seedHash = new Sha512().process(utils.appendBuffer(seed, _reverseSeedHash)).finish().result } generatePrivateKey(seedHash) { + const SECP256K1_CURVE_ORDER = new BigInteger("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141") - const SECP256K1_CURVE_ORDER = new BigInteger("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + const privateKeyHash = seedHash.slice(0, 32) - const privateKeyHash = seedHash.slice(0, 32); - - this.seed58 = Base58.encode(privateKeyHash); + this.seed58 = Base58.encode(privateKeyHash) const _privateKeyHash = [...privateKeyHash] - let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash); + let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash) const privateKey = (privateKeyBigInt.mod(SECP256K1_CURVE_ORDER.subtract(BigInteger.ONE))).add(BigInteger.ONE) this.privateKey = privateKey.toByteArrayUnsigned() } generateChainCode(seedHash) { - - this.chainCode = new Sha256().process(seedHash.slice(32, 64)).finish().result; + this.chainCode = new Sha256().process(seedHash.slice(32, 64)).finish().result } generatePublicKey(privateKey) { - const _privateKey = [...privateKey] - const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey); + const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey) - const epCurve = EllipticCurve.getSECCurveByName("secp256k1"); - const curvePoints = epCurve.getG().multiply(privateKeyBigInt); + const epCurve = EllipticCurve.getSECCurveByName("secp256k1") + const curvePoints = epCurve.getG().multiply(privateKeyBigInt) - const x = curvePoints.getX().toBigInteger(); - const y = curvePoints.getY().toBigInteger(); + const x = curvePoints.getX().toBigInteger() + const y = curvePoints.getY().toBigInteger() /** * Deriving Uncompressed Public Key (65 bytes) * - * const publicKeyBytes = EllipticCurve.integerToBytes(x, 32); - * this.publicKey = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32)); - * this.publicKey.unshift(0x04); // append point indicator + * const publicKeyBytes = EllipticCurve.integerToBytes(x, 32) + * this.publicKey = publicKeyBytes.concat(EllipticCurve.integerToBytes(y, 32)) + * this.publicKey.unshift(0x04) // append point indicator */ - // Compressed Public Key (33 bytes) this.publicKey = EllipticCurve.integerToBytes(x, 32) if (y.isEven()) { - this.publicKey.unshift(0x02) // append point indicator } else { - this.publicKey.unshift(0x03) // append point indicator } @@ -330,7 +314,6 @@ export default class AltcoinHDWallet { } generateMainnetMasterPrivateKey() { - // Serialization Variable const s = [] @@ -375,7 +358,6 @@ export default class AltcoinHDWallet { } generateMainnetMasterPublicKey() { - // Serialization Variable const s = [] @@ -495,19 +477,19 @@ export default class AltcoinHDWallet { // TODO: Make this more better in the future const path = 'm/0/0' - // let p = path.split('/'); + // let p = path.split('/') // Get Public kEY const derivePublicChildKey = () => { const _privateKey = [...this.childPrivateKey] - const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey); + const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey) - const epCurve = EllipticCurve.getSECCurveByName("secp256k1"); - const curvePoints = epCurve.getG().multiply(privateKeyBigInt); + const epCurve = EllipticCurve.getSECCurveByName("secp256k1") + const curvePoints = epCurve.getG().multiply(privateKeyBigInt) - const x = curvePoints.getX().toBigInteger(); - const y = curvePoints.getY().toBigInteger(); + const x = curvePoints.getX().toBigInteger() + const y = curvePoints.getY().toBigInteger() // Compressed Public Key (33 bytes) this.childPublicKey = EllipticCurve.integerToBytes(x, 32) @@ -533,15 +515,15 @@ export default class AltcoinHDWallet { const derivePrivateChildKey = (cI) => { - let ib = []; - ib.push((cI >> 24) & 0xff); - ib.push((cI >> 16) & 0xff); - ib.push((cI >> 8) & 0xff); - ib.push(cI & 0xff); + let ib = [] + ib.push((cI >> 24) & 0xff) + ib.push((cI >> 16) & 0xff) + ib.push((cI >> 8) & 0xff) + ib.push(cI & 0xff) - const s = [...this.publicKey].concat(ib); + const s = [...this.publicKey].concat(ib) - const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.chainCode, format: "UINT8ARRAY" } }); + const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.chainCode, format: "UINT8ARRAY" } }) _hmacSha512.update(new Uint8Array(s)) @@ -550,10 +532,10 @@ export default class AltcoinHDWallet { // SECP256k1 init - const epCurve = EllipticCurve.getSECCurveByName("secp256k1"); + const epCurve = EllipticCurve.getSECCurveByName("secp256k1") - const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.privateKey)).mod(epCurve.getN()); // parse256(IL) + kpar (mod n) ==> ki + const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.privateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki this.childPrivateKey = ki.toByteArrayUnsigned() // Call deriveExtendedPrivateChildKey @@ -577,10 +559,10 @@ export default class AltcoinHDWallet { s.push(...(this.publicKeyHash.slice(0, 4))) // Append Child Index - s.push(childIndex >>> 24); - s.push((childIndex >>> 16) & 0xff); - s.push((childIndex >>> 8) & 0xff); - s.push(childIndex & 0xff); + s.push(childIndex >>> 24) + s.push((childIndex >>> 16) & 0xff) + s.push((childIndex >>> 8) & 0xff) + s.push(childIndex & 0xff) // Append Chain Code s.push(...this.childChainCode) @@ -619,10 +601,10 @@ export default class AltcoinHDWallet { s.push(...(this.publicKeyHash.slice(0, 4))) // Append Child Index - s.push(childIndex >>> 24); - s.push((childIndex >>> 16) & 0xff); - s.push((childIndex >>> 8) & 0xff); - s.push(childIndex & 0xff); + s.push(childIndex >>> 24) + s.push((childIndex >>> 16) & 0xff) + s.push((childIndex >>> 8) & 0xff) + s.push(childIndex & 0xff) // Append Chain Code s.push(...this.childChainCode) @@ -654,24 +636,22 @@ export default class AltcoinHDWallet { const derivePublicGrandChildKey = () => { const _privateKey = [...this.grandChildPrivateKey] - const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey); + const privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKey) - const epCurve = EllipticCurve.getSECCurveByName("secp256k1"); - const curvePoints = epCurve.getG().multiply(privateKeyBigInt); + const epCurve = EllipticCurve.getSECCurveByName("secp256k1") + const curvePoints = epCurve.getG().multiply(privateKeyBigInt) - const x = curvePoints.getX().toBigInteger(); - const y = curvePoints.getY().toBigInteger(); + const x = curvePoints.getX().toBigInteger() + const y = curvePoints.getY().toBigInteger() // Compressed Public Key (33 bytes) this.grandChildPublicKey = EllipticCurve.integerToBytes(x, 32) if (y.isEven()) { - this.grandChildPublicKey.unshift(0x02) // append point indicator } else { - this.grandChildPublicKey.unshift(0x03) // append point indicator } @@ -729,16 +709,16 @@ export default class AltcoinHDWallet { const derivePrivateGrandChildKey = (cI, i) => { - let ib = []; - ib.push((cI >> 24) & 0xff); - ib.push((cI >> 16) & 0xff); - ib.push((cI >> 8) & 0xff); - ib.push(cI & 0xff); + let ib = [] + ib.push((cI >> 24) & 0xff) + ib.push((cI >> 16) & 0xff) + ib.push((cI >> 8) & 0xff) + ib.push(cI & 0xff) - const s = [...this.childPublicKey].concat(ib); + const s = [...this.childPublicKey].concat(ib) - const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.childChainCode, format: "UINT8ARRAY" } }); + const _hmacSha512 = new jsSHA("SHA-512", "UINT8ARRAY", { numRounds: 1, hmacKey: { value: this.childChainCode, format: "UINT8ARRAY" } }) _hmacSha512.update(new Uint8Array(s)) @@ -746,10 +726,10 @@ export default class AltcoinHDWallet { this.grandChildChainCode = _hmacSha512.getHMAC('UINT8ARRAY').slice(32, 64) // IR according to the SPEC // SECP256k1 init - const epCurve = EllipticCurve.getSECCurveByName("secp256k1"); + const epCurve = EllipticCurve.getSECCurveByName("secp256k1") - const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.childPrivateKey)).mod(epCurve.getN()); // parse256(IL) + kpar (mod n) ==> ki + const ki = IL.add(BigInteger.fromByteArrayUnsigned(this.childPrivateKey)).mod(epCurve.getN()) // parse256(IL) + kpar (mod n) ==> ki this.grandChildPrivateKey = ki.toByteArrayUnsigned() @@ -774,10 +754,10 @@ export default class AltcoinHDWallet { s.push(...(this.childPublicKeyHash.slice(0, 4))) // Append Child Index - s.push(childIndex >>> 24); - s.push((childIndex >>> 16) & 0xff); - s.push((childIndex >>> 8) & 0xff); - s.push(childIndex & 0xff); + s.push(childIndex >>> 24) + s.push((childIndex >>> 16) & 0xff) + s.push((childIndex >>> 8) & 0xff) + s.push(childIndex & 0xff) // Append Chain Code s.push(...this.grandChildChainCode) @@ -816,10 +796,10 @@ export default class AltcoinHDWallet { s.push(...(this.childPublicKeyHash.slice(0, 4))) // Append Child Index - s.push(childIndex >>> 24); - s.push((childIndex >>> 16) & 0xff); - s.push((childIndex >>> 8) & 0xff); - s.push(childIndex & 0xff); + s.push(childIndex >>> 24) + s.push((childIndex >>> 16) & 0xff) + s.push((childIndex >>> 8) & 0xff) + s.push(childIndex & 0xff) // Append Chain Code s.push(...this.grandChildChainCode) diff --git a/qortal-ui-crypto/api/constants.js b/qortal-ui-crypto/api/constants.js index 511ab99e..2bbb349f 100644 --- a/qortal-ui-crypto/api/constants.js +++ b/qortal-ui-crypto/api/constants.js @@ -1,152 +1,152 @@ -"use strict"; +'use strict' // Qortal TX types const TX_TYPES = { - 1: "Genesis", - 2: "Payment", - 3: "Name registration", - 4: "Name update", - 5: "Sell name", - 6: "Cancel sell name", - 7: "Buy name", - 8: "Create poll", - 9: "Vote in poll", - 10: "Arbitrary", - 11: "Issue asset", - 12: "Transfer asset", - 13: "Create asset order", - 14: "Cancel asset order", - 15: "Multi-payment transaction", - 16: "Deploy AT", - 17: "Message", - 18: "Chat", - 19: "Publicize", - 20: "Airdrop", - 21: "AT", - 22: "Create group", - 23: "Update group", - 24: "Add group admin", - 25: "Remove group admin", - 26: "Group ban", - 27: "Cancel group ban", - 28: "Group kick", - 29: "Group invite", - 30: "Cancel group invite", - 31: "Join group", - 32: "Leave group", - 33: "Group approval", - 34: "Set group", - 35: "Update asset", - 36: "Account flags", - 37: "Enable forging", - 38: "Reward share", - 39: "Account level", - 40: "Transfer privs", - 41: "Presence" + 1: "Genesis", + 2: "Payment", + 3: "Name registration", + 4: "Name update", + 5: "Sell name", + 6: "Cancel sell name", + 7: "Buy name", + 8: "Create poll", + 9: "Vote in poll", + 10: "Arbitrary", + 11: "Issue asset", + 12: "Transfer asset", + 13: "Create asset order", + 14: "Cancel asset order", + 15: "Multi-payment transaction", + 16: "Deploy AT", + 17: "Message", + 18: "Chat", + 19: "Publicize", + 20: "Airdrop", + 21: "AT", + 22: "Create group", + 23: "Update group", + 24: "Add group admin", + 25: "Remove group admin", + 26: "Group ban", + 27: "Cancel group ban", + 28: "Group kick", + 29: "Group invite", + 30: "Cancel group invite", + 31: "Join group", + 32: "Leave group", + 33: "Group approval", + 34: "Set group", + 35: "Update asset", + 36: "Account flags", + 37: "Enable forging", + 38: "Reward share", + 39: "Account level", + 40: "Transfer privs", + 41: "Presence" } // Qortal error codes const ERROR_CODES = { - 1: "Valid OK", - 2: "Invalid address", - 3: "Negative amount", - 4: "Nagative fee", - 5: "No balance", - 6: "Invalid reference", - 7: "Invalid time length", - 8: "Invalid value length", - 9: "Name already registered", - 10: "Name does not exist", - 11: "Invalid name owner", - 12: "Name already for sale", - 13: "Name not for sale", - 14: "Name buyer already owner", - 15: "Invalid amount", - 16: "Invalid seller", - 17: "Name not lowercase", - 18: "Invalid description length", - 19: "Invalid options length", - 20: "Invalid option length", - 21: "Duplicate option", - 22: "Poll already created", - 23: "Poll already has votes", - 24: "Poll does not exist", - 25: "Option does not exist", - 26: "Already voted for that option", - 27: "Invalid data length", - 28: "Invalid quantity", - 29: "Asset does not exist", - 30: "Invalid return", - 31: "Have equals want", - 32: "Order does not exist", - 33: "Invalid order creator", - 34: "Invalid payments length", - 35: "Negative price", - 36: "Invalid creation bytes", - 37: "Invalid tags length", - 38: "Invalid type length", - 39: "Invalid AT transaction", - 40: "Insufficient fee", - 41: "Asset does not match AT", + 1: "Valid OK", + 2: "Invalid address", + 3: "Negative amount", + 4: "Nagative fee", + 5: "No balance", + 6: "Invalid reference", + 7: "Invalid time length", + 8: "Invalid value length", + 9: "Name already registered", + 10: "Name does not exist", + 11: "Invalid name owner", + 12: "Name already for sale", + 13: "Name not for sale", + 14: "Name buyer already owner", + 15: "Invalid amount", + 16: "Invalid seller", + 17: "Name not lowercase", + 18: "Invalid description length", + 19: "Invalid options length", + 20: "Invalid option length", + 21: "Duplicate option", + 22: "Poll already created", + 23: "Poll already has votes", + 24: "Poll does not exist", + 25: "Option does not exist", + 26: "Already voted for that option", + 27: "Invalid data length", + 28: "Invalid quantity", + 29: "Asset does not exist", + 30: "Invalid return", + 31: "Have equals want", + 32: "Order does not exist", + 33: "Invalid order creator", + 34: "Invalid payments length", + 35: "Negative price", + 36: "Invalid creation bytes", + 37: "Invalid tags length", + 38: "Invalid type length", + 39: "Invalid AT transaction", + 40: "Insufficient fee", + 41: "Asset does not match AT", - 43: "Asset already exists", - 44: "Missing creator", - 45: "Timestamp too old", - 46: "Timestamp too new", - 47: "Too many unconfirmed", - 48: "Group already exists", - 49: "Group does not exist", - 50: "Invalid group owner", - 51: "Already group memeber", - 52: "Group owner can not leave", - 53: "Not group member", - 54: "Already group admin", - 55: "Not group admin", - 56: "Invalid lifetime", - 57: "Invite unknown", - 58: "Ban exists", - 59: "Ban unknown", - 60: "Banned from group", - 61: "Join request", - 62: "Invalid group approval threshold", - 63: "Group ID mismatch", - 64: "Invalid group ID", - 65: "Transaction unknown", - 66: "Transaction already confirmed", - 67: "Invalid TX group", - 68: "TX group ID mismatch", - 69: "Multiple names forbidden", - 70: "Invalid asset owner", - 71: "AT is finished", - 72: "No flag permission", - 73: "Not minting accout", + 43: "Asset already exists", + 44: "Missing creator", + 45: "Timestamp too old", + 46: "Timestamp too new", + 47: "Too many unconfirmed", + 48: "Group already exists", + 49: "Group does not exist", + 50: "Invalid group owner", + 51: "Already group memeber", + 52: "Group owner can not leave", + 53: "Not group member", + 54: "Already group admin", + 55: "Not group admin", + 56: "Invalid lifetime", + 57: "Invite unknown", + 58: "Ban exists", + 59: "Ban unknown", + 60: "Banned from group", + 61: "Join request", + 62: "Invalid group approval threshold", + 63: "Group ID mismatch", + 64: "Invalid group ID", + 65: "Transaction unknown", + 66: "Transaction already confirmed", + 67: "Invalid TX group", + 68: "TX group ID mismatch", + 69: "Multiple names forbidden", + 70: "Invalid asset owner", + 71: "AT is finished", + 72: "No flag permission", + 73: "Not minting accout", - 77: "Invalid rewardshare percent", - 78: "Public key unknown", - 79: "Invalid public key", - 80: "AT unknown", - 81: "AT already exists", - 82: "Group approval not required", - 83: "Group approval decided", - 84: "Maximum reward shares", - 85: "Transaction already exists", - 86: "No blockchain lock", - 87: "Order already closed", - 88: "Clock not synced", - 89: "Asset not spendable", - 90: "Account can not reward share", - 91: "Self share exists", - 92: "Account already exists", - 93: "Invalid group block delay", - 94: "Incorrect nonce", - 95: "Ivalid timestamp signature", - 96: "Address blocked", - 97: "Name Blocked", - 98: "Group approval required", - 99: "Account not transferable", + 77: "Invalid rewardshare percent", + 78: "Public key unknown", + 79: "Invalid public key", + 80: "AT unknown", + 81: "AT already exists", + 82: "Group approval not required", + 83: "Group approval decided", + 84: "Maximum reward shares", + 85: "Transaction already exists", + 86: "No blockchain lock", + 87: "Order already closed", + 88: "Clock not synced", + 89: "Asset not spendable", + 90: "Account can not reward share", + 91: "Self share exists", + 92: "Account already exists", + 93: "Invalid group block delay", + 94: "Incorrect nonce", + 95: "Ivalid timestamp signature", + 96: "Address blocked", + 97: "Name Blocked", + 98: "Group approval required", + 99: "Account not transferable", - 999: "Ivalid but ok", - 1000: "Not yet released." + 999: "Ivalid but ok", + 1000: "Not yet released." } // Qortal 8 decimals @@ -158,6 +158,9 @@ const ADDRESS_VERSION = 58 // Proxy for api calls const PROXY_URL = "/proxy/" +// Chat reference timestamp +const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 9999999999999 + // Used as a salt for all qora addresses. Salts used for storing your private keys in local storage will be randomly generated const STATIC_SALT = new Uint8Array([54, 190, 201, 206, 65, 29, 123, 129, 147, 231, 180, 166, 171, 45, 95, 165, 78, 200, 208, 194, 44, 207, 221, 146, 45, 238, 68, 68, 69, 102, 62, 6]) const BCRYPT_ROUNDS = 10 // Remember that the total work spent on key derivation is BCRYPT_ROUNDS * KDF_THREADS @@ -165,4 +168,4 @@ const BCRYPT_VERSION = "2a" const STATIC_BCRYPT_SALT = `$${BCRYPT_VERSION}$${BCRYPT_ROUNDS}$IxVE941tXVUD4cW0TNVm.O` const KDF_THREADS = 16 -export { TX_TYPES, ERROR_CODES, QORT_DECIMALS, PROXY_URL, STATIC_SALT, ADDRESS_VERSION, KDF_THREADS, STATIC_BCRYPT_SALT } +export { TX_TYPES, ERROR_CODES, QORT_DECIMALS, PROXY_URL, STATIC_SALT, ADDRESS_VERSION, KDF_THREADS, STATIC_BCRYPT_SALT, CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } diff --git a/qortal-ui-crypto/api/createTransaction.js b/qortal-ui-crypto/api/createTransaction.js index d876b98a..2a56aa56 100644 --- a/qortal-ui-crypto/api/createTransaction.js +++ b/qortal-ui-crypto/api/createTransaction.js @@ -6,33 +6,33 @@ import signArbitrary from './transactions/arbitrary/signArbitrary.js' export const createTransaction = (type, keyPair, params) => { - const tx = new transactions[type]() - tx.keyPair = keyPair - Object.keys(params).forEach(param => { - tx[param] = params[param] - }) + const tx = new transactions[type]() + tx.keyPair = keyPair + Object.keys(params).forEach(param => { + tx[param] = params[param] + }) - return tx + return tx } // Compute Chat Nonce export const computeChatNonce = bytes => request('/chat/compute', { - method: 'POST', - body: Base58.encode(bytes) + method: 'POST', + body: Base58.encode(bytes) }) // Sign Chat Transactions export const signChatTransaction = (chatBytes, nonce, keyPair) => { - return signChat(chatBytes, nonce, keyPair) + return signChat(chatBytes, nonce, keyPair) } // Sign Arbitrary Transactions export const signArbitraryTransaction = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) => { - return signArbitrary(arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) + return signArbitrary(arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) } // Process Transactions export const processTransaction = bytes => request('/transactions/process', { - method: 'POST', - body: Base58.encode(bytes) + method: 'POST', + body: Base58.encode(bytes) }) diff --git a/qortal-ui-crypto/api/createWallet.js b/qortal-ui-crypto/api/createWallet.js index d342c7c3..ed978183 100644 --- a/qortal-ui-crypto/api/createWallet.js +++ b/qortal-ui-crypto/api/createWallet.js @@ -4,26 +4,26 @@ import Base58 from './deps/Base58.js' import { decryptStoredWallet } from './decryptStoredWallet.js' export const createWallet = async (sourceType, source, statusUpdateFn) => { - let version, seed + let version, seed - switch (sourceType) { - case 'phrase': - version = 2 - seed = await kdf(source.seedPhrase, void 0, statusUpdateFn) - break - case 'seed': - version = 1 - seed = Base58.decode(source.seed) - break - case 'storedWallet': - case 'backedUpSeed': - version = source.wallet.version - seed = await decryptStoredWallet(source.password, source.wallet, statusUpdateFn) - break - default: - throw 'sourceType ' + sourceType + ' not recognized' - } + switch (sourceType) { + case 'phrase': + version = 2 + seed = await kdf(source.seedPhrase, void 0, statusUpdateFn) + break + case 'seed': + version = 1 + seed = Base58.decode(source.seed) + break + case 'storedWallet': + case 'backedUpSeed': + version = source.wallet.version + seed = await decryptStoredWallet(source.password, source.wallet, statusUpdateFn) + break + default: + throw 'sourceType ' + sourceType + ' not recognized' + } - const wallet = new PhraseWallet(seed, version) - return wallet + const wallet = new PhraseWallet(seed, version) + return wallet } diff --git a/qortal-ui-crypto/api/decryptStoredWallet.js b/qortal-ui-crypto/api/decryptStoredWallet.js index e47a33b4..f98649cd 100644 --- a/qortal-ui-crypto/api/decryptStoredWallet.js +++ b/qortal-ui-crypto/api/decryptStoredWallet.js @@ -3,21 +3,21 @@ import { kdf } from './kdf.js' import { HmacSha512, AES_CBC } from 'asmcrypto.js' export const decryptStoredWallet = async (password, wallet, statusFn = () => { }) => { - statusFn('Decoding saved data') - const encryptedSeedBytes = Base58.decode(wallet.encryptedSeed) - const iv = Base58.decode(wallet.iv) - const salt = Base58.decode(wallet.salt) - statusFn('Generating decryption key') - const key = await kdf(password, salt, statusFn) - const encryptionKey = key.slice(0, 32) - const macKey = key.slice(32, 63) + statusFn('Decoding saved data') + const encryptedSeedBytes = Base58.decode(wallet.encryptedSeed) + const iv = Base58.decode(wallet.iv) + const salt = Base58.decode(wallet.salt) + statusFn('Generating decryption key') + const key = await kdf(password, salt, statusFn) + const encryptionKey = key.slice(0, 32) + const macKey = key.slice(32, 63) - statusFn('Checking key') - const mac = new HmacSha512(macKey).process(encryptedSeedBytes).finish().result - if (Base58.encode(mac) !== wallet.mac) { - throw new Error('Incorrect password') - } - statusFn('Decrypting') - const decryptedBytes = AES_CBC.decrypt(encryptedSeedBytes, encryptionKey, false, iv) - return decryptedBytes + statusFn('Checking key') + const mac = new HmacSha512(macKey).process(encryptedSeedBytes).finish().result + if (Base58.encode(mac) !== wallet.mac) { + throw new Error('Incorrect password') + } + statusFn('Decrypting') + const decryptedBytes = AES_CBC.decrypt(encryptedSeedBytes, encryptionKey, false, iv) + return decryptedBytes } diff --git a/qortal-ui-crypto/api/kdf.js b/qortal-ui-crypto/api/kdf.js index b94134ac..8c18888a 100644 --- a/qortal-ui-crypto/api/kdf.js +++ b/qortal-ui-crypto/api/kdf.js @@ -4,36 +4,36 @@ import { Sha512 } from 'asmcrypto.js' import utils from '../api/deps/utils.js' export const kdf = async (seed, salt, status = () => { }) => { - const state = store.getState() - const config = state.config - const workers = state.app.workers.workers - status('Waiting for workers to be ready') - await stateAwait(state => state.app.workers.ready) - status('Deriving key parts') - salt = new Uint8Array(salt) - const seedParts = await Promise.all(workers.map((worker, index) => { - const nonce = index - return worker.request('kdf', { - key: seed, - salt, - nonce, - staticSalt: config.crypto.staticSalt, - staticBcryptSalt: config.crypto.staticBcryptSalt - }).then(data => { - let jsonData - try { - jsonData = JSON.parse(data) - data = jsonData - } catch (e) { - // ... - } - if (seed !== data.key) throw new Error('Error, incorrect key. ' + seed + ' !== ' + data.key) - if (nonce !== data.nonce) throw new Error('Error, incorrect nonce') - return data.result - }) - })) - status('Combining key parts') - const result = new Sha512().process(utils.stringtoUTF8Array(config.crypto.staticSalt + seedParts.reduce((a, c) => a + c))).finish().result - status('Key is ready ') - return result + const state = store.getState() + const config = state.config + const workers = state.app.workers.workers + status('Waiting for workers to be ready') + await stateAwait(state => state.app.workers.ready) + status('Deriving key parts') + salt = new Uint8Array(salt) + const seedParts = await Promise.all(workers.map((worker, index) => { + const nonce = index + return worker.request('kdf', { + key: seed, + salt, + nonce, + staticSalt: config.crypto.staticSalt, + staticBcryptSalt: config.crypto.staticBcryptSalt + }).then(data => { + let jsonData + try { + jsonData = JSON.parse(data) + data = jsonData + } catch (e) { + // ... + } + if (seed !== data.key) throw new Error('Error, incorrect key. ' + seed + ' !== ' + data.key) + if (nonce !== data.nonce) throw new Error('Error, incorrect nonce') + return data.result + }) + })) + status('Combining key parts') + const result = new Sha512().process(utils.stringtoUTF8Array(config.crypto.staticSalt + seedParts.reduce((a, c) => a + c))).finish().result + status('Key is ready ') + return result } diff --git a/qortal-ui-crypto/api/registerUsername.js b/qortal-ui-crypto/api/registerUsername.js index c270c209..9715a078 100644 --- a/qortal-ui-crypto/api/registerUsername.js +++ b/qortal-ui-crypto/api/registerUsername.js @@ -8,39 +8,32 @@ const CHECK_LAST_REF_INTERVAL = 30 * 1000 // err 30 seconds const pendingAddresses = {} -// const config = store.getState().config -// const node = config.coin.node.api -// const baseUrl = node.url + node.tail - const checkLastRefs = () => { - Object.entries(pendingAddresses).forEach(([address, fn]) => { - // console.log(fn, address) - request('addresses/lastreference/' + address).then(res => { - if (res === 'false') return - fn(res) - delete pendingAddresses[address] - clearInterval(lastRefInterval) - }) - // fetch(baseUrl + 'addresses/lastreference/' + address) - // .then(async res => res.text()) - }) + Object.entries(pendingAddresses).forEach(([address, fn]) => { + request('addresses/lastreference/' + address).then(res => { + if (res === 'false') return + fn(res) + delete pendingAddresses[address] + clearInterval(lastRefInterval) + }) + }) } const lastRefInterval = setInterval(() => checkLastRefs(), CHECK_LAST_REF_INTERVAL) const callOnLastRef = (address, fn) => { - pendingAddresses[address] = fn + pendingAddresses[address] = fn } export const registerUsername = async ({ name, address, lastRef, keyPair }) => { - callOnLastRef(address, lastreference => { - const txBytes = createTransaction(TX_TYPE, keyPair, { - registrantPublicKey: keyPair.publicKey, - registrantAddress: address, - name, - value: address, - lastReference: lastreference - }) - processTransaction(txBytes).then(res => {}) - }) + callOnLastRef(address, lastreference => { + const txBytes = createTransaction(TX_TYPE, keyPair, { + registrantPublicKey: keyPair.publicKey, + registrantAddress: address, + name, + value: address, + lastReference: lastreference + }) + processTransaction(txBytes).then(res => { }) + }) } diff --git a/qortal-ui-crypto/api/storeWallet.js b/qortal-ui-crypto/api/storeWallet.js index eab5fa99..9d16c8af 100644 --- a/qortal-ui-crypto/api/storeWallet.js +++ b/qortal-ui-crypto/api/storeWallet.js @@ -1,33 +1,29 @@ import { HmacSha512, AES_CBC } from 'asmcrypto.js' import { kdf } from './kdf.js' -// import Base58 from '../qora/deps/Base58.js' import Base58 from './deps/Base58.js' const getRandomValues = window.crypto ? window.crypto.getRandomValues.bind(window.crypto) : window.msCrypto.getRandomValues.bind(window.msCrypto) export const generateSaveWalletData = async (wallet, password, kdfThreads, statusUpdateFn) => { - statusUpdateFn('Generating random values') - let iv = new Uint8Array(16) - getRandomValues(iv) - let salt = new Uint8Array(32) - getRandomValues(salt) // Can actually use a salt this time, as we can store the salt with the wallet - - // const key = PBKDF2_HMAC_SHA512.bytes(utils.stringtoUTF8Array(password), salt, PBKDF2_ROUNDS, 64) // 512bit key to be split in two for mac/encryption - const key = await kdf(password, salt, statusUpdateFn) - statusUpdateFn('Encrypting seed') - const encryptionKey = key.slice(0, 32) - const macKey = key.slice(32, 63) - const encryptedSeed = AES_CBC.encrypt(wallet._byteSeed, encryptionKey, false, iv) - // const mac = HmacSha512.bytes(encryptedSeed, macKey) - statusUpdateFn('Generating mac') - const mac = new HmacSha512(macKey).process(encryptedSeed).finish().result - return { - address0: wallet._addresses[0].address, - encryptedSeed: Base58.encode(encryptedSeed), - salt: Base58.encode(salt), - iv: Base58.encode(iv), - version: wallet._walletVersion, - mac: Base58.encode(mac), - kdfThreads - } + statusUpdateFn('Generating random values') + let iv = new Uint8Array(16) + getRandomValues(iv) + let salt = new Uint8Array(32) + getRandomValues(salt) + const key = await kdf(password, salt, statusUpdateFn) + statusUpdateFn('Encrypting seed') + const encryptionKey = key.slice(0, 32) + const macKey = key.slice(32, 63) + const encryptedSeed = AES_CBC.encrypt(wallet._byteSeed, encryptionKey, false, iv) + statusUpdateFn('Generating mac') + const mac = new HmacSha512(macKey).process(encryptedSeed).finish().result + return { + address0: wallet._addresses[0].address, + encryptedSeed: Base58.encode(encryptedSeed), + salt: Base58.encode(salt), + iv: Base58.encode(iv), + version: wallet._walletVersion, + mac: Base58.encode(mac), + kdfThreads + } } diff --git a/qortal-ui-crypto/api/tradeRequest.js b/qortal-ui-crypto/api/tradeRequest.js index f3ae00f0..797cbe5b 100644 --- a/qortal-ui-crypto/api/tradeRequest.js +++ b/qortal-ui-crypto/api/tradeRequest.js @@ -1,145 +1,140 @@ // Trade Bot -import TradeBotCreateRequest from './transactions/trade-portal/tradebot/TradeBotCreateRequest.js'; -import TradeBotRespondRequest from './transactions/trade-portal/tradebot/TradeBotRespondRequest.js'; +import TradeBotCreateRequest from './transactions/trade-portal/tradebot/TradeBotCreateRequest.js' +import TradeBotRespondRequest from './transactions/trade-portal/tradebot/TradeBotRespondRequest.js' import signTradeBotTransaction from './transactions/trade-portal/tradebot/signTradeBotTransaction.js' - -// Trade Offer -import DeleteTradeOffer from './transactions/trade-portal/tradeoffer/DeleteTradeOffer.js'; - +import DeleteTradeOffer from './transactions/trade-portal/tradeoffer/DeleteTradeOffer.js' import { request } from './fetch-request' - // TradeBotCreateRequest export const tradeBotCreateRequest = (requestObject) => { - const txn = new TradeBotCreateRequest().createTransaction(requestObject) - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const txn = new TradeBotCreateRequest().createTransaction(requestObject) + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/tradebot/create?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'text/plain', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(txn) - }) + return request(`/crosschain/tradebot/create?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'text/plain', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(txn) + }) } // TradeBotRespondRequest export const tradeBotRespondRequest = (requestObject) => { - const txn = new TradeBotRespondRequest().createTransaction(requestObject) - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const txn = new TradeBotRespondRequest().createTransaction(requestObject) + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/tradebot/respond?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(txn) - }) + return request(`/crosschain/tradebot/respond?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(txn) + }) } - // Sign Trade Transactions export const signTradeBotTxn = (unsignedTxn, keyPair) => { - return signTradeBotTransaction(unsignedTxn, keyPair) + return signTradeBotTransaction(unsignedTxn, keyPair) } // Delete Trade Offer export const deleteTradeOffer = (requestObject) => { - const txn = new DeleteTradeOffer().createTransaction(requestObject) - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const txn = new DeleteTradeOffer().createTransaction(requestObject) + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/tradeoffer?apiKey=${myNode.apiKey}`, { - method: 'DELETE', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(txn) - }) + return request(`/crosschain/tradeoffer?apiKey=${myNode.apiKey}`, { + method: 'DELETE', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(txn) + }) } // Send BTC export const sendBtc = (requestObject) => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/btc/send?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestObject) - }) + return request(`/crosschain/btc/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) } // Send LTC export const sendLtc = (requestObject) => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/ltc/send?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestObject) - }) + return request(`/crosschain/ltc/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) } // Send DOGE export const sendDoge = (requestObject) => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/doge/send?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestObject) - }) + return request(`/crosschain/doge/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) } // Send DGB export const sendDgb = (requestObject) => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/dgb/send?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestObject) - }) + return request(`/crosschain/dgb/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) } // Send RVN export const sendRvn = (requestObject) => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/rvn/send?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestObject) - }) + return request(`/crosschain/rvn/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) } // Send ARRR export const sendArrr = (requestObject) => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - return request(`/crosschain/arrr/send?apiKey=${myNode.apiKey}`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestObject) - }) + return request(`/crosschain/arrr/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) } diff --git a/qortal-ui-crypto/api/transactions/AirdropTransaction.js b/qortal-ui-crypto/api/transactions/AirdropTransaction.js index 552e42e8..e23029a8 100644 --- a/qortal-ui-crypto/api/transactions/AirdropTransaction.js +++ b/qortal-ui-crypto/api/transactions/AirdropTransaction.js @@ -1,50 +1,35 @@ -'use strict'; +'use strict' import TransactionBase from './TransactionBase.js' import { QORT_DECIMALS } from '../constants.js' -// import { Sha256 } from 'asmcrypto.js/dist_es5/entry-export_all.js' export default class PaymentTransaction extends TransactionBase { - constructor () { - super() - this.type = 20 - this.amount = 42 * Math.pow(10, 8) - this.tests.push( - () => { - if (!(this._amount >= 0)) { - return 'Invalid amount ' + this._amount / QORT_DECIMALS - } - return true - }, - () => { - if (!(this._recipient instanceof Uint8Array && this._recipient.length == 25)) { - return 'Invalid recipient ' + Base58.encode(this._recipient) - } - return true - } - ) - } + constructor() { + super() + this.type = 20 + } - set recipient (recipient) { // Always Base58 encoded. Accepts Uint8Array or Base58 string. - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - } - set amount (amount) { - this._amount = amount * QORT_DECIMALS - this._amountBytes = this.constructor.utils.int64ToBytes(amount) - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + } - set reference (seed) { - const sha = seed => new Sha512().process(seed).finish().result - let reference = sha(sha(seed)) - reference += reference - } + set amount(amount) { + this._amount = amount * QORT_DECIMALS + this._amountBytes = this.constructor.utils.int64ToBytes(amount) + } - get params () { - const params = super.params - params.push( - this._recipient, - this._amountBytes, - this._feeBytes - ) - return params - } + set reference(seed) { + const sha = seed => new Sha512().process(seed).finish().result + let reference = sha(sha(seed)) + reference += reference + } + + get params() { + const params = super.params + params.push( + this._recipient, + this._amountBytes, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/DelegationTransaction.js b/qortal-ui-crypto/api/transactions/DelegationTransaction.js index bc74502a..d2b670b8 100644 --- a/qortal-ui-crypto/api/transactions/DelegationTransaction.js +++ b/qortal-ui-crypto/api/transactions/DelegationTransaction.js @@ -1,31 +1,22 @@ -'use strict'; +'use strict' import TransactionBase from './TransactionBase.js' -// import { QORT_DECIMALS } from "../constants.js" // Not needed, no amount export default class DelegationTransaction extends TransactionBase { - constructor () { - super() - this.type = 18 - this.tests.push( - () => { - if (!(this._superNodeAddress instanceof Uint8Array && this._superNodeAddress.length == 25)) { - return 'Invalid recipient ' + Base58.encode(this._superNodeAddress) - } - return true - } - ) - } + constructor() { + super() + this.type = 18 + } - set superNodeAddress (superNodeAddress) { // Always Base58 encoded. Accepts Uint8Array or Base58 string. - this._superNodeAddress = superNodeAddress instanceof Uint8Array ? superNodeAddress : this.constructor.Base58.decode(superNodeAddress) - } + set superNodeAddress(superNodeAddress) { + this._superNodeAddress = superNodeAddress instanceof Uint8Array ? superNodeAddress : this.constructor.Base58.decode(superNodeAddress) + } - get params () { - const params = super.params - params.push( - this._superNodeAddress, - this._feeBytes - ) - return params - } + get params() { + const params = super.params + params.push( + this._superNodeAddress, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/MessageTransaction.js b/qortal-ui-crypto/api/transactions/MessageTransaction.js index f28a25fe..ea0e4079 100644 --- a/qortal-ui-crypto/api/transactions/MessageTransaction.js +++ b/qortal-ui-crypto/api/transactions/MessageTransaction.js @@ -1,95 +1,47 @@ -"use strict"; -import PaymentTransaction from "./PaymentTransaction.js" -import { QORT_DECIMALS } from "../constants.js" +'use strict' +import PaymentTransaction from './PaymentTransaction.js' +import { QORT_DECIMALS } from '../constants.js' -/* ==================================== -EXTEND THE PAYMENT TRANSACTION YOU CLOWN -====================================== */ +export default class MessageTransaction extends PaymentTransaction { + constructor() { + super() + this.type = 17 + this._key = this.constructor.utils.int64ToBytes(0); + this._isEncrypted = new Uint8Array(1); // Defaults to false + this._isText = new Uint8Array(1); // Defaults to false + } -export default class MessageTransaction extends PaymentTransaction{ - constructor(){ - super(); - this.type = 17 - this._key = this.constructor.utils.int64ToBytes(0); - this._isEncrypted = new Uint8Array(1); // Defaults to false - this._isText = new Uint8Array(1); // Defaults to false - } - - set message(message /* UTF8 String */){ - // ...yes? no? - this.messageText = message; - - // Not sure about encoding here... - //this._message = message instanceof Uint8Array ? message : this.constructor.Base58.decode(message); - this._message = this.constructor.utils.stringtoUTF8Array(message) - this._messageLength = this.constructor.utils.int64ToBytes(this._message.length) - } - set isEncrypted(isEncrypted){ - this._isEncrypted[0] = isEncrypted; - } - set isText(isText){ - this._isText[0] = isText; - } - get _params(){ - // dont extend super because paymentTrasaction is different - //const params = super.params; - return [ - this._typeBytes, - this._timestampBytes, - this._lastReference, - this._keyPair.publicKey, - this._recipient, - this._key, - this._amountBytes, - this._messageLength, - this._message, - this._isEncrypted, - this._isText, - this._feeBytes - ] - } + set message(message /* UTF8 String */) { + // ...yes? no? + this.messageText = message + + // Not sure about encoding here... + this._message = this.constructor.utils.stringtoUTF8Array(message) + this._messageLength = this.constructor.utils.int64ToBytes(this._message.length) + } + + set isEncrypted(isEncrypted) { + this._isEncrypted[0] = isEncrypted + } + + set isText(isText) { + this._isText[0] = isText + } + + get _params() { + return [ + this._typeBytes, + this._timestampBytes, + this._lastReference, + this._keyPair.publicKey, + this._recipient, + this._key, + this._amountBytes, + this._messageLength, + this._message, + this._isEncrypted, + this._isText, + this._feeBytes + ] + } } - -//"use strict"; -//function generateSignatureMessageTransaction(keyPair, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted) => { -// const data = generateMessageTransactionBase(keyPair.publicKey, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted); -// return nacl.sign.detached(data, keyPair.privateKey); -//} -// -//function generateMessageTransaction(keyPair, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted, signature) => { -// return appendBuffer(generateMessageTransactionBase(keyPair.publicKey, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted), -// signature); -//} -//function generateMessageTransactionBase(publicKey, lastReference, recipient, amount, fee, timestamp, message, isText, isEncrypted) => { -// txType = TYPES.MESSAGE_TRANSACTION; -// -// const typeBytes = int32ToBytes(txType); -// const timestampBytes = int64ToBytes(timestamp); -// const amountBytes = int64ToBytes(amount * 100000000); -// const feeBytes = int64ToBytes(fee * 100000000); -// const messageLength = int32ToBytes(message.length); -// const key = int64ToBytes(0); -// -// isTextB = new Uint8Array(1); -// isTextB[0] = isText; -// -// isEncryptedB = new Uint8Array(1); -// isEncryptedB[0] = isEncrypted; -// -// let data = new Uint8Array(); -// -// data = appendBuffer(data, typeBytes); -// data = appendBuffer(data, timestampBytes); -// data = appendBuffer(data, lastReference); -// data = appendBuffer(data, publicKey); -// data = appendBuffer(data, recipient); -// data = appendBuffer(data, key); -// data = appendBuffer(data, amountBytes); -// data = appendBuffer(data, messageLength); -// data = appendBuffer(data, message); -// data = appendBuffer(data, isEncryptedB); -// data = appendBuffer(data, isTextB); -// data = appendBuffer(data, feeBytes); -// -// return data; -//} \ No newline at end of file diff --git a/qortal-ui-crypto/api/transactions/PaymentTransaction.js b/qortal-ui-crypto/api/transactions/PaymentTransaction.js index 655ac285..bde396eb 100644 --- a/qortal-ui-crypto/api/transactions/PaymentTransaction.js +++ b/qortal-ui-crypto/api/transactions/PaymentTransaction.js @@ -1,80 +1,63 @@ -'use strict'; +'use strict' import TransactionBase from './TransactionBase.js' import Base58 from '../deps/Base58.js' import { store } from '../../api.js' export default class PaymentTransaction extends TransactionBase { - constructor() { - super() - this.type = 2 - this.tests.push( - () => { - if (!(this._amount >= 0)) { - return 'Invalid amount ' + this._amount / store.getState().config.coin.decimals - } - return true - }, - () => { - if (!(this._recipient instanceof Uint8Array && this._recipient.length == 25)) { - return 'Invalid recipient ' + Base58.encode(this._recipient) - } - return true - } - ) - } + constructor() { + super() + this.type = 2 + } - set recipient(recipient) { // Always Base58 encoded. Accepts Uint8Array or Base58 string. - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - } + render(html) { + const conf = store.getState().config + return html` + + + + + + + + + ${this.recipientName ? html` + + + + + ` : ''} + + + + +
${this._dialogto}:
${this.dialogAddress} ${' '}-${Base58.encode(this._recipient)}
${this.dialogName} ${' '}-${this.recipientName}
${this._dialogamount}${this._amount / conf.coin.decimals} ${conf.coin.symbol}
+ ` + } - set dialogto(dialogto) { - this._dialogto = dialogto - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + } - set dialogamount(dialogamount) { - this._dialogamount = dialogamount - } - - set amount(amount) { - this._amount = Math.round(amount * store.getState().config.coin.decimals) - this._amountBytes = this.constructor.utils.int64ToBytes(this._amount) - } + set dialogto(dialogto) { + this._dialogto = dialogto + } - get params() { - const params = super.params - params.push( - this._recipient, - this._amountBytes, - this._feeBytes - ) - return params - } + set dialogamount(dialogamount) { + this._dialogamount = dialogamount + } - render(html) { - const conf = store.getState().config - return html` - - - - - - - - - - - ${this.recipientName ? html` - - - - - ` : ''} - - - - - -
${this._dialogto}:
${this.dialogAddress} ${' '}-${Base58.encode(this._recipient)}
${this.dialogName} ${' '}-${this.recipientName}
${this._dialogamount}${this._amount / conf.coin.decimals} ${conf.coin.symbol}
- ` - } + set amount(amount) { + this._amount = Math.round(amount * store.getState().config.coin.decimals) + this._amountBytes = this.constructor.utils.int64ToBytes(this._amount) + } + + get params() { + const params = super.params + params.push( + this._recipient, + this._amountBytes, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/PublicizeTransaction.js b/qortal-ui-crypto/api/transactions/PublicizeTransaction.js index d4982bcb..0243901c 100644 --- a/qortal-ui-crypto/api/transactions/PublicizeTransaction.js +++ b/qortal-ui-crypto/api/transactions/PublicizeTransaction.js @@ -1,23 +1,23 @@ -"use strict"; -import ChatBase from "./chat/ChatBase.js" +'use strict' +import ChatBase from './chat/ChatBase.js' export default class PublicizeTransaction extends ChatBase { - constructor() { - super(); - this.type = 19 - this.fee = 0 - } + constructor() { + super() + this.type = 19 + this.fee = 0 + } - set proofOfWorkNonce(proofOfWorkNonce) { - this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) - } + set proofOfWorkNonce(proofOfWorkNonce) { + this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) + } - get params() { - const params = super.params; - params.push( - this._proofOfWorkNonce, - this._feeBytes - ) - return params; - } + get params() { + const params = super.params + params.push( + this._proofOfWorkNonce, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/TransactionBase.js b/qortal-ui-crypto/api/transactions/TransactionBase.js index f61f1834..ae5f613e 100644 --- a/qortal-ui-crypto/api/transactions/TransactionBase.js +++ b/qortal-ui-crypto/api/transactions/TransactionBase.js @@ -1,166 +1,121 @@ -'use strict'; +'use strict' import { TX_TYPES, QORT_DECIMALS } from '../constants.js' import nacl from '../deps/nacl-fast.js' import Base58 from '../deps/Base58.js' import utils from '../deps/utils.js' export default class TransactionBase { - static get utils() { - return utils - } - static get nacl() { - return nacl - } - static get Base58() { - return Base58 - } + static get utils() { + return utils + } + static get nacl() { + return nacl + } + static get Base58() { + return Base58 + } - constructor() { - // Defaults - this.fee = 0 - this.groupID = 0 - this.timestamp = Date.now() - this.tests = [ - () => { - if (!(this._type >= 1 && this._type in TX_TYPES)) { - return 'Invalid type: ' + this.type - } - return true - }, - () => { - if (this._fee < 0) { - return 'Invalid fee: ' + this._fee / QORT_DECIMALS - } - return true - }, - () => { - if (this._groupID < 0 || !Number.isInteger(this._groupID)) { - return 'Invalid groupID: ' + this._groupID - } - return true - }, - () => { - if (!(new Date(this._timestamp)).getTime() > 0) { - return 'Invalid timestamp: ' + this._timestamp - } - return true - }, - () => { - if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) { - if (this._lastReference == 0) { - // No prior transactions exist - return 'Invalid last reference. Please ensure that you have at least 0.001 QORT for the transaction fee.' - } - return 'Invalid last reference: ' + this._lastReference - } - return true - }, - () => { - if (!(this._keyPair)) { - return 'keyPair must be specified' - } - if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) { - return 'Invalid publicKey' - } - if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) { - return 'Invalid privateKey' - } - return true - } - ] - } + constructor() { + this.fee = 0 + this.groupID = 0 + this.timestamp = Date.now() + } - set keyPair(keyPair) { - this._keyPair = keyPair - } - set type(type) { - this.typeText = TX_TYPES[type] - this._type = type - this._typeBytes = this.constructor.utils.int32ToBytes(this._type) - } - set groupID(groupID) { - this._groupID = groupID - this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) - } - set timestamp(timestamp) { - this._timestamp = timestamp - this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) - } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } - set lastReference(lastReference) { // Always Base58 encoded. Accepts Uint8Array or Base58 string. - // lastReference could be a string or an Uint8Array - this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) - } - get params() { - return [ - this._typeBytes, - this._timestampBytes, - this._groupIDBytes, - this._lastReference, - this._keyPair.publicKey - ] - } - get signedBytes() { - if (!this._signedBytes) { - this.sign() - } - return this._signedBytes - } + render(html) { + return html`render method to display requested transaction info` + } - // render function but NOT lit element - render(html) { - return html`render method to display requested transaction info` - } + set keyPair(keyPair) { + this._keyPair = keyPair + } - validParams() { - let finalResult = { - valid: true - } - // const valid = - this.tests.some(test => { - const result = test() - if (result !== true) { - finalResult = { - valid: false, - message: result - } - return true // exists the loop - } - }) - return finalResult - } + set type(type) { + this.typeText = TX_TYPES[type] + this._type = type + this._typeBytes = this.constructor.utils.int32ToBytes(this._type) + } - generateBase() { - const isValid = this.validParams() - if (!isValid.valid) { - throw new Error(isValid.message) - } - let result = new Uint8Array() + set groupID(groupID) { + this._groupID = groupID + this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) + } - this.params.forEach(item => { - result = this.constructor.utils.appendBuffer(result, item) - }) + set timestamp(timestamp) { + this._timestamp = timestamp + this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) + } - this._base = result - return result - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - sign() { - if (!this._keyPair) { - throw new Error('keyPair not defined') - } + set lastReference(lastReference) { + this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) + } - if (!this._base) { - this.generateBase() - } + get params() { + return [ + this._typeBytes, + this._timestampBytes, + this._groupIDBytes, + this._lastReference, + this._keyPair.publicKey + ] + } - this._signature = this.constructor.nacl.sign.detached(this._base, this._keyPair.privateKey) + get signedBytes() { + if (!this._signedBytes) { + this.sign() + } + return this._signedBytes + } - this._signedBytes = this.constructor.utils.appendBuffer(this._base, this._signature) + validParams() { + let finalResult = { + valid: true + } + this.tests.some(test => { + const result = test() + if (result !== true) { + finalResult = { + valid: false, + message: result + } + return true // exists the loop + } + }) + return finalResult + } - return this._signature - } + generateBase() { + const isValid = this.validParams() + if (!isValid.valid) { + throw new Error(isValid.message) + } + let result = new Uint8Array() + + this.params.forEach(item => { + result = this.constructor.utils.appendBuffer(result, item) + }) + + this._base = result + return result + } + + sign() { + if (!this._keyPair) { + throw new Error('keyPair not defined') + } + + if (!this._base) { + this.generateBase() + } + + this._signature = this.constructor.nacl.sign.detached(this._base, this._keyPair.privateKey) + + this._signedBytes = this.constructor.utils.appendBuffer(this._base, this._signature) + + return this._signature + } } diff --git a/qortal-ui-crypto/api/transactions/TransferPrivsTransaction.js b/qortal-ui-crypto/api/transactions/TransferPrivsTransaction.js index f12d837f..858ac26a 100644 --- a/qortal-ui-crypto/api/transactions/TransferPrivsTransaction.js +++ b/qortal-ui-crypto/api/transactions/TransferPrivsTransaction.js @@ -1,42 +1,42 @@ -'use strict'; +'use strict' import TransactionBase from './TransactionBase.js' import Base58 from '../deps/Base58.js' import { store } from '../../api.js' import { QORT_DECIMALS } from '../constants.js' export default class TransferPrivsTransaction extends TransactionBase { - constructor() { - super() - this.type = 40 - } + constructor() { + super() + this.type = 40 + } - render(html) { - const conf = store.getState().config - return html` + render(html) { + const conf = store.getState().config + return html` Are you sure to transfer privileges to this account ?
${this.theRecipient}
On pressing confirm, the transfer privileges request will be sent! ` - } + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._recipient, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._recipient, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/arbitrary/signArbitrary.js b/qortal-ui-crypto/api/transactions/arbitrary/signArbitrary.js index 47f37f81..84ed0638 100644 --- a/qortal-ui-crypto/api/transactions/arbitrary/signArbitrary.js +++ b/qortal-ui-crypto/api/transactions/arbitrary/signArbitrary.js @@ -2,38 +2,37 @@ import nacl from '../../deps/nacl-fast.js' import utils from '../../deps/utils.js' import Base58 from '../../deps/Base58.js' - const signArbitrary = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair) => { - if (!arbitraryBytesBase58) { - throw new Error('ArbitraryBytesBase58 not defined') - } + if (!arbitraryBytesBase58) { + throw new Error('ArbitraryBytesBase58 not defined') + } - if (!nonce) { - throw new Error('Nonce not defined') - } + if (!nonce) { + throw new Error('Nonce not defined') + } - if (!keyPair) { - throw new Error('keyPair not defined') - } + if (!keyPair) { + throw new Error('keyPair not defined') + } - const arbitraryBytes = Base58.decode(arbitraryBytesBase58) - const _arbitraryBytesBuffer = Object.keys(arbitraryBytes).map(function (key) { return arbitraryBytes[key]; }); - const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer) + const arbitraryBytes = Base58.decode(arbitraryBytesBase58) + const _arbitraryBytesBuffer = Object.keys(arbitraryBytes).map(function (key) { return arbitraryBytes[key]; }) + const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer) - const arbitraryBytesForSigning = Base58.decode(arbitraryBytesForSigningBase58) - const _arbitraryBytesForSigningBuffer = Object.keys(arbitraryBytesForSigning).map(function (key) { return arbitraryBytesForSigning[key]; }); - const arbitraryBytesForSigningBuffer = new Uint8Array(_arbitraryBytesForSigningBuffer) + const arbitraryBytesForSigning = Base58.decode(arbitraryBytesForSigningBase58) + const _arbitraryBytesForSigningBuffer = Object.keys(arbitraryBytesForSigning).map(function (key) { return arbitraryBytesForSigning[key]; }) + const arbitraryBytesForSigningBuffer = new Uint8Array(_arbitraryBytesForSigningBuffer) - const _nonce = utils.int32ToBytes(nonce) - arbitraryBytesBuffer.set(_nonce, 112) - arbitraryBytesForSigningBuffer.set(_nonce, 112) + const _nonce = utils.int32ToBytes(nonce) + arbitraryBytesBuffer.set(_nonce, 112) + arbitraryBytesForSigningBuffer.set(_nonce, 112) - const signature = nacl.sign.detached(arbitraryBytesForSigningBuffer, keyPair.privateKey) + const signature = nacl.sign.detached(arbitraryBytesForSigningBuffer, keyPair.privateKey) - const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature) + const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature) - return signedBytes + return signedBytes } export default signArbitrary diff --git a/qortal-ui-crypto/api/transactions/arbitraryV3.js b/qortal-ui-crypto/api/transactions/arbitraryV3.js index 5d62000a..2c2536af 100644 --- a/qortal-ui-crypto/api/transactions/arbitraryV3.js +++ b/qortal-ui-crypto/api/transactions/arbitraryV3.js @@ -1,42 +1,37 @@ -"use strict"; -/* -TO DO -*/ +'use strict' + (function () { + function generateSignatureArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp) => { + const data = generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp) + return nacl.sign.detached(data, keyPair.privateKey) + } -(function(){ - function generateSignatureArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp) => { - const data = generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp); - return nacl.sign.detached(data, keyPair.privateKey); - } + function generateArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp, signature) => { + return appendBuffer(generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp), signature) + } - function generateArbitraryTransactionV3(keyPair, lastReference, service, arbitraryData, fee, timestamp, signature) => { - return appendBuffer(generateArbitraryTransactionV3Base(keyPair.publicKey, lastReference, service, arbitraryData, fee, timestamp), - signature); - } + function generateArbitraryTransactionV3Base(publicKey, lastReference, service, arbitraryData, fee, timestamp) => { + const txType = TYPES.ARBITRARY_TRANSACTION + const typeBytes = int32ToBytes(txType) + const timestampBytes = int64ToBytes(timestamp) + const feeBytes = int64ToBytes(fee * 100000000) + const serviceBytes = int32ToBytes(service) + const dataSizeBytes = int32ToBytes(arbitraryData.length) + const paymentsLengthBytes = int32ToBytes(0) // Support payments - not yet. - function generateArbitraryTransactionV3Base(publicKey, lastReference, service, arbitraryData, fee, timestamp) => { - const txType = TYPES.ARBITRARY_TRANSACTION; - const typeBytes = int32ToBytes(txType); - const timestampBytes = int64ToBytes(timestamp); - const feeBytes = int64ToBytes(fee * 100000000); - const serviceBytes = int32ToBytes(service); - const dataSizeBytes = int32ToBytes(arbitraryData.length); - const paymentsLengthBytes = int32ToBytes(0); // Support payments - not yet. + var data = new Uint8Array() - var data = new Uint8Array(); + data = appendBuffer(data, typeBytes) + data = appendBuffer(data, timestampBytes) + data = appendBuffer(data, lastReference) + data = appendBuffer(data, publicKey) + data = appendBuffer(data, paymentsLengthBytes) + // Here it is necessary to insert the payments, if there are + data = appendBuffer(data, serviceBytes) + data = appendBuffer(data, dataSizeBytes) + data = appendBuffer(data, arbitraryData) + data = appendBuffer(data, feeBytes) - data = appendBuffer(data, typeBytes); - data = appendBuffer(data, timestampBytes); - data = appendBuffer(data, lastReference); - data = appendBuffer(data, publicKey); - data = appendBuffer(data, paymentsLengthBytes); - // Here it is necessary to insert the payments, if there are - data = appendBuffer(data, serviceBytes); - data = appendBuffer(data, dataSizeBytes); - data = appendBuffer(data, arbitraryData); - data = appendBuffer(data, feeBytes); - - return data; - } -}()) \ No newline at end of file + return data + } + }()) diff --git a/qortal-ui-crypto/api/transactions/chat/ChatBase.js b/qortal-ui-crypto/api/transactions/chat/ChatBase.js index 3a81d3f2..783176ed 100644 --- a/qortal-ui-crypto/api/transactions/chat/ChatBase.js +++ b/qortal-ui-crypto/api/transactions/chat/ChatBase.js @@ -1,137 +1,97 @@ -'use strict'; +'use strict' import { TX_TYPES, QORT_DECIMALS } from '../../constants.js' import nacl from '../../deps/nacl-fast.js' import Base58 from '../../deps/Base58.js' import utils from '../../deps/utils.js' export default class ChatBase { - static get utils() { - return utils - } - static get nacl() { - return nacl - } - static get Base58() { - return Base58 - } + static get utils() { + return utils + } + static get nacl() { + return nacl + } + static get Base58() { + return Base58 + } - constructor() { - this.fee = 0 - this.groupID = 0 - this.tests = [ - () => { - if (!(this._type >= 1 && this._type in TX_TYPES)) { - return 'Invalid type: ' + this.type - } - return true - }, - () => { - if (this._fee < 0) { - return 'Invalid fee: ' + this._fee / QORT_DECIMALS - } - return true - }, - () => { - if (this._groupID < 0 || !Number.isInteger(this._groupID)) { - return 'Invalid groupID: ' + this._groupID - } - return true - }, - () => { - if (!(new Date(this._timestamp)).getTime() > 0) { - return 'Invalid timestamp: ' + this._timestamp - } - return true - }, - () => { - if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) { - return 'Invalid last reference: ' + this._lastReference - } - return true - }, - () => { - if (!(this._keyPair)) { - return 'keyPair must be specified' - } - if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) { - return 'Invalid publicKey' - } - if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) { - return 'Invalid privateKey' - } - return true - } - ] - } + constructor() { + this.fee = 0 + this.groupID = 0 + } - set keyPair(keyPair) { - this._keyPair = keyPair - } - set type(type) { - this.typeText = TX_TYPES[type] - this._type = type - this._typeBytes = this.constructor.utils.int32ToBytes(this._type) - } - set groupID(groupID) { - this._groupID = groupID - this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) - } - set timestamp(timestamp) { - this._timestamp = timestamp - this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) - } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } - set lastReference(lastReference) { - this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) - } - get params() { + set keyPair(keyPair) { + this._keyPair = keyPair + } - return [ - this._typeBytes, - this._timestampBytes, - this._groupIDBytes, - this._lastReference, - this._keyPair.publicKey - ] - } + set type(type) { + this.typeText = TX_TYPES[type] + this._type = type + this._typeBytes = this.constructor.utils.int32ToBytes(this._type) + } - get chatBytes() { + set groupID(groupID) { + this._groupID = groupID + this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) + } - const isValid = this.validParams() - if (!isValid.valid) { - throw new Error(isValid.message) - } + set timestamp(timestamp) { + this._timestamp = timestamp + this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) + } - let result = new Uint8Array() + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - this.params.forEach(item => { - result = this.constructor.utils.appendBuffer(result, item) - }) + set lastReference(lastReference) { + this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) + } - this._chatBytes = result + get params() { + return [ + this._typeBytes, + this._timestampBytes, + this._groupIDBytes, + this._lastReference, + this._keyPair.publicKey + ] + } - return this._chatBytes - } + get chatBytes() { + const isValid = this.validParams() + if (!isValid.valid) { + throw new Error(isValid.message) + } - validParams() { - let finalResult = { - valid: true - } + let result = new Uint8Array() - this.tests.some(test => { - const result = test() - if (result !== true) { - finalResult = { - valid: false, - message: result - } - return true - } - }) - return finalResult - } + this.params.forEach(item => { + result = this.constructor.utils.appendBuffer(result, item) + }) + + this._chatBytes = result + + return this._chatBytes + } + + validParams() { + let finalResult = { + valid: true + } + + this.tests.some(test => { + const result = test() + if (result !== true) { + finalResult = { + valid: false, + message: result + } + return true + } + }) + return finalResult + } } diff --git a/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js b/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js index 6e6dcfd4..642ff744 100644 --- a/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js +++ b/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js @@ -1,77 +1,92 @@ -"use strict"; +'use strict' import ChatBase from "./ChatBase.js" import nacl from '../../deps/nacl-fast.js' import ed2curve from '../../deps/ed2curve.js' import { Sha256 } from 'asmcrypto.js' +import { CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } from '../../constants.js' export default class ChatTransaction extends ChatBase { - constructor() { - super(); - this.type = 18 - this.fee = 0 - } + constructor() { + super() + this.type = 18 + this.fee = 0 + } - set recipientPublicKey(recipientPublicKey) { - this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey - this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey) + set recipientPublicKey(recipientPublicKey) { + this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey + this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey) + } - } + set proofOfWorkNonce(proofOfWorkNonce) { + this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) + } - set proofOfWorkNonce(proofOfWorkNonce) { - this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this._hasReceipient = new Uint8Array(1) + this._hasReceipient[0] = 1 + } + set hasChatReference(hasChatReference) { + this._hasChatReference = new Uint8Array(1) + this._hasChatReference[0] = hasChatReference + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this._hasReceipient = new Uint8Array(1) - this._hasReceipient[0] = 1 - } + set chatReference(chatReference) { + this._chatReference = chatReference instanceof Uint8Array ? chatReference : this.constructor.Base58.decode(chatReference) + } - set message(message) { + set message(message) { + this.messageText = message; + this._message = this.constructor.utils.stringtoUTF8Array(message) + this._messageLength = this.constructor.utils.int32ToBytes(this._message.length) + } - this.messageText = message; + set isEncrypted(isEncrypted) { + this._isEncrypted = new Uint8Array(1) + this._isEncrypted[0] = isEncrypted - this._message = this.constructor.utils.stringtoUTF8Array(message) - this._messageLength = this.constructor.utils.int32ToBytes(this._message.length) - } + if (isEncrypted === 1) { + const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey) + const sharedSecret = new Uint8Array(32) + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - set isEncrypted(isEncrypted) { - this._isEncrypted = new Uint8Array(1); - this._isEncrypted[0] = isEncrypted; + this._chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result + this._encryptedMessage = nacl.secretbox(this._message, this._lastReference.slice(0, 24), this._chatEncryptionSeed) + } - if (isEncrypted === 1) { - const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey) - const sharedSecret = new Uint8Array(32); - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey); + this._myMessage = isEncrypted === 1 ? this._encryptedMessage : this._message + this._myMessageLenth = isEncrypted === 1 ? this.constructor.utils.int32ToBytes(this._myMessage.length) : this._messageLength + } - this._chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result - this._encryptedMessage = nacl.secretbox(this._message, this._lastReference.slice(0, 24), this._chatEncryptionSeed) - } + set isText(isText) { + this._isText = new Uint8Array(1) + this._isText[0] = isText + } - this._myMessage = isEncrypted === 1 ? this._encryptedMessage : this._message - this._myMessageLenth = isEncrypted === 1 ? this.constructor.utils.int32ToBytes(this._myMessage.length) : this._messageLength - } + get params() { + const params = super.params; + params.push( + this._proofOfWorkNonce, + this._hasReceipient, + this._recipient, + this._myMessageLenth, + this._myMessage, + this._isEncrypted, + this._isText, + this._feeBytes + ) - set isText(isText) { - this._isText = new Uint8Array(1); - this._isText[0] = isText; - } + // After the feature trigger timestamp we need to include chat reference + if (new Date(this._timestamp).getTime() >= CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP) { + params.push(this._hasChatReference) - get params() { - const params = super.params; - params.push( - this._proofOfWorkNonce, - this._hasReceipient, - this._recipient, - this._myMessageLenth, - this._myMessage, - this._isEncrypted, - this._isText, - this._feeBytes - ) - return params; - } + if (this._hasChatReference[0] == 1) { + params.push(this._chatReference) + } + } + return params + } } diff --git a/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js b/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js index efbd97b0..e414d10b 100644 --- a/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js +++ b/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js @@ -1,52 +1,67 @@ -"use strict"; +'use strict' import ChatBase from "./ChatBase.js" export default class GroupChatTransaction extends ChatBase { - constructor() { - super(); - this.type = 18 - this.fee = 0 - } + constructor() { + super(); + this.type = 18 + this.fee = 0 + } - set proofOfWorkNonce(proofOfWorkNonce) { - this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) - } + set proofOfWorkNonce(proofOfWorkNonce) { + this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) + } + set hasReceipient(hasReceipient) { + this._hasReceipient = new Uint8Array(1) + this._hasReceipient[0] = hasReceipient + } - set hasReceipient(hasReceipient) { - this._hasReceipient = new Uint8Array(1) - this._hasReceipient[0] = hasReceipient - } + set message(message) { + this.messageText = message + this._message = this.constructor.utils.stringtoUTF8Array(message) + this._messageLength = this.constructor.utils.int32ToBytes(this._message.length) + } - set message(message) { + set hasChatReference(hasChatReference) { + this._hasChatReference = new Uint8Array(1) + this._hasChatReference[0] = hasChatReference + } - this.messageText = message; + set chatReference(chatReference) { + this._chatReference = chatReference instanceof Uint8Array ? chatReference : this.constructor.Base58.decode(chatReference) + } - this._message = this.constructor.utils.stringtoUTF8Array(message) - this._messageLength = this.constructor.utils.int32ToBytes(this._message.length) - } + set isEncrypted(isEncrypted) { + this._isEncrypted = new Uint8Array(1); + this._isEncrypted[0] = isEncrypted + } - set isEncrypted(isEncrypted) { - this._isEncrypted = new Uint8Array(1); - this._isEncrypted[0] = isEncrypted; // Set to false... - } + set isText(isText) { + this._isText = new Uint8Array(1) + this._isText[0] = isText + } - set isText(isText) { - this._isText = new Uint8Array(1); - this._isText[0] = isText; // Set to true - } + get params() { + const params = super.params; + params.push( + this._proofOfWorkNonce, + this._hasReceipient, + this._messageLength, + this._message, + this._isEncrypted, + this._isText, + this._feeBytes + ) - get params() { - const params = super.params; - params.push( - this._proofOfWorkNonce, - this._hasReceipient, - this._messageLength, - this._message, - this._isEncrypted, - this._isText, - this._feeBytes - ) - return params; - } + // After the feature trigger timestamp we need to include chat reference + if (new Date(this._timestamp).getTime() >= CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP) { + params.push(this._hasChatReference) + + if (this._hasChatReference[0] == 1) { + params.push(this._chatReference) + } + } + return params + } } diff --git a/qortal-ui-crypto/api/transactions/chat/decryptChatMessage.js b/qortal-ui-crypto/api/transactions/chat/decryptChatMessage.js index 5ea06ec8..038db155 100644 --- a/qortal-ui-crypto/api/transactions/chat/decryptChatMessage.js +++ b/qortal-ui-crypto/api/transactions/chat/decryptChatMessage.js @@ -3,25 +3,24 @@ import Base58 from '../../deps/Base58.js' import ed2curve from '../../deps/ed2curve.js' import { Sha256 } from 'asmcrypto.js' - export const decryptChatMessage = (encryptedMessage, privateKey, recipientPublicKey, lastReference) => { - let _encryptedMessage = Base58.decode(encryptedMessage) + let _encryptedMessage = Base58.decode(encryptedMessage) - const _base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? Base58.encode(recipientPublicKey) : recipientPublicKey - const _recipientPublicKey = Base58.decode(_base58RecipientPublicKey) + const _base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? Base58.encode(recipientPublicKey) : recipientPublicKey + const _recipientPublicKey = Base58.decode(_base58RecipientPublicKey) - const _lastReference = lastReference instanceof Uint8Array ? lastReference : Base58.decode(lastReference) + const _lastReference = lastReference instanceof Uint8Array ? lastReference : Base58.decode(lastReference) - const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(_recipientPublicKey) - const sharedSecret = new Uint8Array(32); - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey); + const convertedPrivateKey = ed2curve.convertSecretKey(privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(_recipientPublicKey) + const sharedSecret = new Uint8Array(32); + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) - const _chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result - const _decryptedMessage = nacl.secretbox.open(_encryptedMessage, _lastReference.slice(0, 24), _chatEncryptionSeed) + const _chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result + const _decryptedMessage = nacl.secretbox.open(_encryptedMessage, _lastReference.slice(0, 24), _chatEncryptionSeed) - let decryptedMessage = '' + let decryptedMessage = '' - _decryptedMessage === false ? decryptedMessage : decryptedMessage = new TextDecoder('utf-8').decode(_decryptedMessage); - return decryptedMessage + _decryptedMessage === false ? decryptedMessage : decryptedMessage = new TextDecoder('utf-8').decode(_decryptedMessage) + return decryptedMessage } diff --git a/qortal-ui-crypto/api/transactions/chat/signChat.js b/qortal-ui-crypto/api/transactions/chat/signChat.js index 2c8428da..6760dac5 100644 --- a/qortal-ui-crypto/api/transactions/chat/signChat.js +++ b/qortal-ui-crypto/api/transactions/chat/signChat.js @@ -1,46 +1,43 @@ import nacl from '../../deps/nacl-fast.js' import utils from '../../deps/utils.js' - const signChat = (chatBytes, nonce, keyPair) => { - if (!chatBytes) { - throw new Error('Chat Bytes not defined') - } + if (!chatBytes) { + throw new Error('Chat Bytes not defined') + } - if (!nonce) { - throw new Error('Nonce not defined') - } + if (!nonce) { + throw new Error('Nonce not defined') + } - if (!keyPair) { - throw new Error('keyPair not defined') - } + if (!keyPair) { + throw new Error('keyPair not defined') + } - const _nonce = utils.int32ToBytes(nonce) + const _nonce = utils.int32ToBytes(nonce) - if (chatBytes.length === undefined) { - const _chatBytesBuffer = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; }); + if (chatBytes.length === undefined) { + const _chatBytesBuffer = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; }) - const chatBytesBuffer = new Uint8Array(_chatBytesBuffer) - chatBytesBuffer.set(_nonce, 112) + const chatBytesBuffer = new Uint8Array(_chatBytesBuffer) + chatBytesBuffer.set(_nonce, 112) + const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey) - const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey) + const signedBytes = utils.appendBuffer(chatBytesBuffer, signature) - const signedBytes = utils.appendBuffer(chatBytesBuffer, signature) + return signedBytes + } else { + const chatBytesBuffer = new Uint8Array(chatBytes) + chatBytesBuffer.set(_nonce, 112) - return signedBytes - } else { - const chatBytesBuffer = new Uint8Array(chatBytes) - chatBytesBuffer.set(_nonce, 112) + const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey) + const signedBytes = utils.appendBuffer(chatBytesBuffer, signature) - const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey) - - const signedBytes = utils.appendBuffer(chatBytesBuffer, signature) - - return signedBytes - } + return signedBytes + } } export default signChat diff --git a/qortal-ui-crypto/api/transactions/groups/AddGroupAdminTransaction.js b/qortal-ui-crypto/api/transactions/groups/AddGroupAdminTransaction.js index b4d6c120..4f5bf090 100644 --- a/qortal-ui-crypto/api/transactions/groups/AddGroupAdminTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/AddGroupAdminTransaction.js @@ -1,53 +1,53 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class AddGroupAdminTransaction extends TransactionBase { - constructor() { - super() - this.type = 24 - } + constructor() { + super() + this.type = 24 + } - render(html) { - return html` - ${this._addAdminDialog1} -
- ${this.theRecipient} -
- ${this._addAdminDialog2} - ` - } + render(html) { + return html` + ${this._addAdminDialog1} +
+ ${this.theRecipient} +
+ ${this._addAdminDialog2} + ` + } - set addAdminDialog1(addAdminDialog1) { - this._addAdminDialog1 = addAdminDialog1 - } + set addAdminDialog1(addAdminDialog1) { + this._addAdminDialog1 = addAdminDialog1 + } - set addAdminDialog2(addAdminDialog2) { - this._addAdminDialog2 = addAdminDialog2 - } + set addAdminDialog2(addAdminDialog2) { + this._addAdminDialog2 = addAdminDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/CancelGroupBanTransaction.js b/qortal-ui-crypto/api/transactions/groups/CancelGroupBanTransaction.js index 3e36be23..61de1e34 100644 --- a/qortal-ui-crypto/api/transactions/groups/CancelGroupBanTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/CancelGroupBanTransaction.js @@ -1,53 +1,53 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class CancelGroupBanTransaction extends TransactionBase { - constructor() { - super() - this.type = 27 - } + constructor() { + super() + this.type = 27 + } - render(html) { - return html` - ${this._cancelBanMemberDialog1} -
- ${this.theRecipient} -
- ${this._cancelBanMemberDialog2} - ` - } + render(html) { + return html` + ${this._cancelBanMemberDialog1} +
+ ${this.theRecipient} +
+ ${this._cancelBanMemberDialog2} + ` + } - set cancelBanMemberDialog1(cancelBanMemberDialog1) { - this._cancelBanMemberDialog1= cancelBanMemberDialog1 - } + set cancelBanMemberDialog1(cancelBanMemberDialog1) { + this._cancelBanMemberDialog1 = cancelBanMemberDialog1 + } - set cancelBanMemberDialog2(cancelBanMemberDialog2) { - this._cancelBanMemberDialog2 = cancelBanMemberDialog2 - } + set cancelBanMemberDialog2(cancelBanMemberDialog2) { + this._cancelBanMemberDialog2 = cancelBanMemberDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/CancelGroupInviteTransaction.js b/qortal-ui-crypto/api/transactions/groups/CancelGroupInviteTransaction.js index 79d24656..10bb800b 100644 --- a/qortal-ui-crypto/api/transactions/groups/CancelGroupInviteTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/CancelGroupInviteTransaction.js @@ -1,60 +1,60 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class CancelGroupInviteTransaction extends TransactionBase { - constructor() { - super() - this.type = 30 - } + constructor() { + super() + this.type = 30 + } - render(html) { - return html` - ${this._cancelInviteDialog1} -
- ${this._memberName} -
-
- ${this.theRecipient} -
- ${this._cancelInviteDialog2} - ` - } + render(html) { + return html` + ${this._cancelInviteDialog1} +
+ ${this._memberName} +
+
+ ${this.theRecipient} +
+ ${this._cancelInviteDialog2} + ` + } - set memberName(memberName) { - this._memberName = memberName - } + set memberName(memberName) { + this._memberName = memberName + } - set cancelInviteDialog1(cancelInviteDialog1) { - this._cancelInviteDialog1 = cancelInviteDialog1 - } + set cancelInviteDialog1(cancelInviteDialog1) { + this._cancelInviteDialog1 = cancelInviteDialog1 + } - set cancelInviteDialog2(cancelInviteDialog2) { - this._cancelInviteDialog2 = cancelInviteDialog2 - } + set cancelInviteDialog2(cancelInviteDialog2) { + this._cancelInviteDialog2 = cancelInviteDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/CreateGroupTransaction.js b/qortal-ui-crypto/api/transactions/groups/CreateGroupTransaction.js index 909b46bd..0b76ead0 100644 --- a/qortal-ui-crypto/api/transactions/groups/CreateGroupTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/CreateGroupTransaction.js @@ -1,98 +1,98 @@ -"use strict"; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class CreateGroupTransaction extends TransactionBase { - constructor() { - super() - this.type = 22 - } + constructor() { + super() + this.type = 22 + } - render(html) { - return html` - ${this._groupdialog5} -
-
${this._groupdialog7}: ${this._rGroupName}
-
-
${this._groupdialog8}: ${this._rGroupDesc}
-
-
${this._groupdialog9}: ${this.myGroupType === 1 ? "Public" : "Private"}
-
- ${this._groupdialog6} - ` - } + render(html) { + return html` + ${this._groupdialog5} +
+
${this._groupdialog7}: ${this._rGroupName}
+
+
${this._groupdialog8}: ${this._rGroupDesc}
+
+
${this._groupdialog9}: ${this.myGroupType === 1 ? "Public" : "Private"}
+
+ ${this._groupdialog6} + ` + } - set groupdialog5(groupdialog5) { - this._groupdialog5 = groupdialog5 - } + set groupdialog5(groupdialog5) { + this._groupdialog5 = groupdialog5 + } - set groupdialog6(groupdialog6) { - this._groupdialog6 = groupdialog6 - } + set groupdialog6(groupdialog6) { + this._groupdialog6 = groupdialog6 + } - set groupdialog7(groupdialog7) { - this._groupdialog7 = groupdialog7 - } + set groupdialog7(groupdialog7) { + this._groupdialog7 = groupdialog7 + } - set groupdialog8(groupdialog8) { - this._groupdialog8 = groupdialog8 - } + set groupdialog8(groupdialog8) { + this._groupdialog8 = groupdialog8 + } - set groupdialog9(groupdialog9) { - this._groupdialog9 = groupdialog9 - } + set groupdialog9(groupdialog9) { + this._groupdialog9 = groupdialog9 + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set rGroupName(rGroupName) { - this._rGroupName = rGroupName; - this._rGroupNameBytes = this.constructor.utils.stringtoUTF8Array(this._rGroupName.toLocaleLowerCase()) - this._rGroupNameLength = this.constructor.utils.int32ToBytes(this._rGroupNameBytes.length) - } + set rGroupName(rGroupName) { + this._rGroupName = rGroupName + this._rGroupNameBytes = this.constructor.utils.stringtoUTF8Array(this._rGroupName.toLocaleLowerCase()) + this._rGroupNameLength = this.constructor.utils.int32ToBytes(this._rGroupNameBytes.length) + } - set rGroupDesc(rGroupDesc) { - this._rGroupDesc = rGroupDesc; - this._rGroupDescBytes = this.constructor.utils.stringtoUTF8Array(this._rGroupDesc.toLocaleLowerCase()) - this._rGroupDescLength = this.constructor.utils.int32ToBytes(this._rGroupDescBytes.length) - } + set rGroupDesc(rGroupDesc) { + this._rGroupDesc = rGroupDesc + this._rGroupDescBytes = this.constructor.utils.stringtoUTF8Array(this._rGroupDesc.toLocaleLowerCase()) + this._rGroupDescLength = this.constructor.utils.int32ToBytes(this._rGroupDescBytes.length) + } - set rGroupType(rGroupType) { - this.myGroupType = rGroupType; - this._rGroupType = new Uint8Array(1) - this._rGroupType[0] = rGroupType; - } + set rGroupType(rGroupType) { + this.myGroupType = rGroupType + this._rGroupType = new Uint8Array(1) + this._rGroupType[0] = rGroupType + } - set rGroupApprovalThreshold(rGroupApprovalThreshold) { - this._rGroupApprovalThreshold = new Uint8Array(1) - this._rGroupApprovalThreshold[0] = rGroupApprovalThreshold; - } + set rGroupApprovalThreshold(rGroupApprovalThreshold) { + this._rGroupApprovalThreshold = new Uint8Array(1) + this._rGroupApprovalThreshold[0] = rGroupApprovalThreshold + } - set rGroupMinimumBlockDelay(rGroupMinimumBlockDelay) { - this._rGroupMinimumBlockDelay = rGroupMinimumBlockDelay; - this._rGroupMinimumBlockDelayBytes = this.constructor.utils.int32ToBytes(this._rGroupMinimumBlockDelay) - } + set rGroupMinimumBlockDelay(rGroupMinimumBlockDelay) { + this._rGroupMinimumBlockDelay = rGroupMinimumBlockDelay + this._rGroupMinimumBlockDelayBytes = this.constructor.utils.int32ToBytes(this._rGroupMinimumBlockDelay) + } - set rGroupMaximumBlockDelay(rGroupMaximumBlockDelay) { - this._rGroupMaximumBlockDelay = rGroupMaximumBlockDelay; - this._rGroupMaximumBlockDelayBytes = this.constructor.utils.int32ToBytes(this._rGroupMaximumBlockDelay) - } + set rGroupMaximumBlockDelay(rGroupMaximumBlockDelay) { + this._rGroupMaximumBlockDelay = rGroupMaximumBlockDelay + this._rGroupMaximumBlockDelayBytes = this.constructor.utils.int32ToBytes(this._rGroupMaximumBlockDelay) + } - get params() { - const params = super.params; - params.push( - this._rGroupNameLength, - this._rGroupNameBytes, - this._rGroupDescLength, - this._rGroupDescBytes, - this._rGroupType, - this._rGroupApprovalThreshold, - this._rGroupMinimumBlockDelayBytes, - this._rGroupMaximumBlockDelayBytes, - this._feeBytes - ) - return params; - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupNameLength, + this._rGroupNameBytes, + this._rGroupDescLength, + this._rGroupDescBytes, + this._rGroupType, + this._rGroupApprovalThreshold, + this._rGroupMinimumBlockDelayBytes, + this._rGroupMaximumBlockDelayBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/GroupBanTransaction.js b/qortal-ui-crypto/api/transactions/groups/GroupBanTransaction.js index 2d6e2d9c..101cb364 100644 --- a/qortal-ui-crypto/api/transactions/groups/GroupBanTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/GroupBanTransaction.js @@ -1,67 +1,67 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class GroupBanTransaction extends TransactionBase { - constructor() { - super() - this.type = 26 - } + constructor() { + super() + this.type = 26 + } - render(html) { - return html` - ${this._banMemberDialog1} -
- ${this.theRecipient} -
- ${this._banMemberDialog2} - ` - } + render(html) { + return html` + ${this._banMemberDialog1} +
+ ${this.theRecipient} +
+ ${this._banMemberDialog2} + ` + } - set banMemberDialog1(banMemberDialog1) { - this._banMemberDialog1= banMemberDialog1 - } + set banMemberDialog1(banMemberDialog1) { + this._banMemberDialog1 = banMemberDialog1 + } - set banMemberDialog2(banMemberDialog2) { - this._banMemberDialog2 = banMemberDialog2 - } + set banMemberDialog2(banMemberDialog2) { + this._banMemberDialog2 = banMemberDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set rBanReason(rBanReason) { - this._rBanReason = rBanReason - this._rBanReasonBytes = this.constructor.utils.stringtoUTF8Array(this._rBanReason.toLocaleLowerCase()) - this._rBanReasonLength = this.constructor.utils.int32ToBytes(this._rBanReasonBytes.length) - } + set rBanReason(rBanReason) { + this._rBanReason = rBanReason + this._rBanReasonBytes = this.constructor.utils.stringtoUTF8Array(this._rBanReason.toLocaleLowerCase()) + this._rBanReasonLength = this.constructor.utils.int32ToBytes(this._rBanReasonBytes.length) + } - set rBanTime(rBanTime) { - this._rBanTime = rBanTime - this._rBanTimeBytes = this.constructor.utils.int32ToBytes(this._rBanTime) - } + set rBanTime(rBanTime) { + this._rBanTime = rBanTime + this._rBanTimeBytes = this.constructor.utils.int32ToBytes(this._rBanTime) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._rBanReasonLength, - this._rBanReasonBytes, - this._rBanTimeBytes, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._rBanReasonLength, + this._rBanReasonBytes, + this._rBanTimeBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/GroupInviteTransaction.js b/qortal-ui-crypto/api/transactions/groups/GroupInviteTransaction.js index 123ab820..62a89633 100644 --- a/qortal-ui-crypto/api/transactions/groups/GroupInviteTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/GroupInviteTransaction.js @@ -1,59 +1,59 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class GroupInviteTransaction extends TransactionBase { - constructor() { - super() - this.type = 29 - } + constructor() { + super() + this.type = 29 + } - render(html) { - return html` - ${this._inviteMemberDialog1} -
- ${this.theRecipient} -
- ${this._inviteMemberDialog2} - ` - } + render(html) { + return html` + ${this._inviteMemberDialog1} +
+ ${this.theRecipient} +
+ ${this._inviteMemberDialog2} + ` + } - set inviteMemberDialog1(inviteMemberDialog1) { - this._inviteMemberDialog1= inviteMemberDialog1 - } + set inviteMemberDialog1(inviteMemberDialog1) { + this._inviteMemberDialog1 = inviteMemberDialog1 + } - set inviteMemberDialog2(inviteMemberDialog2) { - this._inviteMemberDialog2 = inviteMemberDialog2 - } + set inviteMemberDialog2(inviteMemberDialog2) { + this._inviteMemberDialog2 = inviteMemberDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set rInviteTime(rInviteTime) { - this._rInviteTime = rInviteTime - this._rInviteTimeBytes = this.constructor.utils.int32ToBytes(this._rInviteTime) - } + set rInviteTime(rInviteTime) { + this._rInviteTime = rInviteTime + this._rInviteTimeBytes = this.constructor.utils.int32ToBytes(this._rInviteTime) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._rInviteTimeBytes, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._rInviteTimeBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/GroupKickTransaction.js b/qortal-ui-crypto/api/transactions/groups/GroupKickTransaction.js index 12e6d276..4a2af2c2 100644 --- a/qortal-ui-crypto/api/transactions/groups/GroupKickTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/GroupKickTransaction.js @@ -1,61 +1,61 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class GroupKickTransaction extends TransactionBase { - constructor() { - super() - this.type = 28 - } + constructor() { + super() + this.type = 28 + } - render(html) { - return html` - ${this._kickMemberDialog1} -
- ${this.theRecipient} -
- ${this._kickMemberDialog2} - ` - } + render(html) { + return html` + ${this._kickMemberDialog1} +
+ ${this.theRecipient} +
+ ${this._kickMemberDialog2} + ` + } - set kickMemberDialog1(kickMemberDialog1) { - this._kickMemberDialog1= kickMemberDialog1 - } + set kickMemberDialog1(kickMemberDialog1) { + this._kickMemberDialog1 = kickMemberDialog1 + } - set kickMemberDialog2(kickMemberDialog2) { - this._kickMemberDialog2 = kickMemberDialog2 - } + set kickMemberDialog2(kickMemberDialog2) { + this._kickMemberDialog2 = kickMemberDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set rBanReason(rBanReason) { - this._rBanReason = rBanReason - this._rBanReasonBytes = this.constructor.utils.stringtoUTF8Array(this._rBanReason.toLocaleLowerCase()) - this._rBanReasonLength = this.constructor.utils.int32ToBytes(this._rBanReasonBytes.length) - } + set rBanReason(rBanReason) { + this._rBanReason = rBanReason + this._rBanReasonBytes = this.constructor.utils.stringtoUTF8Array(this._rBanReason.toLocaleLowerCase()) + this._rBanReasonLength = this.constructor.utils.int32ToBytes(this._rBanReasonBytes.length) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._rBanReasonLength, - this._rBanReasonBytes, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._rBanReasonLength, + this._rBanReasonBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/JoinGroupTransaction.js b/qortal-ui-crypto/api/transactions/groups/JoinGroupTransaction.js index 126730ff..57a42bb5 100644 --- a/qortal-ui-crypto/api/transactions/groups/JoinGroupTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/JoinGroupTransaction.js @@ -1,63 +1,55 @@ -"use strict"; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class JoinGroupTransaction extends TransactionBase { - constructor() { - super() - this.type = 31 - this.tests.push( - () => { - if (!(this._registrantAddress instanceof Uint8Array && this._registrantAddress.length == 25)) { - return "Invalid Registrant " + Base58.encode(this._registrantAddress) - } - return true - } - ) - } + constructor() { + super() + this.type = 31 + } - render(html) { - return html` - ${this._groupdialog1} -
- ${this._rGroupName} -
- ${this._groupdialog2} - ` - } + render(html) { + return html` + ${this._groupdialog1} +
+ ${this._rGroupName} +
+ ${this._groupdialog2} + ` + } - set groupdialog1(groupdialog1) { - this._groupdialog1 = groupdialog1 - } + set groupdialog1(groupdialog1) { + this._groupdialog1 = groupdialog1 + } - set groupdialog2(groupdialog2) { - this._groupdialog2 = groupdialog2 - } + set groupdialog2(groupdialog2) { + this._groupdialog2 = groupdialog2 + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set registrantAddress(registrantAddress) {// Always Base58 encoded. Accepts Uint8Array or Base58 string. - this._registrantAddress = registrantAddress instanceof Uint8Array ? registrantAddress : this.constructor.Base58.decode(registrantAddress); - } + set registrantAddress(registrantAddress) { + this._registrantAddress = registrantAddress instanceof Uint8Array ? registrantAddress : this.constructor.Base58.decode(registrantAddress) + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set rGroupName(rGroupName) { - this._rGroupName = rGroupName; - } + set rGroupName(rGroupName) { + this._rGroupName = rGroupName + } - get params() { - const params = super.params; - params.push( - this._rGroupIdBytes, - this._feeBytes - ) - return params; - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/groups/LeaveGroupTransaction.js b/qortal-ui-crypto/api/transactions/groups/LeaveGroupTransaction.js index 0a3939f0..988d768c 100644 --- a/qortal-ui-crypto/api/transactions/groups/LeaveGroupTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/LeaveGroupTransaction.js @@ -1,63 +1,55 @@ -"use strict"; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class LeaveGroupTransaction extends TransactionBase { - constructor() { - super() - this.type = 32 - this.tests.push( - () => { - if (!(this._registrantAddress instanceof Uint8Array && this._registrantAddress.length == 25)) { - return "Invalid Registrant " + Base58.encode(this._registrantAddress) - } - return true - } - ) - } + constructor() { + super() + this.type = 32 + } - render(html) { - return html` - ${this._groupdialog3} -
- ${this._rGroupName} -
- ${this._groupdialog4} - ` - } + render(html) { + return html` + ${this._groupdialog3} +
+ ${this._rGroupName} +
+ ${this._groupdialog4} + ` + } - set groupdialog3(groupdialog3) { - this._groupdialog3 = groupdialog3 - } + set groupdialog3(groupdialog3) { + this._groupdialog3 = groupdialog3 + } - set groupdialog4(groupdialog4) { - this._groupdialog4 = groupdialog4 - } + set groupdialog4(groupdialog4) { + this._groupdialog4 = groupdialog4 + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set registrantAddress(registrantAddress) {// Always Base58 encoded. Accepts Uint8Array or Base58 string. - this._registrantAddress = registrantAddress instanceof Uint8Array ? registrantAddress : this.constructor.Base58.decode(registrantAddress); - } + set registrantAddress(registrantAddress) { + this._registrantAddress = registrantAddress instanceof Uint8Array ? registrantAddress : this.constructor.Base58.decode(registrantAddress) + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set rGroupName(rGroupName) { - this._rGroupName = rGroupName; - } + set rGroupName(rGroupName) { + this._rGroupName = rGroupName + } - get params() { - const params = super.params; - params.push( - this._rGroupIdBytes, - this._feeBytes - ) - return params; - } + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/groups/RemoveGroupAdminTransaction.js b/qortal-ui-crypto/api/transactions/groups/RemoveGroupAdminTransaction.js index 502c6166..05af0da9 100644 --- a/qortal-ui-crypto/api/transactions/groups/RemoveGroupAdminTransaction.js +++ b/qortal-ui-crypto/api/transactions/groups/RemoveGroupAdminTransaction.js @@ -1,53 +1,53 @@ -'use strict'; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class RemoveGroupAdminTransaction extends TransactionBase { - constructor() { - super() - this.type = 25 - } + constructor() { + super() + this.type = 25 + } - render(html) { - return html` - ${this._kickAdminDialog1} -
- ${this.theRecipient} -
- ${this._kickAdminDialog2} - ` - } + render(html) { + return html` + ${this._kickAdminDialog1} +
+ ${this.theRecipient} +
+ ${this._kickAdminDialog2} + ` + } - set kickAdminDialog1(kickAdminDialog1) { - this._kickAdminDialog1 = kickAdminDialog1 - } + set kickAdminDialog1(kickAdminDialog1) { + this._kickAdminDialog1 = kickAdminDialog1 + } - set kickAdminDialog2(kickAdminDialog2) { - this._kickAdminDialog2 = kickAdminDialog2 - } + set kickAdminDialog2(kickAdminDialog2) { + this._kickAdminDialog2 = kickAdminDialog2 + } - set rGroupId(rGroupId) { - this._rGroupId = rGroupId; - this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) - } + set rGroupId(rGroupId) { + this._rGroupId = rGroupId + this._rGroupIdBytes = this.constructor.utils.int32ToBytes(this._rGroupId) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - get params() { - const params = super.params - params.push( - this._rGroupIdBytes, - this._recipient, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._rGroupIdBytes, + this._recipient, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/names/BuyNameTransacion.js b/qortal-ui-crypto/api/transactions/names/BuyNameTransacion.js index 36aa7d60..48671a2a 100644 --- a/qortal-ui-crypto/api/transactions/names/BuyNameTransacion.js +++ b/qortal-ui-crypto/api/transactions/names/BuyNameTransacion.js @@ -1,70 +1,70 @@ -'use strict'; +'use strict' import TransactionBase from '../TransactionBase.js' import { QORT_DECIMALS } from '../../constants.js' export default class BuyNameTransacion extends TransactionBase { - constructor() { - super() - this.type = 7 - } + constructor() { + super() + this.type = 7 + } - render(html) { - return html` - ${this._buyNameDialog1} -
- ${this.nameText} -
- ${this._buyNameDialog2} -
- ${this.showSellPrice} -
- ${this._buyNameDialog3} - ` - } + render(html) { + return html` + ${this._buyNameDialog1} +
+ ${this.nameText} +
+ ${this._buyNameDialog2} +
+ ${this.showSellPrice} +
+ ${this._buyNameDialog3} + ` + } - set buyNameDialog1(buyNameDialog1) { - this._buyNameDialog1 = buyNameDialog1 - } + set buyNameDialog1(buyNameDialog1) { + this._buyNameDialog1 = buyNameDialog1 + } - set buyNameDialog2(buyNameDialog2) { - this._buyNameDialog2 = buyNameDialog2 - } + set buyNameDialog2(buyNameDialog2) { + this._buyNameDialog2 = buyNameDialog2 + } - set buyNameDialog3(buyNameDialog3) { - this._buyNameDialog3 = buyNameDialog3 - } + set buyNameDialog3(buyNameDialog3) { + this._buyNameDialog3 = buyNameDialog3 + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set name(name) { - this.nameText = name - this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) - this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) - } + set name(name) { + this.nameText = name + this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) + this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) + } - set sellPrice(sellPrice) { - this.showSellPrice = sellPrice - this._sellPrice = sellPrice * QORT_DECIMALS - this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice) - } + set sellPrice(sellPrice) { + this.showSellPrice = sellPrice + this._sellPrice = sellPrice * QORT_DECIMALS + this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice) + } - set recipient(recipient) { - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.theRecipient = recipient - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.theRecipient = recipient + } - get params() { - const params = super.params - params.push( - this._nameLength, - this._nameBytes, - this._sellPriceBytes, - this._recipient, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._nameLength, + this._nameBytes, + this._sellPriceBytes, + this._recipient, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/names/CancelSellNameTransacion.js b/qortal-ui-crypto/api/transactions/names/CancelSellNameTransacion.js index bc5a69b3..da8f98bb 100644 --- a/qortal-ui-crypto/api/transactions/names/CancelSellNameTransacion.js +++ b/qortal-ui-crypto/api/transactions/names/CancelSellNameTransacion.js @@ -1,49 +1,49 @@ -'use strict'; +'use strict' import TransactionBase from '../TransactionBase.js' import { QORT_DECIMALS } from '../../constants.js' export default class CancelSellNameTransacion extends TransactionBase { - constructor() { - super() - this.type = 6 - } + constructor() { + super() + this.type = 6 + } - render(html) { - return html` - ${this._cancelSellNameDialog1} -
- ${this.nameText} -
- ${this._cancelSellNameDialog2} - ` - } + render(html) { + return html` + ${this._cancelSellNameDialog1} +
+ ${this.nameText} +
+ ${this._cancelSellNameDialog2} + ` + } - set cancelSellNameDialog1(cancelSellNameDialog1) { - this._cancelSellNameDialog1 = cancelSellNameDialog1 - } + set cancelSellNameDialog1(cancelSellNameDialog1) { + this._cancelSellNameDialog1 = cancelSellNameDialog1 + } - set cancelSellNameDialog2(cancelSellNameDialog2) { - this._cancelSellNameDialog2 = cancelSellNameDialog2 - } + set cancelSellNameDialog2(cancelSellNameDialog2) { + this._cancelSellNameDialog2 = cancelSellNameDialog2 + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set name(name) { - this.nameText = name - this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) - this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) - } + set name(name) { + this.nameText = name + this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) + this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) + } - get params() { - const params = super.params - params.push( - this._nameLength, - this._nameBytes, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._nameLength, + this._nameBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/names/RegisterNameTransaction.js b/qortal-ui-crypto/api/transactions/names/RegisterNameTransaction.js index dac9f69e..6076e7c3 100644 --- a/qortal-ui-crypto/api/transactions/names/RegisterNameTransaction.js +++ b/qortal-ui-crypto/api/transactions/names/RegisterNameTransaction.js @@ -1,57 +1,57 @@ -"use strict"; -import TransactionBase from "../TransactionBase.js" -import { QORT_DECIMALS } from "../../constants.js" +'use strict' +import TransactionBase from '../TransactionBase.js' +import { QORT_DECIMALS } from '../../constants.js' export default class RegisterNameTransaction extends TransactionBase { - constructor() { - super() - this.type = 3 - } + constructor() { + super() + this.type = 3 + } - render(html) { - return html` - ${this._dialogyou} -
- ${this.nameText} -
- ${this._dialogonpress} - ` - } + render(html) { + return html` + ${this._dialogyou} +
+ ${this.nameText} +
+ ${this._dialogonpress} + ` + } - set dialogyou(dialogyou) { - this._dialogyou = dialogyou - } + set dialogyou(dialogyou) { + this._dialogyou = dialogyou + } - set dialogonpress(dialogonpress) { - this._dialogonpress = dialogonpress - } + set dialogonpress(dialogonpress) { + this._dialogonpress = dialogonpress + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set name(name) { - this.nameText = name; - this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) - this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) - } + set name(name) { + this.nameText = name + this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) + this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) + } - set value(value) { - this.valueText = value.length === 0 ? "Registered Name on the Qortal Chain" : value; - this._valueBytes = this.constructor.utils.stringtoUTF8Array(this.valueText) - this._valueLength = this.constructor.utils.int32ToBytes(this._valueBytes.length) - } + set value(value) { + this.valueText = value.length === 0 ? "Registered Name on the Qortal Chain" : value + this._valueBytes = this.constructor.utils.stringtoUTF8Array(this.valueText) + this._valueLength = this.constructor.utils.int32ToBytes(this._valueBytes.length) + } - get params() { - const params = super.params; - params.push( - this._nameLength, - this._nameBytes, - this._valueLength, - this._valueBytes, - this._feeBytes - ) - return params; - } + get params() { + const params = super.params + params.push( + this._nameLength, + this._nameBytes, + this._valueLength, + this._valueBytes, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/names/SellNameTransacion.js b/qortal-ui-crypto/api/transactions/names/SellNameTransacion.js index aeb8b72e..8659edf7 100644 --- a/qortal-ui-crypto/api/transactions/names/SellNameTransacion.js +++ b/qortal-ui-crypto/api/transactions/names/SellNameTransacion.js @@ -1,64 +1,64 @@ -'use strict'; +'use strict' import TransactionBase from '../TransactionBase.js' import { QORT_DECIMALS } from '../../constants.js' export default class SellNameTransacion extends TransactionBase { - constructor() { - super() - this.type = 5 - } + constructor() { + super() + this.type = 5 + } - render(html) { - return html` - ${this._sellNameDialog1} -
- ${this.nameText} -
- ${this._sellNameDialog2} -
- ${this.showSellPrice} -
- ${this._sellNameDialog3} - ` - } + render(html) { + return html` + ${this._sellNameDialog1} +
+ ${this.nameText} +
+ ${this._sellNameDialog2} +
+ ${this.showSellPrice} +
+ ${this._sellNameDialog3} + ` + } - set sellNameDialog1(sellNameDialog1) { - this._sellNameDialog1 = sellNameDialog1 - } + set sellNameDialog1(sellNameDialog1) { + this._sellNameDialog1 = sellNameDialog1 + } - set sellNameDialog2(sellNameDialog2) { - this._sellNameDialog2 = sellNameDialog2 - } + set sellNameDialog2(sellNameDialog2) { + this._sellNameDialog2 = sellNameDialog2 + } - set sellNameDialog3(sellNameDialog3) { - this._sellNameDialog3 = sellNameDialog3 - } + set sellNameDialog3(sellNameDialog3) { + this._sellNameDialog3 = sellNameDialog3 + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set name(name) { - this.nameText = name - this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) - this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) - } + set name(name) { + this.nameText = name + this._nameBytes = this.constructor.utils.stringtoUTF8Array(name) + this._nameLength = this.constructor.utils.int32ToBytes(this._nameBytes.length) + } - set sellPrice(sellPrice) { - this.showSellPrice = sellPrice - this._sellPrice = sellPrice * QORT_DECIMALS - this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice) - } + set sellPrice(sellPrice) { + this.showSellPrice = sellPrice + this._sellPrice = sellPrice * QORT_DECIMALS + this._sellPriceBytes = this.constructor.utils.int64ToBytes(this._sellPrice) + } - get params() { - const params = super.params - params.push( - this._nameLength, - this._nameBytes, - this._sellPriceBytes, - this._feeBytes - ) - return params - } -} \ No newline at end of file + get params() { + const params = super.params + params.push( + this._nameLength, + this._nameBytes, + this._sellPriceBytes, + this._feeBytes + ) + return params + } +} diff --git a/qortal-ui-crypto/api/transactions/registerName_dnsthing.js b/qortal-ui-crypto/api/transactions/registerName_dnsthing.js index 08e7713c..06210cc4 100644 --- a/qortal-ui-crypto/api/transactions/registerName_dnsthing.js +++ b/qortal-ui-crypto/api/transactions/registerName_dnsthing.js @@ -1,39 +1,36 @@ -"use strict"; -/* - TO DO -*/ -(function(){ - function generateSignatureRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp) => { - const data = generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp); - return nacl.sign.detached(data, keyPair.privateKey); - } +'use strict' - function generateRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp, signature) => { - return appendBuffer( generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp), - signature ); - } + (function () { + function generateSignatureRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp) => { + const data = generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp) + return nacl.sign.detached(data, keyPair.privateKey) + } - function generateRegisterNameTransactionBase(publicKey, lastReference, owner, name, value, fee, timestamp) => { - const txType = TYPES.REGISTER_NAME_TRANSACTION; - const typeBytes = int32ToBytes(txType); - const timestampBytes = int64ToBytes(timestamp); - const feeBytes = int64ToBytes(fee * 100000000); - const nameSizeBytes = int32ToBytes(name.length); - const valueSizeBytes = int32ToBytes(value.length); + function generateRegisterNameTransaction(keyPair, lastReference, owner, name, value, fee, timestamp, signature) => { + return appendBuffer(generateRegisterNameTransactionBase(keyPair.publicKey, lastReference, owner, name, value, fee, timestamp), signature) + } - let data = new Uint8Array(); + function generateRegisterNameTransactionBase(publicKey, lastReference, owner, name, value, fee, timestamp) => { + const txType = TYPES.REGISTER_NAME_TRANSACTION + const typeBytes = int32ToBytes(txType) + const timestampBytes = int64ToBytes(timestamp) + const feeBytes = int64ToBytes(fee * 100000000) + const nameSizeBytes = int32ToBytes(name.length) + const valueSizeBytes = int32ToBytes(value.length) - data = appendBuffer(data, typeBytes); - data = appendBuffer(data, timestampBytes); - data = appendBuffer(data, lastReference); - data = appendBuffer(data, publicKey); - data = appendBuffer(data, owner); - data = appendBuffer(data, nameSizeBytes); - data = appendBuffer(data, name); - data = appendBuffer(data, valueSizeBytes); - data = appendBuffer(data, value); - data = appendBuffer(data, feeBytes); + let data = new Uint8Array() - return data; - } -}()) \ No newline at end of file + data = appendBuffer(data, typeBytes) + data = appendBuffer(data, timestampBytes) + data = appendBuffer(data, lastReference) + data = appendBuffer(data, publicKey) + data = appendBuffer(data, owner) + data = appendBuffer(data, nameSizeBytes) + data = appendBuffer(data, name) + data = appendBuffer(data, valueSizeBytes) + data = appendBuffer(data, value) + data = appendBuffer(data, feeBytes) + + return data + } + }()) diff --git a/qortal-ui-crypto/api/transactions/reward-share/RemoveRewardShareTransaction.js b/qortal-ui-crypto/api/transactions/reward-share/RemoveRewardShareTransaction.js index d8ca9480..5610830e 100644 --- a/qortal-ui-crypto/api/transactions/reward-share/RemoveRewardShareTransaction.js +++ b/qortal-ui-crypto/api/transactions/reward-share/RemoveRewardShareTransaction.js @@ -1,55 +1,55 @@ -"use strict"; -import TransactionBase from "../TransactionBase.js" +'use strict' +import TransactionBase from '../TransactionBase.js' import publicKeyToAddress from '../../wallet/publicKeyToAddress.js' -import { Base58 } from "../../deps/deps.js"; +import { Base58 } from '../../deps/deps.js' export default class RemoveRewardShareTransaction extends TransactionBase { - constructor() { - super() - this.type = 38 - } + constructor() { + super() + this.type = 38 + } - render(html) { - return html` - ${this._rewarddialog5} -
- ${this.constructor.Base58.encode(this._recipient)} -
- ${this._rewarddialog6} - ` - } + render(html) { + return html` + ${this._rewarddialog5} +
+ ${this.constructor.Base58.encode(this._recipient)} +
+ ${this._rewarddialog6} + ` + } - set rewarddialog5(rewarddialog5) { - this._rewarddialog5 = rewarddialog5; - } + set rewarddialog5(rewarddialog5) { + this._rewarddialog5 = rewarddialog5 + } - set rewarddialog6(rewarddialog6) { - this._rewarddialog6 = rewarddialog6; - } + set rewarddialog6(rewarddialog6) { + this._rewarddialog6 = rewarddialog6 + } - set rewardShareKeyPairPublicKey(rewardShareKeyPairPublicKey) { - this._rewardShareKeyPairPublicKey = Base58.decode(rewardShareKeyPairPublicKey) - } + set rewardShareKeyPairPublicKey(rewardShareKeyPairPublicKey) { + this._rewardShareKeyPairPublicKey = Base58.decode(rewardShareKeyPairPublicKey) + } - set recipient(recipient) { - const _address = publicKeyToAddress(this._keyPair.publicKey) - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - this.fee = _address === recipient ? 0 : 0.001 - } + set recipient(recipient) { + const _address = publicKeyToAddress(this._keyPair.publicKey) + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + this.fee = _address === recipient ? 0 : 0.001 + } - set percentageShare(share) { - this._percentageShare = share * 100 - this._percentageShareBytes = this.constructor.utils.int64ToBytes(this._percentageShare) - } + set percentageShare(share) { + this._percentageShare = share * 100 + this._percentageShareBytes = this.constructor.utils.int64ToBytes(this._percentageShare) + } - get params() { - const params = super.params - params.push( - this._recipient, - this._rewardShareKeyPairPublicKey, - this._percentageShareBytes, - this._feeBytes - ) - return params; - } + get params() { + const params = super.params + params.push( + this._recipient, + this._rewardShareKeyPairPublicKey, + this._percentageShareBytes, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/reward-share/RewardShareTransaction.js b/qortal-ui-crypto/api/transactions/reward-share/RewardShareTransaction.js index cc67356a..939552f9 100644 --- a/qortal-ui-crypto/api/transactions/reward-share/RewardShareTransaction.js +++ b/qortal-ui-crypto/api/transactions/reward-share/RewardShareTransaction.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict' import publicKeyToAddress from '../../wallet/publicKeyToAddress.js' import TransactionBase from "../TransactionBase.js" import nacl from '../../deps/nacl-fast.js' @@ -6,74 +6,73 @@ import ed2curve from '../../deps/ed2curve.js' import { Sha256 } from 'asmcrypto.js' export default class RewardShareTransaction extends TransactionBase { - constructor() { - super() - this.type = 38 - } + constructor() { + super() + this.type = 38 + } - render(html) { - return html` - ${this._rewarddialog1} ${this._percentageShare / 1e8}% ${this._rewarddialog2} ${this.constructor.Base58.encode(this._recipient)}? - ${this._rewarddialog3} -
- ${this._base58RewardShareSeed} -
- ${this._rewarddialog4} - ` - } + render(html) { + return html` + ${this._rewarddialog1} ${this._percentageShare / 1e8}% ${this._rewarddialog2} ${this.constructor.Base58.encode(this._recipient)}? + ${this._rewarddialog3} +
+ ${this._base58RewardShareSeed} +
+ ${this._rewarddialog4} + ` + } - set rewarddialog1(rewarddialog1) { - this._rewarddialog1 = rewarddialog1; - } + set rewarddialog1(rewarddialog1) { + this._rewarddialog1 = rewarddialog1 + } - set rewarddialog2(rewarddialog2) { - this._rewarddialog2 = rewarddialog2; - } + set rewarddialog2(rewarddialog2) { + this._rewarddialog2 = rewarddialog2 + } - set rewarddialog3(rewarddialog3) { - this._rewarddialog3 = rewarddialog3; - } + set rewarddialog3(rewarddialog3) { + this._rewarddialog3 = rewarddialog3 + } - set rewarddialog4(rewarddialog4) { - this._rewarddialog4 = rewarddialog4; - } + set rewarddialog4(rewarddialog4) { + this._rewarddialog4 = rewarddialog4 + } - set recipientPublicKey(recipientPublicKey) { - this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey - this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey) + set recipientPublicKey(recipientPublicKey) { + this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey + this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey) - this.recipient = publicKeyToAddress(this._recipientPublicKey) + this.recipient = publicKeyToAddress(this._recipientPublicKey) - this.fee = (recipientPublicKey === this.constructor.Base58.encode(this._keyPair.publicKey) ? 0 : 0.001) + this.fee = (recipientPublicKey === this.constructor.Base58.encode(this._keyPair.publicKey) ? 0 : 0.001) - // Reward share keys - const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey) - const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey) - const sharedSecret = new Uint8Array(32); - nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey); - this._rewardShareSeed = new Sha256().process(sharedSecret).finish().result - this._base58RewardShareSeed = this.constructor.Base58.encode(this._rewardShareSeed) + const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey) + const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey) + const sharedSecret = new Uint8Array(32); + nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey); + this._rewardShareSeed = new Sha256().process(sharedSecret).finish().result + this._base58RewardShareSeed = this.constructor.Base58.encode(this._rewardShareSeed) - this._rewardShareKeyPair = nacl.sign.keyPair.fromSeed(this._rewardShareSeed) - } + this._rewardShareKeyPair = nacl.sign.keyPair.fromSeed(this._rewardShareSeed) + } - set recipient(recipient) { // Always Base58 encoded. Accepts Uint8Array or Base58 string. - this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) - } + set recipient(recipient) { + this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) + } - set percentageShare(share) { - this._percentageShare = share * 100 - this._percentageShareBytes = this.constructor.utils.int64ToBytes(this._percentageShare) - } + set percentageShare(share) { + this._percentageShare = share * 100 + this._percentageShareBytes = this.constructor.utils.int64ToBytes(this._percentageShare) + } - get params() { - const params = super.params - params.push( - this._recipient, - this._rewardShareKeyPair.publicKey, - this._percentageShareBytes, - this._feeBytes - ) - return params; - } + get params() { + const params = super.params + params.push( + this._recipient, + this._rewardShareKeyPair.publicKey, + this._percentageShareBytes, + this._feeBytes + ) + return params + } } diff --git a/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotCreateRequest.js b/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotCreateRequest.js index 85d5867c..05178976 100644 --- a/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotCreateRequest.js +++ b/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotCreateRequest.js @@ -5,75 +5,59 @@ */ export default class TradeBotCreateRequest { - constructor() { - // ... - } + constructor() { + // ... + } - createTransaction(txnReq) { + createTransaction(txnReq) { + this.creatorPublicKey(txnReq.creatorPublicKey) + this.qortAmount(txnReq.qortAmount) + this.fundingQortAmount(txnReq.fundingQortAmount) + this.foreignBlockchain(txnReq.foreignBlockchain) + this.foreignAmount(txnReq.foreignAmount) + this.tradeTimeout(txnReq.tradeTimeout) + this.receivingAddress(txnReq.receivingAddress) - this.creatorPublicKey(txnReq.creatorPublicKey); + return this.txnRequest() + } - this.qortAmount(txnReq.qortAmount); + creatorPublicKey(creatorPublicKey) { + this._creatorPublicKey = creatorPublicKey + } - this.fundingQortAmount(txnReq.fundingQortAmount); + qortAmount(qortAmount) { + this._qortAmount = qortAmount + } - this.foreignBlockchain(txnReq.foreignBlockchain); + fundingQortAmount(fundingQortAmount) { + this._fundingQortAmount = fundingQortAmount + } - this.foreignAmount(txnReq.foreignAmount); + foreignBlockchain(foreignBlockchain) { + this._foreignBlockchain = foreignBlockchain + } - this.tradeTimeout(txnReq.tradeTimeout); + foreignAmount(foreignAmount) { + this._foreignAmount = foreignAmount + } - this.receivingAddress(txnReq.receivingAddress); + tradeTimeout(tradeTimeout) { + this._tradeTimeout = tradeTimeout + } - return this.txnRequest(); - } + receivingAddress(receivingAddress) { + this._receivingAddress = receivingAddress + } - creatorPublicKey(creatorPublicKey) { - - this._creatorPublicKey = creatorPublicKey; - - } - - qortAmount(qortAmount) { - this._qortAmount = qortAmount; - } - - - fundingQortAmount(fundingQortAmount) { - - this._fundingQortAmount = fundingQortAmount; - } - - foreignBlockchain(foreignBlockchain) { - - this._foreignBlockchain = foreignBlockchain; - } - - foreignAmount(foreignAmount) { - - this._foreignAmount = foreignAmount; - } - - tradeTimeout(tradeTimeout) { - - this._tradeTimeout = tradeTimeout; - } - - receivingAddress(receivingAddress) { - - this._receivingAddress = receivingAddress; - } - - txnRequest() { - - return { - creatorPublicKey: this._creatorPublicKey, - qortAmount: this._qortAmount, - fundingQortAmount: this._fundingQortAmount, - foreignBlockchain: this._foreignBlockchain, - foreignAmount: this._foreignAmount, - tradeTimeout: this._tradeTimeout, - receivingAddress: this._receivingAddress - } - } + txnRequest() { + return { + creatorPublicKey: this._creatorPublicKey, + qortAmount: this._qortAmount, + fundingQortAmount: this._fundingQortAmount, + foreignBlockchain: this._foreignBlockchain, + foreignAmount: this._foreignAmount, + tradeTimeout: this._tradeTimeout, + receivingAddress: this._receivingAddress + } + } } diff --git a/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotRespondRequest.js b/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotRespondRequest.js index 773ea336..4380b46b 100644 --- a/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotRespondRequest.js +++ b/qortal-ui-crypto/api/transactions/trade-portal/tradebot/TradeBotRespondRequest.js @@ -5,41 +5,35 @@ */ export default class TradeBotRespondRequest { - constructor() { - // ... - } + constructor() { + // ... + } - createTransaction(txnReq) { + createTransaction(txnReq) { + this.atAddress(txnReq.atAddress) + this.foreignKey(txnReq.foreignKey) + this.receivingAddress(txnReq.receivingAddress) - this.atAddress(txnReq.atAddress) + return this.txnRequest() + } - this.foreignKey(txnReq.foreignKey) + atAddress(atAddress) { + this._atAddress = atAddress + } - this.receivingAddress(txnReq.receivingAddress) + foreignKey(foreignKey) { + this._foreignKey = foreignKey + } - return this.txnRequest() - } + receivingAddress(receivingAddress) { + this._receivingAddress = receivingAddress + } - atAddress(atAddress) { - - this._atAddress = atAddress - } - - foreignKey(foreignKey) { - this._foreignKey = foreignKey - } - - receivingAddress(receivingAddress) { - - this._receivingAddress = receivingAddress - } - - txnRequest() { - - return { - atAddress: this._atAddress, - foreignKey: this._foreignKey, - receivingAddress: this._receivingAddress - } - } + txnRequest() { + return { + atAddress: this._atAddress, + foreignKey: this._foreignKey, + receivingAddress: this._receivingAddress + } + } } diff --git a/qortal-ui-crypto/api/transactions/trade-portal/tradebot/signTradeBotTransaction.js b/qortal-ui-crypto/api/transactions/trade-portal/tradebot/signTradeBotTransaction.js index 3671183a..bce40ed8 100644 --- a/qortal-ui-crypto/api/transactions/trade-portal/tradebot/signTradeBotTransaction.js +++ b/qortal-ui-crypto/api/transactions/trade-portal/tradebot/signTradeBotTransaction.js @@ -2,37 +2,30 @@ import Base58 from '../../../deps/Base58.js' import nacl from '../../../deps/nacl-fast.js' import utils from '../../../deps/utils.js' - const signTradeBotTransaction = (unsignedTxn, keyPair) => { + if (!unsignedTxn) { + throw new Error('Unsigned Transaction Bytes not defined') + } - if (!unsignedTxn) { - throw new Error('Unsigned Transaction Bytes not defined') - } + if (!keyPair) { + throw new Error('keyPair not defined') + } - if (!keyPair) { - throw new Error('keyPair not defined') - } + const txnBuffer = Base58.decode(unsignedTxn) - const txnBuffer = Base58.decode(unsignedTxn) + if (keyPair.privateKey.length === undefined) { + const _privateKey = Object.keys(keyPair.privateKey).map(function (key) { return keyPair.privateKey[key]; }) + const privateKey = new Uint8Array(_privateKey) + const signature = nacl.sign.detached(txnBuffer, privateKey) + const signedBytes = utils.appendBuffer(txnBuffer, signature) - if (keyPair.privateKey.length === undefined) { + return signedBytes + } else { + const signature = nacl.sign.detached(txnBuffer, keyPair.privateKey) + const signedBytes = utils.appendBuffer(txnBuffer, signature) - const _privateKey = Object.keys(keyPair.privateKey).map(function (key) { return keyPair.privateKey[key]; }); - const privateKey = new Uint8Array(_privateKey) - - const signature = nacl.sign.detached(txnBuffer, privateKey) - - const signedBytes = utils.appendBuffer(txnBuffer, signature) - - return signedBytes - } else { - - const signature = nacl.sign.detached(txnBuffer, keyPair.privateKey) - - const signedBytes = utils.appendBuffer(txnBuffer, signature) - - return signedBytes - } + return signedBytes + } } export default signTradeBotTransaction diff --git a/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/DeleteTradeOffer.js b/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/DeleteTradeOffer.js index c7b3f0e1..982d2423 100644 --- a/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/DeleteTradeOffer.js +++ b/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/DeleteTradeOffer.js @@ -5,35 +5,29 @@ */ export default class DeleteTradeOffer { - constructor() { - // ... - } + constructor() { + // ... + } - createTransaction(txnReq) { + createTransaction(txnReq) { + this.creatorPublicKey(txnReq.creatorPublicKey) + this.atAddress(txnReq.atAddress) - this.creatorPublicKey(txnReq.creatorPublicKey) + return this.txnRequest() + } - this.atAddress(txnReq.atAddress) + creatorPublicKey(creatorPublicKey) { + this._creatorPublicKey = creatorPublicKey + } - return this.txnRequest() - } + atAddress(atAddress) { + this._atAddress = atAddress + } - creatorPublicKey(creatorPublicKey) { - - this._creatorPublicKey = creatorPublicKey - - } - - atAddress(atAddress) { - - this._atAddress = atAddress - } - - txnRequest() { - - return { - creatorPublicKey: this._creatorPublicKey, - atAddress: this._atAddress - } - } + txnRequest() { + return { + creatorPublicKey: this._creatorPublicKey, + atAddress: this._atAddress + } + } } diff --git a/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/cancelAllOffers.js b/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/cancelAllOffers.js index 425c2684..e3011a59 100644 --- a/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/cancelAllOffers.js +++ b/qortal-ui-crypto/api/transactions/trade-portal/tradeoffer/cancelAllOffers.js @@ -1,24 +1,25 @@ import { request } from '../../../fetch-request.js' -import { deleteTradeOffer, signTradeBotTxn } from '../../../tradeRequest.js'; +import { deleteTradeOffer, signTradeBotTxn } from '../../../tradeRequest.js' import { processTransaction } from '../../../createTransaction.js' export const cancelAllOffers = async (requestObject) => { - const keyPair = requestObject.keyPair; - const publicKey = requestObject.base58PublicKey; - const address = requestObject.address; + const keyPair = requestObject.keyPair + const publicKey = requestObject.base58PublicKey + const address = requestObject.address - const getMyOpenOffers = async () => { - const res = await request('/crosschain/tradeoffers'); - const myOpenTradeOrders = await res.filter(order => order.mode === "OFFERING" && order.qortalCreator === address); - return myOpenTradeOrders; - } + const getMyOpenOffers = async () => { + const res = await request('/crosschain/tradeoffers') + const myOpenTradeOrders = await res.filter(order => order.mode === "OFFERING" && order.qortalCreator === address) + return myOpenTradeOrders + } - const myOpenOffers = await getMyOpenOffers(); - let response = true; - myOpenOffers.forEach( async (openOffer) => { - let unsignedTxn = await deleteTradeOffer({ creatorPublicKey: publicKey, atAddress: openOffer.qortalAtAddress }); - let signedTxnBytes = await signTradeBotTxn(unsignedTxn, keyPair); - await processTransaction(signedTxnBytes); - }); - return response + const myOpenOffers = await getMyOpenOffers() + let response = true + + myOpenOffers.forEach(async (openOffer) => { + let unsignedTxn = await deleteTradeOffer({ creatorPublicKey: publicKey, atAddress: openOffer.qortalAtAddress }) + let signedTxnBytes = await signTradeBotTxn(unsignedTxn, keyPair) + await processTransaction(signedTxnBytes) + }) + return response } diff --git a/qortal-ui-crypto/api/transactions/transactions.js b/qortal-ui-crypto/api/transactions/transactions.js index 84f2759b..b9387184 100644 --- a/qortal-ui-crypto/api/transactions/transactions.js +++ b/qortal-ui-crypto/api/transactions/transactions.js @@ -22,26 +22,26 @@ import RemoveRewardShareTransaction from './reward-share/RemoveRewardShareTransa import TransferPrivsTransaction from './TransferPrivsTransaction.js' export const transactionTypes = { - 2: PaymentTransaction, - 3: RegisterNameTransaction, - 5: SellNameTransacion, - 6: CancelSellNameTransacion, - 7: BuyNameTransacion, - 17: MessageTransaction, - 18: ChatTransaction, - 181: GroupChatTransaction, - 19: PublicizeTransaction, - 22: CreateGroupTransaction, - 24: AddGroupAdminTransaction, - 25: RemoveGroupAdminTransaction, - 26: GroupBanTransaction, - 27: CancelGroupBanTransaction, - 28: GroupKickTransaction, - 29: GroupInviteTransaction, - 30: CancelGroupInviteTransaction, - 31: JoinGroupTransaction, - 32: LeaveGroupTransaction, - 38: RewardShareTransaction, - 381: RemoveRewardShareTransaction, - 40: TransferPrivsTransaction + 2: PaymentTransaction, + 3: RegisterNameTransaction, + 5: SellNameTransacion, + 6: CancelSellNameTransacion, + 7: BuyNameTransacion, + 17: MessageTransaction, + 18: ChatTransaction, + 181: GroupChatTransaction, + 19: PublicizeTransaction, + 22: CreateGroupTransaction, + 24: AddGroupAdminTransaction, + 25: RemoveGroupAdminTransaction, + 26: GroupBanTransaction, + 27: CancelGroupBanTransaction, + 28: GroupKickTransaction, + 29: GroupInviteTransaction, + 30: CancelGroupInviteTransaction, + 31: JoinGroupTransaction, + 32: LeaveGroupTransaction, + 38: RewardShareTransaction, + 381: RemoveRewardShareTransaction, + 40: TransferPrivsTransaction } diff --git a/qortal-ui-crypto/api/wallet/base58PublicKeyToAddress.js b/qortal-ui-crypto/api/wallet/base58PublicKeyToAddress.js index 914a67e0..dbbae27d 100644 --- a/qortal-ui-crypto/api/wallet/base58PublicKeyToAddress.js +++ b/qortal-ui-crypto/api/wallet/base58PublicKeyToAddress.js @@ -1,11 +1,8 @@ import publicKeyToAddress from './publicKeyToAddress' import Base58 from '../deps/Base58.js' - export const base58PublicKeyToAddress = (base58pubkey, qora = false) => { - const decodePubKey = Base58.decode(base58pubkey) - - const address = publicKeyToAddress(decodePubKey, qora) - - return address + const decodePubKey = Base58.decode(base58pubkey) + const address = publicKeyToAddress(decodePubKey, qora) + return address } diff --git a/qortal-ui-crypto/api/wallet/publicKeyToAddress.js b/qortal-ui-crypto/api/wallet/publicKeyToAddress.js index cd484903..1839a05b 100644 --- a/qortal-ui-crypto/api/wallet/publicKeyToAddress.js +++ b/qortal-ui-crypto/api/wallet/publicKeyToAddress.js @@ -1,37 +1,35 @@ -import RIPEMD160 from '../deps/ripemd160.js' +import Base58 from '../deps/Base58.js' import BROKEN_RIPEMD160 from '../deps/broken-ripemd160.js' +import RIPEMD160 from '../deps/ripemd160.js' +import utils from '../deps/utils.js' +import { ADDRESS_VERSION } from '../constants.js' +import { Buffer } from 'buffer' import { Sha256 } from 'asmcrypto.js' -import utils from '../deps/utils.js' -import Base58 from '../deps/Base58.js' -import { Buffer } from 'buffer' - -import { ADDRESS_VERSION } from '../constants.js' - const repeatSHA256 = (passphrase, hashes) => { - let hash = passphrase - for (let i = 0; i < hashes; i++) { - hash = new Sha256().process(hash).finish().result - } - return hash + let hash = passphrase + for (let i = 0; i < hashes; i++) { + hash = new Sha256().process(hash).finish().result + } + return hash } const publicKeyToAddress = (publicKey, qora = false) => { - const publicKeySha256 = new Sha256().process(publicKey).finish().result - const _publicKeyHash = qora ? new BROKEN_RIPEMD160().digest(publicKeySha256) : new RIPEMD160().update(Buffer.from(publicKeySha256)).digest('hex') + const publicKeySha256 = new Sha256().process(publicKey).finish().result + const _publicKeyHash = qora ? new BROKEN_RIPEMD160().digest(publicKeySha256) : new RIPEMD160().update(Buffer.from(publicKeySha256)).digest('hex') + const publicKeyHash = qora ? _publicKeyHash : _publicKeyHash - const publicKeyHash = qora ? _publicKeyHash : _publicKeyHash - let address = new Uint8Array() + let address = new Uint8Array() - address = utils.appendBuffer(address, [ADDRESS_VERSION]) - address = utils.appendBuffer(address, publicKeyHash) + address = utils.appendBuffer(address, [ADDRESS_VERSION]) + address = utils.appendBuffer(address, publicKeyHash) - const checkSum = repeatSHA256(address, 2) - address = utils.appendBuffer(address, checkSum.subarray(0, 4)) + const checkSum = repeatSHA256(address, 2) + address = utils.appendBuffer(address, checkSum.subarray(0, 4)) - address = Base58.encode(address) + address = Base58.encode(address) - return address + return address } export default publicKeyToAddress diff --git a/qortal-ui-crypto/api/wallet/validateAddress.js b/qortal-ui-crypto/api/wallet/validateAddress.js index 515773b1..e487a55e 100644 --- a/qortal-ui-crypto/api/wallet/validateAddress.js +++ b/qortal-ui-crypto/api/wallet/validateAddress.js @@ -1,12 +1,10 @@ import Base58 from '../deps/Base58.js' - export const validateAddress = (address) => { - const decodePubKey = Base58.decode(address) - - if (!(decodePubKey instanceof Uint8Array && decodePubKey.length == 25)) { - return false - } - return true + const decodePubKey = Base58.decode(address) + if (!(decodePubKey instanceof Uint8Array && decodePubKey.length == 25)) { + return false + } + return true } diff --git a/qortal-ui-crypto/config.js b/qortal-ui-crypto/config.js index 6fccb8cc..e17ca4f2 100644 --- a/qortal-ui-crypto/config.js +++ b/qortal-ui-crypto/config.js @@ -6,33 +6,32 @@ const configWatchers = [] const waitingForConfig = [] const subscribeToStore = () => { - if (!store) return setTimeout(() => subscribeToStore(), 50) // 0.05s + if (!store) return setTimeout(() => subscribeToStore(), 50) - store.subscribe(() => { - const cA = store.getState().app - const c = store.getState().config - if (!c.loaded) return - if (!loaded) waitingForConfig.forEach(r => r(cA)) - configWatchers.forEach(fn => fn(cA)) - config = cA - }) + store.subscribe(() => { + const cA = store.getState().app + const c = store.getState().config + if (!c.loaded) return + if (!loaded) waitingForConfig.forEach(r => r(cA)) + configWatchers.forEach(fn => fn(cA)) + config = cA + }) } subscribeToStore() export function getConfig() { - return config + return config } export function watchConfig(fn) { - // config ? fn(config) : void 0 - fn(config) - configWatchers.push(fn) + fn(config) + configWatchers.push(fn) } export function waitForConfig() { - return new Promise((resolve, reject) => { - if (config) return resolve(config) - waitingForConfig.push(resolve) - }) -} \ No newline at end of file + return new Promise((resolve, reject) => { + if (config) return resolve(config) + waitingForConfig.push(resolve) + }) +} diff --git a/qortal-ui-plugins/plugins/core/components/ChatModals.js b/qortal-ui-plugins/plugins/core/components/ChatModals.js index d6cf6aba..62e9b4e6 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatModals.js +++ b/qortal-ui-plugins/plugins/core/components/ChatModals.js @@ -183,6 +183,7 @@ class ChatModals extends LitElement { timestamp: sendTimestamp, recipient: recipient, recipientPublicKey: _publicKey, + hasChatReference: 0, message: messageText, lastReference: reference, proofOfWorkNonce: 0, diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index a3bfba57..c6745df3 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -695,6 +695,7 @@ class ChatPage extends LitElement { timestamp: Date.now(), recipient: this._chatId, recipientPublicKey: this._publicKey.key, + hasChatReference: 0, message: messageText, lastReference: reference, proofOfWorkNonce: 0, @@ -712,6 +713,7 @@ class ChatPage extends LitElement { timestamp: Date.now(), groupID: Number(this._chatId), hasReceipient: 0, + hasChatReference: 0, message: messageText, lastReference: reference, proofOfWorkNonce: 0, diff --git a/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js b/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js index 11f046ff..91d5beec 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js @@ -410,6 +410,7 @@ class ChatWelcomePage extends LitElement { timestamp: sendTimestamp, recipient: recipient, recipientPublicKey: _publicKey, + hasChatReference: 0, message: messageText, lastReference: reference, proofOfWorkNonce: 0, diff --git a/qortal-ui-plugins/plugins/core/components/NameMenu.js b/qortal-ui-plugins/plugins/core/components/NameMenu.js index ca67af73..feb454c8 100644 --- a/qortal-ui-plugins/plugins/core/components/NameMenu.js +++ b/qortal-ui-plugins/plugins/core/components/NameMenu.js @@ -529,6 +529,7 @@ class NameMenu extends LitElement { timestamp: sendTimestamp, recipient: recipient, recipientPublicKey: _publicKey, + hasChatReference: 0, message: messageText, lastReference: reference, proofOfWorkNonce: 0, diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index dc59b97f..984314bd 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -789,6 +789,7 @@ class Chat extends LitElement { timestamp: sendTimestamp, recipient: recipient, recipientPublicKey: _publicKey, + hasChatReference: 0, message: messageText, lastReference: reference, proofOfWorkNonce: 0, From 6049d18f4949db8bb445418652300b0cff4df09f Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 13 Jan 2023 11:22:50 +0100 Subject: [PATCH 03/76] Fixx transactions --- .../api/transactions/TransactionBase.js | 47 +++++ .../api/transactions/chat/ChatBase.js | 190 +++++++++++------- .../api/transactions/chat/ChatTransaction.js | 2 +- .../transactions/chat/GroupChatTransaction.js | 3 +- 4 files changed, 167 insertions(+), 75 deletions(-) diff --git a/qortal-ui-crypto/api/transactions/TransactionBase.js b/qortal-ui-crypto/api/transactions/TransactionBase.js index ae5f613e..f41b7749 100644 --- a/qortal-ui-crypto/api/transactions/TransactionBase.js +++ b/qortal-ui-crypto/api/transactions/TransactionBase.js @@ -19,6 +19,53 @@ export default class TransactionBase { this.fee = 0 this.groupID = 0 this.timestamp = Date.now() + this.tests = [ + () => { + if (!(this._type >= 1 && this._type in TX_TYPES)) { + return 'Invalid type: ' + this.type + } + return true + }, + () => { + if (this._fee < 0) { + return 'Invalid fee: ' + this._fee / QORT_DECIMALS + } + return true + }, + () => { + if (this._groupID < 0 || !Number.isInteger(this._groupID)) { + return 'Invalid groupID: ' + this._groupID + } + return true + }, + () => { + if (!(new Date(this._timestamp)).getTime() > 0) { + return 'Invalid timestamp: ' + this._timestamp + } + return true + }, + () => { + if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) { + if (this._lastReference == 0) { + return 'Invalid last reference. Please ensure that you have at least 0.001 QORT for the transaction fee.' + } + return 'Invalid last reference: ' + this._lastReference + } + return true + }, + () => { + if (!(this._keyPair)) { + return 'keyPair must be specified' + } + if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) { + return 'Invalid publicKey' + } + if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) { + return 'Invalid privateKey' + } + return true + } + ] } render(html) { diff --git a/qortal-ui-crypto/api/transactions/chat/ChatBase.js b/qortal-ui-crypto/api/transactions/chat/ChatBase.js index 783176ed..240c9068 100644 --- a/qortal-ui-crypto/api/transactions/chat/ChatBase.js +++ b/qortal-ui-crypto/api/transactions/chat/ChatBase.js @@ -5,93 +5,137 @@ import Base58 from '../../deps/Base58.js' import utils from '../../deps/utils.js' export default class ChatBase { - static get utils() { - return utils - } - static get nacl() { - return nacl - } - static get Base58() { - return Base58 - } + static get utils() { + return utils + } + static get nacl() { + return nacl + } + static get Base58() { + return Base58 + } - constructor() { - this.fee = 0 - this.groupID = 0 - } + constructor() { + this.fee = 0 + this.groupID = 0 + this.tests = [ + () => { + if (!(this._type >= 1 && this._type in TX_TYPES)) { + return 'Invalid type: ' + this.type + } + return true + }, + () => { + if (this._fee < 0) { + return 'Invalid fee: ' + this._fee / QORT_DECIMALS + } + return true + }, + () => { + if (this._groupID < 0 || !Number.isInteger(this._groupID)) { + return 'Invalid groupID: ' + this._groupID + } + return true + }, + () => { + if (!(new Date(this._timestamp)).getTime() > 0) { + return 'Invalid timestamp: ' + this._timestamp + } + return true + }, + () => { + if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) { + return 'Invalid last reference: ' + this._lastReference + } + return true + }, + () => { + if (!(this._keyPair)) { + return 'keyPair must be specified' + } + if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) { + return 'Invalid publicKey' + } + if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) { + return 'Invalid privateKey' + } + return true + } + ] + } - set keyPair(keyPair) { - this._keyPair = keyPair - } + set keyPair(keyPair) { + this._keyPair = keyPair + } - set type(type) { - this.typeText = TX_TYPES[type] - this._type = type - this._typeBytes = this.constructor.utils.int32ToBytes(this._type) - } + set type(type) { + this.typeText = TX_TYPES[type] + this._type = type + this._typeBytes = this.constructor.utils.int32ToBytes(this._type) + } - set groupID(groupID) { - this._groupID = groupID - this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) - } + set groupID(groupID) { + this._groupID = groupID + this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) + } - set timestamp(timestamp) { - this._timestamp = timestamp - this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) - } + set timestamp(timestamp) { + this._timestamp = timestamp + this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) + } - set fee(fee) { - this._fee = fee * QORT_DECIMALS - this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) - } + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } - set lastReference(lastReference) { - this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) - } + set lastReference(lastReference) { + this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) + } - get params() { - return [ - this._typeBytes, - this._timestampBytes, - this._groupIDBytes, - this._lastReference, - this._keyPair.publicKey - ] - } + get params() { + return [ + this._typeBytes, + this._timestampBytes, + this._groupIDBytes, + this._lastReference, + this._keyPair.publicKey + ] + } - get chatBytes() { - const isValid = this.validParams() - if (!isValid.valid) { - throw new Error(isValid.message) - } + get chatBytes() { + const isValid = this.validParams() + if (!isValid.valid) { + throw new Error(isValid.message) + } - let result = new Uint8Array() + let result = new Uint8Array() - this.params.forEach(item => { - result = this.constructor.utils.appendBuffer(result, item) - }) + this.params.forEach(item => { + result = this.constructor.utils.appendBuffer(result, item) + }) - this._chatBytes = result + this._chatBytes = result - return this._chatBytes - } + return this._chatBytes + } - validParams() { - let finalResult = { - valid: true - } + validParams() { + let finalResult = { + valid: true + } - this.tests.some(test => { - const result = test() - if (result !== true) { - finalResult = { - valid: false, - message: result - } - return true - } - }) - return finalResult - } + this.tests.some(test => { + const result = test() + if (result !== true) { + finalResult = { + valid: false, + message: result + } + return true + } + }) + return finalResult + } } diff --git a/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js b/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js index 642ff744..d6313924 100644 --- a/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js +++ b/qortal-ui-crypto/api/transactions/chat/ChatTransaction.js @@ -67,7 +67,7 @@ export default class ChatTransaction extends ChatBase { } get params() { - const params = super.params; + const params = super.params params.push( this._proofOfWorkNonce, this._hasReceipient, diff --git a/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js b/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js index e414d10b..dc3a856b 100644 --- a/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js +++ b/qortal-ui-crypto/api/transactions/chat/GroupChatTransaction.js @@ -1,5 +1,6 @@ 'use strict' import ChatBase from "./ChatBase.js" +import { CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } from '../../constants.js' export default class GroupChatTransaction extends ChatBase { constructor() { @@ -43,7 +44,7 @@ export default class GroupChatTransaction extends ChatBase { } get params() { - const params = super.params; + const params = super.params params.push( this._proofOfWorkNonce, this._hasReceipient, From 827095888289d1e406dcae2cc6f30da29e0083a7 Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 13 Jan 2023 16:01:26 -0500 Subject: [PATCH 04/76] add chat refence timestamp --- qortal-ui-crypto/api/constants.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qortal-ui-crypto/api/constants.js b/qortal-ui-crypto/api/constants.js index d5c58016..11c0cbbf 100644 --- a/qortal-ui-crypto/api/constants.js +++ b/qortal-ui-crypto/api/constants.js @@ -149,8 +149,6 @@ const ERROR_CODES = { 1000: "Not yet released." } -const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 0 - // Qortal 8 decimals const QORT_DECIMALS = 1e8 @@ -161,7 +159,7 @@ const ADDRESS_VERSION = 58 const PROXY_URL = "/proxy/" // Chat reference timestamp -const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 9999999999999 +const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 1674316800000 // Used as a salt for all qora addresses. Salts used for storing your private keys in local storage will be randomly generated const STATIC_SALT = new Uint8Array([54, 190, 201, 206, 65, 29, 123, 129, 147, 231, 180, 166, 171, 45, 95, 165, 78, 200, 208, 194, 44, 207, 221, 146, 45, 238, 68, 68, 69, 102, 62, 6]) From 8bf0e9c68d40e0480d924cd762ebe7bd46c01dff Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 13 Jan 2023 20:17:28 -0500 Subject: [PATCH 05/76] fix forwarding --- qortal-ui-core/language/us.json | 4 +- qortal-ui-crypto/api/constants.js | 2 +- .../plugins/core/components/ChatPage.js | 118 ++++++++++++++---- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 6818dafc..d2e9d87b 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -548,7 +548,9 @@ "cchange39": "Cannot send an encrypted message to this user since they do not have their publickey on chain.", "cchange40": "IMAGE (click to view)", "cchange41":"Your Balance Is Under 4.20 QORT", - "cchange42":"Out of the need to combat spam, accounts with under 4.20 Qort balance will take a long time to SEND messages in Q-Chat. If you wish to immediately increase the send speed for Q-Chat messages, obtain over 4.20 QORT to your address. This can be done with trades in the Trade Portal, or by way of another Qortian giving you the QORT. Once you have over 4.20 QORT in your account, Q-Chat messages will be instant and this dialog will no more show. Thank you for your understanding of this necessary spam prevention method, and we hope you enjoy Qortal!" + "cchange42":"Out of the need to combat spam, accounts with under 4.20 Qort balance will take a long time to SEND messages in Q-Chat. If you wish to immediately increase the send speed for Q-Chat messages, obtain over 4.20 QORT to your address. This can be done with trades in the Trade Portal, or by way of another Qortian giving you the QORT. Once you have over 4.20 QORT in your account, Q-Chat messages will be instant and this dialog will no more show. Thank you for your understanding of this necessary spam prevention method, and we hope you enjoy Qortal!", + "cchange62": "Wrong Username and Address Inputted! Please try again!", + "cchange63": "Please enter a recipient" }, "welcomepage": { diff --git a/qortal-ui-crypto/api/constants.js b/qortal-ui-crypto/api/constants.js index 11c0cbbf..ae139416 100644 --- a/qortal-ui-crypto/api/constants.js +++ b/qortal-ui-crypto/api/constants.js @@ -159,7 +159,7 @@ const ADDRESS_VERSION = 58 const PROXY_URL = "/proxy/" // Chat reference timestamp -const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 1674316800000 +const CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP = 0 // Used as a salt for all qora addresses. Salts used for storing your private keys in local storage will be randomly generated const STATIC_SALT = new Uint8Array([54, 190, 201, 206, 65, 29, 123, 129, 147, 231, 180, 166, 171, 45, 95, 165, 78, 200, 208, 194, 44, 207, 221, 146, 45, 238, 68, 68, 69, 102, 62, 6]) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 7f7d12e8..f20ca847 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -900,8 +900,10 @@ class ChatPage extends LitElement { id="sendTo" placeholder="${translate("chatpage.cchange7")}" @keydown=${() => { - this.forwardActiveChatHeadUrl = {}; - this.requestUpdate(); + if (this.forwardActiveChatHeadUrl.selected) { + this.forwardActiveChatHeadUrl = {}; + this.requestUpdate(); + } } } /> @@ -977,7 +979,6 @@ class ChatPage extends LitElement { ${translate("chatpage.cchange33")} +
+ ${this.iframeId === "_chatEditorDOM" ? html` +
+ + + { + console.log(e.target.checked) + if(e.target.checked){ + window.parent.reduxStore.dispatch( window.parent.reduxAction.removeAutoLoadImageChat(this.chatId)) + return + } + window.parent.reduxStore.dispatch( window.parent.reduxAction.addAutoLoadImageChat(this.chatId)) + + }} ?checked=${(window.parent.reduxStore.getState().app?.autoLoadImageChats || []).includes(this.chatId)}> +
+ ` : ''}
Date: Tue, 24 Jan 2023 19:49:34 +0100 Subject: [PATCH 40/76] translate --- qortal-ui-core/language/de.json | 3 +- qortal-ui-core/language/es.json | 3 +- qortal-ui-core/language/fr.json | 3 +- qortal-ui-core/language/hindi.json | 3 +- qortal-ui-core/language/hr.json | 3 +- qortal-ui-core/language/hu.json | 3 +- qortal-ui-core/language/it.json | 3 +- qortal-ui-core/language/ko.json | 3 +- qortal-ui-core/language/no.json | 3 +- qortal-ui-core/language/pl.json | 3 +- qortal-ui-core/language/pt.json | 3 +- qortal-ui-core/language/ro.json | 3 +- qortal-ui-core/language/rs.json | 3 +- qortal-ui-core/language/ru.json | 3 +- qortal-ui-core/language/zhc.json | 359 ++++++++++++++--------------- qortal-ui-core/language/zht.json | 21 +- 16 files changed, 211 insertions(+), 211 deletions(-) diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index 88445ac4..00f413af 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -573,7 +573,8 @@ "cchange64": "Eingabe deaktiviert", "cchange65": "Bitte geben Sie einen Empfänger ein", "cchange66": "Beantwortete Nachricht kann nicht abgerufen werden. Nachricht ist zu alt.", - "cchange68": "bearbeitet" + "cchange68": "bearbeitet", + "cchange69": "Zeige Bilder automatisch" }, "welcomepage": { "wcchange1": "Willkommen zu Q-Chat", diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index 220e8c7d..1c378f28 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -573,7 +573,8 @@ "cchange64": "Entrar Deshabilitado", "cchange65": "Ingrese un destinatario", "cchange66": "No se puede recuperar el mensaje respondido. El mensaje es demasiado antiguo.", - "cchange68": "editado" + "cchange68": "editado", + "cchange69": "Mostrar imágenes automáticamente" }, "welcomepage": { "wcchange1": "Bienvenido al Q-Chat", diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index 691b5644..3aef9139 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -573,7 +573,8 @@ "cchange64": "Entrée désactivée", "cchange65": "Veuillez saisir un destinataire", "cchange66": "Impossible de récupérer le message auquel vous avez répondu. Le message est trop ancien.", - "cchange68": "modifié" + "cchange68": "modifié", + "cchange69": "Afficher automatiquement les images" }, "welcomepage": { "wcchange1": "Bienvenue dans Q-Chat", diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index ed14cac9..1601ffdf 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -574,7 +574,8 @@ "cchange64": "अक्षम दर्ज करें", "cchange65": "कृपया एक प्राप्तकर्ता दर्ज करें", "cchange66": "इसका उत्तर दिया गया संदेश प्राप्त नहीं किया जा सकता। संदेश बहुत पुराना है।", - "cchange68": "संपादित" + "cchange68": "संपादित", + "cchange69": "ऑटो-शो छवियां" }, "welcomepage": { "wcchange1": "क्यू-चैट में आपका स्वागत है", diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index ec725520..0a18cf7c 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -573,7 +573,8 @@ "cchange64": "Unos onemogućen", "cchange65": "Molimo unesite primatelja", "cchange66": "Ne mogu dohvatiti poruku s odgovorom. Poruka je prestara.", - "cchange68": "uređeno" + "cchange68": "uređeno", + "cchange69": "Automatsko prikazivanje slika" }, "welcomepage": { "wcchange1": "Dobrodošli u Q-Čavrljanje", diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index 91ec8808..e0480559 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -573,7 +573,8 @@ "cchange64": "Enter Disabled", "cchange65": "Kérjük, adjon meg egy címzettet", "cchange66": "Nem sikerült lekérni a válaszolt üzenetet. Az üzenet túl régi.", - "cchange68": "szerkesztve" + "cchange68": "szerkesztve", + "cchange69": "Képek automatikus megjelenítése" }, "welcomepage": { "wcchange1": "Üdvözöljük a Q-Chathoz", diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index b9b68938..0f3c6058 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -573,7 +573,8 @@ "cchange64": "Inserisci disabilitato", "cchange65": "Inserisci un destinatario", "cchange66": "Impossibile recuperare il messaggio di risposta. Il messaggio è troppo vecchio.", - "cchange68": "modificato" + "cchange68": "modificato", + "cchange69": "Mostra automaticamente le immagini" }, "welcomepage": { "wcchange1": "Benvenuto in Q-Chat", diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index a7c4344c..baf03675 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -573,7 +573,8 @@ "cchange64": "비활성화 입력", "cchange65": "받는 사람을 입력하세요", "cchange66": "답장한 메시지를 가져올 수 없습니다. 메시지가 너무 오래되었습니다.", - "cchange68": "편집됨" + "cchange68": "편집됨", + "cchange69": "이미지 자동 표시" }, "welcomepage": { "wcchange1": "Q-Chat에 오신 것을 환영합니다.", diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index 1be47cfe..d6833c6e 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -573,7 +573,8 @@ "cchange64": "Enter deaktivert", "cchange65": "Vennligst skriv inn en mottaker", "cchange66": "Kan ikke hente besvart melding. Meldingen er for gammel.", - "cchange68": "redigert" + "cchange68": "redigert", + "cchange69": "Vis bilder automatisk" }, "welcomepage": { "wcchange1": "Velkommen til Q-Chat", diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index 08ad528e..32935439 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -573,7 +573,8 @@ "cchange64": "Wprowadź wyłączone", "cchange65": "Wprowadź odbiorcę", "cchange66": "Nie można pobrać wiadomości, na którą udzielono odpowiedzi. Wiadomość jest za stara.", - "cchange68": "edytowano" + "cchange68": "edytowano", + "cchange69": "Automatyczne wyświetlanie obrazów" }, "welcomepage": { "wcchange1": "Witamy w Q-Chat", diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index 03c03388..42cda962 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -573,7 +573,8 @@ "cchange64": "Enter desativado", "cchange65": "Insira um destinatário", "cchange66": "Não foi possível buscar a mensagem respondida. A mensagem é muito antiga.", - "cchange68": "editado" + "cchange68": "editado", + "cchange69": "Mostrar imagens automaticamente" }, "welcomepage": { "wcchange1": "Bem-vindo ao Q-Chat", diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index d74aa972..3037c208 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -573,7 +573,8 @@ "cchange64": "Introducere dezactivată", "cchange65": "Vă rugăm să introduceți un destinatar", "cchange66": "Nu se poate prelua mesajul la care sa răspuns. Mesajul este prea vechi.", - "cchange68": "editat" + "cchange68": "editat", + "cchange69": "Afișează automat imaginile" }, "welcomepage": { "wcchange1": "Bine ai venit la Q-Chat", diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index ac56b30c..791753b6 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -573,7 +573,8 @@ "cchange64": "Unesite onemogućeno", "cchange65": "Unesite primaoca", "cchange66": "Ne mogu preuzeti odgovor na poruku. Poruka je prestara.", - "cchange68": "uređeno" + "cchange68": "uređeno", + "cchange69": "Automatski prikaži slike" }, "welcomepage": { "wcchange1": "Dobrodošli na Q-Chat", diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index ccfd8850..cd7e54f4 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -573,7 +573,8 @@ "cchange64": "Введите отключено", "cchange65": "Пожалуйста, введите получателя", "cchange66": "Невозможно получить ответное сообщение. Сообщение слишком старое.", - "cchange68": "отредактировано" + "cchange68": "отредактировано", + "cchange69": "Автоматическое отображение изображений" }, "welcomepage": { "wcchange1": "Добро пожаловать в Q-Chat", diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index 84c88cce..63b9b1f8 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -36,7 +36,7 @@ "puzzles": "益智游戏", "nodemanagement": "节点管理", "trading": "贸易", - "groups": "群组" + "groups": "团体" }, "login": { "login": "登入", @@ -52,25 +52,25 @@ "seed": "助记词", "seedphrase": "助记词", "saved": "已保存的钱包", - "qora": "Qora钱包助记词", - "backup": "Qortal钱包备份文件", + "qora": "Qora 钱包助记词", + "backup": "Qortal 钱包备份文件", "decrypt": "正在解密钱包备份文件", "save": "保存钱包,以便下次登入.", "prepare": "正在加载你的钱包", "areyousure": "你确定将此钱包在已保存钱包列表中删除吗?", "error1": "备份文件必须为有效的JSON格式文件", "error2": "请选择登入方式", - "createwelcome": "欢迎来到Qortal ,您会发现它类似于RPG游戏,作为Qortal网络上的铸币者(如果您选择成为其中的铸币者),您将有机会升级您的帐户,并随着等级提高而获得更多QORT区块奖励以及参与平台上各种决策投票。 ", + "createwelcome": "欢迎来到 Qortal,您会发现它类似于 RPG 游戏,作为 Qortal 网络上的铸币者(如果您选择成为其中的铸币者),您将有机会升级您的帐户,并随着等级提高而获得更多 QORT 区块奖励以及参与平台上各种决策投票。", "createa": "你的", "click": "点击查看助记词", "confirmpass": "确认密码", - "willbe": "将在后台随机生成。 这将用作您在Qortal中的区块链帐户的私人密钥。 ", - "clicknext": " ▼▼▼点击下一步创建你的Qortal账号▼▼▼ ", - "ready": "您的帐户即将创建成功, 它将保存在此浏览器中。 如果您不希望将新帐户保存在浏览器中,可以取消勾选下面的选项。 您仍可透过使用创建帐户时载的钱包备份文件进行的登入。 ", - "welmessage": "欢迎来到Qortal", - "pleaseenter": "请密码!", + "willbe": "将在后台随机生成。 这将用作您在 Qortal 中的区块链帐户的私人密钥。", + "clicknext": "▼▼▼点击下一步创建你的Qortal账号▼▼▼", + "ready": "您的帐户即将创建成功, 它将保存在此浏览器中。 如果您不希望将新帐户保存在浏览器中,可以取消勾选下面的选项。 您仍可透过使用创建帐户时载的钱包备份文件进行的登入。", + "welmessage": "欢迎来到 Qortal", + "pleaseenter": "请输入密码!", "notmatch": "密码不一致!", - "lessthen8": "你的密码长度少于8位!我们不建议使用,但你仍可继续使用此密码。 ", + "lessthen8": "你的密码长度少于8位! 我们不建议使用,但你仍可继续使用此密码。", "lessthen8-2": "你的密码长度少于8位!", "entername": "请输入一个代称", "downloaded": "你的钱包备份文件已顺利下载!", @@ -81,9 +81,9 @@ "backup2": "请小心保存钱包备份文件,并谨记之前设置好的密码。否则你将会失去这个钱包的所有控制权,请务必将备份文件放在不同的存储装置上", "savewallet": "下载并保存钱包备份文件", "created1": "你的账号已创建成功", - "created2": "并会储存在UI上.", + "created2": " 并会保存在UI上.", "downloadbackup": "下载钱包备份文件", - "passwordhint": "密码必须至少为8个字符。 " + "passwordhint": "密码必须至少为 8 个字符。" }, "logout": { "logout": "登出", @@ -101,16 +101,16 @@ "account": "钱包", "security": "安全性", "qr_login_menu_item": "二维码登录", - "qr_login_description_1": "扫描此代码以使用您登录时使用的相同密码在其他设备上解锁您的钱包。 ", - "qr_login_description_2": "选择一个密码,您将在扫描二维码后用于在其他设备上解锁您的钱包。 ", + "qr_login_description_1": "扫描此代码以使用您登录时使用的相同密码在其他设备上解锁您的钱包。", + "qr_login_description_2": "选择一个密码,您将在扫描二维码后用于在其他设备上解锁您的钱包。", "qr_login_button_1": "显示登录二维码", "qr_login_button_2": "生成登录二维码", "notifications": "通知", "accountsecurity": "钱包安全性", "password": "密码", "download": "下载备份文件", - "choose": "请输入一组密码加密你的备份文件。 (可使用你刚才登入时的相同密码或者不同的密码)", - "block": "区块通知(即将推出... ) ", + "choose": "请输入一组密码加密你的备份文件。(可使用你刚才登入时的相同密码或者不同的密码)", + "block": "区块通知(即将推出...)", "playsound": "开启音效", "shownotifications": "显示通知", "nodeurl": "节点地址", @@ -123,16 +123,16 @@ "import": "导入节点", "export": "导出节点", "deletecustomnode": "删除所有自定义节点", - "warning": "您现有的节点将被删除并从备份中创建新的。 ", + "warning": "您现有的节点将被删除并从备份中创建新的。", "snack1": "成功删除和添加标准节点", - "snack2": "连接到节点的UI", + "snack2": "连接到节点的 UI", "snack3": "成功添加并保存自定义节点", "snack4": "节点成功保存为", "snack5": "节点成功导入", "exp1": "导出主密钥", "exp2": "导出主密钥", "exp3": "导出", - "exp4": "请选择一个钱包来备份私钥。 " + "exp4": "请选择一个钱包来备份私钥。" }, "appinfo": { "blockheight": "区块高度", @@ -155,10 +155,10 @@ "close": "关闭", "back": "上一步", "next": "下一步", - "create": "创建", + "create": "新建", "continue": "继续", "save": "保存", - "balance": "余额", + "balance": "信用", "balances": "您的钱包余额", "update": "更新钱包余额" }, @@ -172,7 +172,7 @@ "smchange7": "结束关系", "smchange8": "向节点添加铸币密钥", "smchange9": "完全的", - "smchange10": "每个节点只允许2个铸币密钥,您正在尝试分配3个密钥,请进入管理-节点管理,并删除您不想分配给该节点的密钥,谢谢! " + "smchange10": "每个节点只允许 2 个铸币密钥,您正在尝试分配 3 个密钥,请进入管理 - 节点管理,并删除您不想分配给该节点的密钥,谢谢!" }, "mintingpage": { "mchange1": "一般铸币信息", @@ -188,7 +188,7 @@ "mchange11": "未激活", "mchange12": "激活你的账号", "mchange13": "激活方法", - "mchange14": "激活账号的方法是进行一笔简单的对外交易。注册名称是最常见的方法。 您可以在Q-Chat中的请求某人向您发送少量QORT ,以便您可以激活您的帐号,或在交易门户中购买QORT ,然后进行任何类型的交易。这样你的公共密钥才会被记录在区块链上,否则你的公钥只有你自己知道,其他人无法从区块链中找到你的公钥。 ", + "mchange14": "激活账号的方法是进行一笔简单的对外交易。注册名称是最常见的方法。 您可以在 Q-Chat 中的请求某人向您发送少量 QORT,以便您可以激活您的帐号,或在交易门户中购买 QORT,然后进行任何类型的交易。这样你的公共密钥才会被记录在区块链上,否则你的公钥只有你自己知道,其他人无法从区块链中找到你的公钥。", "mchange15": "当前状态", "mchange16": "当前等级", "mchange17": "到达下一级所需铸币区块数", @@ -208,10 +208,10 @@ "mchange31": "点击寻求帮助", "mchange32": "成为一个铸币者", "mchange33": "简介", - "mchange34": "在Qortal ,要成为铸币者并随着铸币者等级的提高而开始获得QORT奖励,您必须获得赞助码。 只有创始人、 5级或以上的账号才能提供赞助码。当你获得赞助码并使用该密钥达到1级。一旦您达到1级,您将能够创建自己的铸币密钥并开始获得奖励,以帮助保护Qortal区块链。 ", + "mchange34": "在 Qortal,要成为铸币者并随着铸币者等级的提高而开始获得 QORT 奖励,您必须获得赞助码。 只有创始人、5 级或以上的账号才能提供赞助码。当你获得赞助码并使用该密钥达到 1 级。一旦您达到 1 级,您将能够创建自己的铸币密钥并开始获得奖励,以帮助保护 Qortal 区块链。", "mchange35": "赞助", - "mchange36": "赞助商会给你一个“赞助码”,你必须添加到节点管理中并正式开始铸币(在达到1级之前没有任何奖励。)一旦您达到1级,您就可以创建自己的“铸币密钥”和 开始赚取奖励。 ", - "mchange37": "因此你只需寻找赞助商并获得赞助码,然后返回此处输入赞助码即可开始您的铸币之旅! ", + "mchange36": "赞助商会给你一个“赞助码”,你必须添加到节点管理中并正式开始铸币(在达到 1 级之前没有任何奖励。)一旦您达到 1 级,您就可以创建自己的“铸币密钥”和 开始赚取奖励。", + "mchange37": "因此你只需寻找赞助商并获得赞助码,然后返回此处输入赞助码即可开始您的铸币之旅!", "mchange38": "在" }, "becomeMinterPage": { @@ -224,7 +224,7 @@ "bchange16": "赞助商账户", "bchange17": "复制赞助密钥", "bchange18": "开始铸币", - "bchange19": "成功!您目前正在铸币。 " + "bchange19": "成功!您目前正在铸币。" }, "walletpage": { "wchange1": "正在加载钱包余额...", @@ -246,25 +246,25 @@ "wchange17": "传送", "wchange18": "由钱包", "wchange19": "可用余额", - "wchange20": "收款人(钱包地址或名称)", + "wchange20": "收款人 (钱包地址或名称)", "wchange21": "当前固定手续费:", "wchange22": "钱包", - "wchange23": "收款人(钱包地址)", + "wchange23": "收款人 (钱包地址)", "wchange24": "当前手续费", - "wchange25": "手续费设置越低,交易也相对更久甚至失败。 ", - "wchange26": "当前余额不足(请预留一部分的币作为手续费) !", + "wchange25": "手续费设置越低,交易也相对更久甚至失败。", + "wchange26": "当前余额不足(请预留一部分的币作为手续费)!", "wchange27": "无效的数量!", "wchange28": "接收者不能为空!", "wchange29": "无效的接收者!", "wchange30": "交易成功!", "wchange31": "交易失败!", - "wchange32": "无法加载QORT余额.请再次尝试!", + "wchange32": "无法加载QORT余额. 请再次尝试!", "wchange33": "无法加载", - "wchange34": "余额.请再次尝试!", + "wchange34": "余额. 请再次尝试!", "wchange35": "交易类型", "wchange36": "手续费", "wchange37": "总量", - "wchange38": "当前钱包暂时没有任何交易记录。 ", + "wchange38": "当前钱包暂时没有任何交易记录。", "wchange39": "无法复制钱包地址.", "wchange40": "交易", "wchange41": "状态", @@ -274,15 +274,15 @@ "wchange45": "全部发送", "wchange46": "发送到这个地址", "wchange47": "地址簿", - "wchange48": "此通讯录为空!", + "wchange48": "此通讯录为空 !", "wchange49": "加至地址簿", - "wchange50": "名称不能为空! ", - "wchange51": "地址不能为空! ", - "wchange52": "添加成功! ", + "wchange50": "名称不能为空!", + "wchange51": "地址不能为空!", + "wchange52": "添加成功!", "wchange53": "导入通讯录", "wchange54": "导出通讯录", - "wchange55": "您现有的通讯簿将被删除并从新创建的备份中。 ", - "wchange56": "警告! ", + "wchange55": "您现有的通讯簿将被删除并从新创建的备份中。", + "wchange56": "警告!", "wchange57": "备忘录" }, "tradepage": { @@ -322,14 +322,14 @@ "tchange34": "金额不能为0", "tchange35": "价格不能为0", "tchange36": "待定汽车购买", - "tchange37": "未找到自动购买订单! ", + "tchange37": "未找到自动购买订单!", "tchange38": "添加", "tchange39": "自动购买订单", "tchange40": "价格", - "tchange41": "成功删除自动购买订单! ", + "tchange41": "成功删除自动购买订单!", "tchange42": "开市卖单", "tchange43": "我的购买历史", - "tchange44": "成功添加自动买单! ", + "tchange44": "成功添加自动买单!", "tchange45": "自动购买", "tchange46": "自动购买", "tchange47": "以这个价格出售", @@ -351,7 +351,7 @@ "rchange12": "正在添加中...", "rchange13": "正在添加铸币密钥/赞助码", "rchange14": "添加", - "rchange15": "此账号并没有任何铸币密钥", + "rchange15": "此账号并没有任何奖励分享", "rchange16": "个人铸币密钥", "rchange17": "移除", "rchange18": "不能创建多个铸币密钥!", @@ -370,7 +370,7 @@ "nchange7": "操作", "nchange8": "此账号并没有注册任何名称!", "nchange9": "注册一个名称!", - "nchange10": "描述(选填)", + "nchange10": "描述 (选填)", "nchange11": "正在创建中", "nchange12": "正在创建中", "nchange13": "目前注册名称的手续费是", @@ -386,21 +386,21 @@ "nchange23": "卖出价", "nchange24": "没有名字可以卖", "nchange25": "出售名称", - "nchange26": "你确定要卖这个名字吗? ", - "nchange27": "对于QORT中的这个价格", - "nchange28": "按下确认后,将发送销售名称请求! ", + "nchange26": "你确定要卖这个名字吗?", + "nchange27": "对于 QORT 中的这个价格", + "nchange28": "按下确认后,将发送销售名称请求!", "nchange29": "要取消的名称", - "nchange30": "你确定要取消这个名字的出售吗? ", - "nchange31": "按下确认后,将发送取消销售名称请求! ", - "nchange32": "销售名称请求成功! ", - "nchange33": "取消销售名称请求成功! ", - "nchange34": "购买名称请求成功! ", - "nchange35": "你有名字! ", - "nchange36": "只有没有注册名字的账户才能买名字。 ", - "nchange37": "注意! ", - "nchange38": "你没有足够的qort来购买这个名字。 ", - "nchange39": "你确定要买这个名字吗? ", - "nchange40": "按下确认后,将发送购买名称请求! " + "nchange30": "你确定要取消这个名字的出售吗?", + "nchange31": "按下确认后,将发送取消销售名称请求!", + "nchange32": "销售名称请求成功!", + "nchange33": "取消销售名称请求成功!", + "nchange34": "购买名称请求成功!", + "nchange35": "你有名字!", + "nchange36": "只有没有注册名字的账户才能买名字。", + "nchange37": "注意!", + "nchange38": "你没有足够的 qort 来购买这个名字。", + "nchange39": "你确定要买这个名字吗?", + "nchange40": "按下确认后,将发送购买名称请求!" }, "websitespage": { "schange1": "浏览网站", @@ -458,10 +458,10 @@ "pchange16": "请选择要托管的ZIP文件", "pchange17": "请输入包含静态内容的目录路径", "pchange18": "请输入一个服务名称", - "pchange19": "正在处理中...请稍等...", + "pchange19": "正在处理中... 请稍等...", "pchange20": "错误代码:", "pchange21": "发布网站时出现内部服务器错误", - "pchange22": "计算工作量证明中...请稍等...", + "pchange22": "计算工作量证明中... 请稍等...", "pchange23": "发布成功!", "pchange24": "发布失败!", "pchange25": "选择文件" @@ -481,8 +481,8 @@ "bchange12": "尝试取消关注此注册名称时发生错误。 请再试一次!", "bchange13": "尝试封锁此注册名称时发生错误。 请再试一次!", "bchange14": "尝试解封此注册名称时发生错误。 请再试一次!", - "bchange15": "未能删除本地有关此注册名称的资料。请先取消关注此注册名称。 ", - "bchange16": "尝试删除此注册名称时出错。 请再试一次! " + "bchange15": "未能删除本地有关此注册名称的资料。请先取消关注此注册名称。", + "bchange16": "尝试删除此注册名称时出错。 请再试一次!" }, "datapage": { "dchange1": "资料管理", @@ -508,106 +508,99 @@ "dchange21": "尝试删除此资源时出错。 请再试一次" }, "chatpage": { - "cchange1": "建立新的私人对话", + "cchange1": "新的私人对话", "cchange2": "加载中...", "cchange3": "已封锁的用户名单", "cchange4": "新的信息", "cchange5": "(点击向下滚动)", "cchange6": "输入对方的名称或钱包地址并建立私人对话!", - "cchange7": "名称/钱包地址", + "cchange7": "名称 / 钱包地址", "cchange8": "信息内容...", "cchange9": "传送", "cchange10": "已封锁的用户名单", "cchange11": "名称", "cchange12": "拥有者", "cchange13": "操作", - "cchange14": "此账号没有封锁任何用户。 ", + "cchange14": "此账号没有封锁任何用户。", "cchange15": "没有注册名称", - "cchange16": "成功解封此用户。 ", + "cchange16": "成功解封此用户。", "cchange17": "尝试解封此用户时发生错误。 请再试一次!", "cchange18": "解封", - "cchange19": "无效的名称/钱包地址,检查名称/钱包地址后再次尝试...", + "cchange19": "无效的名称 / 钱包地址, 检查名称 / 钱包地址后再次尝试...", "cchange20": "成功发送信息!", - "cchange21": "发送失败,请再此尝试...", + "cchange21": "发送失败, 请再此尝试...", "cchange22": "正在加载信息内容...", "cchange23": "未能解密信息内容!", - "cchange24": "每个信息的最大字符数为255", + "cchange24": "每个信息的最大字符数为 255", "cchange25": "编辑消息", - "cchange26": "文件大小超过0.5 MB", + "cchange26": "文件大小超过 0.5 MB", "cchange27": "发送图片需要注册名称", "cchange28": "这个文件不是图片", - "cchange29": "最大消息大小为1000字节", - "cchange30": "正在上传图片。这可能需要一分钟。 ", - "cchange31": "正在删除图像。这可能需要一分钟。 ", + "cchange29": "最大消息大小为 1000 字节", + "cchange30": "正在上传图片。这可能需要一分钟。", + "cchange31": "正在删除图像。这可能需要一分钟。", "cchange33": "取消", - "cchange34": "此聊天消息使用的是旧消息版本,无法使用此功能。 ", - "cchange35": "获取用户名时出错,请重试! ", + "cchange34": "此聊天消息使用的是旧消息版本,无法使用此功能。", + "cchange35": "获取用户名时出错,请重试!", "cchange36": "搜索结果", "cchange37": "未找到结果", "cchange38": "用户已验证", - "cchange39": "无法向该用户发送加密消息,因为他们的公钥不在链上。 ", - "cchange40": "图像(点击查看) ", - "cchange41": "您的余额低于4.20 QORT", - "cchange42": "出于打击垃圾邮件的需要, Qort余额低于4.20的账户在Q-Chat中发送消息需要很长时间。如果你想立即提高Q-Chat消息的发送速度,请获取4.20以上QORT到您的地址。这可以通过贸易门户中的交易来完成,或者通过另一个Qortian给您QORT 。一旦您的帐户中有超过4.20 QORT , Q-Chat消息将是即时的并且此对话框将不再显示。感谢您了解这种必要的垃圾邮件预防方法,我们希望您喜欢Qortal ! ", + "cchange39": "无法向该用户发送加密消息,因为他们的公钥不在链上。", + "cchange40": "图像(点击查看)", + "cchange41": "您的余额低于 4.20 QORT", + "cchange42": "出于打击垃圾邮件的需要,Qort余额低于4.20的账户在Q-Chat中发送消息需要很长时间。如果你想立即提高Q-Chat消息的发送速度,请获取4.20以上 QORT 到您的地址。这可以通过贸易门户中的交易来完成,或者通过另一个 Qortian 给您 QORT。一旦您的帐户中有超过 4.20 QORT,Q-Chat 消息将是即时的并且此对话框将不再存在 显示。感谢您了解这种必要的垃圾邮件预防方法,我们希望您喜欢 Qortal!", "cchange43": "打赏QORT给", "cchange44": "发送消息", "cchange45": "提示用户", - "cchange46": "打赏金额", + "cchange46": "小费金额", "cchange47": "可用余额", - "cchange48": "无法获取QORT余额。请重试! ", - "cchange49": "当前手续费", + "cchange48": "无法获取 QORT 余额。请重试!", + "cchange49": "当前静态费用", "cchange50": "发送", - "cchange51": "余额不足! ", - "cchange52": "无效金额! ", - "cchange53": "接收方不能为空! ", - "cchange54": "接收者无效! ", - "cchange55": "交易成功! ", - "cchange56": "交易失败! ", + "cchange51": "资金不足!", + "cchange52": "无效金额!", + "cchange53": "接收方不能为空!", + "cchange54": "接收者无效!", + "cchange55": "交易成功!", + "cchange56": "交易失败!", "cchange57": "用户信息", "cchange58": "发送消息", "cchange59": "提示用户", "cchange60": "群组邀请待定", - "cchange61": "获取群组邀请时出错。请重试! ", - "cchange62": "用户名和地址输入错误!请重试! ", - "cchange63": "启用Enter键直接发送信息", - "cchange64": "禁用Enter键直接发送信息", + "cchange61": "获取群组邀请时出错。请重试!", + "cchange62": "用户名和地址输入错误!请重试!", + "cchange63": "输入启用", + "cchange64": "输入禁用", "cchange65": "请输入收件人", - "cchange66": "无法获取回复消息。消息太旧了。 ", - "cchange68": "编辑" + "cchange66": "无法获取回复消息。消息太旧了。", + "cchange68": "编辑", + "cchange69": "自动显示图像" }, "welcomepage": { - "wcchange1": "欢迎来到Q-Chat", - "wcchange2": "建立新的私人对话", + "wcchange1": "欢迎来到 Q-Chat", + "wcchange2": "新的私人对话", "wcchange3": "输入对方的名称或钱包地址并建立私人对话!", - "wcchange4": "名称/钱包地址", - "wcchange5": "输入内容...", + "wcchange4": "名称 / 钱包地址", + "wcchange5": "信息内容...", "wcchange6": "传送", - "wcchange7": "无效的名称/钱包地址,检查名称/钱包地址后再次尝试...", + "wcchange7": "无效的名称 / 钱包地址, 检查名称 / 钱包地址后再次尝试...", "wcchange8": "成功发送信息!", - "wcchange9": "发送失败,请再此尝试..." + "wcchange9": "发送失败, 请再此尝试..." }, "blockpage": { "bcchange1": "封锁用户", "bcchange2": "成功封锁此用户!", - "bcchange3": "尝试封锁此用户时出错。 请再试一次! ", + "bcchange3": "尝试封锁此用户时出错。 请再试一次!", "bcchange4": "没有注册名称", "bcchange5": "封锁用户请求", - "bcchange6": "你确定要封锁这个用户吗? ", + "bcchange6": "你确定要封锁这个用户吗?", "bcchange7": "菜单", "bcchange8": "复制地址", "bcchange9": "私人信息", - "bcchange10": "更多", - "bcchange11": "回覆", - "bcchange12": "修改", - "bcchange13": "表情反应", - "bcchange14": "转发", - "bcchange15": "信息已转发", - "bcchange16": "选择收件人或在下方搜寻收件人", - "bcchange17": "已转发", - "bcchange18": "打赏" + "bcchange10": "更多的" }, "grouppage": { - "gchange1": "Qortal群组", + "gchange1": "Qortal 群组", "gchange2": "创建群组", "gchange3": "你已加入的群组", "gchange4": "群组名称", @@ -617,7 +610,7 @@ "gchange8": "你不是任何群组的成员!", "gchange9": "公开群组", "gchange10": "拥有者", - "gchange11": "没有可加入的公开群组! ", + "gchange11": "没有可加入的公开群组!", "gchange12": "创建新的群组", "gchange13": "群组分类", "gchange14": "必填", @@ -627,13 +620,13 @@ "gchange18": "设定多少个管理员批准或整体百分比才能通过审批:", "gchange19": "无", "gchange20": "一", - "gchange21": "群组交易最小的延迟值(以区块数目计算) :", + "gchange21": "群组交易最小的延迟值(以区块数目计算):", "gchange22": "分钟", "gchange23": "小时", "gchange24": "小时", "gchange25": "天", "gchange26": "天", - "gchange27": "群组交易最大的延迟值(以区块数目计算) :", + "gchange27": "群组交易最大的延迟值(以区块数目计算):", "gchange28": "正在创建群组", "gchange29": "创建群组", "gchange30": "加入群组请求", @@ -652,8 +645,8 @@ "gchange43": "无效的群组描述", "gchange44": "选择一个群组分类", "gchange45": "选择群组审批门槛", - "gchange46": "选择群组审批最小的延迟值(以区块数目计算) ", - "gchange47": "选择群组审批最小的延迟值(以区块数目计算) ", + "gchange46": "选择群组审批最小的延迟值(以区块数目计算)", + "gchange47": "选择群组审批最小的延迟值(以区块数目计算)", "gchange48": "加入群组请求已成功发送!", "gchange49": "离开群组请求已成功发送!", "gchange50": "离开", @@ -662,9 +655,9 @@ "gchange53": "成员", "gchange54": "成员数量", "gchange55": "搜索私人群组", - "gchange56": "要搜索的群组名", - "gchange57": "未找到私人群组名", - "gchange58": "注意群组名必须完全匹配。 " + "gchange56": "要搜索的组名", + "gchange57": "未找到私人组名", + "gchange58": "注意组名必须完全匹配。" }, "puzzlepage": { "pchange1": "益智游戏", @@ -672,13 +665,13 @@ "pchange3": "得奖者", "pchange4": "名称", "pchange5": "描述", - "pchange6": "提示/答案", + "pchange6": "提示 / 答案", "pchange7": "操作", "pchange8": "猜一下", "pchange9": "输入你的答案", "pchange10": "你的答案必须由43或44个英文字母或数字组成", "pchange11": "不", - "pchange12": "包括数字(0) ,大写字母(I) ,大写字母(O )和小写字母(l).", + "pchange12": "包括数字(0),大写字母(I),大写字母(O)和小写字母(l).", "pchange13": "你的答案", "pchange14": "正在检查你的答案...", "pchange15": "提交", @@ -690,7 +683,7 @@ "nchange2": "节点在线时间:", "nchange3": "此节点的铸币账号", "nchange4": "添加铸币账号", - "nchange5": "如果想使用自己的帐号进行铸币,你必须在铸币密钥页面中建立个人铸币密钥(将奖励分享百分比设置为0 ),然后将个人铸币密钥添加到此处。 .", + "nchange5": "如果想使用自己的帐号进行铸币,你必须在铸币密钥页面中建立个人铸币密钥(将奖励分享百分比设置为 0),然后将个人铸币密钥添加到此处。.", "nchange6": "铸币密钥", "nchange7": "正在添加铸币密钥/赞助码", "nchange8": "添加", @@ -729,18 +722,18 @@ "apipage": { "achange1": "添加API密钥", "achange2": "API密钥", - "achange3": "请输入属于此节点的API密钥(你可以在Qortal安装路径上的“ apikey.txt “文件中找到相关的API密钥)。你可以直接点击“取消“,但某些功能将不能正常使用。 ", + "achange3": "请输入属于此节点的API密钥(你可以在Qortal安装路径上的“apikey.txt“文件中找到相关的API密钥)。你可以直接点击“取消“,但某些功能将不能正常使用。", "achange4": "取消", "achange5": "添加", - "achange6": "成功添加此节点的API密钥。 ", - "achange7": "添加API密钥失败。 " + "achange6": "成功添加此节点的API密钥。", + "achange7": "添加API密钥失败。" }, "transactions": { "amount": "数量", "to": "收款人", - "declined": "交易被用户拒绝!", - "namedialog1": "你正在注册以下名称:", - "namedialog2": "点击确认后,名称将被注册!", + "declined": "交易已被用戶拒绝!", + "namedialog1": "你正在註冊以下名稱:", + "namedialog2": "點擊確認後, 名稱將被註冊!", "groupdialog1": "你正在请求加入下列群组:", "groupdialog2": "点击确认后,加入请求将会被送出!", "groupdialog3": "你正在请求离开下列群组:", @@ -751,14 +744,14 @@ "rewarddialog2": "给", "rewarddialog3": "如果是的话,请保存下面的铸币密钥并添加到任何节点上,以允许它代表您铸币.", "rewarddialog4": "点击确认后,铸币密钥将会创建,但你必须将该密钥添加到节点中才能成功铸币并获得相对应的奖励.", - "rewarddialog5": "您正在删除与此账号关联的铸币密钥: ", - "rewarddialog6": "点击确认后,铸币密钥将被移除并失效。 " + "rewarddialog5": "您正在删除与此账号关联的铸币密钥:", + "rewarddialog6": "点击确认后,铸币密钥将被移除並失效。" }, "sponsorshipspage": { "schange1": "目前有效的赞助记录", "schange2": "被赞助账号", "schange3": "总赞助数目", - "schange4": "距离下一轮可赞助新人还剩下区块数: ", + "schange4": "距离下一轮可赞助新人还剩下区块数:", "schange5": "赞助新人", "schange6": "已完成赞助", "schange7": "已完成", @@ -770,9 +763,9 @@ "schange13": "输入地址", "schange14": "进行中", "schange15": "整理起来", - "schange16": "复制下面的密钥并与您的赞助人分享。 ", + "schange16": "复制下面的密钥并与您的赞助人分享。", "schange17": "已复制到剪贴板", - "schange18": "警告:在完成之前不要离开这个插件或关闭Qortal UI ! ", + "schange18": "警告:在完成之前不要离开这个插件或关闭 Qortal UI!", "schange19": "复制赞助密钥", "schange20": "建立关系", "schange21": "删除赞助密钥" @@ -781,16 +774,16 @@ "exp1": "需要搜索的钱包地址或名称", "exp2": "账户余额", "exp3": "更多信息", - "exp4": "找不到相关钱包地址或名称! ", - "exp5": "请注意,注册名称区分大小写。 ", + "exp4": "找不到相关钱包地址或名称!", + "exp5": "请注意,注册名称区分大小写。", "exp6": "创始人", "exp7": "信息", "exp8": "显示所有买入交易", "exp9": "显示所有卖出交易", "exp10": "买入历史", "exp11": "卖出历史", - "exp12": "还没有买入交易。 ", - "exp13": "还没有卖出交易。 ", + "exp12": "还没有买入交易。", + "exp13": "还没有卖出交易。", "exp14": "显示完整信息", "exp15": "铸币时间", "exp16": "不铸币", @@ -803,82 +796,82 @@ "managegroup": { "mg1": "群组成员", "mg2": "邀请加入群组", - "mg3": "群组管理员", - "mg4": "更新群信息", + "mg3": "组管理员", + "mg4": "更新组", "mg5": "关闭管理组", - "mg6": "禁止", - "mg7": "踢出", - "mg8": "群组代号", + "mg6": "禁令", + "mg7": "踢", + "mg8": "组号", "mg9": "已加入", "mg10": "添加群组管理员", - "mg11": "您确定将此成员添加到管理员吗? ", - "mg12": "按下确认后,将发送添加管理员请求! ", + "mg11": "您确定将此成员添加到管理员吗?", + "mg12": "按下确认后,将发送添加管理员请求!", "mg13": "删除组管理员", "mg14": "删除管理员地址", - "mg15": "你确定要从管理员中删除该成员吗? ", - "mg16": "按下确认后,将发送删除管理员请求! ", + "mg15": "你确定要从管理员中删除该成员吗?", + "mg16": "按下确认后,将发送删除管理员请求!", "mg17": "禁止群组成员", "mg18": "会员姓名", "mg19": "会员地址", "mg20": "禁止多久", "mg21": "封禁原因", - "mg22": "您确定要将此成员加入群组吗? ", - "mg23": "按下确认后,将发送封禁请求! ", - "mg24": "永久", + "mg22": "您确定要将此成员加入群组吗?", + "mg23": "按下确认后,将发送封禁请求!", + "mg24": "永远", "mg25": "被禁止的会员", - "mg26": "取消禁止", + "mg26": "取消禁令", "mg27": "禁止到期", - "mg28": "取消群组成员封禁", - "mg29": "你确定要取消对这个成员的群组禁言吗? ", - "mg30": "按下确认后,将发送取消禁令请求! ", + "mg28": "取消群成员封禁", + "mg29": "你确定要取消对这个成员的群禁言吗?", + "mg30": "按下确认后,将发送取消禁令请求!", "mg31": "将成员踢出群组", "mg32": "踢球原因", - "mg33": "您确定将该成员踢出群吗? ", - "mg34": "按下确认后,将发送踢球请求! ", - "mg35": "没有公开群组邀请", - "mg36": "你的公开群组邀请", + "mg33": "您确定将该成员踢出群吗?", + "mg34": "按下确认后,将发送踢球请求!", + "mg35": "没有公开组邀请", + "mg36": "你的公开组邀请", "mg37": "邀请地址或姓名", "mg38": "邀请到期时间", "mg39": "所有字段都需要", - "mg40": "您确定邀请该成员加入群组吗? ", - "mg41": "按下确认后,将发送邀请请求! ", - "mg42": "群组类型", + "mg40": "您确定邀请该成员加入群组吗?", + "mg41": "按下确认后,将发送邀请请求!", + "mg42": "组类型", "mg43": "邀请到期", - "mg44": "公开群组", - "mg45": "私人群组", + "mg44": "公共组", + "mg45": "私有组", "mg46": "取消邀请", "mg47": "取消群邀请", - "mg48": "您确定要取消对该会员的邀请吗? ", - "mg49": "按下确认后,将发送取消邀请请求! ", - "mg50": "即将推出…… ", - "mg51": "最少3个字符/最多32个字符", - "mg52": "最多128个字符", + "mg48": "您确定要取消对该会员的邀请吗?", + "mg49": "按下确认后,将发送取消邀请请求!", + "mg50": "即将推出……", + "mg51": "最少 3 个字符 / 最多 32 个字符", + "mg52": "最多 128 个字符", "mg53": "您的公开加入请求", "mg54": "没有开放的加入请求", - "mg55": "您确定接受该会员的加入请求吗? ", - "mg56": "按下确认后,将发送接受加入请求! ", + "mg55": "您确定接受该会员的加入请求吗?", + "mg56": "按下确认后,将发送接受加入请求!", "mg57": "成功接受加入请求", "mg58": "出了点问题", "mg59": "取消加入请求已成功接受", - "mg60": "您确定要取消该会员的加入请求吗? ", - "mg61": "按下确认后,将发送取消加入请求! " + "mg60": "您确定要取消该会员的加入请求吗?", + "mg61": "按下确认后,将发送取消加入请求!" }, "info": { "inf1": "贸易门户信息", "inf2": "关闭交易门户信息", - "inf3": "这是购买QORT的市场", - "inf4": "- '公开市场卖出'是QORT卖出订单。 ", + "inf3": "这是购买 QORT 的市场", + "inf4": "- '公开市场卖出'是 QORT 卖出订单。", "inf5": "您一次只能购买一个订单,只需点击您希望购买的订单", - "inf6": "它将用详细信息填充'购买QORT'框,然后单击购买。 ", - "inf7": "什么是自动购买(A?", - "inf8": "关闭", - "inf9": "'Auto Buy'是一项允许在贸易门户网站上放置'买单'的功能。这些'买单'仅对放置它们的人可见。它们不是像'公开市场销售'是,并且不存储在Qortal区块链上。自动购买是一个UI功能,因此需要UI正在运行。 ", - "inf10": "要放置自动购买订单,请单击“添加自动购买订单”按钮并填写出现的框。输入您希望购买的QORT数量,以及您愿意购买的价格。一旦 订单有效, Auto Buy将为您购买UP TO数量的QORT ,价格上限为您设定的价格(从最低订单开始向上移动。) ", - "inf11": "只需让您的UI保持运行状态, Auto Buy会自动完成剩下的工作! ", - "inf12": "您可以浏览UI中的其他插件( Q-Chat 、钱包等),但如果您希望完成自动购买,则不能关闭UI 。将UI保留在'任务栏'上'最小化'或 “面板”,只要UI保持打开状态, Auto Buy就会起作用。 ", + "inf6": "它将用详细信息填充'购买 QORT' 框,然后单击购买。", + "inf7": "汽车购买信息", + "inf8": "关闭自动购买信息", + "inf9": "'Auto Buy' 是一项允许在贸易门户网站上放置'买单'的功能。这些'买单'仅对放置它们的人可见。它们不是像 '公开市场销售'是,并且不存储在 Qortal 区块链上。自动购买是一个 UI 功能,因此需要 UI 正在运行。", + "inf10": "要放置自动购买订单,请单击“添加自动购买订单”按钮并填写出现的框。输入您希望购买的 QORT 数量,以及您愿意购买的价格。一旦 订单有效,Auto Buy 将为您购买 UP TO 数量的 QORT,价格上限为您设定的价格(从最低订单开始向上移动。)", + "inf11": "只需让您的 UI 保持运行状态,Auto Buy 会自动完成剩下的工作!", + "inf12": "您可以浏览 UI 中的其他插件(Q-Chat、钱包等),但如果您希望完成自动购买,则不能关闭 UI。将 UI 保留在‘任务栏’上‘最小化’或 “面板”很好,只要 UI 保持打开状态,Auto Buy 就会起作用。", "inf13": "自动购买", "inf14": "与", - "inf15": "有效的自动购买订单", + "inf15": "活跃的自动购买订单", "inf16": "自动购买" } } diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index b2008c3a..f6774414 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -573,7 +573,8 @@ "cchange64": "禁用Enter鍵直接發送信息", "cchange65": "請輸入收件人", "cchange66": "無法獲取回复消息。消息太舊了。", - "cchange68": "編輯" + "cchange68": "編輯", + "cchange69": "自動顯示圖像" }, "welcomepage": { "wcchange1": "歡迎來到 Q-Chat", @@ -596,15 +597,7 @@ "bcchange7": "菜單", "bcchange8": "複製地址", "bcchange9": "私人信息", - "bcchange10": "更多", - "bcchange11": "回覆", - "bcchange12": "修改", - "bcchange13": "表情反應", - "bcchange14": "轉發", - "bcchange15": "信息已轉發", - "bcchange16": "選擇收件人或在下方搜尋收件人", - "bcchange17": "已轉發", - "bcchange18": "打賞" + "bcchange10": "更多" }, "grouppage": { "gchange1": "Qortal 群組", @@ -662,9 +655,9 @@ "gchange53": "成員", "gchange54": "成員數量", "gchange55": "搜索私人群組", - "gchange56": "要搜索的群組名", - "gchange57": "未找到私人群組名", - "gchange58": "注意群組名必須完全匹配。" + "gchange56": "要搜索的組名", + "gchange57": "未找到私人組名", + "gchange58": "注意組名必須完全匹配。" }, "puzzlepage": { "pchange1": "益智游戲", @@ -807,7 +800,7 @@ "mg4": "更新群信息", "mg5": "關閉管理組", "mg6": "禁止", - "mg7": "踢出", + "mg7": "踢", "mg8": "群組代號", "mg9": "已加入", "mg10": "添加群組管理員", From 432c98bee67cbda2d610b4d8d38ddd23b20446fe Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Tue, 24 Jan 2023 15:11:12 -0500 Subject: [PATCH 41/76] Changed message bubble colors + added new badges --- img/badges/Level-8.png | Bin 0 -> 6797 bytes img/badges/level-10.png | Bin 0 -> 6404 bytes img/badges/level-6.png | Bin 0 -> 6806 bytes img/badges/level-7.png | Bin 0 -> 6012 bytes img/badges/level-9.png | Bin 0 -> 6331 bytes qortal-ui-core/font/switch-theme.css | 2 + qortal-ui-core/src/styles/switch-theme.css | 2 + .../core/components/ChatScroller-css.js | 30 +++++++++-- .../plugins/core/components/ChatScroller.js | 47 +++++++++--------- .../plugins/core/components/LevelFounder.js | 1 + 10 files changed, 54 insertions(+), 28 deletions(-) create mode 100644 img/badges/Level-8.png create mode 100644 img/badges/level-10.png create mode 100644 img/badges/level-6.png create mode 100644 img/badges/level-7.png create mode 100644 img/badges/level-9.png diff --git a/img/badges/Level-8.png b/img/badges/Level-8.png new file mode 100644 index 0000000000000000000000000000000000000000..b5dede1779cf2d3ecc91e1bd93ce6288760f9b2c GIT binary patch literal 6797 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 literal 0 HcmV?d00001 diff --git a/img/badges/level-10.png b/img/badges/level-10.png new file mode 100644 index 0000000000000000000000000000000000000000..22dfc605b35514b382bccc1030c994b8557c09a5 GIT binary patch literal 6404 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 literal 0 HcmV?d00001 diff --git a/img/badges/level-7.png b/img/badges/level-7.png new file mode 100644 index 0000000000000000000000000000000000000000..b9141272f49291e9db8f243ff9118f13ab1f7099 GIT binary patch literal 6012 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 Y`u_h8^%jw|j}8D81x@*Hvak>T0}VE)WdHyG literal 0 HcmV?d00001 diff --git a/img/badges/level-9.png b/img/badges/level-9.png new file mode 100644 index 0000000000000000000000000000000000000000..77fa2d522e3199c3137297df084a3f413f921f69 GIT binary patch literal 6331 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 PCxCP{4K=FNZKM7NuusgP literal 0 HcmV?d00001 diff --git a/qortal-ui-core/font/switch-theme.css b/qortal-ui-core/font/switch-theme.css index 6c78e322..d79d6906 100644 --- a/qortal-ui-core/font/switch-theme.css +++ b/qortal-ui-core/font/switch-theme.css @@ -10,6 +10,7 @@ html { --chat-group: #080808; --chat-bubble: #9f9f9f0a; --chat-bubble-bg: #e6e6e6; + --chat-bubble-myBg: #d1ddf2; --chat-bubble-msg-color: #080808; --reaction-bubble-outline: #6b6969; --chat-menu-bg: #ffffff; @@ -65,6 +66,7 @@ html[theme="dark"] { --chat-group: #ffffff; --chat-bubble: #9694941a; --chat-bubble-bg: #2d3749; + --chat-bubble-myBg: #40444d; --chat-bubble-msg-color: #ffffff; --reaction-bubble-outline: #ffffff; --chat-menu-bg: #32394c; diff --git a/qortal-ui-core/src/styles/switch-theme.css b/qortal-ui-core/src/styles/switch-theme.css index fe928e12..ab8187c9 100644 --- a/qortal-ui-core/src/styles/switch-theme.css +++ b/qortal-ui-core/src/styles/switch-theme.css @@ -10,6 +10,7 @@ html { --chat-group: #080808; --chat-bubble: #9f9f9f0a; --chat-bubble-bg: #e6e6e6; + --chat-bubble-myBg: #d1ddf2; --chat-bubble-msg-color: #080808; --reaction-bubble-outline: #6b6969; --chat-menu-bg: #ffffff; @@ -62,6 +63,7 @@ html[theme="dark"] { --chat-group: #ffffff; --chat-bubble: #9694941a; --chat-bubble-bg: #2d3749; + --chat-bubble-myBg: #40444d; --chat-bubble-msg-color: #ffffff; --reaction-bubble-outline: #ffffff; --chat-menu-bg: #32394c; diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js index 177f9265..f3d8c32b 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js @@ -77,8 +77,8 @@ export const chatStyles = css` } .message-data-my-name { - color: var(--mdc-theme-primary); - text-shadow: 0 0 3px var(--mdc-theme-primary); + color: #05be0e; + font-weight: bold; } .message-data-time { @@ -137,6 +137,11 @@ export const chatStyles = css` min-width: 150px; } + + .message-myBg { + background-color: var(--chat-bubble-myBg) !important; + } + .message-triangle { position: relative; } @@ -153,6 +158,22 @@ export const chatStyles = css` border-color: transparent transparent var(--chat-bubble-bg) transparent; } + .message-myTriangle { + position: relative; + } + + .message-myTriangle:after { + content: ""; + position: absolute; + bottom: 0px; + left: -9px; + width: 0; + height: 0; + border-style: solid; + border-width: 0px 0px 7px 9px; + border-color: transparent transparent var(--chat-bubble-myBg) transparent; + } + .message-reactions { background-color: transparent; width: calc(100% - 54px); @@ -185,9 +206,7 @@ export const chatStyles = css` } .original-message-sender { - margin: 0 0 5px 0; color: var(--mdc-theme-primary); - cursor: pointer; } .replied-message { @@ -198,6 +217,7 @@ export const chatStyles = css` max-width: 300px; max-height: 40px; } + .replied-message p { margin: 0px; padding: 0px; @@ -412,7 +432,7 @@ export const chatStyles = css` .message-data-level { height: 21px; - width: 21px; + width: auto; overflow: hidden; } diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 4178041b..fc905f64 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -502,9 +502,12 @@ class MessageTemplate extends LitElement { `}
+

${repliedToData.senderName ?? cropAddress(repliedToData.sender)}

- - - ${version.toString() === '1' ? html` - ${repliedToData.decodedMessage.messageText} - ` : ''} - ${version.toString() === '2' ? html` - ${unsafeHTML(generateHTML(repliedToData.decodedMessage.messageText, [ - StarterKit, - Underline, - Highlight - // other extensions … - ]))} - ` : ''} - -

+ ${version.toString() === '1' ? html` + ${repliedToData.decodedMessage.messageText} + ` : ''} + ${version.toString() === '2' ? html` + ${unsafeHTML(generateHTML(repliedToData.decodedMessage.messageText, [ + StarterKit, + Underline, + Highlight + // other extensions … + ]))} + ` + : ''} +

`} ${image && !isImageDeleted && !this.viewImage && this.myAddress !== this.messageObj.sender ? html` @@ -604,7 +606,6 @@ class MessageTemplate extends LitElement { { this.openDeleteImage = true; - this.chatE }} class="image-delete-icon" icon="vaadin:close" slot="icon"> ` : ''} diff --git a/qortal-ui-plugins/plugins/core/components/LevelFounder.js b/qortal-ui-plugins/plugins/core/components/LevelFounder.js index 76b13677..d389e054 100644 --- a/qortal-ui-plugins/plugins/core/components/LevelFounder.js +++ b/qortal-ui-plugins/plugins/core/components/LevelFounder.js @@ -63,6 +63,7 @@ class LevelFounder extends LitElement { .message-data { display: flex; justify-content: center; + align-items: center; gap: 5px; } From 6888db2f18e27f750b6efa1a518dc73b596568f5 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:24:42 +0100 Subject: [PATCH 42/76] Bump version v3.0.1 --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a81e8f38..9217fc03 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Easiest way to install the lastest required packages on Linux is via nvm. ``` nvm ls-remote ``` (Fetch list of available versions)
``` nvm install v16.17.1 ``` (LTS: Gallium supported by Electron)
``` npm --location=global install yarn@1.22.19 ```
-``` npm --location=global install npm@9.3.0 ```
+``` npm --location=global install npm@9.3.1 ```
On BSD do a ``` pkg_add node followed by npm install -g yarn ``` diff --git a/package.json b/package.json index 2a790cdd..e868253e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "qortal-ui", - "version": "3.0.0", + "version": "3.0.1", "description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet", "keywords": [ "QORT", From f770cc0da70b608c22669a23164fa39004b6c81e Mon Sep 17 00:00:00 2001 From: "Jaymen.C" <68678251+JaymenChou@users.noreply.github.com> Date: Wed, 25 Jan 2023 13:16:00 +0800 Subject: [PATCH 43/76] Update zht.json Fix missing varibles translation in current update. --- qortal-ui-core/language/zht.json | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index f6774414..def41926 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -491,7 +491,7 @@ "dchange4": "搜尋", "dchange5": "已註冊名稱", "dchange6": "服務", - "dchange7": "標識符", + "dchange7": "標籤", "dchange8": "操作", "dchange9": "此節點已下載的資料", "dchange10": "資料名稱不能為空!", @@ -547,7 +547,7 @@ "cchange38": "用戶已驗證", "cchange39": "無法向該用戶發送加密消息,因為他們的公鑰不在鏈上。", "cchange40": "圖像(點擊查看)", - "cchange41": "您的餘額低於 4.20 QORT", + "cchange41": "您的QORT餘額低於4.20", "cchange42": "出於打擊垃圾郵件的需要,Qort餘額低於4.20的賬戶在Q-Chat中發送消息需要很長時間。如果你想立即提高Q-Chat消息的發送速度,請獲取4.20以上 QORT 到您的地址。這可以通過貿易門戶中的交易來完成,或者通過另一個 Qortian 給您 QORT。一旦您的帳戶中有超過 4.20 QORT,Q-Chat 消息將是即時的並且此對話框將不再顯示。感謝您了解這種必要的垃圾郵件預防方法,我們希望您喜歡 Qortal!", "cchange43": "打賞QORT給", "cchange44": "發送消息", @@ -572,7 +572,7 @@ "cchange63": "啟用Enter鍵直接發送信息", "cchange64": "禁用Enter鍵直接發送信息", "cchange65": "請輸入收件人", - "cchange66": "無法獲取回复消息。消息太舊了。", + "cchange66": "無法獲取回覆消息。消息太舊了。", "cchange68": "編輯", "cchange69": "自動顯示圖像" }, @@ -597,7 +597,15 @@ "bcchange7": "菜單", "bcchange8": "複製地址", "bcchange9": "私人信息", - "bcchange10": "更多" + "bcchange10": "更多", + "bcchange11": "回覆", + "bcchange12": "修改", + "bcchange13": "表情反應", + "bcchange14": "轉發", + "bcchange15": "信息已轉發", + "bcchange16": "選擇收件人或在下方搜尋收件人", + "bcchange17": "已轉發", + "bcchange18": "打賞" }, "grouppage": { "gchange1": "Qortal 群組", @@ -655,9 +663,9 @@ "gchange53": "成員", "gchange54": "成員數量", "gchange55": "搜索私人群組", - "gchange56": "要搜索的組名", - "gchange57": "未找到私人組名", - "gchange58": "注意組名必須完全匹配。" + "gchange56": "要搜索的群組名稱", + "gchange57": "未找到私人群組名稱", + "gchange58": "注意群組名稱必須完全匹配。" }, "puzzlepage": { "pchange1": "益智游戲", @@ -757,9 +765,9 @@ "schange7": "已完成", "schange8": "錢包地址", "schange9": "您目前沒有有效的贊助記錄", - "schange10": "公鑰查找", + "schange10": "查詢公鑰", "schange11": "複製", - "schange12": "地址到公鑰轉換器", + "schange12": "查詢錢包地址對應公鑰", "schange13": "輸入地址", "schange14": "進行中", "schange15": "整理起來", @@ -863,10 +871,10 @@ "inf4": "- '公開市場賣出'是 QORT 賣出訂單。", "inf5": "您一次只能購買一個訂單,只需點擊您希望購買的訂單", "inf6": "它將用詳細信息填充'購買 QORT' 框,然後單擊購買。", - "inf7": "甚麼是自動購買(A?", + "inf7": "甚麼是自動購買(Auto Buy)?", "inf8": "關閉", - "inf9": "'Auto Buy' 是一項允許在貿易門戶網站上放置'買單'的功能。這些'買單'僅對放置它們的人可見。它們不是像 '公開市場銷售'是,並且不存儲在 Qortal 區塊鏈上。自動購買是一個 UI 功能,因此需要 UI 正在運行。", - "inf10": "要放置自動購買訂單,請單擊“添加自動購買訂單”按鈕並填寫出現的框。輸入您希望購買的 QORT 數量,以及您願意購買的價格。一旦 訂單有效,Auto Buy 將為您購買 UP TO 數量的 QORT,價格上限為您設定的價格(從最低訂單開始向上移動。)", + "inf9": "'Auto Buy' 是一項允許在貿易門戶網站上添加'買單'的功能。這些'買單'僅限自己可見。你不會在貿易門戶上看到,並且不會存儲在 Qortal 區塊鏈上。自動購買是一個 UI 功能,因此需要保持 UI 運行。", + "inf10": "要放置自動購買訂單,請單擊“添加自動購買訂單”按鈕並填寫相關資料。輸入您希望購買的 QORT 數量,以及您願意購買的價格。一旦 訂單有效,Auto Buy 將為您購買對應數量的 QORT,價格上限為您設定的價格(從最低訂單開始向上移動。)", "inf11": "只需讓您的 UI 保持運行狀態,Auto Buy 會自動完成剩下的工作!", "inf12": "您可以瀏覽 UI 中的其他插件(Q-Chat、錢包等),但如果您希望完成自動購買,則不能關閉 UI。將 UI 保留在‘任務欄’上‘最小化’或 “面板”,只要 UI 保持打開狀態,Auto Buy 就會起作用。", "inf13": "自動購買", From 0dba69bd3eb4ba6f98fb55a7e96da3e87cbeb7cf Mon Sep 17 00:00:00 2001 From: "Jaymen.C" <68678251+JaymenChou@users.noreply.github.com> Date: Wed, 25 Jan 2023 13:17:07 +0800 Subject: [PATCH 44/76] Update zhc.json fix missing variables in translation in current update --- qortal-ui-core/language/zhc.json | 182 ++++++++++++++++--------------- 1 file changed, 95 insertions(+), 87 deletions(-) diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index 63b9b1f8..1dfdff92 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -36,7 +36,7 @@ "puzzles": "益智游戏", "nodemanagement": "节点管理", "trading": "贸易", - "groups": "团体" + "groups": "群组" }, "login": { "login": "登入", @@ -52,23 +52,23 @@ "seed": "助记词", "seedphrase": "助记词", "saved": "已保存的钱包", - "qora": "Qora 钱包助记词", - "backup": "Qortal 钱包备份文件", + "qora": "Qora钱包助记词", + "backup": "Qortal钱包备份文件", "decrypt": "正在解密钱包备份文件", "save": "保存钱包,以便下次登入.", "prepare": "正在加载你的钱包", "areyousure": "你确定将此钱包在已保存钱包列表中删除吗?", "error1": "备份文件必须为有效的JSON格式文件", "error2": "请选择登入方式", - "createwelcome": "欢迎来到 Qortal,您会发现它类似于 RPG 游戏,作为 Qortal 网络上的铸币者(如果您选择成为其中的铸币者),您将有机会升级您的帐户,并随着等级提高而获得更多 QORT 区块奖励以及参与平台上各种决策投票。", + "createwelcome": "欢迎来到Qortal,您会发现它类似于RPG 游戏,作为Qortal 网络上的铸币者(如果您选择成为其中的铸币者),您将有机会升级您的帐户,并随着等级提高而获得更多QORT 区块奖励以及参与平台上各种决策投票。", "createa": "你的", "click": "点击查看助记词", "confirmpass": "确认密码", - "willbe": "将在后台随机生成。 这将用作您在 Qortal 中的区块链帐户的私人密钥。", - "clicknext": "▼▼▼点击下一步创建你的Qortal账号▼▼▼", + "willbe": "将在后台随机生成。 这将用作您在Qortal 中的区块链帐户的私人密钥。", + "clicknext": " ▼▼▼点击下一步创建你的Qortal账号▼▼▼", "ready": "您的帐户即将创建成功, 它将保存在此浏览器中。 如果您不希望将新帐户保存在浏览器中,可以取消勾选下面的选项。 您仍可透过使用创建帐户时载的钱包备份文件进行的登入。", - "welmessage": "欢迎来到 Qortal", - "pleaseenter": "请输入密码!", + "welmessage": "欢迎来到Qortal", + "pleaseenter": "请密码!", "notmatch": "密码不一致!", "lessthen8": "你的密码长度少于8位! 我们不建议使用,但你仍可继续使用此密码。", "lessthen8-2": "你的密码长度少于8位!", @@ -81,9 +81,9 @@ "backup2": "请小心保存钱包备份文件,并谨记之前设置好的密码。否则你将会失去这个钱包的所有控制权,请务必将备份文件放在不同的存储装置上", "savewallet": "下载并保存钱包备份文件", "created1": "你的账号已创建成功", - "created2": " 并会保存在UI上.", + "created2": "并会储存在UI上.", "downloadbackup": "下载钱包备份文件", - "passwordhint": "密码必须至少为 8 个字符。" + "passwordhint": "密码必须至少为8 个字符。" }, "logout": { "logout": "登出", @@ -125,7 +125,7 @@ "deletecustomnode": "删除所有自定义节点", "warning": "您现有的节点将被删除并从备份中创建新的。", "snack1": "成功删除和添加标准节点", - "snack2": "连接到节点的 UI", + "snack2": "连接到节点的UI", "snack3": "成功添加并保存自定义节点", "snack4": "节点成功保存为", "snack5": "节点成功导入", @@ -155,10 +155,10 @@ "close": "关闭", "back": "上一步", "next": "下一步", - "create": "新建", + "create": "创建", "continue": "继续", "save": "保存", - "balance": "信用", + "balance": "余额", "balances": "您的钱包余额", "update": "更新钱包余额" }, @@ -172,7 +172,7 @@ "smchange7": "结束关系", "smchange8": "向节点添加铸币密钥", "smchange9": "完全的", - "smchange10": "每个节点只允许 2 个铸币密钥,您正在尝试分配 3 个密钥,请进入管理 - 节点管理,并删除您不想分配给该节点的密钥,谢谢!" + "smchange10": "每个节点只允许2 个铸币密钥,您正在尝试分配3 个密钥,请进入管理- 节点管理,并删除您不想分配给该节点的密钥,谢谢!" }, "mintingpage": { "mchange1": "一般铸币信息", @@ -188,7 +188,7 @@ "mchange11": "未激活", "mchange12": "激活你的账号", "mchange13": "激活方法", - "mchange14": "激活账号的方法是进行一笔简单的对外交易。注册名称是最常见的方法。 您可以在 Q-Chat 中的请求某人向您发送少量 QORT,以便您可以激活您的帐号,或在交易门户中购买 QORT,然后进行任何类型的交易。这样你的公共密钥才会被记录在区块链上,否则你的公钥只有你自己知道,其他人无法从区块链中找到你的公钥。", + "mchange14": "激活账号的方法是进行一笔简单的对外交易。注册名称是最常见的方法。 您可以在Q-Chat 中的请求某人向您发送少量QORT,以便您可以激活您的帐号,或在交易门户中购买QORT,然后进行任何类型的交易。这样你的公共密钥才会被记录在区块链上,否则你的公钥只有你自己知道,其他人无法从区块链中找到你的公钥。", "mchange15": "当前状态", "mchange16": "当前等级", "mchange17": "到达下一级所需铸币区块数", @@ -208,9 +208,9 @@ "mchange31": "点击寻求帮助", "mchange32": "成为一个铸币者", "mchange33": "简介", - "mchange34": "在 Qortal,要成为铸币者并随着铸币者等级的提高而开始获得 QORT 奖励,您必须获得赞助码。 只有创始人、5 级或以上的账号才能提供赞助码。当你获得赞助码并使用该密钥达到 1 级。一旦您达到 1 级,您将能够创建自己的铸币密钥并开始获得奖励,以帮助保护 Qortal 区块链。", + "mchange34": "在Qortal,要成为铸币者并随着铸币者等级的提高而开始获得QORT 奖励,您必须获得赞助码。 只有创始人、5 级或以上的账号才能提供赞助码。当你获得赞助码并使用该密钥达到1 级。一旦您达到1 级,您将能够创建自己的铸币密钥并开始获得奖励,以帮助保护Qortal 区块链。", "mchange35": "赞助", - "mchange36": "赞助商会给你一个“赞助码”,你必须添加到节点管理中并正式开始铸币(在达到 1 级之前没有任何奖励。)一旦您达到 1 级,您就可以创建自己的“铸币密钥”和 开始赚取奖励。", + "mchange36": "赞助商会给你一个“赞助码”,你必须添加到节点管理中并正式开始铸币(在达到1 级之前没有任何奖励。)一旦您达到1 级,您就可以创建自己的“铸币密钥”和开始赚取奖励。", "mchange37": "因此你只需寻找赞助商并获得赞助码,然后返回此处输入赞助码即可开始您的铸币之旅!", "mchange38": "在" }, @@ -246,10 +246,10 @@ "wchange17": "传送", "wchange18": "由钱包", "wchange19": "可用余额", - "wchange20": "收款人 (钱包地址或名称)", + "wchange20": "收款人(钱包地址或名称)", "wchange21": "当前固定手续费:", "wchange22": "钱包", - "wchange23": "收款人 (钱包地址)", + "wchange23": "收款人(钱包地址)", "wchange24": "当前手续费", "wchange25": "手续费设置越低,交易也相对更久甚至失败。", "wchange26": "当前余额不足(请预留一部分的币作为手续费)!", @@ -274,11 +274,11 @@ "wchange45": "全部发送", "wchange46": "发送到这个地址", "wchange47": "地址簿", - "wchange48": "此通讯录为空 !", + "wchange48": "此通讯录为空!", "wchange49": "加至地址簿", - "wchange50": "名称不能为空!", - "wchange51": "地址不能为空!", - "wchange52": "添加成功!", + "wchange50": "名称不能为空!", + "wchange51": "地址不能为空!", + "wchange52": "添加成功!", "wchange53": "导入通讯录", "wchange54": "导出通讯录", "wchange55": "您现有的通讯簿将被删除并从新创建的备份中。", @@ -351,7 +351,7 @@ "rchange12": "正在添加中...", "rchange13": "正在添加铸币密钥/赞助码", "rchange14": "添加", - "rchange15": "此账号并没有任何奖励分享", + "rchange15": "此账号并没有任何铸币密钥", "rchange16": "个人铸币密钥", "rchange17": "移除", "rchange18": "不能创建多个铸币密钥!", @@ -370,7 +370,7 @@ "nchange7": "操作", "nchange8": "此账号并没有注册任何名称!", "nchange9": "注册一个名称!", - "nchange10": "描述 (选填)", + "nchange10": "描述(选填)", "nchange11": "正在创建中", "nchange12": "正在创建中", "nchange13": "目前注册名称的手续费是", @@ -387,7 +387,7 @@ "nchange24": "没有名字可以卖", "nchange25": "出售名称", "nchange26": "你确定要卖这个名字吗?", - "nchange27": "对于 QORT 中的这个价格", + "nchange27": "对于QORT 中的这个价格", "nchange28": "按下确认后,将发送销售名称请求!", "nchange29": "要取消的名称", "nchange30": "你确定要取消这个名字的出售吗?", @@ -398,7 +398,7 @@ "nchange35": "你有名字!", "nchange36": "只有没有注册名字的账户才能买名字。", "nchange37": "注意!", - "nchange38": "你没有足够的 qort 来购买这个名字。", + "nchange38": "你没有足够的qort 来购买这个名字。", "nchange39": "你确定要买这个名字吗?", "nchange40": "按下确认后,将发送购买名称请求!" }, @@ -491,7 +491,7 @@ "dchange4": "搜寻", "dchange5": "已注册名称", "dchange6": "服务", - "dchange7": "标识符", + "dchange7": "标签", "dchange8": "操作", "dchange9": "此节点已下载的资料", "dchange10": "资料名称不能为空!", @@ -508,13 +508,13 @@ "dchange21": "尝试删除此资源时出错。 请再试一次" }, "chatpage": { - "cchange1": "新的私人对话", + "cchange1": "建立新的私人对话", "cchange2": "加载中...", "cchange3": "已封锁的用户名单", "cchange4": "新的信息", "cchange5": "(点击向下滚动)", "cchange6": "输入对方的名称或钱包地址并建立私人对话!", - "cchange7": "名称 / 钱包地址", + "cchange7": "名称/ 钱包地址", "cchange8": "信息内容...", "cchange9": "传送", "cchange10": "已封锁的用户名单", @@ -526,17 +526,17 @@ "cchange16": "成功解封此用户。", "cchange17": "尝试解封此用户时发生错误。 请再试一次!", "cchange18": "解封", - "cchange19": "无效的名称 / 钱包地址, 检查名称 / 钱包地址后再次尝试...", + "cchange19": "无效的名称/ 钱包地址, 检查名称/ 钱包地址后再次尝试...", "cchange20": "成功发送信息!", "cchange21": "发送失败, 请再此尝试...", "cchange22": "正在加载信息内容...", "cchange23": "未能解密信息内容!", - "cchange24": "每个信息的最大字符数为 255", + "cchange24": "每个信息的最大字符数为255", "cchange25": "编辑消息", - "cchange26": "文件大小超过 0.5 MB", + "cchange26": "文件大小超过0.5 MB", "cchange27": "发送图片需要注册名称", "cchange28": "这个文件不是图片", - "cchange29": "最大消息大小为 1000 字节", + "cchange29": "最大消息大小为1000 字节", "cchange30": "正在上传图片。这可能需要一分钟。", "cchange31": "正在删除图像。这可能需要一分钟。", "cchange33": "取消", @@ -547,17 +547,17 @@ "cchange38": "用户已验证", "cchange39": "无法向该用户发送加密消息,因为他们的公钥不在链上。", "cchange40": "图像(点击查看)", - "cchange41": "您的余额低于 4.20 QORT", - "cchange42": "出于打击垃圾邮件的需要,Qort余额低于4.20的账户在Q-Chat中发送消息需要很长时间。如果你想立即提高Q-Chat消息的发送速度,请获取4.20以上 QORT 到您的地址。这可以通过贸易门户中的交易来完成,或者通过另一个 Qortian 给您 QORT。一旦您的帐户中有超过 4.20 QORT,Q-Chat 消息将是即时的并且此对话框将不再存在 显示。感谢您了解这种必要的垃圾邮件预防方法,我们希望您喜欢 Qortal!", + "cchange41": "您的QORT余额低于4.20", + "cchange42": "出于打击垃圾邮件的需要,Qort余额低于4.20的账户在Q-Chat中发送消息需要很长时间。如果你想立即提高Q-Chat消息的发送速度,请获取4.20以上QORT 到您的地址。这可以通过贸易门户中的交易来完成,或者通过另一个Qortian 给您QORT。一旦您的帐户中有超过4.20 QORT,Q-Chat 消息将是即时的并且此对话框将不再显示。感谢您了解这种必要的垃圾邮件预防方法,我们希望您喜欢Qortal!", "cchange43": "打赏QORT给", "cchange44": "发送消息", "cchange45": "提示用户", - "cchange46": "小费金额", + "cchange46": "打赏金额", "cchange47": "可用余额", - "cchange48": "无法获取 QORT 余额。请重试!", - "cchange49": "当前静态费用", + "cchange48": "无法获取QORT 余额。请重试!", + "cchange49": "当前手续费", "cchange50": "发送", - "cchange51": "资金不足!", + "cchange51": "余额不足!", "cchange52": "无效金额!", "cchange53": "接收方不能为空!", "cchange54": "接收者无效!", @@ -569,21 +569,21 @@ "cchange60": "群组邀请待定", "cchange61": "获取群组邀请时出错。请重试!", "cchange62": "用户名和地址输入错误!请重试!", - "cchange63": "输入启用", - "cchange64": "输入禁用", + "cchange63": "启用Enter键直接发送信息", + "cchange64": "禁用Enter键直接发送信息", "cchange65": "请输入收件人", - "cchange66": "无法获取回复消息。消息太旧了。", + "cchange66": "无法获取回覆消息。消息太旧了。", "cchange68": "编辑", "cchange69": "自动显示图像" }, "welcomepage": { - "wcchange1": "欢迎来到 Q-Chat", - "wcchange2": "新的私人对话", + "wcchange1": "欢迎来到Q-Chat", + "wcchange2": "建立新的私人对话", "wcchange3": "输入对方的名称或钱包地址并建立私人对话!", - "wcchange4": "名称 / 钱包地址", - "wcchange5": "信息内容...", + "wcchange4": "名称/ 钱包地址", + "wcchange5": "输入内容...", "wcchange6": "传送", - "wcchange7": "无效的名称 / 钱包地址, 检查名称 / 钱包地址后再次尝试...", + "wcchange7": "无效的名称/ 钱包地址, 检查名称/ 钱包地址后再次尝试...", "wcchange8": "成功发送信息!", "wcchange9": "发送失败, 请再此尝试..." }, @@ -597,10 +597,18 @@ "bcchange7": "菜单", "bcchange8": "复制地址", "bcchange9": "私人信息", - "bcchange10": "更多的" + "bcchange10": "更多", + "bcchange11": "回覆", + "bcchange12": "修改", + "bcchange13": "表情反应", + "bcchange14": "转发", + "bcchange15": "信息已转发", + "bcchange16": "选择收件人或在下方搜寻收件人", + "bcchange17": "已转发", + "bcchange18": "打赏" }, "grouppage": { - "gchange1": "Qortal 群组", + "gchange1": "Qortal群组", "gchange2": "创建群组", "gchange3": "你已加入的群组", "gchange4": "群组名称", @@ -655,9 +663,9 @@ "gchange53": "成员", "gchange54": "成员数量", "gchange55": "搜索私人群组", - "gchange56": "要搜索的组名", - "gchange57": "未找到私人组名", - "gchange58": "注意组名必须完全匹配。" + "gchange56": "要搜索的群组名称", + "gchange57": "未找到私人群组名称", + "gchange58": "注意群组名称必须完全匹配。" }, "puzzlepage": { "pchange1": "益智游戏", @@ -665,7 +673,7 @@ "pchange3": "得奖者", "pchange4": "名称", "pchange5": "描述", - "pchange6": "提示 / 答案", + "pchange6": "提示/ 答案", "pchange7": "操作", "pchange8": "猜一下", "pchange9": "输入你的答案", @@ -683,7 +691,7 @@ "nchange2": "节点在线时间:", "nchange3": "此节点的铸币账号", "nchange4": "添加铸币账号", - "nchange5": "如果想使用自己的帐号进行铸币,你必须在铸币密钥页面中建立个人铸币密钥(将奖励分享百分比设置为 0),然后将个人铸币密钥添加到此处。.", + "nchange5": "如果想使用自己的帐号进行铸币,你必须在铸币密钥页面中建立个人铸币密钥(将奖励分享百分比设置为0),然后将个人铸币密钥添加到此处。.", "nchange6": "铸币密钥", "nchange7": "正在添加铸币密钥/赞助码", "nchange8": "添加", @@ -731,9 +739,9 @@ "transactions": { "amount": "数量", "to": "收款人", - "declined": "交易已被用戶拒绝!", - "namedialog1": "你正在註冊以下名稱:", - "namedialog2": "點擊確認後, 名稱將被註冊!", + "declined": "交易被用户拒绝!", + "namedialog1": "你正在注册以下名称:", + "namedialog2": "点击确认后, 名称将被注册!", "groupdialog1": "你正在请求加入下列群组:", "groupdialog2": "点击确认后,加入请求将会被送出!", "groupdialog3": "你正在请求离开下列群组:", @@ -745,7 +753,7 @@ "rewarddialog3": "如果是的话,请保存下面的铸币密钥并添加到任何节点上,以允许它代表您铸币.", "rewarddialog4": "点击确认后,铸币密钥将会创建,但你必须将该密钥添加到节点中才能成功铸币并获得相对应的奖励.", "rewarddialog5": "您正在删除与此账号关联的铸币密钥:", - "rewarddialog6": "点击确认后,铸币密钥将被移除並失效。" + "rewarddialog6": "点击确认后,铸币密钥将被移除并失效。" }, "sponsorshipspage": { "schange1": "目前有效的赞助记录", @@ -757,15 +765,15 @@ "schange7": "已完成", "schange8": "钱包地址", "schange9": "您目前没有有效的赞助记录", - "schange10": "公钥查找", + "schange10": "查询公钥", "schange11": "复制", - "schange12": "地址到公钥转换器", + "schange12": "查询钱包地址对应公钥", "schange13": "输入地址", "schange14": "进行中", "schange15": "整理起来", "schange16": "复制下面的密钥并与您的赞助人分享。", "schange17": "已复制到剪贴板", - "schange18": "警告:在完成之前不要离开这个插件或关闭 Qortal UI!", + "schange18": "警告:在完成之前不要离开这个插件或关闭Qortal UI!", "schange19": "复制赞助密钥", "schange20": "建立关系", "schange21": "删除赞助密钥" @@ -796,12 +804,12 @@ "managegroup": { "mg1": "群组成员", "mg2": "邀请加入群组", - "mg3": "组管理员", - "mg4": "更新组", + "mg3": "群组管理员", + "mg4": "更新群信息", "mg5": "关闭管理组", - "mg6": "禁令", + "mg6": "禁止", "mg7": "踢", - "mg8": "组号", + "mg8": "群组代号", "mg9": "已加入", "mg10": "添加群组管理员", "mg11": "您确定将此成员添加到管理员吗?", @@ -817,35 +825,35 @@ "mg21": "封禁原因", "mg22": "您确定要将此成员加入群组吗?", "mg23": "按下确认后,将发送封禁请求!", - "mg24": "永远", + "mg24": "永久", "mg25": "被禁止的会员", - "mg26": "取消禁令", + "mg26": "取消禁止", "mg27": "禁止到期", - "mg28": "取消群成员封禁", - "mg29": "你确定要取消对这个成员的群禁言吗?", + "mg28": "取消群组成员封禁", + "mg29": "你确定要取消对这个成员的群组禁言吗?", "mg30": "按下确认后,将发送取消禁令请求!", "mg31": "将成员踢出群组", "mg32": "踢球原因", "mg33": "您确定将该成员踢出群吗?", "mg34": "按下确认后,将发送踢球请求!", - "mg35": "没有公开组邀请", - "mg36": "你的公开组邀请", + "mg35": "没有公开群组邀请", + "mg36": "你的公开群组邀请", "mg37": "邀请地址或姓名", "mg38": "邀请到期时间", "mg39": "所有字段都需要", "mg40": "您确定邀请该成员加入群组吗?", "mg41": "按下确认后,将发送邀请请求!", - "mg42": "组类型", + "mg42": "群组类型", "mg43": "邀请到期", - "mg44": "公共组", - "mg45": "私有组", + "mg44": "公开群组", + "mg45": "私人群组", "mg46": "取消邀请", "mg47": "取消群邀请", "mg48": "您确定要取消对该会员的邀请吗?", "mg49": "按下确认后,将发送取消邀请请求!", "mg50": "即将推出……", - "mg51": "最少 3 个字符 / 最多 32 个字符", - "mg52": "最多 128 个字符", + "mg51": "最少3 个字符/ 最多32 个字符", + "mg52": "最多128 个字符", "mg53": "您的公开加入请求", "mg54": "没有开放的加入请求", "mg55": "您确定接受该会员的加入请求吗?", @@ -859,19 +867,19 @@ "info": { "inf1": "贸易门户信息", "inf2": "关闭交易门户信息", - "inf3": "这是购买 QORT 的市场", - "inf4": "- '公开市场卖出'是 QORT 卖出订单。", + "inf3": "这是购买QORT 的市场", + "inf4": "- '公开市场卖出'是QORT 卖出订单。", "inf5": "您一次只能购买一个订单,只需点击您希望购买的订单", - "inf6": "它将用详细信息填充'购买 QORT' 框,然后单击购买。", - "inf7": "汽车购买信息", - "inf8": "关闭自动购买信息", - "inf9": "'Auto Buy' 是一项允许在贸易门户网站上放置'买单'的功能。这些'买单'仅对放置它们的人可见。它们不是像 '公开市场销售'是,并且不存储在 Qortal 区块链上。自动购买是一个 UI 功能,因此需要 UI 正在运行。", - "inf10": "要放置自动购买订单,请单击“添加自动购买订单”按钮并填写出现的框。输入您希望购买的 QORT 数量,以及您愿意购买的价格。一旦 订单有效,Auto Buy 将为您购买 UP TO 数量的 QORT,价格上限为您设定的价格(从最低订单开始向上移动。)", - "inf11": "只需让您的 UI 保持运行状态,Auto Buy 会自动完成剩下的工作!", - "inf12": "您可以浏览 UI 中的其他插件(Q-Chat、钱包等),但如果您希望完成自动购买,则不能关闭 UI。将 UI 保留在‘任务栏’上‘最小化’或 “面板”很好,只要 UI 保持打开状态,Auto Buy 就会起作用。", + "inf6": "它将用详细信息填充'购买QORT' 框,然后单击购买。", + "inf7": "什么是自动购买(Auto Buy)?", + "inf8": "关闭", + "inf9": "'Auto Buy'是一项允许在贸易门户网站上添加'买单'的功能。这些'买单'仅限自己可见。你不会在贸易门户上看到,并且不会存储在Qortal 区块链上。自动购买是一个UI 功能,因此需要保持UI 运行。", + "inf10": "要放置自动购买订单,请单击“添加自动购买订单”按钮并填写相关资料。输入您希望购买的QORT 数量,以及您愿意购买的价格。一旦订单有效,Auto Buy 将为您购买对应数量的QORT,价格上限为您设定的价格(从最低订单开始向上移动。)", + "inf11": "只需让您的UI 保持运行状态,Auto Buy 会自动完成剩下的工作!", + "inf12": "您可以浏览UI 中的其他插件(Q-Chat、钱包等),但如果您希望完成自动购买,则不能关闭UI。将UI 保留在'任务栏'上'最小化'或“面板”,只要UI 保持打开状态,Auto Buy 就会起作用。", "inf13": "自动购买", "inf14": "与", - "inf15": "活跃的自动购买订单", + "inf15": "有效的自动购买订单", "inf16": "自动购买" } } From c921daed78a61316dc97fa52810f7d7ca421489b Mon Sep 17 00:00:00 2001 From: Phillip Date: Wed, 25 Jan 2023 10:40:59 +0200 Subject: [PATCH 45/76] fix send name/address in replies --- .../plugins/utils/replace-messages-edited.js | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/qortal-ui-plugins/plugins/utils/replace-messages-edited.js b/qortal-ui-plugins/plugins/utils/replace-messages-edited.js index 1d6a2941..7ee2cb06 100644 --- a/qortal-ui-plugins/plugins/utils/replace-messages-edited.js +++ b/qortal-ui-plugins/plugins/utils/replace-messages-edited.js @@ -52,33 +52,47 @@ export const replaceMessagesEdited = async ({ msgQuery = `&txGroupId=${msg.txGroupId}` } if (parsedMessageObj.repliedTo) { + const originalReply = await parentEpml.request("apiCall", { + type: "api", + url: `/chat/messages?reference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}`, + }) const response = await parentEpml.request("apiCall", { type: "api", url: `/chat/messages?chatreference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}`, }) + if ( + originalReply && + Array.isArray(originalReply) && + originalReply.length !== 0 && response && Array.isArray(response) && response.length !== 0 ) { + const decodeOriginalReply = decodeMessageFunc(originalReply[0], isReceipient, _publicKey) + + const decodeUpdatedReply = decodeMessageFunc(response[0], isReceipient, _publicKey) + const formattedRepliedToData = { + ...decodeUpdatedReply, + senderName: decodeOriginalReply.senderName, + sender: decodeOriginalReply.sender, + } msgItem = { ...msg, - repliedToData: decodeMessageFunc(response[0], isReceipient, _publicKey), + repliedToData: formattedRepliedToData, } } else { - const response2 = await parentEpml.request("apiCall", { - type: "api", - url: `/chat/messages?reference=${parsedMessageObj.repliedTo}&reverse=true${msgQuery}`, - }) + if ( - response2 && - Array.isArray(response2) && - response2.length !== 0 + originalReply && + Array.isArray(originalReply) && + originalReply.length !== 0 ) { + msgItem = { ...msg, - repliedToData: decodeMessageFunc(response2[0], isReceipient, _publicKey), + repliedToData: decodeMessageFunc(originalReply[0], isReceipient, _publicKey), } } } From cc01ca599a8ca42c898901591fb303804675b67b Mon Sep 17 00:00:00 2001 From: Phillip Date: Wed, 25 Jan 2023 16:51:09 +0200 Subject: [PATCH 46/76] add intial value to autoLoadImageChats --- qortal-ui-core/src/redux/app/app-reducer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qortal-ui-core/src/redux/app/app-reducer.js b/qortal-ui-core/src/redux/app/app-reducer.js index 9d650ec9..6f3d8e1d 100644 --- a/qortal-ui-core/src/redux/app/app-reducer.js +++ b/qortal-ui-core/src/redux/app/app-reducer.js @@ -1,5 +1,5 @@ // Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage. -import { saveStateToLocalStorage } from '../../localStorageHelpers.js' +import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js' import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT } from './app-action-types.js' import { initWorkersReducer } from './reducers/init-workers.js' import { loginReducer } from './reducers/login-reducer.js' @@ -44,7 +44,7 @@ const INITIAL_STATE = { isOpen: false, elementId: '' }, - autoLoadImageChats: [] + autoLoadImageChats: loadStateFromLocalStorage('autoLoadImageChats') || [] } export default (state = INITIAL_STATE, action) => { From 4caa08f9fae39c4b2636d8466255473c5fbc1c07 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Wed, 25 Jan 2023 16:36:36 +0100 Subject: [PATCH 47/76] WIP --- .../plugins/core/messaging/q-chat/q-chat-css.src.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js index bb8cec28..eb4f7ca3 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js @@ -51,11 +51,11 @@ export const qchatStyles = css` } .people-list .blockedusers { + z-index: 1; position: absolute; bottom: 0; width: 20vw; background: var(--white); - border-top: 1px solid var(--border); border-right: 3px #ddd solid; display: flex; justify-content: space-between; @@ -476,4 +476,4 @@ export const qchatStyles = css` color: #04aa2e; font-size: 13px; } -` \ No newline at end of file +` From fefbe1334f698ca8364ac2f8caf18faf905408ad Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Wed, 25 Jan 2023 16:38:20 +0100 Subject: [PATCH 48/76] Remove console log --- .../plugins/core/group-management/group-management.src.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js index a4fd9f81..0148f33b 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js +++ b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js @@ -1820,7 +1820,6 @@ class GroupManagement extends LitElement { setTimeout(getGroupInvites, 1) configLoaded = true } - console.log('parse', JSON.parse(c)) this.config = JSON.parse(c) }) parentEpml.subscribe('copy_menu_switch', async value => { @@ -3640,4 +3639,4 @@ class GroupManagement extends LitElement { } } -window.customElements.define('group-management', GroupManagement) \ No newline at end of file +window.customElements.define('group-management', GroupManagement) From 95db4912969490dc9eb342007b5059f4b7bb34d2 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Thu, 26 Jan 2023 15:06:57 -0500 Subject: [PATCH 49/76] Tooltip done --- qortal-ui-core/font/switch-theme.css | 4 +- qortal-ui-core/src/styles/switch-theme.css | 4 +- .../plugins/core/components/ChatPage.js | 13 +++- .../core/components/ChatScroller-css.js | 13 ++-- .../plugins/core/components/ChatScroller.js | 75 ++++++++++++++++--- 5 files changed, 90 insertions(+), 19 deletions(-) diff --git a/qortal-ui-core/font/switch-theme.css b/qortal-ui-core/font/switch-theme.css index d79d6906..c8b139c3 100644 --- a/qortal-ui-core/font/switch-theme.css +++ b/qortal-ui-core/font/switch-theme.css @@ -52,6 +52,7 @@ html { --lightChatHeadHover: #1e1f201a; --group-header: #929292; --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; + --reactions-tooltip-bg: #ffffff; } html[theme="dark"] { @@ -107,5 +108,6 @@ html[theme="dark"] { --chatHeadTextActive: #ffffff; --lightChatHeadHover: #e0e1e31a; --group-header: #c8c8c8; - --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px; + --reactions-tooltip-bg: #161515; } \ No newline at end of file diff --git a/qortal-ui-core/src/styles/switch-theme.css b/qortal-ui-core/src/styles/switch-theme.css index ab8187c9..130e8b8d 100644 --- a/qortal-ui-core/src/styles/switch-theme.css +++ b/qortal-ui-core/src/styles/switch-theme.css @@ -49,6 +49,7 @@ html { --chatHeadTextActive: #080808; --group-header: #929292; --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; + --reactions-tooltip-bg: #ffffff; } html[theme="dark"] { @@ -101,5 +102,6 @@ html[theme="dark"] { --chatHeadText: #ffffff; --chatHeadTextActive: #ffffff; --group-header: #c8c8c8; - --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px; + --reactions-tooltip-bg: #161515; } \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 538240e9..55231d7e 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -2641,6 +2641,7 @@ class ChatPage extends LitElement { const stringifyMessageObject = JSON.stringify(messageObject); this.sendMessage(stringifyMessageObject, typeMessage); } else if (outSideMsg && outSideMsg.type === 'reaction') { + const userName = await getName(this.selectedAddress.address); typeMessage = 'edit'; let chatReference = outSideMsg.editedMessageObj.reference; @@ -2662,11 +2663,14 @@ class ChatPage extends LitElement { const findEmojiIndex = reactions.findIndex((reaction)=> reaction.type === outSideMsg.reaction) if(findEmojiIndex !== -1){ let users = reactions[findEmojiIndex].users || [] - const findUserIndex = users.findIndex((user)=> user === this.selectedAddress.address ) + const findUserIndex = users.findIndex((user)=> user.address === this.selectedAddress.address ) if(findUserIndex !== -1){ users.splice(findUserIndex, 1) } else { - users.push(this.selectedAddress.address) + users.push({ + address: this.selectedAddress.address, + name: userName + }) } reactions[findEmojiIndex] = { ...reactions[findEmojiIndex], @@ -2680,7 +2684,10 @@ class ChatPage extends LitElement { reactions = [...reactions, { type: outSideMsg.reaction, qty: 1, - users: [this.selectedAddress.address] + users: [{ + address: this.selectedAddress.address, + name: userName + }] }] } const messageObject = { diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js index f3d8c32b..bbe4778a 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js @@ -175,9 +175,13 @@ export const chatStyles = css` } .message-reactions { - background-color: transparent; - width: calc(100% - 54px); - margin-left: 54px; + background-color: transparent; + width: calc(100% - 54px); + margin-left: 54px; + display: flex; + flex-flow: row wrap; + justify-content: left; + gap: 8px; } .original-message { @@ -412,11 +416,11 @@ export const chatStyles = css` } .reactions-bg { + position: relative; background-color: #d5d5d5; border-radius: 10px; padding: 5px; color: black; - margin-right: 10px; transition: all 0.1s ease-in-out; border: 0.5px solid transparent; cursor: pointer; @@ -723,6 +727,5 @@ export const chatStyles = css` transform: rotate(360deg); } } - ` diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 62033e44..17e40e3f 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -13,6 +13,7 @@ import './WrapperModal'; import "./UserInfo/UserInfo"; import '@vaadin/icons'; import '@vaadin/icon'; +import '@vaadin/tooltip'; import '@material/mwc-button'; import '@material/mwc-dialog'; import '@material/mwc-icon'; @@ -293,10 +294,9 @@ class MessageTemplate extends LitElement { setUserName: { attribute: false }, openTipUser:{ type: Boolean }, goToRepliedMessage: { attribute: false }, - listSeenMessages: {type: Array}, - addSeenMessage: {attribute: false}, - chatId: {type: String} - + listSeenMessages: { type: Array }, + addSeenMessage: { attribute: false }, + chatId: { type: String }, } } @@ -349,6 +349,13 @@ class MessageTemplate extends LitElement { if(autoSeeChatList.includes(this.chatId) || this.listSeenMessages.includes(this.messageObj.reference)){ this.viewImage = true } + + const tooltips = this.shadowRoot.querySelectorAll('vaadin-tooltip'); + tooltips.forEach(tooltip => { + const overlay = tooltip.shadowRoot.querySelector('vaadin-tooltip-overlay'); + overlay.shadowRoot.getElementById("overlay").style.cssText = "background-color: transparent; box-shadow: rgb(50 50 93 / 25%) 0px 2px 5px -1px, rgb(0 0 0 / 30%) 0px 1px 3px -1px"; + overlay.shadowRoot.getElementById('content').style.cssText = "background-color: var(--reactions-tooltip-bg); color: var(--chat-bubble-msg-color); text-align: center; padding: 20px 10px; border-radius: 8px; font-family: Roboto, sans-serif; letter-spacing: 0.3px; font-weight: 300; font-size: 13.5px; transition: all 0.3s ease-in-out;"; + }); } render() { @@ -377,6 +384,7 @@ class MessageTemplate extends LitElement { repliedToData = this.messageObj.repliedToData; isImageDeleted = parsedMessageObj.isImageDeleted; reactions = parsedMessageObj.reactions || []; + console.log(reactions, 'reactions here'); version = parsedMessageObj.version; isForwarded = parsedMessageObj.type === 'forward'; isEdited = parsedMessageObj.isEdited && true; @@ -684,17 +692,66 @@ class MessageTemplate extends LitElement {
- ${reactions.map((reaction)=> { + ${reactions.map((reaction, index)=> { return html` this.sendMessage({ + @click=${() => this.sendMessage({ type: 'reaction', editedMessageObj: this.messageObj, reaction: reaction.type, })} - class="reactions-bg"> - ${reaction.type} ${reaction.qty} - ` + id=${`reactions-${index}`} + class="reactions-bg"> + ${reaction.type} + ${reaction.qty} + 3 ? + ( + `${reaction.users[0].name + ? reaction.users[0].name + : cropAddress(reaction.users[0].address)}, + ${reaction.users[1].name + ? reaction.users[1].name + : cropAddress(reaction.users[1].address)}, + ${reaction.users[2].name + ? reaction.users[2].name + : cropAddress(reaction.users[2].address)} + and ${reaction.users.length - 3} other${(reaction.users.length - 3) > 1 ? "s" : ""} reacted with ${reaction.type}` + ) : reaction.users.length === 3 ? + ( + `${reaction.users[0].name + ? reaction.users[0].name + : cropAddress(reaction.users[0].address)}, + ${reaction.users[1].name + ? reaction.users[1].name + : cropAddress(reaction.users[1].address)} + and + ${reaction.users[2].name + ? reaction.users[2].name + : cropAddress(reaction.users[2].address)} reacted with ${reaction.type}` + ) : reaction.users.length === 2 ? + ( + `${reaction.users[0].name + ? reaction.users[0].name + : cropAddress(reaction.users[0].address)} + and + ${reaction.users[1].name + ? reaction.users[1].name + : cropAddress(reaction.users[1].address)} reacted with ${reaction.type}` + ) : reaction.users.length === 1 ? + ( + `${reaction.users[0].name + ? reaction.users[0].name + : cropAddress(reaction.users[0].address)} reacted with ${reaction.type}` + ) + : "" }> + + + ` })}
From dab0bb6bd4add8927865aa506c767d5fab10ddaa Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Fri, 27 Jan 2023 13:08:49 -0500 Subject: [PATCH 50/76] Paste image into text editor done --- qortal-ui-core/language/us.json | 5 +- .../plugins/core/components/ChatPage.js | 60 +++++++++++++++++-- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index a8d0ab47..dd0cb1d6 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -574,7 +574,8 @@ "cchange65": "Please enter a recipient", "cchange66": "Cannot fetch replied-to message. Message is too old.", "cchange68": "edited", - "cchange69": "Auto-show images" + "cchange69": "Auto-show images", + "cchange70": "This image type is not supported" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -882,4 +883,4 @@ "inf15": "Active Auto Buy Orders", "inf16": "Auto Buy" } -} +} \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 538240e9..3a0484c4 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -830,6 +830,7 @@ class ChatPage extends LitElement { this.getOldMessage = this.getOldMessage.bind(this) this._sendMessage = this._sendMessage.bind(this) this.insertImage = this.insertImage.bind(this) + this.pasteImage = this.pasteImage.bind(this) this.toggleEnableChatEnter = this.toggleEnableChatEnter.bind(this) this._downObserverhandler = this._downObserverhandler.bind(this) this.setOpenTipUser = this.setOpenTipUser.bind(this) @@ -1334,7 +1335,7 @@ class ChatPage extends LitElement { - async connectedCallback() { + async connectedCallback() { super.connectedCallback(); this.webWorker = new WebWorker(); this.webWorkerImage = new WebWorkerImage(); @@ -1411,7 +1412,8 @@ class ChatPage extends LitElement { ] }) document.addEventListener('keydown', this.initialChat); - } + document.addEventListener('paste', this.pasteImage); + } disconnectedCallback() { super.disconnectedCallback(); @@ -1420,7 +1422,8 @@ class ChatPage extends LitElement { this.editor.destroy() this.editorImage.destroy() document.removeEventListener('keydown', this.initialChat); - } + document.removeEventListener('paste', this.pasteImage); + } initialChat(e) { if (this.editor && !this.editor.isFocused && this.currentEditor === '_chatEditorDOM' && !this.openForwardOpen && !this.openTipUser) { @@ -1433,8 +1436,55 @@ class ChatPage extends LitElement { this.editor.commands.focus('end') } } + } - + + async pasteImage (e) { + const event = e; + const handleTransferIntoURL = (dataTransfer) => { + try { + const [firstItem] = dataTransfer.items; + console.log({firstItem}); + const blob = firstItem.getAsFile(); + console.log({blob}); + return blob; + } catch (error) { + console.log(error); + } + } + if (event.clipboardData) { + const blobFound = handleTransferIntoURL(event.clipboardData) + if (blobFound) { + this.insertImage(blobFound); + return; + } else { + const item_list = await navigator.clipboard.read(); + let image_type; + const item = item_list.find(item => + item.types.some( type => { + if (type.startsWith( 'image/')) { + image_type = type; + return true; + } + }) + ); + if (item) { + try { + const blob = item && await item.getType(image_type); + let file = new File([blob], "name", { + type: image_type + }); + this.insertImage(file); + } catch (error) { + console.error(error); + let errorMsg = get("chatpage.cchange70") + parentEpml.request('showSnackBar', `${errorMsg}`) + } + } else { + return + } + } + } } async goToRepliedMessage(message){ @@ -2569,6 +2619,8 @@ class ChatPage extends LitElement { if (!userName) { parentEpml.request('showSnackBar', get("chatpage.cchange27")); this.isLoading = false; + this.isUploadingImage = false; + this.imageFile = null; return; } From c6e98525cbd5f440b31a9606ce6493c25233e8c4 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Fri, 27 Jan 2023 13:39:28 -0500 Subject: [PATCH 51/76] Fixed translations for message reactions --- qortal-ui-core/language/us.json | 8 ++++++-- .../plugins/core/components/ChatScroller.js | 12 ++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index a8d0ab47..7ccf206a 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -574,7 +574,11 @@ "cchange65": "Please enter a recipient", "cchange66": "Cannot fetch replied-to message. Message is too old.", "cchange68": "edited", - "cchange69": "Auto-show images" + "cchange69": "Auto-show images", + "cchange71": "and", + "cchange72": "other", + "cchange73": "s", + "cchange74": "reacted with" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -882,4 +886,4 @@ "inf15": "Active Auto Buy Orders", "inf16": "Auto Buy" } -} +} \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 17e40e3f..eddcb8b6 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -720,7 +720,7 @@ class MessageTemplate extends LitElement { ${reaction.users[2].name ? reaction.users[2].name : cropAddress(reaction.users[2].address)} - and ${reaction.users.length - 3} other${(reaction.users.length - 3) > 1 ? "s" : ""} reacted with ${reaction.type}` + ${get("chatpage.cchange71")} ${reaction.users.length - 3} ${get("chatpage.cchange72")}${(reaction.users.length - 3) > 1 ? html`${get("chatpage.cchange73")}` : ""} ${get("chatpage.cchange74")} ${reaction.type}` ) : reaction.users.length === 3 ? ( `${reaction.users[0].name @@ -729,24 +729,24 @@ class MessageTemplate extends LitElement { ${reaction.users[1].name ? reaction.users[1].name : cropAddress(reaction.users[1].address)} - and + ${get("chatpage.cchange71")} ${reaction.users[2].name ? reaction.users[2].name - : cropAddress(reaction.users[2].address)} reacted with ${reaction.type}` + : cropAddress(reaction.users[2].address)} ${get("chatpage.cchange74")} ${reaction.type}` ) : reaction.users.length === 2 ? ( `${reaction.users[0].name ? reaction.users[0].name : cropAddress(reaction.users[0].address)} - and + ${get("chatpage.cchange71")} ${reaction.users[1].name ? reaction.users[1].name - : cropAddress(reaction.users[1].address)} reacted with ${reaction.type}` + : cropAddress(reaction.users[1].address)} ${get("chatpage.cchange74")} ${reaction.type}` ) : reaction.users.length === 1 ? ( `${reaction.users[0].name ? reaction.users[0].name - : cropAddress(reaction.users[0].address)} reacted with ${reaction.type}` + : cropAddress(reaction.users[0].address)} ${get("chatpage.cchange74")} ${reaction.type}` ) : "" }> From 7f26208e7f2deb922f8355cf23cf458dc9cc9d3a Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 28 Jan 2023 00:41:03 +0200 Subject: [PATCH 52/76] improve lagginess in scroll --- .../plugins/core/components/ChatPage.js | 12 ++----- .../plugins/core/components/ChatScroller.js | 3 -- .../core/messaging/q-chat/q-chat.src.js | 35 ++++++------------- .../plugins/utils/replace-messages-edited.js | 3 -- 4 files changed, 12 insertions(+), 41 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 538240e9..f8566b18 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -1319,7 +1319,6 @@ class ChatPage extends LitElement { name: name ? name : undefined } } catch (error) { - console.log(error) } return memberItem @@ -1328,7 +1327,6 @@ class ChatPage extends LitElement { this.groupMembers = membersWithName this.pageNumber = this.pageNumber + 1 } catch (error) { - console.error(error) } } @@ -1506,7 +1504,6 @@ class ChatPage extends LitElement { this.userFoundModalOpen = true; } catch (error) { this.loading = false; - console.error(error); let err4string = get("chatpage.cchange35"); parentEpml.request('showSnackBar', `${err4string}`) } @@ -1535,7 +1532,6 @@ class ChatPage extends LitElement { const stringifyMessageObject = JSON.stringify(message); this.sendMessage(stringifyMessageObject, undefined, '', true) } catch (error) { - console.log({error}); } } @@ -1638,7 +1634,6 @@ class ChatPage extends LitElement { name: name ? name : undefined } } catch (error) { - console.log(error) } return memberItem @@ -1653,7 +1648,6 @@ class ChatPage extends LitElement { name: name ? name : undefined } } catch (error) { - console.log(error) } return memberItem @@ -1663,7 +1657,6 @@ class ChatPage extends LitElement { this.groupMembers = membersWithName this.groupInfo = getGroupInfo } catch (error) { - console.error(error) } } @@ -1716,10 +1709,10 @@ class ChatPage extends LitElement { if (changedProperties && changedProperties.has('isLoading')) { - if (this.isLoading === true && this.currentEditor === '_chatEditorDOM') { + if (this.isLoading === true && this.currentEditor === '_chatEditorDOM' && this.editor && this.editor.setEditable) { this.editor.setEditable(false) } - if (this.isLoading === false && this.currentEditor === '_chatEditorDOM') { + if (this.isLoading === false && this.currentEditor === '_chatEditorDOM' && this.editor && this.editor.setEditable) { this.editor.setEditable(true) } } @@ -2432,7 +2425,6 @@ class ChatPage extends LitElement { this._publicKey.hasPubKey = false } } catch (error) { - console.error(error); } if(!hasPublicKey || !this._publicKey.hasPubKey){ diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 62033e44..b94fd3f4 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -466,7 +466,6 @@ class MessageTemplate extends LitElement { const parsedMsg = JSON.parse(repliedToData.decodedMessage); repliedToData.decodedMessage = parsedMsg; } catch (error) { - console.error(error); } } @@ -856,7 +855,6 @@ class ChatMenu extends LitElement { this.setForwardProperties(stringifyMessageObject) } catch (error) { - console.log({error}) } } render() { @@ -874,7 +872,6 @@ class ChatMenu extends LitElement { this.setToggledMessage(this.originalMessage) this.emojiPicker.togglePicker(e.target) } catch (error) { - console.log({error}) } }} diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index 11458bd6..8fce2d88 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -1,5 +1,9 @@ import { LitElement, html, css } from 'lit'; import { render } from 'lit/html.js'; +import { passiveSupport } from 'passive-events-support/src/utils' +passiveSupport({ + events: ['touchstart'] + }) import { Epml } from '../../../../epml.js'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'; import { qchatStyles } from './q-chat-css.src.js' @@ -163,6 +167,7 @@ class Chat extends LitElement { } render() { + console.log('q-chat update') return html`
@@ -389,26 +394,7 @@ class Chat extends LitElement { this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation); - // let typingTimer; - // let doneTypingInterval = 3000; - - // //on keyup, start the countdown - // nameInput.addEventListener('keyup', () => { - // clearTimeout(typingTimer); - // if (nameInput.value) { - // console.log("typing started!"); - // typingTimer = setTimeout(this.userSearch, doneTypingInterval); - // } - // }); - - const getDataFromURL = () => { - let tempUrl = document.location.href - let splitedUrl = decodeURI(tempUrl).split('?') - let urlData = splitedUrl[1] - if (urlData !== undefined) { - this.chatId = urlData - } - } + const runFunctionsAfterPageLoad = () => { // Functions to exec after render while waiting for page info... @@ -526,7 +512,6 @@ class Chat extends LitElement { } this.userFoundModalOpen = true; } catch (error) { - console.error(error); let err4string = get("chatpage.cchange35"); parentEpml.request('showSnackBar', `${err4string}`) } @@ -767,7 +752,6 @@ class Chat extends LitElement { }) this.groupInvites = pendingGroupInvites; } catch (error) { - console.error(error); let err4string = get("chatpage.cchange61"); parentEpml.request('showSnackBar', `${err4string}`) } @@ -876,9 +860,10 @@ class Chat extends LitElement { } setChatHeads(chatObj) { - - let groupList = chatObj.groups.map(group => group.groupId === 0 ? { groupId: group.groupId, url: `group/${group.groupId}`, groupName: "Qortal General Chat", timestamp: group.timestamp === undefined ? 2 : group.timestamp } : { ...group, timestamp: group.timestamp === undefined ? 1 : group.timestamp, url: `group/${group.groupId}` }) - let directList = chatObj.direct.map(dc => { + const chatObjGroups = Array.isArray(chatObj.groups) ? chatObj.groups : []; + const chatObjDirect = Array.isArray(chatObj.direct) ? chatObj.direct : []; + let groupList = chatObjGroups.map(group => group.groupId === 0 ? { groupId: group.groupId, url: `group/${group.groupId}`, groupName: "Qortal General Chat", timestamp: group.timestamp === undefined ? 2 : group.timestamp } : { ...group, timestamp: group.timestamp === undefined ? 1 : group.timestamp, url: `group/${group.groupId}` }) + let directList = chatObjDirect.map(dc => { return { ...dc, url: `direct/${dc.address}` } }) const compareNames = (a, b) => { diff --git a/qortal-ui-plugins/plugins/utils/replace-messages-edited.js b/qortal-ui-plugins/plugins/utils/replace-messages-edited.js index 7ee2cb06..5a55ff16 100644 --- a/qortal-ui-plugins/plugins/utils/replace-messages-edited.js +++ b/qortal-ui-plugins/plugins/utils/replace-messages-edited.js @@ -31,7 +31,6 @@ export const replaceMessagesEdited = async ({ } } } catch (error) { - console.log(error) } return msgItem @@ -42,7 +41,6 @@ export const replaceMessagesEdited = async ({ try { parsedMessageObj = JSON.parse(msg.decodedMessage) } catch (error) { - console.log('error') return msg } let msgItem = msg @@ -98,7 +96,6 @@ export const replaceMessagesEdited = async ({ } } } catch (error) { - console.log(error) } return msgItem From f327ce5be62c1db741e47ba9269633096781c3b6 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:40:30 +0100 Subject: [PATCH 53/76] Update us.json --- qortal-ui-core/language/us.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index dd0cb1d6..a8d0ab47 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -574,8 +574,7 @@ "cchange65": "Please enter a recipient", "cchange66": "Cannot fetch replied-to message. Message is too old.", "cchange68": "edited", - "cchange69": "Auto-show images", - "cchange70": "This image type is not supported" + "cchange69": "Auto-show images" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -883,4 +882,4 @@ "inf15": "Active Auto Buy Orders", "inf16": "Auto Buy" } -} \ No newline at end of file +} From 8a72a064d3ee7c08da48a7bc084ef4ba847a9867 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sat, 28 Jan 2023 08:42:00 +0100 Subject: [PATCH 54/76] Update us.json --- qortal-ui-core/language/us.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 7ccf206a..55ad9dd7 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -574,7 +574,8 @@ "cchange65": "Please enter a recipient", "cchange66": "Cannot fetch replied-to message. Message is too old.", "cchange68": "edited", - "cchange69": "Auto-show images", + "cchange69": "Auto-view images", + "cchange70": "This image type is not supported", "cchange71": "and", "cchange72": "other", "cchange73": "s", @@ -886,4 +887,4 @@ "inf15": "Active Auto Buy Orders", "inf16": "Auto Buy" } -} \ No newline at end of file +} From 5abc5f2dc73a82af600d8305641bebe338dd0860 Mon Sep 17 00:00:00 2001 From: "Jaymen.C" <68678251+JaymenChou@users.noreply.github.com> Date: Sat, 28 Jan 2023 18:16:14 +0800 Subject: [PATCH 55/76] Update zht.json Update new variables --- qortal-ui-core/language/zht.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index def41926..f797fd5e 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -574,7 +574,12 @@ "cchange65": "請輸入收件人", "cchange66": "無法獲取回覆消息。消息太舊了。", "cchange68": "編輯", - "cchange69": "自動顯示圖像" + "cchange69": "自動顯示圖像", + "cchange70": "不支援此類型圖像", + "cchange71": "和", + "cchange72": "其他", + "cchange73": "的", + "cchange74": "心情回應" }, "welcomepage": { "wcchange1": "歡迎來到 Q-Chat", From 69a2c61cff09367977459f118cd209a97ebe2fb3 Mon Sep 17 00:00:00 2001 From: "Jaymen.C" <68678251+JaymenChou@users.noreply.github.com> Date: Sat, 28 Jan 2023 18:17:16 +0800 Subject: [PATCH 56/76] Update zhc.json Update new variables --- qortal-ui-core/language/zhc.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index 1dfdff92..4b4ccde5 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -574,7 +574,12 @@ "cchange65": "请输入收件人", "cchange66": "无法获取回覆消息。消息太旧了。", "cchange68": "编辑", - "cchange69": "自动显示图像" + "cchange69": "自动显示图像", + "cchange70": "不支援此类型图像", + "cchange71": "和", + "cchange72": "其他", + "cchange73": "的", + "cchange74": "心情回应" }, "welcomepage": { "wcchange1": "欢迎来到Q-Chat", From dba09d2a7d73c3e7bc08b8dd173ea86bdabf424a Mon Sep 17 00:00:00 2001 From: Phillip Date: Sun, 29 Jan 2023 00:27:01 +0200 Subject: [PATCH 57/76] add packages --- qortal-ui-plugins/package.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index a891f694..7ab1011d 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -21,15 +21,16 @@ "@material/mwc-list": "0.27.0", "@material/mwc-select": "0.27.0", "@tiptap/core": "2.0.0-beta.209", + "@tiptap/extension-highlight": "2.0.0-beta.209", "@tiptap/extension-image": "2.0.0-beta.209", "@tiptap/extension-placeholder": "2.0.0-beta.209", "@tiptap/extension-underline": "2.0.0-beta.209", - "@tiptap/extension-highlight": "2.0.0-beta.209", "@tiptap/html": "2.0.0-beta.209", "@tiptap/starter-kit": "2.0.0-beta.209", "asmcrypto.js": "2.3.2", "compressorjs": "1.1.1", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", + "localforage": "1.10.0", "prosemirror-commands": "1.5.0", "prosemirror-dropcursor": "1.6.1", "prosemirror-gapcursor": "1.3.1", @@ -40,7 +41,6 @@ "prosemirror-state": "1.4.2", "prosemirror-transform": "1.7.0", "prosemirror-view": "1.29.1", - "localforage": "1.10.0", "short-unique-id": "4.4.4" }, "devDependencies": { @@ -48,12 +48,12 @@ "@material/mwc-button": "0.27.0", "@material/mwc-checkbox": "0.27.0", "@material/mwc-dialog": "0.27.0", - "@material/mwc-fab": "0.27.0", "@material/mwc-formfield": "0.27.0", "@material/mwc-icon": "0.27.0", "@material/mwc-icon-button": "0.27.0", "@material/mwc-slider": "0.27.0", "@material/mwc-snackbar": "0.27.0", + "@material/mwc-fab": "0.27.0", "@material/mwc-tab": "0.27.0", "@material/mwc-tab-bar": "0.27.0", "@material/mwc-textfield": "0.27.0", @@ -84,9 +84,10 @@ "rollup": "3.10.1", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", - "rollup-plugin-web-worker-loader": "1.6.1" + "rollup-plugin-web-worker-loader": "1.6.1", + "passive-events-support": "1.0.33" }, "engines": { "node": ">=16.17.1" } -} \ No newline at end of file +} From 64319250a462614b16594e03b5434a1191b6e14c Mon Sep 17 00:00:00 2001 From: Phillip Date: Sun, 29 Jan 2023 00:29:47 +0200 Subject: [PATCH 58/76] remove log --- qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js | 1 - 1 file changed, 1 deletion(-) diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index 8fce2d88..a8b268e5 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -167,7 +167,6 @@ class Chat extends LitElement { } render() { - console.log('q-chat update') return html`
From d5fee6848938dfaed25b6e5d1ce088a09f646aed Mon Sep 17 00:00:00 2001 From: Phillip Date: Sun, 29 Jan 2023 22:00:16 +0200 Subject: [PATCH 59/76] refactor websockets for q-chat --- .../plugins/core/components/ChatPage.js | 40 +++++++++++-------- .../plugins/core/components/ChatTextEditor.js | 1 - .../plugins/utils/replace-messages-edited.js | 2 +- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index f8566b18..2a170104 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -940,7 +940,6 @@ class ChatPage extends LitElement {
` : null} -
${this.isLoadingMessages ? html` @@ -1334,6 +1333,7 @@ class ChatPage extends LitElement { async connectedCallback() { super.connectedCallback(); + await this.initUpdate() this.webWorker = new WebWorker(); this.webWorkerImage = new WebWorkerImage(); await this.getUpdateCompleteTextEditor(); @@ -1413,6 +1413,10 @@ class ChatPage extends LitElement { disconnectedCallback() { super.disconnectedCallback(); + if(this.webSocket){ + this.webSocket.close(1000, 'switch chat') + this.webSocket= '' + } this.webWorker.terminate(); this.webWorkerImage.terminate(); this.editor.destroy() @@ -1561,10 +1565,6 @@ class ChatPage extends LitElement { } async initUpdate(){ - if(this.webSocket){ - this.webSocket.close() - this.webSocket= '' - } this.pageNumber = 1 const getAddressPublicKey = () => { @@ -1691,7 +1691,7 @@ class ChatPage extends LitElement { if(isEnabledChatEnter){ this.isEnabledChatEnter = isEnabledChatEnter === 'false' ? false : true } - await this.initUpdate() + } async updated(changedProperties) { @@ -1703,9 +1703,6 @@ class ChatPage extends LitElement { } } - if (changedProperties && changedProperties.has('chatId') && changedProperties.get('chatId')) { - await this.initUpdate() - } if (changedProperties && changedProperties.has('isLoading')) { @@ -2213,7 +2210,7 @@ class ChatPage extends LitElement { async fetchChatMessages(chatId) { - const initDirect = async (cid) => { + const initDirect = async (cid, noInitial) => { let initial = 0 let directSocketTimeout @@ -2233,17 +2230,15 @@ class ChatPage extends LitElement { } this.webSocket = new WebSocket(directSocketLink); - // Open Connection this.webSocket.onopen = () => { - setTimeout(pingDirectSocket, 50) } // Message Event this.webSocket.onmessage = async (e) => { if (initial === 0) { - + if(noInitial) return const cachedData = null let getInitialMessages = [] if (cachedData && cachedData.length !== 0) { @@ -2275,8 +2270,10 @@ class ChatPage extends LitElement { } // Closed Event - this.webSocket.onclose = () => { + this.webSocket.onclose = (e) => { clearTimeout(directSocketTimeout) + if(e.reason === 'switch chat') return + restartDirectWebSocket() } // Error Event @@ -2291,8 +2288,17 @@ class ChatPage extends LitElement { } }; + const restartDirectWebSocket = () => { + const noInitial = true + setTimeout(() => initDirect(chatId, noInitial), 50) + } + const restartGroupWebSocket = () => { + const noInitial = true + let groupChatId = Number(chatId) + setTimeout(() => initGroup(groupChatId, noInitial), 50) + } - const initGroup = (gId) => { + const initGroup = (gId, noInitial) => { let groupId = Number(gId) let initial = 0 @@ -2325,7 +2331,7 @@ class ChatPage extends LitElement { this.webSocket.onmessage = async (e) => { if (initial === 0) { - + if(noInitial) return const cachedData = null; let getInitialMessages = [] if (cachedData && cachedData.length !== 0) { @@ -2362,6 +2368,8 @@ class ChatPage extends LitElement { // Closed Event this.webSocket.onclose = () => { clearTimeout(groupSocketTimeout) + if(e.reason === 'switch chat') return + restartGroupWebSocket() } // Error Event diff --git a/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js b/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js index 6f1ce796..3c06df95 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js +++ b/qortal-ui-plugins/plugins/core/components/ChatTextEditor.js @@ -375,7 +375,6 @@ mwc-checkbox::shadow .mdc-checkbox::after, mwc-checkbox::shadow .mdc-checkbox::b } render() { - console.log('this.chatId2', this.chatId) return html`
Date: Sun, 29 Jan 2023 23:12:25 +0200 Subject: [PATCH 60/76] put in missing param --- qortal-ui-plugins/plugins/core/components/ChatPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 2a170104..eb1f7926 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -2366,7 +2366,7 @@ class ChatPage extends LitElement { } // Closed Event - this.webSocket.onclose = () => { + this.webSocket.onclose = (e) => { clearTimeout(groupSocketTimeout) if(e.reason === 'switch chat') return restartGroupWebSocket() From a19eea4ad7819b047a290f1f8ae4b3a50606c196 Mon Sep 17 00:00:00 2001 From: Phillip Date: Mon, 30 Jan 2023 00:27:02 +0200 Subject: [PATCH 61/76] add loader to goToReply --- .../plugins/core/components/ChatPage.js | 64 +++++++++++++++---- .../plugins/core/components/ChatScroller.js | 2 +- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index eb1f7926..861cb419 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -103,7 +103,8 @@ class ChatPage extends LitElement { openUserInfo: { type: Boolean }, selectedHead: { type: Object }, userName: { type: String }, - goToRepliedMessage: {attribute: false} + goToRepliedMessage: {attribute: false}, + isLoadingGoToRepliedMessage: {type: Object} } } @@ -890,6 +891,12 @@ class ChatPage extends LitElement { this.currentEditor = '_chatEditorDOM' this.initialChat = this.initialChat.bind(this) this.isEnabledChatEnter = true + this.isLoadingGoToRepliedMessage = { + isLoading: false, + top: 0, + left: 0, + offsetHeight: 0 + } } _toggle(value) { @@ -957,6 +964,9 @@ class ChatPage extends LitElement { ` : this.renderChatScroller()}
+ ${this.isLoadingGoToRepliedMessage && this.isLoadingGoToRepliedMessage.loading ? html` +
+ ` : ''}
this.setSelectedHead(val)} ?openTipUser=${this.openTipUser} .selectedHead=${this.selectedHead} - .goToRepliedMessage=${(val)=> this.goToRepliedMessage(val)} + .goToRepliedMessage=${(val, val2)=> this.goToRepliedMessage(val, val2)} .getOldMessageAfter=${(val)=> this.getOldMessageAfter(val)} > diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index b94fd3f4..e9a9c895 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -554,7 +554,7 @@ class MessageTemplate extends LitElement { ${repliedToData && html`
{ - this.goToRepliedMessage(repliedToData) + this.goToRepliedMessage(repliedToData, this.messageObj) }}>

Date: Mon, 30 Jan 2023 00:56:17 +0200 Subject: [PATCH 62/76] remove log --- qortal-ui-plugins/plugins/core/components/ChatPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index d5118de7..91691e05 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -1535,7 +1535,6 @@ class ChatPage extends LitElement { if((message.timestamp - this.messagesRendered[0].timestamp) < 86400000){ const findOriginalMessage = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById(clickedOnMessage.reference) - console.log({clickedOnMessage, findOriginalMessage}) if(findOriginalMessage){ const messageClientRect = findOriginalMessage.getBoundingClientRect() this.isLoadingGoToRepliedMessage = { From b0b05eba805b3a036ce81b0ea4fcf0d6f3b8983e Mon Sep 17 00:00:00 2001 From: Phillip Date: Mon, 30 Jan 2023 01:42:08 +0200 Subject: [PATCH 63/76] remove log --- qortal-ui-plugins/plugins/core/components/ChatScroller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 0d81986a..1337aef4 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -384,7 +384,6 @@ class MessageTemplate extends LitElement { repliedToData = this.messageObj.repliedToData; isImageDeleted = parsedMessageObj.isImageDeleted; reactions = parsedMessageObj.reactions || []; - console.log(reactions, 'reactions here'); version = parsedMessageObj.version; isForwarded = parsedMessageObj.type === 'forward'; isEdited = parsedMessageObj.isEdited && true; From cc05764863fb554b5e2bc7bd86fba2a557b2a045 Mon Sep 17 00:00:00 2001 From: Phillip Date: Tue, 31 Jan 2023 12:53:25 +0200 Subject: [PATCH 64/76] missing import highlight --- qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index a8b268e5..f4922363 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -28,6 +28,8 @@ import '@vaadin/grid' import StarterKit from '@tiptap/starter-kit' import Underline from '@tiptap/extension-underline'; import Placeholder from '@tiptap/extension-placeholder' +import Highlight from '@tiptap/extension-highlight' + import { Editor, Extension } from '@tiptap/core' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) From 648db552e7943f7bb57a6129945bfdb6df46f6e1 Mon Sep 17 00:00:00 2001 From: Phillip Date: Thu, 2 Feb 2023 10:19:52 +0200 Subject: [PATCH 65/76] fix bug that when a user clicks on a notification and goes back to the app it correctly show the chat page. before it would have an infinite spinner --- .../notification-actions/new-message.js | 5 +-- .../core/messaging/q-chat/q-chat.src.js | 39 ++++++++++++++++--- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/qortal-ui-core/src/notifications/notification-actions/new-message.js b/qortal-ui-core/src/notifications/notification-actions/new-message.js index faaaad32..f430fdd2 100644 --- a/qortal-ui-core/src/notifications/notification-actions/new-message.js +++ b/qortal-ui-core/src/notifications/notification-actions/new-message.js @@ -2,7 +2,6 @@ import { store } from '../../store.js' import { doPageUrl } from '../../redux/app/app-actions.js' export const newMessage = (data) => { - const alert = playSound(data.sound) // Should I show notification ? @@ -18,7 +17,7 @@ export const newMessage = (data) => { } notify.onclick = (e) => { - const pageUrl = `/app/q-chat/${data.req.url}` + const pageUrl = `/app/q-chat/?chat=${data.req.url}` store.dispatch(doPageUrl(pageUrl)) } } else { @@ -26,7 +25,7 @@ export const newMessage = (data) => { const notify = new Notification(data.title, data.options) notify.onclick = (e) => { - const pageUrl = `/app/q-chat/${data.req.url}` + const pageUrl = `/app/q-chat/?chat=${data.req.url}` store.dispatch(doPageUrl(pageUrl)) } } diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index a8b268e5..fbe12aa5 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -29,7 +29,7 @@ import StarterKit from '@tiptap/starter-kit' import Underline from '@tiptap/extension-underline'; import Placeholder from '@tiptap/extension-placeholder' import { Editor, Extension } from '@tiptap/core' - +import Highlight from '@tiptap/extension-highlight' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class Chat extends LitElement { @@ -55,7 +55,7 @@ class Chat extends LitElement { userFoundModalOpen: { type: Boolean }, userSelected: { type: Object }, editor: {type: Object}, - groupInvites: { type: Array } + groupInvites: { type: Array }, } } @@ -118,6 +118,7 @@ class Chat extends LitElement { } async connectedCallback() { + super.connectedCallback(); await this.getUpdateCompleteTextEditor(); @@ -147,15 +148,36 @@ class Chat extends LitElement { }}) ] }) + + this.unsubscribeStore = window.parent.reduxStore.subscribe(() => { + try { + + if(window.parent.location && window.parent.location.search){ + const queryString = window.parent.location.search; + const params = new URLSearchParams(queryString); + const chat = params.get("chat") + if(chat && chat !== this.activeChatHeadUrl){ + let url = window.parent.location.href; + let newUrl = url.split("?")[0]; + window.parent.history.pushState({}, "", newUrl); + this.setActiveChatHeadUrl(chat) + } + } + } catch (error) { + console.error(error) + } + + }); } disconnectedCallback() { super.disconnectedCallback(); - this.editor.destroy() - + this.editor.destroy(); + this.unsubscribeStore(); } + updatePlaceholder(editor, text){ editor.extensionManager.extensions.forEach((extension) => { if (extension.name === "placeholder") { @@ -215,7 +237,7 @@ class Chat extends LitElement {

- ${window.parent.location.pathname !== "/app/q-chat" || this.activeChatHeadUrl ? html`${this.renderChatPage(this.chatId)}` : html`${this.renderChatWelcomePage()}`} + ${this.activeChatHeadUrl ? html`${this.renderChatPage()}` : html`${this.renderChatWelcomePage()}`}
@@ -367,6 +389,8 @@ class Chat extends LitElement { ` } + + async firstUpdated() { this.changeLanguage(); this.changeTheme(); @@ -482,8 +506,11 @@ class Chat extends LitElement { }) }) parentEpml.imReady() + } + + setOpenPrivateMessage(props) { this.openPrivateMessage = props.open; this.shadowRoot.getElementById("sendTo").value = props.name @@ -839,7 +866,7 @@ class Chat extends LitElement { }) } - renderChatPage(chatId) { + renderChatPage() { // Check for the chat ID from and render chat messages // Else render Welcome to Q-CHat From e07884c1e1a718485de3760a4c04581a33167d05 Mon Sep 17 00:00:00 2001 From: Phillip Date: Fri, 3 Feb 2023 16:07:14 +0200 Subject: [PATCH 66/76] last message timestamp with red dot --- qortal-ui-core/language/us.json | 3 +- qortal-ui-core/package.json | 5 +- qortal-ui-core/src/components/app-view.js | 18 ++++ .../src/components/login-view/login-view.js | 6 +- qortal-ui-core/src/plugins/streams.js | 5 ++ .../src/redux/app/actions/app-core.js | 15 +++- .../src/redux/app/app-action-types.js | 4 +- qortal-ui-core/src/redux/app/app-reducer.js | 42 ++++++++- .../plugins/core/components/ChatHead.js | 88 ++++++++++++++++--- .../plugins/core/components/ChatPage.js | 18 ++-- .../plugins/core/components/TimeAgo.js | 3 +- 11 files changed, 178 insertions(+), 29 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 55ad9dd7..6f625f02 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -579,7 +579,8 @@ "cchange71": "and", "cchange72": "other", "cchange73": "s", - "cchange74": "reacted with" + "cchange74": "reacted with", + "cchange90": "No messages" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index 5515942d..8e4f2ad3 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -77,9 +77,10 @@ "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0", - "rollup-plugin-web-worker-loader": "1.6.1" + "rollup-plugin-web-worker-loader": "1.6.1", + "localforage": "1.10.0" }, "engines": { "node": ">=16.17.1" } -} \ No newline at end of file +} diff --git a/qortal-ui-core/src/components/app-view.js b/qortal-ui-core/src/components/app-view.js index cffc315f..60d02813 100644 --- a/qortal-ui-core/src/components/app-view.js +++ b/qortal-ui-core/src/components/app-view.js @@ -4,6 +4,11 @@ import { store } from '../store.js' import { Epml } from '../epml.js' import { addTradeBotRoutes } from '../tradebot/addTradeBotRoutes.js' import { get, translate, translateUnsafeHTML } from 'lit-translate' +import localForage from "localforage"; + +const chatLastSeen = localForage.createInstance({ + name: "chat-last-seen", +}); import '@polymer/paper-icon-button/paper-icon-button.js' import '@polymer/paper-progress/paper-progress.js' @@ -27,6 +32,7 @@ import './user-info-view/user-info-view.js' import '../functional-components/side-menu.js' import '../functional-components/side-menu-item.js' import './start-minting.js' +import { setChatLastSeen } from '../redux/app/app-actions.js' const parentEpml = new Epml({type: 'WINDOW', source: window.parent}) @@ -1386,6 +1392,17 @@ class AppView extends connect(store)(LitElement) { } } + const getChatLastSeen=async() => { + let items = []; + + await chatLastSeen.iterate(function(value, key, iterationNumber) { + + items.push({key, timestamp: value}); + }) + store.dispatch(setChatLastSeen(items)) + return items; + } + await getOpenTradesBTC() await appDelay(1000) await getOpenTradesLTC() @@ -1397,6 +1414,7 @@ class AppView extends connect(store)(LitElement) { await getOpenTradesRVN() await appDelay(1000) await getOpenTradesARRR() + await getChatLastSeen() } async getNodeType() { diff --git a/qortal-ui-core/src/components/login-view/login-view.js b/qortal-ui-core/src/components/login-view/login-view.js index aadc1973..ebdf31f2 100644 --- a/qortal-ui-core/src/components/login-view/login-view.js +++ b/qortal-ui-core/src/components/login-view/login-view.js @@ -14,12 +14,14 @@ import './login-section.js' import '../qort-theme-toggle.js' import settings from '../../functional-components/settings-page.js' -import { addAutoLoadImageChat, removeAutoLoadImageChat } from '../../redux/app/app-actions.js' +import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen } from '../../redux/app/app-actions.js' window.reduxStore = store window.reduxAction = { addAutoLoadImageChat: addAutoLoadImageChat, - removeAutoLoadImageChat: removeAutoLoadImageChat + removeAutoLoadImageChat: removeAutoLoadImageChat, + addChatLastSeen: addChatLastSeen + } const animationDuration = 0.7 // Seconds diff --git a/qortal-ui-core/src/plugins/streams.js b/qortal-ui-core/src/plugins/streams.js index ad6696d1..9cb6c3f7 100644 --- a/qortal-ui-core/src/plugins/streams.js +++ b/qortal-ui-core/src/plugins/streams.js @@ -9,6 +9,7 @@ const CHAT_HEADS_STREAM_NAME = 'chat_heads' const NODE_CONFIG_STREAM_NAME = 'node_config' const COPY_MENU_SWITCH = 'copy_menu_switch' const FRAME_PASTE_MENU_SWITCH = 'frame_paste_menu_switch' +const CHAT_LAST_SEEN = 'chat_last_seen' export const loggedInStream = new EpmlStream(LOGIN_STREAM_NAME, () => store.getState().app.loggedIn) export const configStream = new EpmlStream(CONFIG_STREAM_NAME, () => store.getState().config) @@ -18,6 +19,7 @@ export const chatHeadsStateStream = new EpmlStream(CHAT_HEADS_STREAM_NAME, () => export const nodeConfigStream = new EpmlStream(NODE_CONFIG_STREAM_NAME, () => store.getState().app.nodeConfig) export const copyMenuSwitchStream = new EpmlStream(COPY_MENU_SWITCH, () => store.getState().app.copyMenuSwitch) export const framePasteMenuSwitchStream = new EpmlStream(FRAME_PASTE_MENU_SWITCH, () => store.getState().app.framePasteMenuSwitch) +export const chatLastSeenStream = new EpmlStream(CHAT_LAST_SEEN, () => store.getState().app.chatLastSeen) let oldState = { @@ -46,6 +48,9 @@ store.subscribe(() => { if (oldState.app.framePasteMenuSwitch !== state.app.framePasteMenuSwitch) { framePasteMenuSwitchStream.emit(state.app.framePasteMenuSwitch) } + if (oldState.app.chatLastSeen !== state.app.chatLastSeen) { + chatLastSeenStream.emit(state.app.chatLastSeen) + } if (oldState.app.selectedAddress !== state.app.selectedAddress) { selectedAddressStream.emit({ diff --git a/qortal-ui-core/src/redux/app/actions/app-core.js b/qortal-ui-core/src/redux/app/actions/app-core.js index d91c2fa2..894f2c2e 100644 --- a/qortal-ui-core/src/redux/app/actions/app-core.js +++ b/qortal-ui-core/src/redux/app/actions/app-core.js @@ -1,5 +1,5 @@ // Core App Actions here... -import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT } from '../app-action-types.js' +import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from '../app-action-types.js' export const doUpdateBlockInfo = (blockObj) => { return (dispatch, getState) => { @@ -120,3 +120,16 @@ export const removeAutoLoadImageChat = (payload) => { } } +export const setChatLastSeen = (payload) => { + return { + type: SET_CHAT_LAST_SEEN, + payload + } +} +export const addChatLastSeen = (payload) => { + return { + type: ADD_CHAT_LAST_SEEN, + payload + } +} + diff --git a/qortal-ui-core/src/redux/app/app-action-types.js b/qortal-ui-core/src/redux/app/app-action-types.js index b0bb7813..518d4cd7 100644 --- a/qortal-ui-core/src/redux/app/app-action-types.js +++ b/qortal-ui-core/src/redux/app/app-action-types.js @@ -21,4 +21,6 @@ export const COPY_MENU_SWITCH = 'COPY_MENU_SWITCH' export const PASTE_MENU_SWITCH = 'PASTE_MENU_SWITCH' export const FRAME_PASTE_MENU_SWITCH = 'FRAME_PASTE_MENU_SWITCH' export const ADD_AUTO_LOAD_IMAGES_CHAT = 'ADD_AUTO_LOAD_IMAGES_CHAT' -export const REMOVE_AUTO_LOAD_IMAGES_CHAT = 'REMOVE_AUTO_LOAD_IMAGES_CHAT' \ No newline at end of file +export const REMOVE_AUTO_LOAD_IMAGES_CHAT = 'REMOVE_AUTO_LOAD_IMAGES_CHAT' +export const SET_CHAT_LAST_SEEN = 'SET_CHAT_LAST_SEEN' +export const ADD_CHAT_LAST_SEEN = 'ADD_CHAT_LAST_SEEN' diff --git a/qortal-ui-core/src/redux/app/app-reducer.js b/qortal-ui-core/src/redux/app/app-reducer.js index 6f3d8e1d..68a48675 100644 --- a/qortal-ui-core/src/redux/app/app-reducer.js +++ b/qortal-ui-core/src/redux/app/app-reducer.js @@ -1,9 +1,14 @@ // Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage. import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js' -import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT } from './app-action-types.js' +import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from './app-action-types.js' import { initWorkersReducer } from './reducers/init-workers.js' import { loginReducer } from './reducers/login-reducer.js' import { setNode, addNode } from './reducers/manage-node.js' +import localForage from "localforage"; +const chatLastSeen = localForage.createInstance({ + name: "chat-last-seen", +}); + const INITIAL_STATE = { loggedIn: false, @@ -44,7 +49,8 @@ const INITIAL_STATE = { isOpen: false, elementId: '' }, - autoLoadImageChats: loadStateFromLocalStorage('autoLoadImageChats') || [] + autoLoadImageChats: loadStateFromLocalStorage('autoLoadImageChats') || [], + chatLastSeen: [] } export default (state = INITIAL_STATE, action) => { @@ -169,6 +175,38 @@ export default (state = INITIAL_STATE, action) => { autoLoadImageChats: updatedState } } + case SET_CHAT_LAST_SEEN: { + return { + ...state, + chatLastSeen: action.payload + } + } + case ADD_CHAT_LAST_SEEN: { + const chatId = action.payload.key + const timestamp = action.payload.timestamp + if(!chatId || !timestamp) return state + let newChatLastSeen = [...state.chatLastSeen] + const findChatIndex = state.chatLastSeen.findIndex((chat)=> chat.key === chatId) + if(findChatIndex !== -1){ + + newChatLastSeen[findChatIndex] = { + key: chatId, + timestamp, + } + } + if(findChatIndex === -1){ + + newChatLastSeen = [...newChatLastSeen, { + key: chatId, + timestamp, + }] + } + chatLastSeen.setItem(chatId, timestamp) + return { + ...state, + chatLastSeen: newChatLastSeen + } + } default: return state diff --git a/qortal-ui-plugins/plugins/core/components/ChatHead.js b/qortal-ui-plugins/plugins/core/components/ChatHead.js index c28a583f..7b706e0c 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatHead.js +++ b/qortal-ui-plugins/plugins/core/components/ChatHead.js @@ -1,11 +1,15 @@ import { LitElement, html, css } from 'lit' import { render } from 'lit/html.js' import { Epml } from '../../../epml.js' +import localForage from "localforage"; +import { translate} from 'lit-translate'; import '@material/mwc-icon' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) - +const chatLastSeen = localForage.createInstance({ + name: "chat-last-seen", +}); class ChatHead extends LitElement { static get properties() { return { @@ -15,7 +19,8 @@ class ChatHead extends LitElement { iconName: { type: String }, activeChatHeadUrl: { type: String }, isImageLoaded: { type: Boolean }, - setActiveChatHeadUrl: {attribute: false} + setActiveChatHeadUrl: {attribute: false}, + lastReadMessageTimestamp: {type: Number} } } @@ -24,9 +29,13 @@ class ChatHead extends LitElement { li { width: 100%; - padding: 7px 5px 7px 5px; + padding: 10px 5px 10px 5px; cursor: pointer; width: 100%; + box-sizing: border-box; + display: flex; + align-items: flex-start; + } li:hover { @@ -44,12 +53,21 @@ class ChatHead extends LitElement { color: var(--chat-group); } - .about { - margin-top: 8px; - } + .about { - padding-left: 8px; + + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + margin: 0px; + } + .inner-container { + display: flex; + width: calc(100% - 45px); + flex-direction: column; + justify-content: center; } .status { @@ -64,6 +82,13 @@ class ChatHead extends LitElement { clear: both; height: 0; } + + .name { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } ` } @@ -82,6 +107,7 @@ class ChatHead extends LitElement { this.activeChatHeadUrl = '' this.isImageLoaded = false this.imageFetches = 0 + this.lastReadMessageTimestamp = 0 } createImage(imageUrl) { @@ -108,33 +134,59 @@ class ChatHead extends LitElement { }; return imageHTMLRes; } + updated(){ + } render() { let avatarImg = ''; let backupAvatarImg = '' + let isUnread = false + if(this.chatInfo.name){ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`; avatarImg= this.createImage(avatarUrl) - } + if(this.lastReadMessageTimestamp && this.chatInfo.timestamp){ + if(this.lastReadMessageTimestamp < this.chatInfo.timestamp){ + isUnread = true + } + } + + if(this.activeChatHeadUrl === this.chatInfo.url){ + isUnread = false + } + return html`
  • this.getUrl(this.chatInfo.url)} class="clearfix ${this.activeChatHeadUrl === this.chatInfo.url ? 'active' : ''}"> ${this.isImageLoaded ? html`${avatarImg}` : html`` } ${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? html`account_circle` : html`` } - ${!this.isImageLoaded && this.chatInfo.name ? html`
    ${this.chatInfo.name.charAt(0)}
    `: ''} - ${!this.isImageLoaded && this.chatInfo.groupName ? html`
    ${this.chatInfo.groupName.charAt(0)}
    `: ''} + ${!this.isImageLoaded && this.chatInfo.name ? html`
    ${this.chatInfo.name.charAt(0)}
    `: ''} + ${!this.isImageLoaded && this.chatInfo.groupName ? html`
    ${this.chatInfo.groupName.charAt(0)}
    `: ''} +
    -
    ${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} ${this.chatInfo.groupId !== undefined ? 'lock_open' : 'lock'}
    +
    ${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} ${this.chatInfo.groupId !== undefined ? 'lock_open' : 'lock'}
    +
    +
    +
    +
    + + ${translate('chatpage.cchange90')} +
    +
    +
    +
    +
  • ` } - firstUpdated() { + async firstUpdated() { let configLoaded = false + this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatInfo.url) || 0 parentEpml.ready().then(() => { parentEpml.subscribe('selected_address', async selectedAddress => { this.selectedAddress = {} @@ -142,6 +194,15 @@ class ChatHead extends LitElement { if (!selectedAddress || Object.entries(selectedAddress).length === 0) return this.selectedAddress = selectedAddress }) + parentEpml.subscribe('chat_last_seen', async chatList => { + const parsedChatList = JSON.parse(chatList) + const findChatSeen = parsedChatList.find(chat=> chat.key === this.chatInfo.url) + + if(findChatSeen && this.lastReadMessageTimestamp !== findChatSeen.timestamp){ + this.lastReadMessageTimestamp = findChatSeen.timestamp + this.requestUpdate() + } + }) parentEpml.subscribe('config', c => { if (!configLoaded) { configLoaded = true @@ -156,6 +217,9 @@ class ChatHead extends LitElement { if(changedProperties.has('activeChatHeadUrl')){ return true } + if(changedProperties.has('lastReadMessageTimestamp')){ + return true + } if(changedProperties.has('chatInfo')){ return true } diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 91691e05..8aacdc1b 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -10,7 +10,7 @@ import Highlight from '@tiptap/extension-highlight' import {unsafeHTML} from 'lit/directives/unsafe-html.js'; import { Editor, Extension } from '@tiptap/core' -// import localForage from "localforage"; +import localForage from "localforage"; registerTranslateConfig({ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) }); @@ -42,9 +42,9 @@ import WebWorker from 'web-worker:./computePowWorker.js'; import WebWorkerImage from 'web-worker:./computePowWorkerImage.js'; import '@polymer/paper-dialog/paper-dialog.js' -// const messagesCache = localForage.createInstance({ -// name: "messages-cache", -// }); +const chatLastSeen = localForage.createInstance({ + name: "chat-last-seen", +}); const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -1444,6 +1444,14 @@ class ChatPage extends LitElement { document.removeEventListener('keydown', this.initialChat); document.removeEventListener('paste', this.pasteImage); + if(this.messagesRendered.length !== 0){ + window.parent.reduxStore.dispatch( window.parent.reduxAction.addChatLastSeen({ + key: this.chatId, + timestamp: Date.now() + })) + + } + } initialChat(e) { @@ -1465,9 +1473,7 @@ class ChatPage extends LitElement { const handleTransferIntoURL = (dataTransfer) => { try { const [firstItem] = dataTransfer.items; - console.log({firstItem}); const blob = firstItem.getAsFile(); - console.log({blob}); return blob; } catch (error) { console.log(error); diff --git a/qortal-ui-plugins/plugins/core/components/TimeAgo.js b/qortal-ui-plugins/plugins/core/components/TimeAgo.js index ca3633b7..66164179 100644 --- a/qortal-ui-plugins/plugins/core/components/TimeAgo.js +++ b/qortal-ui-plugins/plugins/core/components/TimeAgo.js @@ -19,7 +19,7 @@ class TimeAgo extends LitElement { updated(changedProps) { changedProps.forEach((OldProp, name) => { - if (name === 'timeIso') { + if (name === 'timeIso' || name === 'timestamp') { this.renderTime(this.timestamp) } }); @@ -35,7 +35,6 @@ class TimeAgo extends LitElement { } render() { - return html` ` From 5c98615d540e2ff8e90a3c59060f8aa8d5be4c65 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 3 Feb 2023 21:19:53 +0100 Subject: [PATCH 67/76] add new search field and sort member column --- .../group-management/group-management.src.js | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js index 0148f33b..3338464c 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js +++ b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js @@ -22,6 +22,8 @@ import '@vaadin/icon' import '@vaadin/icons' import '@vaadin/grid' import '@vaadin/grid/vaadin-grid-filter-column.js' +import '@vaadin/grid/vaadin-grid-sort-column.js' +import '@vaadin/text-field' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -33,6 +35,7 @@ class GroupManagement extends LitElement { privateGroups: { type: Array }, joinedGroups: { type: Array }, groupInvites: { type: Array }, + filteredItems: { type: Array }, privateGroupSearch: { type: Array }, newMembersList: { type: Array }, newAdminsList: { type: Array }, @@ -111,6 +114,9 @@ class GroupManagement extends LitElement { --_lumo-grid-secondary-border-color: var(--border2); } +[part="input-field"] { + background-color: #fff; +} #group-management-page { background: var(--white); padding: 12px 24px; @@ -437,6 +443,7 @@ class GroupManagement extends LitElement { this.privateGroups = [] this.joinedGroups = [] this.groupInvites = [] + this.filteredItems = [] this.privateGroupSearch = [] this.newMembersList = [] this.newAdminsList = [] @@ -1314,8 +1321,8 @@ class GroupManagement extends LitElement {

    ${translate("grouppage.gchange3")}

    - - + + { render(html`${this.renderRole(data.item)}`, root) }}> @@ -1359,11 +1366,25 @@ class GroupManagement extends LitElement {

    ${translate("grouppage.gchange9")}

    - - - - - + + +
    + + + + + { render(html` this.joinGroup(data.item)}>queue ${translate("grouppage.gchange51")}`, root) }}> @@ -1773,7 +1794,8 @@ class GroupManagement extends LitElement { this.publicGroups = results this.privateGroups = _privateGroups this.joinedGroups = _joinedGroups - setTimeout(getOpen_JoinedGroups, 60000) + this.filteredItems = this.publicGroups + setTimeout(getOpen_JoinedGroups, 600000) } window.addEventListener("contextmenu", (event) => { From 24e1028e37aacb99b8777fa002cfd7abe1b25d8f Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sat, 4 Feb 2023 14:07:17 +0100 Subject: [PATCH 68/76] add hide ticker button --- qortal-ui-core/language/de.json | 3 ++- qortal-ui-core/language/es.json | 3 ++- qortal-ui-core/language/fr.json | 3 ++- qortal-ui-core/language/hindi.json | 3 ++- qortal-ui-core/language/hr.json | 3 ++- qortal-ui-core/language/hu.json | 3 ++- qortal-ui-core/language/it.json | 3 ++- qortal-ui-core/language/ko.json | 3 ++- qortal-ui-core/language/no.json | 3 ++- qortal-ui-core/language/pl.json | 5 +++-- qortal-ui-core/language/pt.json | 3 ++- qortal-ui-core/language/ro.json | 3 ++- qortal-ui-core/language/rs.json | 3 ++- qortal-ui-core/language/ru.json | 3 ++- qortal-ui-core/language/us.json | 3 ++- qortal-ui-core/language/zhc.json | 3 ++- qortal-ui-core/language/zht.json | 3 ++- qortal-ui-core/src/components/app-view.js | 25 +++++++++++++++++++++-- 18 files changed, 58 insertions(+), 20 deletions(-) diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index 00f413af..f55a563e 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -657,7 +657,8 @@ "gchange55": "Private Gruppe suchen", "gchange56": "Zu suchender Gruppenname", "gchange57": "Privater Gruppenname nicht gefunden", - "gchange58": "Beachten Sie, dass der Gruppenname genau übereinstimmen muss." + "gchange58": "Beachten Sie, dass der Gruppenname genau übereinstimmen muss.", + "gchange59": "Ticker ein-/ausblenden" }, "puzzlepage": { "pchange1": "Rätsel", diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index 1c378f28..b7c9c8ba 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -657,7 +657,8 @@ "gchange55": "Buscar grupo privado", "gchange56": "Nombre del grupo a buscar", "gchange57": "Nombre de grupo privado no encontrado", - "gchange58": "Tenga en cuenta que el nombre del grupo debe coincidir exactamente." + "gchange58": "Tenga en cuenta que el nombre del grupo debe coincidir exactamente.", + "gchange59": "Mostrar/ocultar teletipo" }, "puzzlepage": { "pchange1": "Rompecabezas", diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index 3aef9139..ab1adae2 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -657,7 +657,8 @@ "gchange55": "Rechercher un groupe privé", "gchange56": "Nom du groupe à rechercher", "gchange57": "Nom de groupe privé introuvable", - "gchange58": "Notez que le nom du groupe doit correspondre exactement." + "gchange58": "Notez que le nom du groupe doit correspondre exactement.", + "gchange59": "Afficher / Masquer le téléscripteur" }, "puzzlepage": { "pchange1": "Puzzles", diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index 1601ffdf..ac392733 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -658,7 +658,8 @@ "gchange55": "निजी समूह खोजें", "gchange56": "खोजने के लिए समूह का नाम", "gchange57": "निजी समूह का नाम नहीं मिला", - "gchange58": "ध्यान दें कि समूह का नाम सटीक मेल खाना चाहिए।" + "gchange58": "ध्यान दें कि समूह का नाम सटीक मेल खाना चाहिए।", + "gchange59": "टिकर दिखाएं / छुपाएं" }, "puzzlepage": { "pchange1": "पहेलि", diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index 0a18cf7c..5759c849 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -657,7 +657,8 @@ "gchange55": "Traži privatnu grupu", "gchange56": "Naziv grupe za pretraživanje", "gchange57": "Ime privatne grupe nije pronađeno", - "gchange58": "Imajte na umu da se naziv grupe mora točno podudarati." + "gchange58": "Imajte na umu da se naziv grupe mora točno podudarati.", + "gchange59": "Prikaži / sakrij ticker" }, "puzzlepage": { "pchange1": "Zagonetke", diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index e0480559..6e7e8ee9 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -657,7 +657,8 @@ "gchange55": "Keresés privát csoportban", "gchange56": "A keresendő csoport neve", "gchange57": "A privát csoport neve nem található", - "gchange58": "Ne feledje, hogy a csoport nevének pontosan meg kell egyeznie." + "gchange58": "Ne feledje, hogy a csoport nevének pontosan meg kell egyeznie.", + "gchange59": "Ticker megjelenítése / elrejtése" }, "puzzlepage": { "pchange1": "Rejtvények", diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index 0f3c6058..e4a5c8c2 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -657,7 +657,8 @@ "gchange55": "Cerca gruppo privato", "gchange56": "Nome gruppo da cercare", "gchange57": "Nome gruppo privato non trovato", - "gchange58": "Nota che il nome del gruppo deve corrispondere esattamente." + "gchange58": "Nota che il nome del gruppo deve corrispondere esattamente.", + "gchange59": "Mostra / Nascondi ticker" }, "puzzlepage": { "pchange1": "Puzzle", diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index baf03675..e5db9895 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -657,7 +657,8 @@ "gchange55": "비공개 그룹 검색", "gchange56": "검색할 그룹 이름", "gchange57": "비공개 그룹 이름을 찾을 수 없음", - "gchange58": "그룹 이름이 정확히 일치해야 합니다." + "gchange58": "그룹 이름이 정확히 일치해야 합니다.", + "gchange59": "티커 표시/숨기기" }, "puzzlepage": { "pchange1": "퍼즐", diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index d6833c6e..791e89b5 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -657,7 +657,8 @@ "gchange55": "Søk i privat gruppe", "gchange56": "Gruppenavn å søke", "gchange57": "Privat gruppenavn ikke funnet", - "gchange58": "Merk at gruppenavnet må samsvare nøyaktig." + "gchange58": "Merk at gruppenavnet må samsvare nøyaktig.", + "gchange59": "Vis / Skjul Ticker" }, "puzzlepage": { "pchange1": "Puzzles", diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index 32935439..3100be86 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -657,7 +657,8 @@ "gchange55": "Wyszukaj grupę prywatną", "gchange56": "Nazwa grupy do wyszukania", "gchange57": "Nie znaleziono nazwy grupy prywatnej", - "gchange58": "Zauważ, że nazwa grupy musi dokładnie pasować." + "gchange58": "Zauważ, że nazwa grupy musi dokładnie pasować.", + "gchange59": "Pokaż / Ukryj Znacznik" }, "puzzlepage": { "pchange1": "Zagadki", @@ -868,7 +869,7 @@ "inf9": "„Automatyczne kupowanie” to funkcja umożliwiająca składanie „zleceń kupna” w portalu handlowym. Te „zlecenia kupna” są widoczne tylko dla osoby, która je składa. Nie są to „publiczne” zlecenia kupna, jak np. „sprzedaże z otwartego rynku” są i NIE są przechowywane w łańcuchu blokowym Qortal. Auto Buy to funkcja interfejsu użytkownika i jako taka wymaga, aby interfejs użytkownika URUCHAMIAŁ.", "inf10": "Aby złożyć zamówienie automatycznego zakupu, kliknij przycisk „Dodaj zamówienie automatycznego zakupu” i wypełnij pole, które się pojawi. Wprowadź KWOTĘ KWARTOŚCI, którą chcesz KUPIĆ, oraz CENĘ, do której chcesz KUPIĆ. Raz zamówienie jest aktywne, Auto Buy kupi dla ciebie DO tej kwoty QORT, po MAKSYMALNIE ustalonej cenie (zaczynając od najniższego zamówienia i przesuwając się w górę).", "inf11": "Po prostu ZOSTAW DZIAŁAJĄCY UI, a Auto Buy zrobi resztę automatycznie!", - "inf12": "MOŻESZ przeglądać inne wtyczki w interfejsie użytkownika (Q-Chat, portfele itp.), ale NIE MOŻESZ ZAMKNĄĆ interfejsu użytkownika, jeśli chcesz, aby zakup automatyczny został zakończony. Pozostawienie interfejsu użytkownika „zminimalizowanego” na „pasku zadań” lub „panel” jest w porządku, o ile interfejs użytkownika pozostaje OTWARTY, Auto Buy będzie działać." + "inf12": "MOŻESZ przeglądać inne wtyczki w interfejsie użytkownika (Q-Chat, portfele itp.), ale NIE MOŻESZ ZAMKNĄĆ interfejsu użytkownika, jeśli chcesz, aby zakup automatyczny został zakończony. Pozostawienie interfejsu użytkownika „zminimalizowanego” na „pasku zadań” lub „panel” jest w porządku, o ile interfejs użytkownika pozostaje OTWARTY, Auto Buy będzie działać.", "inf13": "Kup automatycznie", "inf14": "z", "inf15": "Aktywne automatyczne zamówienia zakupu", diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index 42cda962..6e5e33b6 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -657,7 +657,8 @@ "gchange55": "Pesquisar Grupo Privado", "gchange56": "Nome do grupo para pesquisar", "gchange57": "Nome do grupo privado não encontrado", - "gchange58": "Observe que o nome do grupo deve corresponder exatamente." + "gchange58": "Observe que o nome do grupo deve corresponder exatamente.", + "gchange59": "Mostrar / Ocultar Ticker" }, "puzzlepage": { "pchange1": "Enigmas", diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index 3037c208..756c8fce 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -657,7 +657,8 @@ "gchange55": "Căutați grup privat", "gchange56": "Numele grupului de căutat", "gchange57": "Numele grupului privat nu a fost găsit", - "gchange58": "Rețineți că numele grupului trebuie să se potrivească exact." + "gchange58": "Rețineți că numele grupului trebuie să se potrivească exact.", + "gchange59": "Afișează / Ascunde Ticker" }, "puzzlepage": { "pchange1": "Puzzle-uri", diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index 791753b6..61a6f04b 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -657,7 +657,8 @@ "gchange55": "Pretraži privatnu grupu", "gchange56": "Ime grupe za pretragu", "gchange57": "Ime privatne grupe nije pronađeno", - "gchange58": "Imajte na umu da ime grupe mora potpuno da se podudara." + "gchange58": "Imajte na umu da ime grupe mora potpuno da se podudara.", + "gchange59": "Prikaži / Sakrij Oznaku" }, "puzzlepage": { "pchange1": "Slagalice", diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index cd7e54f4..dfcaa64d 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -657,7 +657,8 @@ "gchange55": "Поиск в закрытой группе", "gchange56": "Имя группы для поиска", "gchange57": "Имя частной группы не найдено", - "gchange58": "Обратите внимание, что название группы должно точно совпадать." + "gchange58": "Обратите внимание, что название группы должно точно совпадать.", + "gchange59": "Показать/скрыть бегущую строку" }, "puzzlepage": { "pchange1": "Головоломки", diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 55ad9dd7..87760fd7 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -670,7 +670,8 @@ "gchange55": "Search Private Group", "gchange56": "Group Name To Search", "gchange57": "Private Group Name Not Found", - "gchange58": "Note that group name must exact match." + "gchange58": "Note that group name must exact match.", + "gchange59": "Show / Hide Ticker" }, "puzzlepage": { "pchange1": "Puzzles", diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index 4b4ccde5..57fe5ec0 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -670,7 +670,8 @@ "gchange55": "搜索私人群组", "gchange56": "要搜索的群组名称", "gchange57": "未找到私人群组名称", - "gchange58": "注意群组名称必须完全匹配。" + "gchange58": "注意群组名称必须完全匹配。", + "gchange59": "显示/隐藏代码" }, "puzzlepage": { "pchange1": "益智游戏", diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index f797fd5e..457d0bc4 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -670,7 +670,8 @@ "gchange55": "搜索私人群組", "gchange56": "要搜索的群組名稱", "gchange57": "未找到私人群組名稱", - "gchange58": "注意群組名稱必須完全匹配。" + "gchange58": "注意群組名稱必須完全匹配。", + "gchange59": "顯示/隱藏代碼" }, "puzzlepage": { "pchange1": "益智游戲", diff --git a/qortal-ui-core/src/components/app-view.js b/qortal-ui-core/src/components/app-view.js index cffc315f..5e9c58de 100644 --- a/qortal-ui-core/src/components/app-view.js +++ b/qortal-ui-core/src/components/app-view.js @@ -207,7 +207,7 @@ class AppView extends connect(store)(LitElement) { #balanceheader { flex: 0 0 24px; - padding: 12px 12px 20px 12px; + padding: 12px 12px 45px 12px; border-bottom: 1px solid var(--border); background: var(--sidetopbar); } @@ -329,7 +329,16 @@ class AppView extends connect(store)(LitElement) { .sideBarMenu::-webkit-scrollbar-thumb:hover { background-color: rgb(148, 146, 146); cursor: pointer; - } + } + + .balanceButton { + background-color: #03a9f4; + color: #ffffff; + margin-left: 12px; + margin-right: 12px; + padding-top: 5px; + padding-bottom: 5px; + } ` ] } @@ -426,6 +435,8 @@ class AppView extends connect(store)(LitElement) {
    + +
    @@ -1399,6 +1411,15 @@ class AppView extends connect(store)(LitElement) { await getOpenTradesARRR() } + shBalanceTicker() { + const targetDiv = this.shadowRoot.getElementById("theTicker") + if (targetDiv.style.display !== "none") { + targetDiv.style.display = "none"; + } else { + targetDiv.style.display = "inline"; + } + } + async getNodeType() { const myAppNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node] const nodeAppUrl = myAppNode.protocol + '://' + myAppNode.domain + ':' + myAppNode.port From b674fd2e6980cae96d9d4106dd89a9dbc9c66018 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sat, 4 Feb 2023 14:26:54 +0100 Subject: [PATCH 69/76] change update error string --- locales/bg.json | 2 +- locales/de.json | 2 +- locales/en.json | 2 +- locales/es.json | 2 +- locales/fr.json | 2 +- locales/it.json | 2 +- locales/ko.json | 2 +- locales/nl.json | 2 +- locales/pt.json | 2 +- locales/pt_BR.json | 2 +- locales/ru_RU.json | 2 +- locales/tr.json | 2 +- locales/uk.json | 2 +- locales/zh_CN.json | 2 +- locales/zh_TW.json | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/locales/bg.json b/locales/bg.json index 2b9de1c2..17038a8a 100644 --- a/locales/bg.json +++ b/locales/bg.json @@ -10,7 +10,7 @@ "electron_translate_7": "Актуализацията е готова за инсталиране", "electron_translate_8": "Беше изтеглена нова версия на Qortal UI.", "electron_translate_9": "Щракнете върху ИНСТАЛИРАНЕ СЕГА, за да приложите актуализация, МОЖЕ БИ ПО-КЪСНО, за да не актуализирате потребителския интерфейс.", - "electron_translate_10": "Грешка при актуализиране...", + "electron_translate_10": "Временна неуспешна актуализация, ще опитаме отново по-късно", "electron_translate_11": "ИЗТЕГЛЕТЕ АКТУАЛИЗАЦИЯТА", "electron_translate_12": "Ще бъде изтеглено ⌛️ във фонов режим!" } \ No newline at end of file diff --git a/locales/de.json b/locales/de.json index 590401f2..6761d651 100644 --- a/locales/de.json +++ b/locales/de.json @@ -10,7 +10,7 @@ "electron_translate_7": "Update zur Installation bereit", "electron_translate_8": "Eine neue Qortal-UI-Version wurde heruntergeladen.", "electron_translate_9": "Klicken Sie auf JETZT INSTALLIEREN, um das Update anzuwenden, VIELLEICHT SPÄTER, um die Benutzeroberfläche nicht zu aktualisieren.", - "electron_translate_10": "Fehler beim Aktualisieren...", + "electron_translate_10": "Vorübergehender Aktualisierungsfehler, wir versuchen es später erneut", "electron_translate_11": "UPDATE HERUNTERLADEN", "electron_translate_12": "Das Update wird im Hintergrund heruntergeladen ⌛️!" } \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index a10a2de0..177e5ca7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -10,7 +10,7 @@ "electron_translate_7": "Update ready to install", "electron_translate_8": "A new Qortal UI version has been downloaded.", "electron_translate_9": "Click INSTALL NOW to apply update, MAYBE LATER to not update the UI.", - "electron_translate_10": "Error while Updating...", + "electron_translate_10": "Temporary update failure, will try again later", "electron_translate_11": "DOWNLOAD UPDATE", "electron_translate_12": "It will be downloaded ⌛️ in the background!" } \ No newline at end of file diff --git a/locales/es.json b/locales/es.json index 552305c9..9aec6683 100644 --- a/locales/es.json +++ b/locales/es.json @@ -10,7 +10,7 @@ "electron_translate_7": "Actualización lista para instalar", "electron_translate_8": "Se ha descargado una nueva versión de la interfaz de usuario de Qortal.", "electron_translate_9": "Haz clic en INSTALAR AHORA para aplicar la actualización, QUIZÁS MÁS TARDE para no actualizar la interfaz de usuario"., - "electron_translate_10": "Error al actualizar...", + "electron_translate_10": "Error de actualización temporal, lo intentaré más tarde", "electron_translate_11": "DESCARGAR ACTUALIZACIÓN", "electron_translate_12": "¡Se descargará ⌛️ en segundo plano!" } \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index 624cbdee..4b8a821e 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -10,7 +10,7 @@ "electron_translate_7": "Mise à jour prête à installer", "electron_translate_8": "Une nouvelle version de l'interface utilisateur de Qortal a été téléchargée.", "electron_translate_9": "Cliquez sur INSTALLER MAINTENANT pour appliquer la mise à jour, PEUT-ÊTRE PLUS TARD pour ne pas mettre à jour l'interface utilisateur.", - "electron_translate_10": "Erreur lors de la mise à jour...", + "electron_translate_10": "Échec de la mise à jour temporaire, réessayera plus tard", "electron_translate_11": "TÉLÉCHARGER LA MISE À JOUR", "electron_translate_12": "Il sera téléchargé ⌛️ en arrière-plan !" } \ No newline at end of file diff --git a/locales/it.json b/locales/it.json index bd851cd6..de35772c 100644 --- a/locales/it.json +++ b/locales/it.json @@ -10,7 +10,7 @@ "electron_translate_7": "Aggiornamento pronto per l'installazione", "electron_translate_8": "È stata scaricata una nuova versione dell'interfaccia utente di Qortal.", "electron_translate_9": "Fai clic su INSTALLA ORA per applicare l'aggiornamento, FORSE DOPO per non aggiornare l'interfaccia utente.", - "electron_translate_10": "Errore durante l'aggiornamento...", + "electron_translate_10": "Errore di aggiornamento temporaneo, riproverà più tardi", "electron_translate_11": "SCARICA AGGIORNAMENTO", "electron_translate_12": "Verrà scaricato ⌛️ in background!" } \ No newline at end of file diff --git a/locales/ko.json b/locales/ko.json index 65f679d4..3b89345d 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -10,7 +10,7 @@ "electron_translate_7": "업데이트 설치 준비 완료", "electron_translate_8": "새로운 Qortal UI 버전이 다운로드되었습니다.", "electron_translate_9": "업데이트를 적용하려면 지금 설치를 클릭하고 UI를 업데이트하지 않으려면 나중에 할 수도 있습니다.", - "electron_translate_10": "업데이트 중 오류...", + "electron_translate_10": "임시 업데이트 실패, 나중에 다시 시도합니다.", "electron_translate_11": "업데이트 다운로드", "electron_translate_12": "백그라운드에서 ⌛️ 다운로드됩니다!" } \ No newline at end of file diff --git a/locales/nl.json b/locales/nl.json index 73756911..82bd482f 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -10,7 +10,7 @@ "electron_translate_7": "Update klaar om te installeren", "electron_translate_8": "Er is een nieuwe Qortal UI-versie gedownload.", "electron_translate_9": "Klik op NU INSTALLEREN om de update toe te passen, MISSCHIEN LATER om de gebruikersinterface niet bij te werken.", - "electron_translate_10": "Fout tijdens updaten...", + "electron_translate_10": "Tijdelijke update mislukt, zal het later opnieuw proberen", "electron_translate_11": "UPDATE DOWNLOADEN", "electron_translate_12": "Het wordt ⌛️ op de achtergrond gedownload!" } \ No newline at end of file diff --git a/locales/pt.json b/locales/pt.json index 516e26cd..7a02c1b5 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -10,7 +10,7 @@ "electron_translate_7": "Atualização pronta para instalar", "electron_translate_8": "Uma nova versão Qortal UI foi baixada.", "electron_translate_9": "Clique em INSTALAR AGORA para aplicar a atualização, TALVEZ MAIS TARDE para não atualizar a UI.", - "electron_translate_10": "Erro ao atualizar...", + "electron_translate_10": "Falha de atualização temporária, tentará novamente mais tarde", "electron_translate_11": "BAIXAR ATUALIZAÇÃO", "electron_translate_12": "Será baixado ⌛️ em segundo plano!" } \ No newline at end of file diff --git a/locales/pt_BR.json b/locales/pt_BR.json index 6e272b8d..9293187f 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -10,7 +10,7 @@ "electron_translate_7": "Atualização pronta para instalar", "electron_translate_8": "Uma nova versão Qortal UI foi baixada.", "electron_translate_9": "Clique em INSTALAR AGORA para aplicar a atualização, TALVEZ MAIS TARDE para não atualizar a UI.", - "electron_translate_10": "Erro ao atualizar...", + "electron_translate_10": "Falha de atualização temporária, tentará novamente mais tarde", "electron_translate_11": "BAIXAR ATUALIZAÇÃO", "electron_translate_12": "Será baixado ⌛️ em segundo plano!" } \ No newline at end of file diff --git a/locales/ru_RU.json b/locales/ru_RU.json index c0f6ff7c..09a1e79d 100644 --- a/locales/ru_RU.json +++ b/locales/ru_RU.json @@ -10,7 +10,7 @@ "electron_translate_7": "Обновление готово к установке", "electron_translate_8": "Загружена новая версия пользовательского интерфейса Qortal.", "electron_translate_9": "Нажмите УСТАНОВИТЬ СЕЙЧАС, чтобы применить обновление, МОЖЕТ БЫТЬ ПОЗЖЕ, чтобы не обновлять пользовательский интерфейс.", - "electron_translate_10": "Ошибка при обновлении...", + "electron_translate_10": "Временная ошибка обновления, повторите попытку позже", "electron_translate_11": "СКАЧАТЬ ОБНОВЛЕНИЕ", "electron_translate_12": "Он будет загружен ⌛️ в фоновом режиме!" } \ No newline at end of file diff --git a/locales/tr.json b/locales/tr.json index 11491409..b3b089f2 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -10,7 +10,7 @@ "electron_translate_7": "Güncelleme yüklenmeye hazır", "electron_translate_8": "Yeni bir Qortal UI sürümü indirildi.", "electron_translate_9": "Güncellemeyi uygulamak için ŞİMDİ YÜKLE'ye tıklayın, kullanıcı arayüzünü güncellememek için MAYBE SONRA tıklayın.", - "electron_translate_10": "Güncelleme Sırasında Hata...", + "electron_translate_10": "Geçici güncelleme hatası, daha sonra tekrar denenecek", "electron_translate_11": "GÜNCELLEMEYİ İNDİRİN", "electron_translate_12": "Arka planda ⌛️ indirilecek!" } \ No newline at end of file diff --git a/locales/uk.json b/locales/uk.json index 1e52aca0..a3ef9499 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -10,7 +10,7 @@ "electron_translate_7": "Update ready to install", "electron_translate_8": "A new Qortal UI version has been downloaded.", "electron_translate_9": "Click INSTALL NOW to apply update, MAYBE LATER to not update the UI.", - "electron_translate_10": "Error while Updating...", + "electron_translate_10": "Temporary update failure, will try again later", "electron_translate_11": "DOWNLOAD UPDATE", "electron_translate_12": "It will be downloaded ⌛️ in the background!" } \ No newline at end of file diff --git a/locales/zh_CN.json b/locales/zh_CN.json index 7fe1625d..b0f3e0e4 100644 --- a/locales/zh_CN.json +++ b/locales/zh_CN.json @@ -10,7 +10,7 @@ "electron_translate_7": "更新准备安装", "electron_translate_8": "已下载新的 Qortal UI 版本。", "electron_translate_9": "点击现在安装应用更新,可能稍后不更新用户界面。", - "electron_translate_10": "更新时出错...", + "electron_translate_10": "暂时更新失败,稍后再试", "electron_translate_11": "下载更新", "electron_translate_12": "它将在后台下载 ⌛️!" } \ No newline at end of file diff --git a/locales/zh_TW.json b/locales/zh_TW.json index 07182899..ae8699a5 100644 --- a/locales/zh_TW.json +++ b/locales/zh_TW.json @@ -10,7 +10,7 @@ "electron_translate_7": "更新準備安裝", "electron_translate_8": "已下載新的 Qortal UI 版本。", "electron_translate_9": "點擊現在安裝應用更新,可能稍後不更新用戶界面。", - "electron_translate_10": "更新時出錯...", + "electron_translate_10": "暫時更新失敗,稍後再試", "electron_translate_11": "下載更新", "electron_translate_12": "它將在後台下載 ⌛️!" } \ No newline at end of file From fe9af1dc828f07e0bfc8b2975e94b64d801b39f1 Mon Sep 17 00:00:00 2001 From: Phillip Date: Sat, 4 Feb 2023 17:34:43 +0200 Subject: [PATCH 70/76] fix avatar issue --- .../plugins/core/components/ChatHead.js | 22 ++++++++++++++----- .../core/messaging/q-chat/q-chat.src.js | 8 +++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatHead.js b/qortal-ui-plugins/plugins/core/components/ChatHead.js index 7b706e0c..61a30fb2 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatHead.js +++ b/qortal-ui-plugins/plugins/core/components/ChatHead.js @@ -108,9 +108,10 @@ class ChatHead extends LitElement { this.isImageLoaded = false this.imageFetches = 0 this.lastReadMessageTimestamp = 0 + this.loggedInAddress = window.parent.reduxStore.getState().app.selectedAddress.address } - createImage(imageUrl) { + createImage(imageUrl) { const imageHTMLRes = new Image(); imageHTMLRes.src = imageUrl; imageHTMLRes.style= "width:40px; height:40px; float: left; border-radius:50%"; @@ -125,7 +126,7 @@ class ChatHead extends LitElement { setTimeout(() => { this.imageFetches = this.imageFetches + 1; imageHTMLRes.src = imageUrl; - }, 500); + }, 750); } else { @@ -134,9 +135,9 @@ class ChatHead extends LitElement { }; return imageHTMLRes; } - updated(){ - } + + render() { let avatarImg = ''; let backupAvatarImg = '' @@ -158,7 +159,10 @@ class ChatHead extends LitElement { if(this.activeChatHeadUrl === this.chatInfo.url){ isUnread = false } - + + if(this.chatInfo.sender === this.loggedInAddress){ + isUnread = false + } return html`
  • this.getUrl(this.chatInfo.url)} class="clearfix ${this.activeChatHeadUrl === this.chatInfo.url ? 'active' : ''}"> ${this.isImageLoaded ? html`${avatarImg}` : html`` } @@ -221,6 +225,14 @@ class ChatHead extends LitElement { return true } if(changedProperties.has('chatInfo')){ + + const prevChatInfo = changedProperties.get('chatInfo') + + if(prevChatInfo.address !== this.chatInfo.address){ + + this.isImageLoaded = false + this.requestUpdate() + } return true } diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index fbe12aa5..872802d6 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -8,6 +8,7 @@ import { Epml } from '../../../../epml.js'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'; import { qchatStyles } from './q-chat-css.src.js' import WebWorker from 'web-worker:./computePowWorker.src.js'; +import {repeat} from 'lit/directives/repeat.js'; registerTranslateConfig({ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) @@ -856,14 +857,11 @@ class Chat extends LitElement { } renderChatHead(chatHeadArr) { - - let tempUrl = document.location.href - let splitedUrl = decodeURI(tempUrl).split('?') - // let activeChatHeadUrl = splitedUrl[1] === undefined ? '' : splitedUrl[1] - + return chatHeadArr.map(eachChatHead => { return html` this.setActiveChatHeadUrl(val)} chatInfo=${JSON.stringify(eachChatHead)}>` }) + } renderChatPage() { From 96e235ef92846e72b41489428fc19d8eb35c0962 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Sat, 4 Feb 2023 23:11:15 -0500 Subject: [PATCH 71/76] Fix error due to duplicate line SyntaxError: Identifier 'Highlight' has already been declared --- qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index b62fea3f..e618a1b0 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -32,7 +32,6 @@ import Placeholder from '@tiptap/extension-placeholder' import Highlight from '@tiptap/extension-highlight' import { Editor, Extension } from '@tiptap/core' -import Highlight from '@tiptap/extension-highlight' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class Chat extends LitElement { @@ -982,4 +981,4 @@ class Chat extends LitElement { } } -window.customElements.define('q-chat', Chat) \ No newline at end of file +window.customElements.define('q-chat', Chat) From 330f556f15020c40d064a0c573672666e115c61c Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sun, 5 Feb 2023 13:36:14 +0100 Subject: [PATCH 72/76] Update Translations --- qortal-ui-core/language/de.json | 17 +++++++++++++++-- qortal-ui-core/language/es.json | 17 +++++++++++++++-- qortal-ui-core/language/fr.json | 17 +++++++++++++++-- qortal-ui-core/language/hindi.json | 17 +++++++++++++++-- qortal-ui-core/language/hr.json | 17 +++++++++++++++-- qortal-ui-core/language/hu.json | 17 +++++++++++++++-- qortal-ui-core/language/it.json | 17 +++++++++++++++-- qortal-ui-core/language/ko.json | 17 +++++++++++++++-- qortal-ui-core/language/no.json | 17 +++++++++++++++-- qortal-ui-core/language/pl.json | 17 +++++++++++++++-- qortal-ui-core/language/pt.json | 17 +++++++++++++++-- qortal-ui-core/language/ro.json | 17 +++++++++++++++-- qortal-ui-core/language/rs.json | 17 +++++++++++++++-- qortal-ui-core/language/ru.json | 17 +++++++++++++++-- qortal-ui-core/language/us.json | 3 +-- 15 files changed, 211 insertions(+), 30 deletions(-) diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index f55a563e..326683b0 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -574,7 +574,12 @@ "cchange65": "Bitte geben Sie einen Empfänger ein", "cchange66": "Beantwortete Nachricht kann nicht abgerufen werden. Nachricht ist zu alt.", "cchange68": "bearbeitet", - "cchange69": "Zeige Bilder automatisch" + "cchange69": "Zeige Bilder automatisch", + "cchange70": "Dieser Bildtyp wird nicht unterstützt", + "cchange71": "und", + "cchange72": "andere", + "cchange73": "s", + "cchange74": "reagiert mit" }, "welcomepage": { "wcchange1": "Willkommen zu Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENÜ", "bcchange8": "Adresse Kopieren", "bcchange9": "Private Nachricht", - "bcchange10": "Mehr" + "bcchange10": "Mehr", + "bcchange11": "Antworten", + "bcchange12": "Bearbeiten", + "bcchange13": "Reaktion", + "bcchange14": "Weiterleiten", + "bcchange15": "Nachricht weitergeleitet", + "bcchange16": "Empfänger auswählen oder darunter suchen", + "bcchange17": "WEITERGELEITET", + "bcchange18": "Tipp Benutzer" }, "grouppage": { "gchange1": "Qortal-Gruppen", diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index b7c9c8ba..82e6dce4 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -574,7 +574,12 @@ "cchange65": "Ingrese un destinatario", "cchange66": "No se puede recuperar el mensaje respondido. El mensaje es demasiado antiguo.", "cchange68": "editado", - "cchange69": "Mostrar imágenes automáticamente" + "cchange69": "Mostrar imágenes automáticamente", + "cchange70": "Este tipo de imagen no es compatible", + "cchange71": "y", + "cchange72": "otro", + "cchange73": "s", + "cchange74": "reaccionó con" }, "welcomepage": { "wcchange1": "Bienvenido al Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENÚ", "bcchange8": "Copiar Dirección", "bcchange9": "Mensaje Privado", - "bcchange10": "Más" + "bcchange10": "Más", + "bcchange11": "Responder", + "bcchange12": "Editar", + "bcchange13": "Reacción", + "bcchange14": "Adelante", + "bcchange15": "Mensaje reenviado", + "bcchange16": "Elegir destinatario o buscar uno a continuación", + "bcchange17": "REENVIADO", + "bcchange18": "Sugerencia para el usuario" }, "grouppage": { "gchange1": "Grupos Qortal", diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index ab1adae2..62cd43e1 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -574,7 +574,12 @@ "cchange65": "Veuillez saisir un destinataire", "cchange66": "Impossible de récupérer le message auquel vous avez répondu. Le message est trop ancien.", "cchange68": "modifié", - "cchange69": "Afficher automatiquement les images" + "cchange69": "Afficher automatiquement les images", + "cchange70": "Ce type d'image n'est pas pris en charge", + "cchange71": "et", + "cchange72": "autre", + "cchange73": "s", + "cchange74": "a réagi avec" }, "welcomepage": { "wcchange1": "Bienvenue dans Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENU", "bcchange8": "Copier l'Adresse", "bcchange9": "Message Privé", - "bcchange10": "Suite" + "bcchange10": "Suite", + "bcchange11": "Répondre", + "bcchange12": "Modifier", + "bcchange13": "Réaction", + "bcchange14": "En avant", + "bcchange15": "Message transféré", + "bcchange16": "Choisissez le destinataire ou recherchez-en un ci-dessous", + "bcchange17": "TRANSMIS", + "bcchange18": "Astuce à l'utilisateur" }, "grouppage": { "gchange1": "Groupes Qortal", diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index ac392733..2ef18b37 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -575,7 +575,12 @@ "cchange65": "कृपया एक प्राप्तकर्ता दर्ज करें", "cchange66": "इसका उत्तर दिया गया संदेश प्राप्त नहीं किया जा सकता। संदेश बहुत पुराना है।", "cchange68": "संपादित", - "cchange69": "ऑटो-शो छवियां" + "cchange69": "ऑटो-शो छवियां", + "cchange70": "यह छवि प्रकार समर्थित नहीं है", + "cchange71": "और", + "cchange72": "अन्य", + "cchange73": "s", + "cchange74": "के साथ प्रतिक्रिया" }, "welcomepage": { "wcchange1": "क्यू-चैट में आपका स्वागत है", @@ -598,7 +603,15 @@ "bcchange7": "मेन्यू", "bcchange8": "कॉपी पता", "bcchange9": "निजी संदेश", - "bcchange10": "अधिक" + "bcchange10": "अधिक", + "bcchange11": "उत्तर", + "bcchange12": "संपादित करें", + "bcchange13": "प्रतिक्रिया", + "bcchange14": "आगे", + "bcchange15": "संदेश अग्रेषित किया गया", + "bcchange16": "प्राप्तकर्ता चुनें या नीचे किसी को खोजें", + "bcchange17": "अग्रेषित", + "bcchange18": "टिप उपयोगकर्ता" }, "grouppage": { "gchange1": "क्वॉर्टल समूह", diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index 5759c849..26fc0d4a 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -574,7 +574,12 @@ "cchange65": "Molimo unesite primatelja", "cchange66": "Ne mogu dohvatiti poruku s odgovorom. Poruka je prestara.", "cchange68": "uređeno", - "cchange69": "Automatsko prikazivanje slika" + "cchange69": "Automatsko prikazivanje slika", + "cchange70": "Ova vrsta slike nije podržana", + "cchange71": "i", + "cchange72": "ostalo", + "cchange73": "s", + "cchange74": "reagirao sa" }, "welcomepage": { "wcchange1": "Dobrodošli u Q-Čavrljanje", @@ -597,7 +602,15 @@ "bcchange7": "MENI", "bcchange8": "Kopiraj Adresu", "bcchange9": "Privatna Poruka", - "bcchange10": "Više" + "bcchange10": "Više", + "bcchange11": "Odgovori", + "bcchange12": "Uredi", + "bcchange13": "Reakcija", + "bcchange14": "Naprijed", + "bcchange15": "Poruka proslijeđena", + "bcchange16": "Odaberite primatelja ili potražite jednog ispod", + "bcchange17": "PROSLJEĐENO", + "bcchange18": "Savjet korisniku" }, "grouppage": { "gchange1": "Qortal Grupe", diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index 6e7e8ee9..d92390cf 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -574,7 +574,12 @@ "cchange65": "Kérjük, adjon meg egy címzettet", "cchange66": "Nem sikerült lekérni a válaszolt üzenetet. Az üzenet túl régi.", "cchange68": "szerkesztve", - "cchange69": "Képek automatikus megjelenítése" + "cchange69": "Képek automatikus megjelenítése", + "cchange70": "Ez a képtípus nem támogatott", + "cchange71": "és", + "cchange72": "egyéb", + "cchange73": "s", + "cchange74": "reagált:" }, "welcomepage": { "wcchange1": "Üdvözöljük a Q-Chathoz", @@ -597,7 +602,15 @@ "bcchange7": "MENÜ", "bcchange8": "Cím Másolása", "bcchange9": "Privát Üzenet", - "bcchange10": "Több" + "bcchange10": "Több", + "bcchange11": "Válasz", + "bcchange12": "Szerkesztés", + "bcchange13": "Reakció", + "bcchange14": "Tovább", + "bcchange15": "Üzenet továbbítva", + "bcchange16": "Válasszon címzettet vagy keressen egyet lent", + "bcchange17": "TOVÁLTVA", + "bcchange18": "Tipp felhasználó" }, "grouppage": { "gchange1": "Qortal Csoportok", diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index e4a5c8c2..1523e212 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -574,7 +574,12 @@ "cchange65": "Inserisci un destinatario", "cchange66": "Impossibile recuperare il messaggio di risposta. Il messaggio è troppo vecchio.", "cchange68": "modificato", - "cchange69": "Mostra automaticamente le immagini" + "cchange69": "Mostra automaticamente le immagini", + "cchange70": "Questo tipo di immagine non è supportato", + "cchange71": "e", + "cchange72": "altro", + "cchange73": "s", + "cchange74": "ha reagito con" }, "welcomepage": { "wcchange1": "Benvenuto in Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENÙ", "bcchange8": "Copia Indirizzo", "bcchange9": "Messaggio Privato", - "bcchange10": "Di più" + "bcchange10": "Di più", + "bcchange11": "Rispondi", + "bcchange12": "Modifica", + "bcchange13": "Reazione", + "bcchange14": "Avanti", + "bcchange15": "Messaggio inoltrato", + "bcchange16": "Scegli il destinatario o cercane uno qui sotto", + "bcchange17": "INOLTRATO", + "bcchange18": "Suggerimento utente" }, "grouppage": { "gchange1": "Gruppi Qortal", diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index e5db9895..5e533527 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -574,7 +574,12 @@ "cchange65": "받는 사람을 입력하세요", "cchange66": "답장한 메시지를 가져올 수 없습니다. 메시지가 너무 오래되었습니다.", "cchange68": "편집됨", - "cchange69": "이미지 자동 표시" + "cchange69": "이미지 자동 표시", + "cchange70": "이 이미지 유형은 지원되지 않습니다", + "cchange71": "그리고", + "cchange72": "기타", + "cchange73": "들", + "cchange74": "반응" }, "welcomepage": { "wcchange1": "Q-Chat에 오신 것을 환영합니다.", @@ -597,7 +602,15 @@ "bcchange7": "메뉴", "bcchange8": "주소 복사", "bcchange9": "개인 메시지", - "bcchange10": "더" + "bcchange10": "더", + "bcchange11": "답장", + "bcchange12": "편집", + "bcchange13": "반응", + "bcchange14": "앞으로", + "bcchange15": "전달된 메시지", + "bcchange16": "받는 사람을 선택하거나 아래에서 검색하십시오", + "bcchange17": "전달됨", + "bcchange18": "팁 사용자" }, "grouppage": { "gchange1": "Qortal 그룹", diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index 791e89b5..1ee638af 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -574,7 +574,12 @@ "cchange65": "Vennligst skriv inn en mottaker", "cchange66": "Kan ikke hente besvart melding. Meldingen er for gammel.", "cchange68": "redigert", - "cchange69": "Vis bilder automatisk" + "cchange69": "Vis bilder automatisk", + "cchange70": "Denne bildetypen støttes ikke", + "cchange71": "og", + "cchange72": "annet", + "cchange73": "s", + "cchange74": "reagerte med" }, "welcomepage": { "wcchange1": "Velkommen til Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENY", "bcchange8": "Kopier adresse", "bcchange9": "Privat melding", - "bcchange10": "Mer" + "bcchange10": "Mer", + "bcchange11": "Svar", + "bcchange12": "Rediger", + "bcchange13": "Reaksjon", + "bcchange14": "Videresend", + "bcchange15": "Melding videresendt", + "bcchange16": "Velg mottaker eller søk etter en nedenfor", + "bcchange17": "VIDERESENDE", + "bcchange18": "Tipsbruker" }, "grouppage": { "gchange1": "Qortal-grupper", diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index 3100be86..5c75270f 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -574,7 +574,12 @@ "cchange65": "Wprowadź odbiorcę", "cchange66": "Nie można pobrać wiadomości, na którą udzielono odpowiedzi. Wiadomość jest za stara.", "cchange68": "edytowano", - "cchange69": "Automatyczne wyświetlanie obrazów" + "cchange69": "Automatyczne wyświetlanie obrazów", + "cchange70": "Ten typ obrazu nie jest obsługiwany", + "cchange71": "i", + "cchange72": "inne", + "cchange73": "s", + "cchange74": "zareagował z" }, "welcomepage": { "wcchange1": "Witamy w Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENU", "bcchange8": "Kopiuj Adres", "bcchange9": "Prywatna Wiadomość", - "bcchange10": "Więcej" + "bcchange10": "Więcej", + "bcchange11": "Odpowiedz", + "bcchange12": "Edytuj", + "bcchange13": "Reakcja", + "bcchange14": "Przekaż", + "bcchange15": "Wiadomość przekazana", + "bcchange16": "Wybierz odbiorcę lub wyszukaj poniżej", + "bcchange17": "PRZEKAZANA", + "bcchange18": "Użytkownik napiwku" }, "grouppage": { "gchange1": "Grupy Qortal", diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index 6e5e33b6..870b3dd3 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -574,7 +574,12 @@ "cchange65": "Insira um destinatário", "cchange66": "Não foi possível buscar a mensagem respondida. A mensagem é muito antiga.", "cchange68": "editado", - "cchange69": "Mostrar imagens automaticamente" + "cchange69": "Mostrar imagens automaticamente", + "cchange70": "Este tipo de imagem não é suportado", + "cchange71": "e", + "cchange72": "outro", + "cchange73": "s", + "cchange74": "reagiu com" }, "welcomepage": { "wcchange1": "Bem-vindo ao Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENU", "bcchange8": "Copiar Endereço", "bcchange9": "Mensagem Privada", - "bcchange10": "Mais" + "bcchange10": "Mais", + "bcchange11": "Responder", + "bcchange12": "Editar", + "bcchange13": "Reação", + "bcchange14": "Avançar", + "bcchange15": "Mensagem encaminhada", + "bcchange16": "Escolha o destinatário ou procure um abaixo", + "bcchange17": "ENCAMINHADO", + "bcchange18": "Dica de usuário" }, "grouppage": { "gchange1": "Grupos Qortal", diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index 756c8fce..4e17e959 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -574,7 +574,12 @@ "cchange65": "Vă rugăm să introduceți un destinatar", "cchange66": "Nu se poate prelua mesajul la care sa răspuns. Mesajul este prea vechi.", "cchange68": "editat", - "cchange69": "Afișează automat imaginile" + "cchange69": "Afișează automat imaginile", + "cchange70": "Acest tip de imagine nu este acceptat", + "cchange71": "și", + "cchange72": "altul", + "cchange73": "s", + "cchange74": "a reacționat cu" }, "welcomepage": { "wcchange1": "Bine ai venit la Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENIU", "bcchange8": "Copiati adresa", "bcchange9": "Mesaj privat", - "bcchange10": "Mai mult" + "bcchange10": "Mai mult", + "bcchange11": "Răspuns", + "bcchange12": "Editați", + "bcchange13": "Reacție", + "bcchange14": "Înainte", + "bcchange15": "Mesajul redirecționat", + "bcchange16": "Alegeți destinatarul sau căutați unul mai jos", + "bcchange17": "REMISE", + "bcchange18": "Sfat utilizator" }, "grouppage": { "gchange1": "Grupuri Qortal Groups", diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index 61a6f04b..e1722ca2 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -574,7 +574,12 @@ "cchange65": "Unesite primaoca", "cchange66": "Ne mogu preuzeti odgovor na poruku. Poruka je prestara.", "cchange68": "uređeno", - "cchange69": "Automatski prikaži slike" + "cchange69": "Automatski prikaži slike", + "cchange70": "Ovaj tip slike nije podržan", + "cchange71": "i", + "cchange72": "drugo", + "cchange73": "s", + "cchange74": "reagovao sa" }, "welcomepage": { "wcchange1": "Dobrodošli na Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "MENI", "bcchange8": "Kopiraj Adresu", "bcchange9": "Privatna Poruka", - "bcchange10": "Više" + "bcchange10": "Više", + "bcchange11": "Odgovori", + "bcchange12": "Izmeni", + "bcchange13": "Reakcija", + "bcchange14": "Napred", + "bcchange15": "Poruka je prosleđena", + "bcchange16": "Izaberite primaoca ili potražite jednog ispod", + "bcchange17": "PROSLEĐEN", + "bcchange18": "Korisnik saveta" }, "grouppage": { "gchange1": "Qortal Grupe", diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index dfcaa64d..ea20a79d 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -574,7 +574,12 @@ "cchange65": "Пожалуйста, введите получателя", "cchange66": "Невозможно получить ответное сообщение. Сообщение слишком старое.", "cchange68": "отредактировано", - "cchange69": "Автоматическое отображение изображений" + "cchange69": "Автоматическое отображение изображений", + "cchange70": "Этот тип изображения не поддерживается", + "cchange71": "и", + "cchange72": "другое", + "cchange73": "с", + "cchange74": "отреагировал" }, "welcomepage": { "wcchange1": "Добро пожаловать в Q-Chat", @@ -597,7 +602,15 @@ "bcchange7": "МЕНЮ", "bcchange8": "Копировать адрес", "bcchange9": "Приватное сообщение", - "bcchange10": "Более" + "bcchange10": "Более", + "bcchange11": "Ответить", + "bcchange12": "Редактировать", + "bcchange13": "Реакция", + "bcchange14": "Вперед", + "bcchange15": "Сообщение переадресовано", + "bcchange16": "Выберите получателя или найдите его ниже", + "bcchange17": "ПЕРЕДАНО", + "bcchange18": "Подсказка пользователю" }, "grouppage": { "gchange1": "Qortal группы", diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 02bb9586..87760fd7 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -579,8 +579,7 @@ "cchange71": "and", "cchange72": "other", "cchange73": "s", - "cchange74": "reacted with", - "cchange90": "No messages" + "cchange74": "reacted with" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", From fd96605148ae7c9a42f7e6d9d6433feebd137e43 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sun, 5 Feb 2023 13:42:19 +0100 Subject: [PATCH 73/76] Add sell name --- .../name-registration.src.js | 809 +++++++++++++++++- 1 file changed, 784 insertions(+), 25 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js b/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js index 037d9d85..1e3e0289 100644 --- a/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js +++ b/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js @@ -7,11 +7,17 @@ registerTranslateConfig({ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json()) }) -import '@material/mwc-icon' import '@material/mwc-button' -import '@material/mwc-textfield' import '@material/mwc-dialog' +import '@material/mwc-formfield' +import '@material/mwc-icon' +import '@material/mwc-icon-button' +import '@material/mwc-textfield' import '@polymer/paper-spinner/paper-spinner-lite.js' +import '@polymer/paper-progress/paper-progress.js' +import '@vaadin/button' +import '@vaadin/icon' +import '@vaadin/icons' import '@vaadin/grid' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -19,17 +25,32 @@ const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class NameRegistration extends LitElement { static get properties() { return { + theme: { type: String, reflect: true }, + qortWalletBalance: { type: Number }, loading: { type: Boolean }, names: { type: Array }, + marketSellNames: { type: Array }, recipientPublicKey: { type: String }, selectedAddress: { type: Object }, btnDisable: { type: Boolean }, + isLoading: { type: Boolean }, registerNameLoading: { type: Boolean }, error: { type: Boolean }, message: { type: String }, removeError: { type: Boolean }, removeMessage: { type: String }, - theme: { type: String, reflect: true } + fee: { type: Number }, + sellFee: { type: Number }, + cancelSellFee: { type: Number }, + buyFee: { type: Number }, + toSellName: { type: String }, + toSellPrice: { type: String }, + toCancelSellName: { type: String }, + toBuyName: { type: String }, + toBuyPrice: { type: String }, + toBuySeller: { type: String }, + errorMessage: { type: String }, + successMessage: { type: String } } } @@ -37,20 +58,32 @@ class NameRegistration extends LitElement { return css` * { --mdc-theme-primary: rgb(3, 169, 244); - --mdc-theme-secondary: var(--mdc-theme-primary); --paper-input-container-focus-color: var(--mdc-theme-primary); --mdc-theme-surface: var(--white); + --mdc-text-field-outlined-idle-border-color: var(--txtfieldborder); + --mdc-text-field-outlined-hover-border-color: var(--txtfieldhoverborder); + --mdc-text-field-label-ink-color: var(--black); + --mdc-text-field-ink-color: var(--black); --mdc-dialog-content-ink-color: var(--black); + --mdc-dialog-min-width: 400px; + --mdc-dialog-max-width: 1024px; --lumo-primary-text-color: rgb(0, 167, 245); --lumo-primary-color-50pct: rgba(0, 167, 245, 0.5); --lumo-primary-color-10pct: rgba(0, 167, 245, 0.1); --lumo-primary-color: hsl(199, 100%, 48%); --lumo-base-color: var(--white); --lumo-body-text-color: var(--black); + --lumo-secondary-text-color: var(--sectxt); + --lumo-contrast-60pct: var(--vdicon); --_lumo-grid-border-color: var(--border); --_lumo-grid-secondary-border-color: var(--border2); } + [hidden] { + display: hidden !important; + visibility: none !important; + } + #name-registration-page { background: var(--white); padding: 12px 24px; @@ -78,21 +111,100 @@ class NameRegistration extends LitElement { max-height: 42px; } + paper-progress { + --paper-progress-active-color: var(--mdc-theme-primary); + } + .red { --mdc-theme-primary: #F44336; } + + .green { + --mdc-theme-primary: #198754; + } + + .buttons { + text-align: right; + } + + .card-container { + background-color: var(--white); + border-radius: 5px; + color: var(--black); + padding-top: 30px; + position: relative; + width: 350px; + max-width: 100%; + text-align: center; + } + + .successBox { + height: 34px; + min-width: 300px; + width: 100%; + border: 1px solid green; + border-radius: 5px; + background-color: transparent; + margin-top: 15px; + } + + .errorBox { + height: 34px; + min-width: 300px; + width: 100%; + border: 1px solid red; + border-radius: 5px; + background-color: transparent; + margin-top: 15px; + } + + .manage-group-dialog { + min-height: 300px; + min-width: 350px; + box-sizing: border-box; + position: relative; + } + + .btn-clear-success { + --mdc-icon-button-size: 32px; + color: red; + } + + .btn-clear-error { + --mdc-icon-button-size: 32px; + color: green; + } + + .error-icon { + font-size: 48px; + color: red; + } ` } constructor() { super() + this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' + this.qortWalletBalance = 0 this.selectedAddress = {} this.names = [] + this.marketSellNames = [] this.recipientPublicKey = '' this.btnDisable = false + this.isLoading = false this.registerNameLoading = false this.fee = 0.001 - this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' + this.sellFee = 0.001 + this.cancelSellFee = 0.001 + this.buyFee = 0.001 + this.toSellName = '' + this.toSellPrice = '' + this.toCancelSellName = '' + this.toBuyName = '' + this.toBuyPrice = '' + this.toBuySeller = '' + this.errorMessage = '' + this.successMessage = '' } render() { @@ -114,13 +226,38 @@ class NameRegistration extends LitElement { { render(html`${this.renderAvatarButton(data.item)}`, root) }}> + { + if (this.marketSellNames.some(e => e.owner === this.selectedAddress.address)) { + render(html`${this.renderCancelSellNameButton(data.item)}`, root) + } else { + render(html`${this.renderSellNameButton(data.item)}`, root) + } + }}> ${this.isEmptyArray(this.names) ? html` ${translate("registernamepage.nchange8")} `: ''}
  • +

    +
    +

    ${translate("registernamepage.nchange22")}

    + + + + + { + if (data.item.owner === this.selectedAddress.address) { + render(html`${this.renderCancelSellNameButton(data.item)}`, root) + } else { + render(html`${this.renderBuyNameButton(data.item)}`, root) + } + }}> + + ${this.isEmptyArray(this.marketSellNames) ? html` + ${translate("registernamepage.nchange24")} + `: ''} +
    -
    ${translate("registernamepage.nchange9")}

    @@ -161,6 +298,204 @@ class NameRegistration extends LitElement { ${translate("general.close")}
    + + +
    +
    +

    ${translate("registernamepage.nchange19")}

    +
    +
    +
    +

    + + +

    +

    + + +

    +
    +

    ${translate("walletpage.wchange21")} ${this.sellFee} QORT

    +
    +
    + ${this.renderClearSuccess()} + ${this.renderClearError()} + ${this.isLoading ? html`` : ''} +
    +
    + this.createSellName()}> + + ${translate("registernamepage.nchange19")} + +
    +
    +
    + + ${translate("general.close")} + +
    + + +
    +
    +

    ${translate("registernamepage.nchange20")} ${translate("registernamepage.nchange5")}

    +
    +
    +
    +

    + + +

    +
    +

    ${translate("walletpage.wchange21")} ${this.cancelSellFee} QORT

    +
    +
    + ${this.renderClearSuccess()} + ${this.renderClearError()} + ${this.isLoading ? html`` : ''} +
    +
    + this.createCancelSellName()}> + + ${translate("registernamepage.nchange20")} ${translate("registernamepage.nchange5")} + +
    +
    +
    + + ${translate("general.close")} + +
    + + +
    +
    +

    ${translate("registernamepage.nchange21")}

    +
    +
    +
    +

    + + +

    +

    + + +

    +

    + + +

    +
    +

    ${translate("walletpage.wchange21")} ${this.buyFee} QORT

    +
    +
    + ${this.renderClearSuccess()} + ${this.renderClearError()} + ${this.isLoading ? html`` : ''} +
    +
    + this.openCheckFunds()}> + + ${translate("registernamepage.nchange21")} + +
    +
    +
    + + ${translate("general.close")} + +
    + + +
    + warning +

    ${translate("registernamepage.nchange35")}

    +

    ${translate("registernamepage.nchange36")}

    +
    + this.closeBuyErrorNameDialog()} + class="red" + > + ${translate("general.close")} + +
    + + +
    + warning +

    ${translate("registernamepage.nchange37")}

    +

    ${translate("registernamepage.nchange38")}

    +
    + this.closeBuyErrorPriceDialog()} + class="red" + > + ${translate("general.close")} + +
    ` } @@ -170,6 +505,9 @@ class NameRegistration extends LitElement { this.changeTheme() this.changeLanguage() this.unitFee() + this.unitSellFee() + this.unitCancelSellFee() + this.unitBuyFee() const fetchNames = () => { parentEpml.request('apiCall', { @@ -180,6 +518,15 @@ class NameRegistration extends LitElement { setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval) } + const fetchMarketSellNames = async () => { + await parentEpml.request('apiCall', { + url: `/names/forsale?limit=0&reverse=true` + }).then(res => { + this.marketSellNames = res + }) + setTimeout(fetchMarketSellNames, 60000) + } + window.addEventListener("contextmenu", (event) => { event.preventDefault() this._textMenu(event) @@ -221,6 +568,7 @@ class NameRegistration extends LitElement { parentEpml.subscribe('config', c => { if (!configLoaded) { setTimeout(fetchNames, 1) + setTimeout(fetchMarketSellNames, 1) configLoaded = true } this.config = JSON.parse(c) @@ -237,11 +585,11 @@ class NameRegistration extends LitElement { changeTheme() { const checkTheme = localStorage.getItem('qortalTheme') if (checkTheme === 'dark') { - this.theme = 'dark'; + this.theme = 'dark' } else { - this.theme = 'light'; + this.theme = 'light' } - document.querySelector('html').setAttribute('theme', this.theme); + document.querySelector('html').setAttribute('theme', this.theme) } changeLanguage() { @@ -255,6 +603,50 @@ class NameRegistration extends LitElement { } } + async updateQortWalletBalance() { + let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address + + await parentEpml.request('apiCall', { + url: `/addresses/balance/${qortAddress}`, + }).then((res) => { + this.qortWalletBalance = res + }) + } + + renderClearSuccess() { + let strSuccessValue = this.successMessage + if (strSuccessValue === "") { + return html`` + } else { + return html` +
    + ${this.successMessage} + +
    +
    +

    ${translate("walletpage.wchange43")}

    +
    + ` + } + } + + renderClearError() { + let strErrorValue = this.errorMessage + if (strErrorValue === "") { + return html`` + } else { + return html` +
    + ${this.errorMessage} + +
    +
    +

    ${translate("walletpage.wchange44")}

    +
    + ` + } + } + renderCoreText() { return html`${translate("registernamepage.nchange16")}` } @@ -263,6 +655,18 @@ class NameRegistration extends LitElement { return html`${translate("registernamepage.nchange18")}` } + renderSellSuccessText() { + return html`${translate("registernamepage.nchange32")}` + } + + renderCancelSuccessText() { + return html`${translate("registernamepage.nchange33")}` + } + + renderBuySuccessText() { + return html`${translate("registernamepage.nchange34")}` + } + renderFailText() { return html`${translate("registernamepage.nchange17")}` } @@ -271,7 +675,7 @@ class NameRegistration extends LitElement { let name = nameObj.name const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port - const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`; + const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}` return html`` } @@ -280,28 +684,168 @@ class NameRegistration extends LitElement { } async uploadAvatar(nameObj) { - let name = encodeURIComponent(nameObj.name) + let name = nameObj.name window.location.href = `../qdn/publish/index.html?service=THUMBNAIL&identifier=qortal_avatar&name=${name}&uploadType=file&category=Avatar&showName=false&showService=false&showIdentifier=false` } + renderSellNameButton(nameObj) { + return html` this.openSellNameDialog(nameObj)}>sell ${translate("registernamepage.nchange19")}` + } + + openSellNameDialog(nameObj) { + this.toSellName = '' + this.toSellPrice = '' + this.shadowRoot.getElementById("toSellName").value = '' + this.shadowRoot.getElementById("toSellPrice").value = '' + this.toSellName = nameObj.name + this.toSellPrice = '5' + this.shadowRoot.querySelector('#sellNameDialog').show() + } + + closeSellNameDialog() { + this.shadowRoot.querySelector('#sellNameDialog').close() + this.toSellName = '' + this.toSellPrice = '' + this.shadowRoot.getElementById("toSellName").value = '' + this.shadowRoot.getElementById("toSellPrice").value = '' + } + + renderCancelSellNameButton(nameObj) { + return html` this.openCancelSellNameDialog(nameObj)}>cancel ${translate("registernamepage.nchange20")}` + } + + openCancelSellNameDialog(nameObj) { + this.toCancelSellName = '' + this.shadowRoot.getElementById("toCancelSellName").value = '' + this.toCancelSellName = nameObj.name + this.shadowRoot.querySelector('#cancelSellNameDialog').show() + } + + closeCancelSellNameDialog() { + this.shadowRoot.querySelector('#cancelSellNameDialog').close() + this.toCancelSellName = '' + this.shadowRoot.getElementById("toCancelSellName").value = '' + } + + renderBuyNameButton(nameObj) { + return html` this.openCheck(nameObj)}>shop ${translate("registernamepage.nchange21")}` + } + + openCheck(nameObj) { + const _name = nameObj.name + const _seller = nameObj.owner + const _price = nameObj.salePrice + if (this.isEmptyArray(this.names) === true) { + this.openBuyNameDialog(_name, _seller, _price) + } else { + this.shadowRoot.querySelector('#buyErrorNameDialog').show() + } + } + + openBuyNameDialog(_name, _seller, _price) { + this.toBuyName = '' + this.toBuyPrice = '' + this.toBuySeller = '' + this.shadowRoot.getElementById("toBuyName").value = '' + this.shadowRoot.getElementById("toBuyPrice").value = '' + this.shadowRoot.getElementById("toBuySeller").value = '' + this.toBuyName = _name + this.toBuyPrice = _price + this.toBuySeller = _seller + this.shadowRoot.querySelector('#buyNameDialog').show() + } + + closeBuyNameDialog() { + this.toBuyName = '' + this.toBuyPrice = '' + this.toBuySeller = '' + this.shadowRoot.getElementById("toBuyName").value = '' + this.shadowRoot.getElementById("toBuyPrice").value = '' + this.shadowRoot.getElementById("toBuySeller").value = '' + this.shadowRoot.querySelector('#buyNameDialog').close() + } + + async openCheckFunds() { + await this.updateQortWalletBalance() + + const myFunds = this.round(parseFloat(this.qortWalletBalance)) + const myBuyPrice = this.round(parseFloat(this.toBuyPrice)) + + if (Number(myFunds) < Number(myBuyPrice)) { + this.shadowRoot.querySelector('#buyErrorPriceDialog').show() + } else { + this.createBuyName() + } + } + + closeBuyErrorNameDialog() { + this.shadowRoot.querySelector('#buyErrorNameDialog').close() + } + + closeBuyErrorPriceDialog() { + this.shadowRoot.querySelector('#buyErrorPriceDialog').close() + } + async unitFee() { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; - const url = `${nodeUrl}/transactions/unitfee?txType=REGISTER_NAME`; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/transactions/unitfee?txType=REGISTER_NAME` await fetch(url).then((response) => { if (response.ok) { - return response.json(); + return response.json() } - return Promise.reject(response); + return Promise.reject(response) }).then((json) => { - this.fee = (Number(json) / 1e8).toFixed(2); + this.fee = (Number(json) / 1e8).toFixed(2) + }) + } + + async unitSellFee() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/transactions/unitfee?txType=SELL_NAME` + await fetch(url).then((response) => { + if (response.ok) { + return response.json() + } + return Promise.reject(response) + }).then((json) => { + this.sellFee = (Number(json) / 1e8).toFixed(8) + }) + } + + async unitCancelSellFee() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/transactions/unitfee?txType=CANCEL_SELL_NAME` + await fetch(url).then((response) => { + if (response.ok) { + return response.json() + } + return Promise.reject(response) + }).then((json) => { + this.cancelSellFee = (Number(json) / 1e8).toFixed(8) + }) + } + + async unitBuyFee() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + const url = `${nodeUrl}/transactions/unitfee?txType=BUY_NAME` + await fetch(url).then((response) => { + if (response.ok) { + return response.json() + } + return Promise.reject(response) + }).then((json) => { + this.buyFee = (Number(json) / 1e8).toFixed(8) }) } getApiKey() { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - let apiKey = myNode.apiKey; - return apiKey; + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + let apiKey = myNode.apiKey + return apiKey } clearSelection() { @@ -391,16 +935,227 @@ class NameRegistration extends LitElement { this.registerNameLoading = false } + async createSellName() { + const name = this.shadowRoot.getElementById("toSellName").value + const price = this.shadowRoot.getElementById("toSellPrice").value + const sellFeeInput = this.sellFee + this.isLoading = true + this.btnDisable = true + + const getLastRef = async () => { + let myRef = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/lastreference/${this.selectedAddress.address}` + }) + return myRef + } + + const validateReceiver = async () => { + let lastRef = await getLastRef() + let myTransaction = await makeTransactionRequest(lastRef) + getTxnRequestResponse(myTransaction) + } + + const makeTransactionRequest = async (lastRef) => { + const myName = name + const myPrice = price + const myLastRef = lastRef + const myFee = sellFeeInput + const mySellNameDialog1 = get("registernamepage.nchange26") + const mySellNameDialog2 = get("registernamepage.nchange27") + const mySellNameDialog3 = get("registernamepage.nchange28") + + let myTxnrequest = await parentEpml.request('transaction', { + type: 5, + nonce: this.selectedAddress.nonce, + params: { + fee: myFee, + name: myName, + sellPrice: myPrice, + lastReference: myLastRef, + sellNameDialog1: mySellNameDialog1, + sellNameDialog2: mySellNameDialog2, + sellNameDialog3: mySellNameDialog3 + } + }) + return myTxnrequest + } + + const getTxnRequestResponse = (txnResponse) => { + if (txnResponse.success === false && txnResponse.message) { + this.errorMessage = txnResponse.message + this.isLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else if (txnResponse.success === true && !txnResponse.data.error) { + this.shadowRoot.getElementById("toSellName").value = '' + this.shadowRoot.getElementById("toSellPrice").value = '' + this.toSellName = '' + this.toSellPrice = '' + this.errorMessage = '' + this.successMessage = this.renderSellSuccessText() + this.isLoading = false + this.btnDisable = false + } else { + this.errorMessage = txnResponse.data.message + this.isLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } + } + validateReceiver() + } + + async createCancelSellName() { + const name = this.shadowRoot.getElementById("toCancelSellName").value + const cancelSellFeeInput = this.cancelSellFee + this.isLoading = true + this.btnDisable = true + + const getLastRef = async () => { + let myRef = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/lastreference/${this.selectedAddress.address}` + }) + return myRef + } + + const validateReceiver = async () => { + let lastRef = await getLastRef() + let myTransaction = await makeTransactionRequest(lastRef) + getTxnRequestResponse(myTransaction) + } + + const makeTransactionRequest = async (lastRef) => { + const myName = name + const myLastRef = lastRef + const myFee = cancelSellFeeInput + const myCancelSellNameDialog1 = get("registernamepage.nchange30") + const myCancelSellNameDialog2 = get("registernamepage.nchange31") + + let myTxnrequest = await parentEpml.request('transaction', { + type: 6, + nonce: this.selectedAddress.nonce, + params: { + fee: myFee, + name: myName, + lastReference: myLastRef, + cancelSellNameDialog1: myCancelSellNameDialog1, + cancelSellNameDialog2: myCancelSellNameDialog2 + } + }) + return myTxnrequest + } + + const getTxnRequestResponse = (txnResponse) => { + if (txnResponse.success === false && txnResponse.message) { + this.errorMessage = txnResponse.message + this.isLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else if (txnResponse.success === true && !txnResponse.data.error) { + this.shadowRoot.getElementById("toCancelSellName").value = '' + this.toCancelSellName = '' + this.errorMessage = '' + this.successMessage = this.renderCancelSuccessText() + this.isLoading = false + this.btnDisable = false + } else { + this.errorMessage = txnResponse.data.message + this.isLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } + } + validateReceiver() + } + + createBuyName() { + const name = this.shadowRoot.getElementById("toBuyName").value + const price = this.shadowRoot.getElementById("toBuyPrice").value + const seller = this.shadowRoot.getElementById("toBuySeller").value + const buyFeeInput = this.buyFee + this.isLoading = true + this.btnDisable = true + + const getLastRef = async () => { + let myRef = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/lastreference/${this.selectedAddress.address}` + }) + return myRef + } + + const validateReceiver = async () => { + let lastRef = await getLastRef() + let myTransaction = await makeTransactionRequest(lastRef) + getTxnRequestResponse(myTransaction) + } + + const makeTransactionRequest = async (lastRef) => { + const myName = name + const myPrice = price + const mySeller = seller + const myLastRef = lastRef + const myFee = buyFeeInput + const myBuyNameDialog1 = get("registernamepage.nchange39") + const myBuyNameDialog2 = get("registernamepage.nchange27") + const myBuyNameDialog3 = get("registernamepage.nchange40") + + let myTxnrequest = await parentEpml.request('transaction', { + type: 7, + nonce: this.selectedAddress.nonce, + params: { + fee: myFee, + name: myName, + sellPrice: myPrice, + recipient: mySeller, + lastReference: myLastRef, + buyNameDialog1: myBuyNameDialog1, + buyNameDialog2: myBuyNameDialog2, + buyNameDialog3: myBuyNameDialog3 + } + }) + return myTxnrequest + } + + const getTxnRequestResponse = (txnResponse) => { + if (txnResponse.success === false && txnResponse.message) { + this.errorMessage = txnResponse.message + this.isLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else if (txnResponse.success === true && !txnResponse.data.error) { + this.shadowRoot.getElementById("toBuyName").value = '' + this.shadowRoot.getElementById("toBuyPrice").value = '' + this.shadowRoot.getElementById("toBuySeller").value = '' + this.toBuyName = '' + this.toBuyPrice = '' + this.toBuySeller = '' + this.errorMessage = '' + this.successMessage = this.renderBuySuccessText() + this.isLoading = false + this.btnDisable = false + } else { + this.errorMessage = txnResponse.data.message + this.isLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } + } + validateReceiver() + } + _textMenu(event) { const getSelectedText = () => { - var text = ""; + var text = "" if (typeof window.getSelection != "undefined") { - text = window.getSelection().toString(); + text = window.getSelection().toString() } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { - text = this.shadowRoot.selection.createRange().text; + text = this.shadowRoot.selection.createRange().text } - return text; + return text } const checkSelectedTextAndShowMenu = () => { @@ -414,10 +1169,14 @@ class NameRegistration extends LitElement { parentEpml.request('openCopyTextMenu', textMenuObject) } } - checkSelectedTextAndShowMenu() } + round(number) { + let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8) + return result + } + isEmptyArray(arr) { if (!arr) { return true } return arr.length === 0 From 3a115c35e351f8c4585d4acddc81f0306ed1e391 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:16:00 +0100 Subject: [PATCH 74/76] Add missing translation --- qortal-ui-core/language/de.json | 3 ++- qortal-ui-core/language/es.json | 3 ++- qortal-ui-core/language/fr.json | 3 ++- qortal-ui-core/language/hindi.json | 3 ++- qortal-ui-core/language/hr.json | 3 ++- qortal-ui-core/language/hu.json | 3 ++- qortal-ui-core/language/it.json | 3 ++- qortal-ui-core/language/ko.json | 3 ++- qortal-ui-core/language/no.json | 3 ++- qortal-ui-core/language/pl.json | 3 ++- qortal-ui-core/language/pt.json | 3 ++- qortal-ui-core/language/ro.json | 3 ++- qortal-ui-core/language/rs.json | 3 ++- qortal-ui-core/language/ru.json | 3 ++- qortal-ui-core/language/us.json | 3 ++- qortal-ui-core/language/zhc.json | 3 ++- qortal-ui-core/language/zht.json | 3 ++- 17 files changed, 34 insertions(+), 17 deletions(-) diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index 326683b0..89e22f0a 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -579,7 +579,8 @@ "cchange71": "und", "cchange72": "andere", "cchange73": "s", - "cchange74": "reagiert mit" + "cchange74": "reagiert mit", + "cchange90": "Keine Nachrichten" }, "welcomepage": { "wcchange1": "Willkommen zu Q-Chat", diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index 82e6dce4..f214975c 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -579,7 +579,8 @@ "cchange71": "y", "cchange72": "otro", "cchange73": "s", - "cchange74": "reaccionó con" + "cchange74": "reaccionó con", + "cchange90": "Sin mensajes" }, "welcomepage": { "wcchange1": "Bienvenido al Q-Chat", diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index 62cd43e1..1c675ae8 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -579,7 +579,8 @@ "cchange71": "et", "cchange72": "autre", "cchange73": "s", - "cchange74": "a réagi avec" + "cchange74": "a réagi avec", + "cchange90": "Aucun message" }, "welcomepage": { "wcchange1": "Bienvenue dans Q-Chat", diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index 2ef18b37..fcc46ed9 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -580,7 +580,8 @@ "cchange71": "और", "cchange72": "अन्य", "cchange73": "s", - "cchange74": "के साथ प्रतिक्रिया" + "cchange74": "के साथ प्रतिक्रिया", + "cchange90": "कोई संदेश नहीं" }, "welcomepage": { "wcchange1": "क्यू-चैट में आपका स्वागत है", diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index 26fc0d4a..287904ce 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -579,7 +579,8 @@ "cchange71": "i", "cchange72": "ostalo", "cchange73": "s", - "cchange74": "reagirao sa" + "cchange74": "reagirao sa", + "cchange90": "Nema poruka" }, "welcomepage": { "wcchange1": "Dobrodošli u Q-Čavrljanje", diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index d92390cf..0ddb80d5 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -579,7 +579,8 @@ "cchange71": "és", "cchange72": "egyéb", "cchange73": "s", - "cchange74": "reagált:" + "cchange74": "reagált:", + "cchange90": "Nincs üzenet" }, "welcomepage": { "wcchange1": "Üdvözöljük a Q-Chathoz", diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index 1523e212..bae18193 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -579,7 +579,8 @@ "cchange71": "e", "cchange72": "altro", "cchange73": "s", - "cchange74": "ha reagito con" + "cchange74": "ha reagito con", + "cchange90": "Nessun messaggio" }, "welcomepage": { "wcchange1": "Benvenuto in Q-Chat", diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index 5e533527..e07e921e 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -579,7 +579,8 @@ "cchange71": "그리고", "cchange72": "기타", "cchange73": "들", - "cchange74": "반응" + "cchange74": "반응", + "cchange90": "메시지 없음" }, "welcomepage": { "wcchange1": "Q-Chat에 오신 것을 환영합니다.", diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index 1ee638af..f32175ed 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -579,7 +579,8 @@ "cchange71": "og", "cchange72": "annet", "cchange73": "s", - "cchange74": "reagerte med" + "cchange74": "reagerte med", + "cchange90": "Ingen meldinger" }, "welcomepage": { "wcchange1": "Velkommen til Q-Chat", diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index 5c75270f..ee1d4b14 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -579,7 +579,8 @@ "cchange71": "i", "cchange72": "inne", "cchange73": "s", - "cchange74": "zareagował z" + "cchange74": "zareagował z", + "cchange90": "Brak wiadomości" }, "welcomepage": { "wcchange1": "Witamy w Q-Chat", diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index 870b3dd3..6558c1f4 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -579,7 +579,8 @@ "cchange71": "e", "cchange72": "outro", "cchange73": "s", - "cchange74": "reagiu com" + "cchange74": "reagiu com", + "cchange90": "Sem mensagens" }, "welcomepage": { "wcchange1": "Bem-vindo ao Q-Chat", diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index 4e17e959..e5908fb5 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -579,7 +579,8 @@ "cchange71": "și", "cchange72": "altul", "cchange73": "s", - "cchange74": "a reacționat cu" + "cchange74": "a reacționat cu", + "cchange90": "Fără mesaje" }, "welcomepage": { "wcchange1": "Bine ai venit la Q-Chat", diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index e1722ca2..1873c837 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -579,7 +579,8 @@ "cchange71": "i", "cchange72": "drugo", "cchange73": "s", - "cchange74": "reagovao sa" + "cchange74": "reagovao sa", + "cchange90": "Nema poruka" }, "welcomepage": { "wcchange1": "Dobrodošli na Q-Chat", diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index ea20a79d..a27dce40 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -579,7 +579,8 @@ "cchange71": "и", "cchange72": "другое", "cchange73": "с", - "cchange74": "отреагировал" + "cchange74": "отреагировал", + "cchange90": "Нет сообщений" }, "welcomepage": { "wcchange1": "Добро пожаловать в Q-Chat", diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 87760fd7..02bb9586 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -579,7 +579,8 @@ "cchange71": "and", "cchange72": "other", "cchange73": "s", - "cchange74": "reacted with" + "cchange74": "reacted with", + "cchange90": "No messages" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index 57fe5ec0..ee0c77b5 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -579,7 +579,8 @@ "cchange71": "和", "cchange72": "其他", "cchange73": "的", - "cchange74": "心情回应" + "cchange74": "心情回应", + "cchange90": "没有消息" }, "welcomepage": { "wcchange1": "欢迎来到Q-Chat", diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index 457d0bc4..1842d4d9 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -579,7 +579,8 @@ "cchange71": "和", "cchange72": "其他", "cchange73": "的", - "cchange74": "心情回應" + "cchange74": "心情回應", + "cchange90": "沒有消息" }, "welcomepage": { "wcchange1": "歡迎來到 Q-Chat", From 8bf10588b95c33ce9dec637650a074613c898c5b Mon Sep 17 00:00:00 2001 From: Phillip Date: Mon, 6 Feb 2023 12:19:08 +0200 Subject: [PATCH 75/76] fix unread error in general chat --- .../plugins/core/components/ChatPage.js | 16 ++++++++++++++-- .../plugins/core/messaging/q-chat/q-chat.src.js | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 8aacdc1b..bb6023b1 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -1421,6 +1421,12 @@ class ChatPage extends LitElement { }) document.addEventListener('keydown', this.initialChat); document.addEventListener('paste', this.pasteImage); + if(this.chatId){ + window.parent.reduxStore.dispatch( window.parent.reduxAction.addChatLastSeen({ + key: this.chatId, + timestamp: Date.now() + })) + } } disconnectedCallback() { @@ -1444,7 +1450,7 @@ class ChatPage extends LitElement { document.removeEventListener('keydown', this.initialChat); document.removeEventListener('paste', this.pasteImage); - if(this.messagesRendered.length !== 0){ + if(this.chatId){ window.parent.reduxStore.dispatch( window.parent.reduxAction.addChatLastSeen({ key: this.chatId, timestamp: Date.now() @@ -2181,7 +2187,13 @@ class ChatPage extends LitElement { await this.renderNewMessage(msg) }) await Promise.all(renderEachMessage) - + if(this.chatId){ + window.parent.reduxStore.dispatch( window.parent.reduxAction.addChatLastSeen({ + key: this.chatId, + timestamp: Date.now() + })) + + } // this.newMessages = this.newMessages.concat(_newMessages) this.messagesRendered = [...this.messagesRendered].sort(function (a, b) { return a.timestamp diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index e618a1b0..3ed87067 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -887,7 +887,7 @@ class Chat extends LitElement { setChatHeads(chatObj) { const chatObjGroups = Array.isArray(chatObj.groups) ? chatObj.groups : []; const chatObjDirect = Array.isArray(chatObj.direct) ? chatObj.direct : []; - let groupList = chatObjGroups.map(group => group.groupId === 0 ? { groupId: group.groupId, url: `group/${group.groupId}`, groupName: "Qortal General Chat", timestamp: group.timestamp === undefined ? 2 : group.timestamp } : { ...group, timestamp: group.timestamp === undefined ? 1 : group.timestamp, url: `group/${group.groupId}` }) + let groupList = chatObjGroups.map(group => group.groupId === 0 ? { groupId: group.groupId, url: `group/${group.groupId}`, groupName: "Qortal General Chat", timestamp: group.timestamp === undefined ? 2 : group.timestamp, sender: group.sender } : { ...group, timestamp: group.timestamp === undefined ? 1 : group.timestamp, url: `group/${group.groupId}` }) let directList = chatObjDirect.map(dc => { return { ...dc, url: `direct/${dc.address}` } }) From ce6a7873665e32581ca89a227fc942bdd3fbe317 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:27:04 +0100 Subject: [PATCH 76/76] Update dependencies --- package.json | 2 +- qortal-ui-core/package.json | 24 ++++++++++++------------ qortal-ui-plugins/package.json | 29 +++++++++++++++-------------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index e868253e..256ce0c4 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "os-locale": "3.0.0" }, "devDependencies": { - "electron": "22.0.3", + "electron": "22.2.0", "electron-builder": "23.6.0", "electron-packager": "17.1.1", "shelljs": "0.8.5" diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index 8e4f2ad3..d8361eda 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -17,9 +17,9 @@ "author": "QORTAL ", "license": "GPL-3.0", "dependencies": { - "@hapi/hapi": "21.2.0", + "@hapi/hapi": "21.2.1", "@hapi/inert": "7.0.0", - "sass": "1.57.1" + "sass": "1.58.0" }, "devDependencies": { "@babel/core": "7.20.12", @@ -58,27 +58,27 @@ "@rollup/plugin-commonjs": "24.0.1", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.3.0", - "@vaadin/button": "23.3.5", - "@vaadin/grid": "23.3.5", - "@vaadin/icons": "23.3.5", - "@vaadin/password-field": "23.3.5", - "@vaadin/tooltip": "23.3.5", + "@rollup/plugin-terser": "0.4.0", + "@vaadin/button": "23.3.6", + "@vaadin/grid": "23.3.6", + "@vaadin/icons": "23.3.6", + "@vaadin/password-field": "23.3.6", + "@vaadin/tooltip": "23.3.6", "asmcrypto.js": "2.3.2", "bcryptjs": "2.4.3", "epml": "0.3.3", "file-saver": "2.0.5", "lit": "2.6.1", "lit-translate": "2.0.1", + "localforage": "1.10.0", "pwa-helpers": "0.9.1", - "redux": "4.2.0", + "redux": "4.2.1", "redux-thunk": "2.4.2", - "rollup": "3.10.1", + "rollup": "3.14.0", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0", - "rollup-plugin-web-worker-loader": "1.6.1", - "localforage": "1.10.0" + "rollup-plugin-web-worker-loader": "1.6.1" }, "engines": { "node": ">=16.17.1" diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index 7ab1011d..261ca4d0 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -20,13 +20,14 @@ "@lit-labs/motion": "1.0.3", "@material/mwc-list": "0.27.0", "@material/mwc-select": "0.27.0", - "@tiptap/core": "2.0.0-beta.209", - "@tiptap/extension-highlight": "2.0.0-beta.209", - "@tiptap/extension-image": "2.0.0-beta.209", - "@tiptap/extension-placeholder": "2.0.0-beta.209", - "@tiptap/extension-underline": "2.0.0-beta.209", - "@tiptap/html": "2.0.0-beta.209", - "@tiptap/starter-kit": "2.0.0-beta.209", + "@tiptap/pm": "2.0.0-beta.212", + "@tiptap/core": "2.0.0-beta.212", + "@tiptap/extension-highlight": "2.0.0-beta.212", + "@tiptap/extension-image": "2.0.0-beta.212", + "@tiptap/extension-placeholder": "2.0.0-beta.212", + "@tiptap/extension-underline": "2.0.0-beta.212", + "@tiptap/html": "2.0.0-beta.212", + "@tiptap/starter-kit": "2.0.0-beta.212", "asmcrypto.js": "2.3.2", "compressorjs": "1.1.1", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", @@ -69,19 +70,19 @@ "@rollup/plugin-commonjs": "24.0.1", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.3.0", - "@vaadin/avatar": "23.3.5", - "@vaadin/button": "23.3.5", - "@vaadin/grid": "23.3.5", - "@vaadin/icons": "23.3.5", - "@vaadin/tooltip": "23.3.5", + "@rollup/plugin-terser": "0.4.0", + "@vaadin/avatar": "23.3.6", + "@vaadin/button": "23.3.6", + "@vaadin/grid": "23.3.6", + "@vaadin/icons": "23.3.6", + "@vaadin/tooltip": "23.3.6", "epml": "0.3.3", "file-saver": "2.0.5", "highcharts": "10.3.3", "html-escaper": "3.0.3", "lit": "2.6.1", "lit-translate": "2.0.1", - "rollup": "3.10.1", + "rollup": "3.14.0", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-web-worker-loader": "1.6.1",