Updated on 2026-08-14
This commit is contained in:
commit
554456e809
52 changed files with 1709 additions and 518 deletions
914
app/src/main/assets/erc20_tokens.json
Normal file
914
app/src/main/assets/erc20_tokens.json
Normal file
|
|
@ -0,0 +1,914 @@
|
|||
[
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ZRX",
|
||||
"name" : "0x",
|
||||
"contractAddress" : "0xE41d2489571d322189246DaFA5ebDe1F4699F498"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "AAVE",
|
||||
"name" : "Aave",
|
||||
"contractAddress" : "0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "LEND",
|
||||
"name" : "Aave (OLD)",
|
||||
"contractAddress" : "0x80fB784B7eD66730e8b1DBd9820aFD29931aab03"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ADX",
|
||||
"name" : "AdEx",
|
||||
"contractAddress" : "0xADE00C28244d5CE17D72E40330B1c318cD12B7c3"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 9,
|
||||
"symbol" : "ADT",
|
||||
"name" : "adToken",
|
||||
"contractAddress" : "0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ELF",
|
||||
"name" : "Aelf",
|
||||
"contractAddress" : "0xbf2179859fc6d5bee9bf9158632dc51678a4100e"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "ARN",
|
||||
"name" : "Aeron",
|
||||
"contractAddress" : "0xBA5F11b16B155792Cf3B2E6880E8706859A8AEB6"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "AE",
|
||||
"name" : "Aeternity",
|
||||
"contractAddress" : "0x5ca9a71b1d01849c0a95490cc00559717fcf0d1d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "AION",
|
||||
"name" : "Aion",
|
||||
"contractAddress" : "0x4CEdA7906a5Ed2179785Cd3A40A69ee8bc99C466"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 4,
|
||||
"symbol" : "AST",
|
||||
"name" : "Airswap",
|
||||
"contractAddress" : "0x27054b13b1b798b345b591a4d22e6562d47ea75a"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "AMB",
|
||||
"name" : "Amber",
|
||||
"contractAddress" : "0x4dc3643dbc642b72c158e7f3d2ff232df61cb6ce"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "AMLT",
|
||||
"name" : "AMLT by Coinfirm",
|
||||
"contractAddress" : "0xca0e7269600d353f70b14ad118a49575455c0f2f"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "APPC",
|
||||
"name" : "AppCoins",
|
||||
"contractAddress" : "0x1a7a8bd9106f2b8d977e08582dc7d24c723ab0db"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ANT",
|
||||
"name" : "Aragon",
|
||||
"contractAddress" : "0xa117000000f279d81a1d3cc75430faa017fa5a2e"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ABT",
|
||||
"name" : "ArcBlock",
|
||||
"contractAddress" : "0xb98d4c97425d9908e66e53a6fdf673acca0be986"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ATMI",
|
||||
"name" : "Atonomi",
|
||||
"contractAddress" : "0x97aeb5066e1a590e868b511457beb6fe99d329f5"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "REP",
|
||||
"name" : "Augur",
|
||||
"contractAddress" : "0x1985365e9f78359a9B6AD760e32412f4a445E862"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "AVM",
|
||||
"name" : "AVM Ecosystem",
|
||||
"contractAddress" : "0x74004a7227615fb52b82d17ffabfa376907d8a4d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BNT",
|
||||
"name" : "Bancor",
|
||||
"contractAddress" : "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BAT",
|
||||
"name" : "Basic Attention",
|
||||
"contractAddress" : "0x0D8775F648430679A709E98d2b0Cb6250d2887EF"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BNB",
|
||||
"name" : "Binance Coin",
|
||||
"contractAddress" : "0xb8c77482e45f1f44de1745f52c74426c631bdd52"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BUSD",
|
||||
"name" : "Binance USD",
|
||||
"contractAddress" : "0x4fabb145d64652a948d72533023f6e7a623c7c53"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "STU",
|
||||
"name" : "bitJob",
|
||||
"contractAddress" : "0x0371a82e4a9d0a4312f3ee2ac9c6958512891372"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BIX",
|
||||
"name" : "BIX Token",
|
||||
"contractAddress" : "0xb3104b4b9da82025e8b9f8fb28b3553ce2f67069"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "VEE",
|
||||
"name" : "BLOCKv",
|
||||
"contractAddress" : "0x340d2bde5eb28c1eed91b2f790723e3b160613b7"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BLZ",
|
||||
"name" : "Bluzelle",
|
||||
"contractAddress" : "0x5732046a883704404f284ce41ffadd5b007fd668"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "BRD",
|
||||
"name" : "BRD Token",
|
||||
"contractAddress" : "0x558ec3152e2eb2174905cd19aea4e34a23de9ad6"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "BTM",
|
||||
"name" : "Bytom",
|
||||
"contractAddress" : "0xcb97e65f07da24d46bcdd078ebebd7c6e6e3d750"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CAS",
|
||||
"name" : "Cashaa",
|
||||
"contractAddress" : "0xe8780b48bdb05f928697a5e8155f672ed91462f7"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CSP",
|
||||
"name" : "Caspian",
|
||||
"contractAddress" : "0xa6446d655a0c34bc4f05042ee88170d056cbaf45"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "LINK",
|
||||
"name" : "ChainLink",
|
||||
"contractAddress" : "0x514910771af9ca656af840dff83e8264ecf986ca"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "TIME",
|
||||
"name" : "Chronobank",
|
||||
"contractAddress" : "0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CND",
|
||||
"name" : "Cindicator",
|
||||
"contractAddress" : "0xd4c435f5b09f855c3317c8524cb1f586e42795fa"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "CVC",
|
||||
"name" : "Civic",
|
||||
"contractAddress" : "0x41e5560054824ea6b0732e656e3ad64e20e94e45"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CNN",
|
||||
"name" : "CNN Token",
|
||||
"contractAddress" : "0x8713d26637cf49e1b6b4a7ce57106aabc9325343"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CFI",
|
||||
"name" : "Cofound.it",
|
||||
"contractAddress" : "0x12FEF5e57bF45873Cd9B62E9DBd7BFb99e32D73e"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CCC",
|
||||
"name" : "Container Crypto Coin",
|
||||
"contractAddress" : "0x9e3359f862b6c7f5c660cfd6d1aa6909b1d9504d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "CS",
|
||||
"name" : "Credits",
|
||||
"contractAddress" : "0x46b9ad944d1059450da1163511069c718f699d31"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CRPT",
|
||||
"name" : "Crypterium",
|
||||
"contractAddress" : "0x08389495d7456e1951ddf7c3a1314a4bfb646d8b"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "AUTO",
|
||||
"name" : "CUBE",
|
||||
"contractAddress" : "0x622dFfCc4e83C64ba959530A5a5580687a57581b"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "CMT",
|
||||
"name" : "CyberMiles",
|
||||
"contractAddress" : "0xf85fEea2FdD81d51177F6b8F35F0e6734Ce45F5F"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "DAI",
|
||||
"name" : "Dai",
|
||||
"contractAddress" : "0x6b175474e89094c44da98b954eedeac495271d0f"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "MANA",
|
||||
"name" : "Decentraland",
|
||||
"contractAddress" : "0x0F5D2fB29fb7d3CFeE444a200298f468908cC942"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "DENT",
|
||||
"name" : "DENT",
|
||||
"contractAddress" : "0x3597bfd533a99c9aa083587b074434e61eb0a258"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 0,
|
||||
"symbol" : "XJP",
|
||||
"name" : "Digital JPY",
|
||||
"contractAddress" : "0x39689fE671C01fcE173395f6BC45D4C332026666"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 9,
|
||||
"symbol" : "DGD",
|
||||
"name" : "DigixDAO",
|
||||
"contractAddress" : "0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "DNT",
|
||||
"name" : "district0x",
|
||||
"contractAddress" : "0x0abdace70d3790235af448c88547603b945604ea"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "DOV",
|
||||
"name" : "Dovu",
|
||||
"contractAddress" : "0xac3211a5025414af2866ff09c23fc18bc97e79b1"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "DRGN",
|
||||
"name" : "Dragon",
|
||||
"contractAddress" : "0x419c4db4b9e25d6db2ad9691ccb832c8d9fda05e"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 0,
|
||||
"symbol" : "EDG",
|
||||
"name" : "Edgeless",
|
||||
"contractAddress" : "0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "EDO",
|
||||
"name" : "Eidoo",
|
||||
"contractAddress" : "0xced4e93198734ddaff8492d525bd258d49eb388e"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "ENG",
|
||||
"name" : "Enigma",
|
||||
"contractAddress" : "0xf0ee6b27b759c9893ce4f094b49ad28fd15a23e4"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ENJ",
|
||||
"name" : "EnjinCoin",
|
||||
"contractAddress" : "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "EOS",
|
||||
"name" : "EOS",
|
||||
"contractAddress" : "0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 2,
|
||||
"symbol" : "EUR.AVM",
|
||||
"name" : "EUR AVM",
|
||||
"contractAddress" : "0xF01Cd2f1c9E42c509d309aC8C5b29B6dA8E64b1a"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "XUC",
|
||||
"name" : "Exchange Union",
|
||||
"contractAddress" : "0xc324a2f6b05880503444451b8b27e6f9e63287cb"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "1ST",
|
||||
"name" : "FirstBlood",
|
||||
"contractAddress" : "0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "FXC",
|
||||
"name" : "Flexacoin",
|
||||
"contractAddress" : "0x4a57E687b9126435a9B19E4A802113e266AdeBde"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "FUN",
|
||||
"name" : "FunFair",
|
||||
"contractAddress" : "0x419D0d8BdD9aF5e606Ae2232ed285Aff190E711b"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "FSN",
|
||||
"name" : "Fusion",
|
||||
"contractAddress" : "0xd0352a019e9ab9d757776f532377aaebd36fd541"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 2,
|
||||
"symbol" : "GUSD",
|
||||
"name" : "Gemini Dollar",
|
||||
"contractAddress" : "0x056fd409e1d7a124bd7017459dfea2f387b6d5cd"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 9,
|
||||
"symbol" : "GNX",
|
||||
"name" : "Genaro Network",
|
||||
"contractAddress" : "0x6ec8a24cabdc339a06a172f8223ea557055adaa5"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "GVT",
|
||||
"name" : "Genesis Vision",
|
||||
"contractAddress" : "0x103c3A209da59d3E7C4A89307e66521e081CFDF0"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 5,
|
||||
"symbol" : "GTO",
|
||||
"name" : "Gifto",
|
||||
"contractAddress" : "0xc5bbae50781be1669306b9e001eff57a2957b09d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "GBX",
|
||||
"name" : "Globitex",
|
||||
"contractAddress" : "0x12fcd6463e66974cf7bbc24ffc4d40d6be458283"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "GNO",
|
||||
"name" : "Gnosis",
|
||||
"contractAddress" : "0x6810e776880C02933D47DB1b9fc05908e5386b96"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "GNT",
|
||||
"name" : "Golem",
|
||||
"contractAddress" : "0xa74476443119A942dE498590Fe1f2454d7D4aC0d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "HPB",
|
||||
"name" : "HPBCoin",
|
||||
"contractAddress" : "0x38c6a68304cdefb9bec48bbfaaba5c5b47818bb2"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "HYDRO",
|
||||
"name" : "Hydro",
|
||||
"contractAddress" : "0xebbdf302c940c6bfd49c6b165f457fdb324649bc"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ICX",
|
||||
"name" : "ICON",
|
||||
"contractAddress" : "0xb5a5f22694352c15b00323844ad545abb2b11028"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ICN",
|
||||
"name" : "ICONOMI",
|
||||
"contractAddress" : "0x888666CA69E0f178DED6D75b5726Cee99A87D698"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 9,
|
||||
"symbol" : "RLC",
|
||||
"name" : "iExec RLC",
|
||||
"contractAddress" : "0x607F4C5BB672230e8672085532f7e901544a7375"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "IOST",
|
||||
"name" : "IOStoken",
|
||||
"contractAddress" : "0xfa1a856cfa3409cfa145fa4e20eb270df3eb21ab"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ITC",
|
||||
"name" : "IOT Chain",
|
||||
"contractAddress" : "0x5e6b6d9abad9093fdc861ea1600eba1b355cd940"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "IXT",
|
||||
"name" : "iXledger",
|
||||
"contractAddress" : "0xfca47962d45adfdfd1ab2d972315db4ce7ccf094"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "KIN",
|
||||
"name" : "Kin",
|
||||
"contractAddress" : "0x818Fc6C2Ec5986bc6E2CBf00939d90556aB12ce5"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "KNC",
|
||||
"name" : "Kyber Network",
|
||||
"contractAddress" : "0xdd974D5C2e2928deA5F71b9825b8b646686BD200"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "LOOM",
|
||||
"name" : "Loom",
|
||||
"contractAddress" : "0xa4e8c3ec456107ea67d3075bf9e3df3a75823db0"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "LRC",
|
||||
"name" : "Loopring",
|
||||
"contractAddress" : "0xbbbbca6a901c926f240b89eacb641d8aec7aeafd"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "LUN",
|
||||
"name" : "Lunyr",
|
||||
"contractAddress" : "0xfa05A73FfE78ef8f1a739473e462c54bae6567D9"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "MKR",
|
||||
"name" : "Maker",
|
||||
"contractAddress" : "0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 3,
|
||||
"symbol" : "GUP",
|
||||
"name" : "Matchpool",
|
||||
"contractAddress" : "0xf7B098298f7C69Fc14610bf71d5e02c60792894C"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "MAN",
|
||||
"name" : "MATRIX AI Network",
|
||||
"contractAddress" : "0xe25bcec5d3801ce3a794079bf94adf1b8ccd802d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "MTL",
|
||||
"name" : "Metal",
|
||||
"contractAddress" : "0xF433089366899D83a9f26A773D59ec7eCF30355e"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "MCO",
|
||||
"name" : "Monaco",
|
||||
"contractAddress" : "0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "MYST",
|
||||
"name" : "Mysterium",
|
||||
"contractAddress" : "0xa645264C5603E96c3b0B078cdab68733794B0A71"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "NAS",
|
||||
"name" : "Nebulas",
|
||||
"contractAddress" : "0x5d65D971895Edc438f465c17DB6992698a52318D"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "NEXO",
|
||||
"name" : "Nexo",
|
||||
"contractAddress" : "0xb62132e35a6c13ee1ee0f84dc5d40bad8d815206"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "NCASH",
|
||||
"name" : "Nucleus Vision",
|
||||
"contractAddress" : "0x809826cceab68c387726af962713b64cb5cb3cca"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "NULS",
|
||||
"name" : "Nuls",
|
||||
"contractAddress" : "0xb91318f35bdb262e9423bc7c7c2a3a93dd93c92c"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "NMR",
|
||||
"name" : "Numeraire",
|
||||
"contractAddress" : "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "OMG",
|
||||
"name" : "OmiseGO",
|
||||
"contractAddress" : "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "OXT",
|
||||
"name" : "Orchid",
|
||||
"contractAddress" : "0x4575f41308ec1483f3d399aa9a2826d74da13deb"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "OST",
|
||||
"name" : "OST",
|
||||
"contractAddress" : "0x2C4e8f2D746113d0696cE89B35F0d8bF88E0AEcA"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "PRL",
|
||||
"name" : "Oyster Pearl",
|
||||
"contractAddress" : "0x1844b21593262668b7248d0f57a220caaba46ab9"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "PTOY",
|
||||
"name" : "Patientory",
|
||||
"contractAddress" : "0x8Ae4BF2C33a8e667de34B54938B0ccD03Eb8CC06"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "PAX",
|
||||
"name" : "Paxos Standard",
|
||||
"contractAddress" : "0x8e870d67f660d95d5be530380d0ec0bd388289e1"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "PMTN",
|
||||
"name" : "Peer Mountain",
|
||||
"contractAddress" : "0xe91df2bb9bccd18c45f01843cab88768d64f2d32"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "POE",
|
||||
"name" : "Po.et",
|
||||
"contractAddress" : "0x0e0989b1f9b8a38983c2ba8053269ca62ec9b195"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "PAL",
|
||||
"name" : "PolicyPal Network",
|
||||
"contractAddress" : "0xfeDAE5642668f8636A11987Ff386bfd215F942EE"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "POLY",
|
||||
"name" : "Polymath",
|
||||
"contractAddress" : "0x9992eC3cF6A55b00978cdDF2b27BC6882d88D1eC"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "PPT",
|
||||
"name" : "Populous",
|
||||
"contractAddress" : "0xd4fa1460F537bb9085d22C7bcCB5DD450Ef28e3a"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "POWR",
|
||||
"name" : "Power Ledger",
|
||||
"contractAddress" : "0x595832f8fc6bf59c85c527fec3740a1b7a361269"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "NPXS",
|
||||
"name" : "Pundi X Token",
|
||||
"contractAddress" : "0xa15c7ebe1f07caf6bff097d8a589fb8ac49ae5b3"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "QASH",
|
||||
"name" : "QASH",
|
||||
"contractAddress" : "0x618e75ac90b12c6049ba3b27f5d5f8651b0037f6"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "QRL",
|
||||
"name" : "QRL",
|
||||
"contractAddress" : "0x697beac28B09E122C4332D163985e8a73121b97F"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "QSP",
|
||||
"name" : "Quantstamp",
|
||||
"contractAddress" : "0x99ea4dB9EE77ACD40B119BD1dC4E33e1C070b80d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "RDN",
|
||||
"name" : "Raiden Network",
|
||||
"contractAddress" : "0x255aa6df07540cb5d3d297f0d0d4d84cb52bc8e6"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "RCC",
|
||||
"name" : "Reality Clash",
|
||||
"contractAddress" : "0x9b6443b0fb9c241a7fdac375595cea13e6b7807a"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "RC1U03",
|
||||
"name" : "RentalCoin 1.0",
|
||||
"contractAddress" : "0x7384db1aaa06364d1e6e67f5434391d3eea2a038"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "REQ",
|
||||
"name" : "Request",
|
||||
"contractAddress" : "0x8f8221aFbB33998d8584A2B05749bA73c37a938a"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 0,
|
||||
"symbol" : "REV",
|
||||
"name" : "Revain",
|
||||
"contractAddress" : "0x48f775efbe4f5ece6e0df2f7b5932df56823b990"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "RCN",
|
||||
"name" : "Ripio Credit",
|
||||
"contractAddress" : "0xf970b8e36e23f7fc3fd752eea86f8be8d83375a6"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "RVT",
|
||||
"name" : "Rivetz",
|
||||
"contractAddress" : "0x3d1ba9be9f66b8ee101911bc36d3fb562eac2244"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "RUFF",
|
||||
"name" : "RUFF",
|
||||
"contractAddress" : "0xf278c1ca969095ffddded020290cf8b5c424ace2"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SAI",
|
||||
"name" : "Sai",
|
||||
"contractAddress" : "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "SALT",
|
||||
"name" : "SALT",
|
||||
"contractAddress" : "0x4156D3342D5c385a87D264F90653733592000581"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SAN",
|
||||
"name" : "SAN",
|
||||
"contractAddress" : "0x7C5A0CE9267ED19B22F8cae653F198e3E8daf098"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "SENT",
|
||||
"name" : "SENTinel",
|
||||
"contractAddress" : "0xa44e5137293e855b1b7bc7e2c6f8cd796ffcb037"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 0,
|
||||
"symbol" : "SNGLS",
|
||||
"name" : "Singular DTV",
|
||||
"contractAddress" : "0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "AGI",
|
||||
"name" : "SingularityNET",
|
||||
"contractAddress" : "0x8eB24319393716668D768dCEC29356ae9CfFe285"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SRN",
|
||||
"name" : "SIRIN",
|
||||
"contractAddress" : "0x68d57c9a1C35f63E2c83eE8e49A64e9d70528D25"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SNM",
|
||||
"name" : "SONM",
|
||||
"contractAddress" : "0x983F6d60db79ea8cA4eB9968C6aFf8cfA04B3c63"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SNT",
|
||||
"name" : "Status",
|
||||
"contractAddress" : "0x744d70FDBE2Ba4CF95131626614a1763DF805B9E"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "STK",
|
||||
"name" : "STK",
|
||||
"contractAddress" : "0xae73b38d1c9a8b274127ec30160a4927c4d71824"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "STQ",
|
||||
"name" : "Storiqa",
|
||||
"contractAddress" : "0x5c3a228510d246b78a3765c20221cbf3082b44a4"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "STORJ",
|
||||
"name" : "Storj",
|
||||
"contractAddress" : "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "STORM",
|
||||
"name" : "Storm",
|
||||
"contractAddress" : "0xD0a4b8946Cb52f0661273bfbC6fD0E0C75Fc6433"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "STMX",
|
||||
"name" : "StormX",
|
||||
"contractAddress" : "0xbE9375C6a420D2eEB258962efB95551A5b722803"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "STX",
|
||||
"name" : "Stox",
|
||||
"contractAddress" : "0x006BeA43Baa3f7A6f765F14f10A1a1b08334EF45"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SUB",
|
||||
"name" : "Substratum",
|
||||
"contractAddress" : "0x8D75959f1E61EC2571aa72798237101F084DE63a"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SNC",
|
||||
"name" : "SunContract",
|
||||
"contractAddress" : "0xF4134146AF2d511Dd5EA8cDB1C4AC88C57D60404"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "SUSHI",
|
||||
"name" : "SushiSwap",
|
||||
"contractAddress" : "0x6b3595068778dd592e39a122f4f5a5cf09c90fe2"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 2,
|
||||
"symbol" : "TEL",
|
||||
"name" : "Telcoin",
|
||||
"contractAddress" : "0x467bccd9d29f223bce8043b84e8c8b282827790f"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "PAY",
|
||||
"name" : "TenX",
|
||||
"contractAddress" : "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "USDT",
|
||||
"name" : "Tether USD",
|
||||
"contractAddress" : "0xdac17f958d2ee523a2206206994597c13d831ec7"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "THETA",
|
||||
"name" : "Theta Token",
|
||||
"contractAddress" : "0x3883f5e181fccaf8410fa61e12b59bad963fb645"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "TRX",
|
||||
"name" : "TRON",
|
||||
"contractAddress" : "0xf230b790e05390fc8295f4d3f60332c93bed42e2"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "TUSD",
|
||||
"name" : "TrueUSD",
|
||||
"contractAddress" : "0x0000000000085d4780B73119b644AE5ecd22b376"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "UCASH",
|
||||
"name" : "UCASH",
|
||||
"contractAddress" : "0x92e52a1a235d9a103d970901066ce910aacefd37"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "UNI",
|
||||
"name" : "Uniswap",
|
||||
"contractAddress" : "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "USDC",
|
||||
"name" : "USD Coin",
|
||||
"contractAddress" : "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "VIB",
|
||||
"name" : "Viberate",
|
||||
"contractAddress" : "0x2C974B2d0BA1716E644c1FC59982a89DDD2fF724"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "VGX",
|
||||
"name" : "Voyager",
|
||||
"contractAddress" : "0x5af2be193a6abca9c8817001f45744777db30756"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "WTC",
|
||||
"name" : "Waltonchain",
|
||||
"contractAddress" : "0xb7cb1c96db6b22b0d3d9536e0108d062bd488f74"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 8,
|
||||
"symbol" : "WAX",
|
||||
"name" : "WAX",
|
||||
"contractAddress" : "0x39Bb259F66E1C59d5ABEF88375979b4D20D98022"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "WPR",
|
||||
"name" : "WePower",
|
||||
"contractAddress" : "0x4CF488387F035FF08c371515562CBa712f9015d4"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "WINGS",
|
||||
"name" : "Wings",
|
||||
"contractAddress" : "0x667088b212ce3d06a1b553a7221E1fD19000d9aF"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 6,
|
||||
"symbol" : "WRC",
|
||||
"name" : "Worldcore",
|
||||
"contractAddress" : "0x72adadb447784dd7ab1f472467750fc485e4cb2d"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 18,
|
||||
"symbol" : "ZLA",
|
||||
"name" : "Zilla",
|
||||
"contractAddress" : "0xfd8971d5e8e1740ce2d0a84095fca4de729d0c16"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 0,
|
||||
"symbol" : "GD",
|
||||
"name" : "Zilla GD",
|
||||
"contractAddress" : "0xb4cebdb66b3a5183fd4764a25cad1fc109535016"
|
||||
},
|
||||
{
|
||||
"decimalCount" : 12,
|
||||
"symbol" : "ZIL",
|
||||
"name" : "Zilliqa",
|
||||
"contractAddress" : "0x05f4a42e251f2d52b8ed15E9FEdAacFcEF1FAD27"
|
||||
}
|
||||
]
|
||||
1
app/src/main/assets/tangem-android-config
Submodule
1
app/src/main/assets/tangem-android-config
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 9a731fcb5a58d53c90d7db79e5441bdf18e087fc
|
||||
|
|
@ -6,7 +6,9 @@ import android.nfc.NfcAdapter
|
|||
import android.nfc.Tag
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.CardFilter
|
||||
import com.tangem.Config
|
||||
import com.tangem.TangemSdk
|
||||
|
|
@ -52,9 +54,13 @@ private fun initCoroutineExceptionHandler(): CoroutineExceptionHandler {
|
|||
}
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private var snackbar: Snackbar? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
store.state.globalState.feedbackManager?.updateAcivity(this)
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
||||
|
||||
|
|
@ -103,4 +109,21 @@ class MainActivity : AppCompatActivity() {
|
|||
store.dispatch(NavigationAction.ActivityDestroyed)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
fun showSnackbar(text: Int, buttonTitle: Int? = null, action: View.OnClickListener? = null) {
|
||||
if (snackbar != null) return
|
||||
|
||||
snackbar = Snackbar.make(
|
||||
fragment_container, getString(text), Snackbar.LENGTH_INDEFINITE
|
||||
)
|
||||
if (buttonTitle != null && action != null) {
|
||||
snackbar?.setAction(getString(buttonTitle), action)
|
||||
}
|
||||
snackbar?.show()
|
||||
}
|
||||
|
||||
fun dismissSnackbar() {
|
||||
snackbar?.dismiss()
|
||||
snackbar = null
|
||||
}
|
||||
}
|
||||
|
|
@ -69,12 +69,11 @@ class TapApplication : Application() {
|
|||
|
||||
private fun initFeedbackManager() {
|
||||
val infoHolder = AdditionalEmailInfo()
|
||||
infoHolder.updateAppVersion(this)
|
||||
infoHolder.setAppVersion(this)
|
||||
|
||||
val logWriter = TangemLogCollector()
|
||||
Log.addLogger(logWriter)
|
||||
|
||||
val feedbackManager = FeedbackManager(infoHolder, this, logWriter)
|
||||
store.dispatch(GlobalAction.SetFeedbackManager(feedbackManager))
|
||||
store.dispatch(GlobalAction.SetFeedbackManager(FeedbackManager(infoHolder, logWriter)))
|
||||
}
|
||||
}
|
||||
|
|
@ -7,15 +7,15 @@ import com.tangem.wallet.R
|
|||
@DrawableRes
|
||||
fun Blockchain.getIconRes(): Int {
|
||||
return when (this) {
|
||||
Blockchain.Unknown, Blockchain.Ducatus, Blockchain.BitcoinTestnet, Blockchain.EthereumTestnet,
|
||||
Blockchain.BinanceTestnet -> 1
|
||||
Blockchain.Bitcoin -> R.drawable.ic_btc
|
||||
Blockchain.Unknown -> R.drawable.shape_circle
|
||||
Blockchain.Ducatus -> R.drawable.ic_ducatus
|
||||
Blockchain.Bitcoin, Blockchain.BitcoinTestnet,-> R.drawable.ic_btc
|
||||
Blockchain.BitcoinCash -> R.drawable.ic_btc_cash
|
||||
Blockchain.Litecoin -> R.drawable.ic_ltc
|
||||
Blockchain.Ethereum -> R.drawable.ic_eth
|
||||
Blockchain.Ethereum, Blockchain.EthereumTestnet, -> R.drawable.ic_eth
|
||||
Blockchain.RSK -> R.drawable.ic_rsk
|
||||
Blockchain.Cardano, Blockchain.CardanoShelley -> R.drawable.ic_cardano
|
||||
Blockchain.Binance -> R.drawable.ic_binance
|
||||
Blockchain.Binance, Blockchain.BinanceTestnet -> R.drawable.ic_binance
|
||||
Blockchain.Tezos -> R.drawable.ic_tezos
|
||||
Blockchain.XRP -> R.drawable.ic_xrp
|
||||
Blockchain.Stellar -> R.drawable.ic_stellar
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun <T> List<T>.containsAny(list: List<T>): Boolean {
|
||||
this.forEach { mainItem ->
|
||||
list.forEach { if (it == mainItem) return true }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -3,9 +3,14 @@ package com.tangem.tap.common.extensions
|
|||
import androidx.annotation.ColorInt
|
||||
import androidx.core.graphics.toColorInt
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@ColorInt
|
||||
fun Token.getColor(): Int {
|
||||
return ("#" + this.contractAddress.subSequence(2..7).toString())
|
||||
.toColorInt()
|
||||
return try {
|
||||
("#" + this.contractAddress.subSequence(2..7).toString())
|
||||
.toColorInt()
|
||||
} catch (exception: Exception) {
|
||||
R.color.lightGray4
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.domain.configurable.config.ConfigManager
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
|
|
@ -11,18 +12,25 @@ import org.rekotlin.Action
|
|||
|
||||
sealed class GlobalAction : Action {
|
||||
|
||||
object ScanFailsCounter {
|
||||
data class ChooseBehavior(val result: CompletionResult<ScanNoteResponse>) : GlobalAction()
|
||||
object Reset : GlobalAction()
|
||||
object Increment : GlobalAction()
|
||||
}
|
||||
|
||||
data class SaveScanNoteResponse(val scanNoteResponse: ScanNoteResponse) : GlobalAction()
|
||||
data class ChangeAppCurrency(val appCurrency: FiatCurrencyName) : GlobalAction()
|
||||
object RestoreAppCurrency : GlobalAction() {
|
||||
data class Success(val appCurrency: FiatCurrencyName) : GlobalAction()
|
||||
}
|
||||
|
||||
data class UpdateWalletSignedHashes(val walletSignedHashes: Int?) : GlobalAction()
|
||||
data class HideWarningMessage(val warning: WarningMessage) : GlobalAction()
|
||||
data class UpdateSecurityOptions(val securityOption: SecurityOption) : GlobalAction()
|
||||
|
||||
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
|
||||
data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction()
|
||||
data class SetFeedbackManager(val feedbackManager: FeedbackManager): GlobalAction()
|
||||
data class SetFeedbackManager(val feedbackManager: FeedbackManager) : GlobalAction()
|
||||
|
||||
data class SendFeedback(val emailData: EmailData): GlobalAction()
|
||||
data class SendFeedback(val emailData: EmailData) : GlobalAction()
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.TangemSdkError
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.preferencesStorage
|
||||
|
|
@ -13,6 +15,22 @@ val globalMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
{ nextDispatch ->
|
||||
{ action ->
|
||||
when (action) {
|
||||
is GlobalAction.ScanFailsCounter.ChooseBehavior -> {
|
||||
when (action.result) {
|
||||
is CompletionResult.Success -> store.dispatch(GlobalAction.ScanFailsCounter.Reset)
|
||||
is CompletionResult.Failure -> {
|
||||
if (action.result.error is TangemSdkError.UserCancelled) {
|
||||
store.dispatch(GlobalAction.ScanFailsCounter.Increment)
|
||||
if (store.state.globalState.scanCardFailsCounter >= 2) {
|
||||
store.dispatch(HomeAction.ShowDialog.ScanFails)
|
||||
store.dispatch(WalletAction.ShowDialog.ScanFails)
|
||||
}
|
||||
} else {
|
||||
store.dispatch(GlobalAction.ScanFailsCounter.Reset)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is GlobalAction.RestoreAppCurrency -> {
|
||||
store.dispatch(GlobalAction.RestoreAppCurrency.Success(
|
||||
preferencesStorage.getAppCurrency()
|
||||
|
|
@ -26,10 +44,8 @@ val globalMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
store.dispatch(WalletAction.Warnings.CheckHashesCount.SaveCardId)
|
||||
}
|
||||
|
||||
store.dispatch(WalletAction.Warnings.SetWarnings(
|
||||
it.getWarnings(WarningMessage.Location.MainScreen)))
|
||||
store.dispatch(SendAction.SetWarnings(
|
||||
it.getWarnings(WarningMessage.Location.SendScreen)))
|
||||
store.dispatch(WalletAction.Warnings.Update)
|
||||
store.dispatch(SendAction.Warnings.Update)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
val globalState = state.globalState
|
||||
|
||||
return when (action) {
|
||||
is GlobalAction.ScanFailsCounter.Increment -> {
|
||||
globalState.copy(scanCardFailsCounter = globalState.scanCardFailsCounter + 1)
|
||||
}
|
||||
is GlobalAction.ScanFailsCounter.Reset -> {
|
||||
globalState.copy(scanCardFailsCounter = 0)
|
||||
}
|
||||
is GlobalAction.SaveScanNoteResponse ->
|
||||
globalState.copy(scanNoteResponse = action.scanNoteResponse)
|
||||
is GlobalAction.ChangeAppCurrency -> {
|
||||
|
|
@ -33,7 +39,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState {
|
|||
globalState.copy(configManager = action.configManager)
|
||||
}
|
||||
is GlobalAction.SetWarningManager -> globalState.copy(warningManager = action.warningManager)
|
||||
is GlobalAction.HideWarningMessage -> globalState
|
||||
is GlobalAction.UpdateSecurityOptions -> {
|
||||
val card = when (action.securityOption) {
|
||||
SecurityOption.LongTap -> globalState.scanNoteResponse?.card?.copy(
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ data class GlobalState(
|
|||
val configManager: ConfigManager? = null,
|
||||
val warningManager: WarningMessagesManager? = null,
|
||||
val feedbackManager: FeedbackManager? = null,
|
||||
val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY
|
||||
val appCurrency: FiatCurrencyName = DEFAULT_FIAT_CURRENCY,
|
||||
val scanCardFailsCounter: Int = 0,
|
||||
) : StateType
|
||||
|
||||
typealias CryptoCurrencyName = String
|
||||
typealias FiatCurrencyName = String
|
||||
|
||||
|
||||
interface StateDialog
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.CardStatus
|
||||
import com.tangem.commands.common.network.Result
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
|
|
@ -13,6 +14,7 @@ import com.tangem.tap.domain.configurable.config.ConfigManager
|
|||
import com.tangem.tap.domain.extensions.amountToCreateAccount
|
||||
import com.tangem.tap.domain.extensions.isNoAccountError
|
||||
import com.tangem.tap.domain.tasks.ScanNoteResponse
|
||||
import com.tangem.tap.domain.tokens.CardCurrencies
|
||||
import com.tangem.tap.domain.twins.TwinsHelper
|
||||
import com.tangem.tap.domain.twins.isTwinCard
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
|
|
@ -31,7 +33,7 @@ class TapWalletManager {
|
|||
private val blockchainSdkConfig by lazy {
|
||||
store.state.globalState.configManager?.config?.blockchainSdkConfig ?: BlockchainSdkConfig()
|
||||
}
|
||||
private val walletManagerFactory: WalletManagerFactory
|
||||
val walletManagerFactory: WalletManagerFactory
|
||||
by lazy { WalletManagerFactory(blockchainSdkConfig) }
|
||||
|
||||
suspend fun loadWalletData(walletManager: WalletManager) {
|
||||
|
|
@ -84,9 +86,8 @@ class TapWalletManager {
|
|||
FirebaseAnalyticsHandler.triggerEvent(AnalyticsEvent.CARD_IS_SCANNED, data.card)
|
||||
}
|
||||
TapWorkarounds.updateCard(data.card)
|
||||
store.state.globalState.warningManager?.setBlockchain(data.walletManager?.wallet?.blockchain)
|
||||
store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(data.card)
|
||||
updateConfigManager(data)
|
||||
updateFeedbackManager(data)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
store.dispatch(WalletAction.ResetState)
|
||||
|
|
@ -124,61 +125,27 @@ class TapWalletManager {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateFeedbackManager(data: ScanNoteResponse) {
|
||||
val card = data.card
|
||||
val wallet = data.walletManager?.wallet ?: return
|
||||
val infoHolder = store.state.globalState.feedbackManager?.infoHolder ?: return
|
||||
|
||||
infoHolder.cardId = card.cardId
|
||||
infoHolder.cardFirmwareVersion = card.firmwareVersion.version
|
||||
infoHolder.signedHashesCount = card.walletSignedHashes?.toString() ?: "0"
|
||||
infoHolder.sourceAddress = wallet.address
|
||||
infoHolder.explorerLink = wallet.getExploreUrl(wallet.address)
|
||||
infoHolder.blockchain = wallet.blockchain
|
||||
}
|
||||
|
||||
suspend fun loadData(data: ScanNoteResponse) {
|
||||
withContext(Dispatchers.Main) {
|
||||
store.dispatch(WalletAction.Warnings.CheckIfNeeded)
|
||||
val artworkId = data.verifyResponse?.artworkInfo?.id
|
||||
if (data.walletManager != null) {
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection))
|
||||
return@withContext
|
||||
}
|
||||
val config = store.state.globalState.configManager?.config ?: return@withContext
|
||||
|
||||
val primaryWalletManager = data.walletManager
|
||||
val primaryBlockchain = listOf(data.walletManager.wallet.blockchain)
|
||||
val primaryBlockchain = data.walletManager.wallet.blockchain
|
||||
val primaryTokenSymbol = data.card.cardData?.tokenSymbol
|
||||
val primaryToken = primaryWalletManager.presetTokens.toList()
|
||||
.firstOrNull { it.symbol == primaryTokenSymbol }
|
||||
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryBlockchain(primaryBlockchain[0]))
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryBlockchain(primaryBlockchain))
|
||||
if (primaryToken != null) {
|
||||
store.dispatch(WalletAction.MultiWallet.SetPrimaryToken(primaryToken))
|
||||
}
|
||||
|
||||
if (data.card.isMultiwalletAllowed) {
|
||||
val savedCurrencies = currenciesRepository.loadCardCurrencies(data.card.cardId)
|
||||
|
||||
val walletManagers = listOf(primaryWalletManager) +
|
||||
currenciesRepository.getBlockchains()
|
||||
.filterNot { it == primaryWalletManager.wallet.blockchain }
|
||||
.mapNotNull { walletManagerFactory.makeWalletManager(data.card, it) }
|
||||
val otherBlockhains = savedCurrencies.blockchains
|
||||
|
||||
val activeTokens = walletManagers.first { it.wallet.blockchain == Blockchain.Ethereum}
|
||||
.presetTokens.toList()
|
||||
val tokens = activeTokens + savedCurrencies.tokens
|
||||
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(primaryBlockchain + otherBlockhains))
|
||||
store.dispatch(WalletAction.MultiWallet.AddTokens(tokens))
|
||||
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
|
||||
loadMultiWalletData(data.card, primaryBlockchain, primaryWalletManager)
|
||||
} else {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(listOf(primaryWalletManager)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(primaryBlockchain))
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain)))
|
||||
}
|
||||
store.dispatch(WalletAction.SetArtworkId(data.verifyResponse?.artworkInfo?.id))
|
||||
store.dispatch(WalletAction.LoadWallet(config.isTopUpEnabled))
|
||||
|
|
@ -191,6 +158,35 @@ class TapWalletManager {
|
|||
store.dispatch(WalletAction.LoadData.Failure(TapError.UnknownBlockchain))
|
||||
store.dispatch(WalletAction.LoadArtwork(data.card, artworkId))
|
||||
}
|
||||
store.dispatch(WalletAction.Warnings.CheckIfNeeded)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMultiWalletData(
|
||||
card: Card, primaryBlockchain: Blockchain, primaryWalletManager: WalletManager
|
||||
) {
|
||||
val presetTokens = primaryWalletManager.presetTokens.toList()
|
||||
val savedCurrencies = currenciesRepository.loadCardCurrencies(card.cardId)
|
||||
|
||||
if (savedCurrencies == null) {
|
||||
store.dispatch(WalletAction.MultiWallet.SaveCurrencies(
|
||||
CardCurrencies(
|
||||
blockchains = listOf(primaryBlockchain), tokens = presetTokens
|
||||
)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(primaryWalletManager))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(listOf(primaryBlockchain)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddTokens(presetTokens))
|
||||
store.dispatch(WalletAction.MultiWallet.FindBlockchainsInUse(card, walletManagerFactory))
|
||||
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
|
||||
} else {
|
||||
val blockchains = listOf(primaryBlockchain) + savedCurrencies.blockchains
|
||||
val walletManagers = walletManagerFactory.makeWalletManagers(card, blockchains)
|
||||
val tokens = presetTokens + savedCurrencies.tokens
|
||||
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(walletManagers))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchains(blockchains))
|
||||
store.dispatch(WalletAction.MultiWallet.AddTokens(tokens))
|
||||
store.dispatch(WalletAction.MultiWallet.FindTokensInUse)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +213,10 @@ class TapWalletManager {
|
|||
when (result) {
|
||||
is Result.Success -> store.dispatch(WalletAction.LoadWallet.Success(result.data))
|
||||
is Result.Failure -> {
|
||||
if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
store.dispatch(WalletAction.LoadData.Failure(TapError.NoInternetConnection))
|
||||
return@withContext
|
||||
}
|
||||
val error = result.error
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
if (error != null && blockchain.isNoAccountError(error)) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ interface Loader<T> {
|
|||
|
||||
companion object {
|
||||
const val featuresName = "features_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
const val configValuesName = "config_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
const val configValuesName = "tangem-android-config/config_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
const val warnings = "warnings_${BuildConfig.CONFIG_ENVIRONMENT}"
|
||||
}
|
||||
}
|
||||
|
|
@ -31,11 +31,12 @@ class ConfigManager(
|
|||
localLoader.load { config ->
|
||||
setupFeature(config.features)
|
||||
setupKey(config.configValues)
|
||||
}
|
||||
remoteLoader.load { config ->
|
||||
setupFeature(config.features)
|
||||
onComplete?.invoke()
|
||||
}
|
||||
// Uncomment to enable remote config
|
||||
// remoteLoader.load { config ->
|
||||
// setupFeature(config.features)
|
||||
// }
|
||||
}
|
||||
|
||||
fun turnOff(name: String) {
|
||||
|
|
@ -79,7 +80,7 @@ class ConfigManager(
|
|||
blockchainSdkConfig = BlockchainSdkConfig(
|
||||
blockchairApiKey = values.blockchairApiKey,
|
||||
blockcypherTokens = values.blockcypherTokens,
|
||||
infuraProjectId = values.infuraProjectId
|
||||
infuraProjectId = values.infuraProjectId
|
||||
)
|
||||
)
|
||||
defaultConfig = defaultConfig.copy(
|
||||
|
|
@ -89,7 +90,7 @@ class ConfigManager(
|
|||
blockchainSdkConfig = BlockchainSdkConfig(
|
||||
blockchairApiKey = values.blockchairApiKey,
|
||||
blockcypherTokens = values.blockcypherTokens,
|
||||
infuraProjectId = values.infuraProjectId
|
||||
infuraProjectId = values.infuraProjectId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.domain.configurable.warningMessage
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tangem_sdk_new.ui.animation.VoidCallback
|
||||
import com.tangem.tap.common.extensions.containsAny
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
|
|
@ -11,7 +12,6 @@ class WarningMessagesManager(
|
|||
private val warningLoader: RemoteWarningLoader,
|
||||
) {
|
||||
|
||||
private var blockchain: Blockchain? = null
|
||||
private val warningsList: MutableList<WarningMessage> = mutableListOf()
|
||||
|
||||
fun load(onComplete: VoidCallback? = null) {
|
||||
|
|
@ -23,10 +23,6 @@ class WarningMessagesManager(
|
|||
}
|
||||
}
|
||||
|
||||
fun setBlockchain(blockchain: Blockchain?) {
|
||||
this.blockchain = blockchain
|
||||
}
|
||||
|
||||
fun addWarning(warning: WarningMessage) {
|
||||
if (findWarning(warning) == null) {
|
||||
warningsList.add(warning)
|
||||
|
|
@ -34,14 +30,14 @@ class WarningMessagesManager(
|
|||
}
|
||||
}
|
||||
|
||||
fun getWarnings(location: WarningMessage.Location): List<WarningMessage> {
|
||||
fun getWarnings(location: WarningMessage.Location, forBlockchains: List<Blockchain> = emptyList()): List<WarningMessage> {
|
||||
return warningsList
|
||||
.filter { !it.isHidden && it.location.contains(location) }
|
||||
.filter {
|
||||
val blockchainList = it.blockchainList
|
||||
val list = it.blockchainList
|
||||
when {
|
||||
blockchainList == null -> true
|
||||
blockchainList.contains(blockchain) -> true
|
||||
list == null -> true
|
||||
list.containsAny(forBlockchains) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
|
@ -117,5 +113,17 @@ class WarningMessagesManager(
|
|||
fun isAlreadySignedHashesWarning(warning: WarningMessage): Boolean {
|
||||
return warning.messageResId == R.string.alert_card_signed_transactions
|
||||
}
|
||||
|
||||
fun onlineVerificationFailed(): WarningMessage = WarningMessage(
|
||||
"",
|
||||
"",
|
||||
type = WarningMessage.Type.Permanent,
|
||||
priority = WarningMessage.Priority.Critical,
|
||||
listOf(WarningMessage.Location.MainScreen),
|
||||
null,
|
||||
R.string.warning_failed_to_verify_card_title,
|
||||
R.string.warning_failed_to_verify_card_message,
|
||||
WarningMessage.Origin.Local
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
package com.tangem.tap.domain.tasks
|
||||
|
||||
import com.tangem.CardSession
|
||||
import com.tangem.CardSessionRunnable
|
||||
import com.tangem.TangemError
|
||||
import com.tangem.TangemSdkError
|
||||
import com.tangem.*
|
||||
import com.tangem.blockchain.common.BlockchainSdkConfig
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.WalletManagerFactory
|
||||
|
|
@ -32,10 +29,6 @@ data class ScanNoteResponse(
|
|||
class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteResponse> {
|
||||
override val requiresPin2 = false
|
||||
|
||||
private val blockchainSdkConfig = store.state.globalState.configManager?.config
|
||||
?.blockchainSdkConfig ?: BlockchainSdkConfig()
|
||||
private val walletManagerFactory = WalletManagerFactory(blockchainSdkConfig)
|
||||
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<ScanNoteResponse>) -> Unit) {
|
||||
ScanTask().run(session) { result ->
|
||||
when (result) {
|
||||
|
|
@ -59,7 +52,7 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
|
|||
}
|
||||
|
||||
val walletManager = try {
|
||||
walletManagerFactory.makeWalletManager(card)
|
||||
getWalletManagerFactory().makeWalletManager(card)
|
||||
} catch (exception: Exception) {
|
||||
return@run callback(CompletionResult.Success(ScanNoteResponse(null, card)))
|
||||
}
|
||||
|
|
@ -100,7 +93,7 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
|
|||
if (verified) {
|
||||
val twinPublicKey = readDataResult.data.issuerData.sliceArray(0 until 65)
|
||||
val walletManager = try {
|
||||
walletManagerFactory.makeMultisigWalletManager(card, twinPublicKey)
|
||||
getWalletManagerFactory().makeMultisigWalletManager(card, twinPublicKey)
|
||||
} catch (exception: Exception) {
|
||||
callback(CompletionResult.Success(ScanNoteResponse(null, card)))
|
||||
return@run
|
||||
|
|
@ -124,5 +117,10 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanNoteRespons
|
|||
return null
|
||||
}
|
||||
|
||||
private fun getWalletManagerFactory(): WalletManagerFactory {
|
||||
val blockchainSdkConfig = store.state.globalState.configManager?.config
|
||||
?.blockchainSdkConfig ?: BlockchainSdkConfig()
|
||||
return WalletManagerFactory(blockchainSdkConfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@ class CurrenciesRepository(val context: Application) {
|
|||
Types.newParameterizedType(List::class.java, Blockchain::class.java)
|
||||
)
|
||||
|
||||
fun loadCardCurrencies(cardId: String): CardCurrencies {
|
||||
return CardCurrencies(loadSavedTokens(cardId), loadSavedBlockchains(cardId))
|
||||
fun loadCardCurrencies(cardId: String): CardCurrencies? {
|
||||
val blockchains = loadSavedBlockchains(cardId)
|
||||
if (blockchains.isEmpty()) return null
|
||||
|
||||
return CardCurrencies(loadSavedTokens(cardId), blockchains)
|
||||
}
|
||||
|
||||
fun saveCardCurrencies(cardId: String, currencies: CardCurrencies) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,30 @@
|
|||
package com.tangem.tap.features.feedback
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.tangem.Log
|
||||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.store
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.io.StringWriter
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -22,39 +32,60 @@ import java.io.StringWriter
|
|||
*/
|
||||
class FeedbackManager(
|
||||
val infoHolder: AdditionalEmailInfo,
|
||||
private val context: Context,
|
||||
private val logCollector: TangemLogCollector,
|
||||
private val email: String = "support@tangem.com",
|
||||
) {
|
||||
|
||||
private lateinit var activity: Activity
|
||||
|
||||
fun updateAcivity(activity: Activity) {
|
||||
this.activity = activity
|
||||
}
|
||||
|
||||
fun send(emailData: EmailData) {
|
||||
val fileLog = if (emailData is ScanFailsEmail) createLogFile() else null
|
||||
sendTo(email, emailData.subject, emailData.joinTogether(infoHolder), fileLog)
|
||||
}
|
||||
|
||||
private fun sendTo(email: String, subject: String, message: String, fileLog: File? = null) {
|
||||
val intent = Intent(Intent.ACTION_SENDTO).apply {
|
||||
data = Uri.parse("mailto:$email")
|
||||
putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||
putExtra(Intent.EXTRA_TEXT, message)
|
||||
fileLog?.let {
|
||||
val uri = FileProvider.getUriForFile(context, "${context.packageName}.provider", it)
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
}
|
||||
}
|
||||
|
||||
val emailFilterIntent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))
|
||||
val originalIntentResults = activity.packageManager.queryIntentActivities(emailFilterIntent, 0)
|
||||
val emailFilterIntentResults = activity.packageManager.queryIntentActivities(emailFilterIntent, 0)
|
||||
val targetedIntents = originalIntentResults
|
||||
.filter { originalResult ->
|
||||
emailFilterIntentResults.any {
|
||||
originalResult.activityInfo.packageName == it.activityInfo.packageName
|
||||
}
|
||||
}
|
||||
.map {
|
||||
createEmailShareIntent(email, subject, message, fileLog).apply {
|
||||
setPackage(it.activityInfo.packageName)
|
||||
}
|
||||
}
|
||||
.toMutableList()
|
||||
try {
|
||||
val chooserIntent = Intent.createChooser(intent, "Send mail...")
|
||||
val chooserIntent = Intent.createChooser(targetedIntents.removeAt(0), "Send mail...")
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toTypedArray())
|
||||
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
ContextCompat.startActivity(context, chooserIntent, null)
|
||||
ContextCompat.startActivity(activity, chooserIntent, null)
|
||||
} catch (ex: ActivityNotFoundException) {
|
||||
Timber.e(ex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEmailShareIntent(recipient: String, subject: String, text: String, file: File? = null): Intent {
|
||||
val builder = ShareCompat.IntentBuilder.from(activity)
|
||||
.setType("message/rfc822")
|
||||
.setEmailTo(arrayOf(recipient))
|
||||
.setSubject(subject)
|
||||
.setText(text)
|
||||
file?.let { builder.setStream(FileProvider.getUriForFile(activity, "${activity.packageName}.provider", it)) }
|
||||
return builder.intent
|
||||
}
|
||||
|
||||
private fun createLogFile(): File? {
|
||||
return try {
|
||||
val file = File(context.filesDir, "logs.txt")
|
||||
val file = File(activity.filesDir, "logs.txt")
|
||||
file.delete()
|
||||
file.createNewFile()
|
||||
|
||||
|
|
@ -73,10 +104,12 @@ class FeedbackManager(
|
|||
}
|
||||
|
||||
class TangemLogCollector : TangemSdkLogger {
|
||||
private val dateFormatter = SimpleDateFormat("HH:mm:ss.SSS")
|
||||
private val logs = mutableListOf<String>()
|
||||
|
||||
override fun log(message: () -> String, level: Log.Level) {
|
||||
logs.add(message())
|
||||
val time = dateFormatter.format(Date())
|
||||
logs.add("$time: ${message()}\n")
|
||||
}
|
||||
|
||||
fun getLogs(): List<String> = logs.toList()
|
||||
|
|
@ -87,26 +120,36 @@ class TangemLogCollector : TangemSdkLogger {
|
|||
}
|
||||
|
||||
class AdditionalEmailInfo {
|
||||
var cardId: String = ""
|
||||
var cardFirmwareVersion: String = ""
|
||||
var blockchain: Blockchain = Blockchain.Unknown
|
||||
class EmailWalletInfo(
|
||||
var blockchain: Blockchain = Blockchain.Unknown,
|
||||
var address: String = "",
|
||||
var explorerLink: String = "",
|
||||
// var outputsCount: String = ""
|
||||
// var transactionHex: String = ""
|
||||
)
|
||||
|
||||
var phoneModel: String = Build.MODEL
|
||||
var osVersion: String = Build.VERSION.SDK_INT.toString()
|
||||
var appVersion: String = ""
|
||||
|
||||
var token: String = ""
|
||||
var sourceAddress: String = ""
|
||||
// card
|
||||
var cardId: String = ""
|
||||
var cardFirmwareVersion: String = ""
|
||||
|
||||
// wallets
|
||||
internal val walletsInfo = mutableListOf<EmailWalletInfo>()
|
||||
internal var onSendErrorWalletInfo: EmailWalletInfo? = null
|
||||
var signedHashesCount: String = ""
|
||||
|
||||
// device
|
||||
var phoneModel: String = Build.MODEL
|
||||
var osVersion: String = Build.VERSION.SDK_INT.toString()
|
||||
|
||||
// send error
|
||||
var destinationAddress: String = ""
|
||||
var amount: String = ""
|
||||
var fee: String = ""
|
||||
var token: String = ""
|
||||
|
||||
// var transactionHex: String = ""
|
||||
var signedHashesCount: String = ""
|
||||
var explorerLink: String = ""
|
||||
// var outputsCount: String = ""
|
||||
|
||||
fun updateAppVersion(context: Context) {
|
||||
fun setAppVersion(context: Context) {
|
||||
try {
|
||||
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
appVersion = pInfo.versionName
|
||||
|
|
@ -114,6 +157,51 @@ class AdditionalEmailInfo {
|
|||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun setCardInfo(card: Card) {
|
||||
cardId = card.cardId
|
||||
cardFirmwareVersion = card.firmwareVersion.version
|
||||
signedHashesCount = card.walletSignedHashes?.toString() ?: "0"
|
||||
}
|
||||
|
||||
fun setWalletsInfo(wallets: List<Wallet>) {
|
||||
walletsInfo.clear()
|
||||
wallets.forEach { walletsInfo.add(EmailWalletInfo(it.blockchain, getAddress(it), getExploreUri(it))) }
|
||||
}
|
||||
|
||||
fun updateOnSendError(wallet: Wallet, amountToSend: Amount, feeAmount: Amount, destinationAddress: String) {
|
||||
val amountState = store.state.sendState.amountState
|
||||
onSendErrorWalletInfo = EmailWalletInfo(wallet.blockchain, getAddress(wallet), getExploreUri(wallet))
|
||||
|
||||
this.destinationAddress = destinationAddress
|
||||
amount = amountToSend.value?.stripZeroPlainString() ?: "0"
|
||||
fee = feeAmount.value?.stripZeroPlainString() ?: "0"
|
||||
if (amountState.typeOfAmount is AmountType.Token) {
|
||||
token = amountState.amountToExtract?.currencySymbol ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAddress(wallet: Wallet): String {
|
||||
return if (wallet.addresses.size == 1) {
|
||||
wallet.address
|
||||
} else {
|
||||
val addresses = wallet.addresses.joinToString(", ") {
|
||||
"${it.type.javaClass.simpleName} - ${it.value}"
|
||||
}
|
||||
"Multiple address: $addresses"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getExploreUri(wallet: Wallet): String {
|
||||
return if (wallet.addresses.size == 1) {
|
||||
wallet.getExploreUrl(wallet.address)
|
||||
} else {
|
||||
val links = wallet.addresses.joinToString(", ") {
|
||||
"${it.type.javaClass.simpleName} - ${wallet.getExploreUrl(it.value)}"
|
||||
}
|
||||
"Multiple explorers links: $links"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface EmailData {
|
||||
|
|
@ -133,9 +221,10 @@ class RateCanBeBetterEmail : EmailData {
|
|||
override val mainMessage: String = "Tell us what functions you are missing, and we will try to help you."
|
||||
|
||||
override fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String {
|
||||
val walletInfo = infoHolder.walletsInfo[0]
|
||||
return StringBuilder().apply {
|
||||
appendKeyValue("Card ID", infoHolder.cardId)
|
||||
appendKeyValue("Blockchain", infoHolder.blockchain.fullName)
|
||||
appendKeyValue("Blockchain", walletInfo.blockchain.fullName)
|
||||
appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
appendKeyValue("OS version", infoHolder.osVersion)
|
||||
appendKeyValue("App version", infoHolder.appVersion)
|
||||
|
|
@ -159,12 +248,13 @@ class SendTransactionFailedEmail(private val error: String) : EmailData {
|
|||
override val subject: String = "Can’t send a transaction"
|
||||
override val mainMessage: String = "Please tell us more about your issue. Every small detail can help."
|
||||
override fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String {
|
||||
val walletInfo = infoHolder.onSendErrorWalletInfo ?: AdditionalEmailInfo.EmailWalletInfo()
|
||||
return StringBuilder().apply {
|
||||
appendKeyValue("Error", error)
|
||||
appendKeyValue("Card ID", infoHolder.cardId)
|
||||
appendKeyValue("Blockchain", infoHolder.blockchain.fullName)
|
||||
appendKeyValue("Blockchain", walletInfo.blockchain.fullName)
|
||||
appendKeyValue("Token", infoHolder.token)
|
||||
appendKeyValue("Source address", infoHolder.sourceAddress)
|
||||
appendKeyValue("Source address", walletInfo.address)
|
||||
appendKeyValue("Destination address", infoHolder.destinationAddress)
|
||||
appendKeyValue("Amount", infoHolder.amount)
|
||||
appendKeyValue("Fee", infoHolder.fee)
|
||||
|
|
@ -181,17 +271,20 @@ class FeedbackEmail : EmailData {
|
|||
override val subject: String = "Tangem Tap feedback"
|
||||
override val mainMessage: String = "Hi Tangem,"
|
||||
override fun createOptionalMessage(infoHolder: AdditionalEmailInfo): String {
|
||||
return StringBuilder().apply {
|
||||
appendKeyValue("Card ID", infoHolder.cardId)
|
||||
appendKeyValue("Firmware version", infoHolder.cardFirmwareVersion)
|
||||
appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
appendKeyValue("Blockchain", infoHolder.blockchain.fullName)
|
||||
appendKeyValue("Wallet address", infoHolder.sourceAddress)
|
||||
appendKeyValue("Explorer link", infoHolder.explorerLink)
|
||||
val builder = StringBuilder()
|
||||
builder.appendKeyValue("Card ID", infoHolder.cardId)
|
||||
builder.appendKeyValue("Firmware version", infoHolder.cardFirmwareVersion)
|
||||
builder.appendKeyValue("Signed hashes", infoHolder.signedHashesCount)
|
||||
|
||||
infoHolder.walletsInfo.forEach {
|
||||
builder.appendKeyValue("Blockchain", it.blockchain.fullName)
|
||||
builder.appendKeyValue("Wallet address", it.address)
|
||||
builder.appendKeyValue("Explorer link", it.explorerLink)
|
||||
}
|
||||
// appendKeyValue("Outputs count", infoHolder.outputsCount)
|
||||
appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
appendKeyValue("OS version", infoHolder.osVersion)
|
||||
}.toString()
|
||||
builder.appendKeyValue("Phone model", infoHolder.phoneModel)
|
||||
builder.appendKeyValue("OS version", infoHolder.osVersion)
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.tap.features.home
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeDialog
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.ScanFailsDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
|
|
@ -13,6 +17,8 @@ import org.rekotlin.StoreSubscriber
|
|||
|
||||
class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState> {
|
||||
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
|
|
@ -39,6 +45,19 @@ class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState
|
|||
btn_shop.text = getText(R.string.home_button_shop)
|
||||
btn_yes.text = getText(R.string.home_button_scan)
|
||||
}
|
||||
handleDialog(state.dialog)
|
||||
}
|
||||
|
||||
private fun handleDialog(stateDialog: StateDialog?) {
|
||||
when (stateDialog) {
|
||||
is HomeDialog.ScanFailsDialog -> {
|
||||
if (dialog == null) dialog = ScanFailsDialog.create(requireContext()).apply { show() }
|
||||
}
|
||||
else -> {
|
||||
dialog?.dismiss()
|
||||
dialog = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,10 @@ sealed class HomeAction : Action {
|
|||
object CheckIfFirstLaunch : HomeAction() {
|
||||
data class Result(val firstLaunch: Boolean) : HomeAction()
|
||||
}
|
||||
|
||||
object ShowDialog : HomeAction() {
|
||||
object ScanFails : HomeAction()
|
||||
}
|
||||
|
||||
object HideDialog : HomeAction()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class HomeMiddleware {
|
|||
scope.launch {
|
||||
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler)
|
||||
withContext(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.ScanFailsCounter.ChooseBehavior(result))
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ private fun internalReduce(action: Action, state: AppState): HomeState {
|
|||
is HomeAction.CheckIfFirstLaunch.Result -> {
|
||||
homeState = homeState.copy(firstLaunch = action.firstLaunch)
|
||||
}
|
||||
is HomeAction.ShowDialog.ScanFails -> {
|
||||
homeState = homeState.copy(dialog = HomeDialog.ScanFailsDialog)
|
||||
}
|
||||
is HomeAction.HideDialog -> {
|
||||
homeState = homeState.copy(dialog = null)
|
||||
}
|
||||
}
|
||||
|
||||
return homeState
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class HomeState(
|
||||
val firstLaunch: Boolean = true
|
||||
val firstLaunch: Boolean = true,
|
||||
val dialog: StateDialog? = null
|
||||
) : StateType
|
||||
|
||||
sealed class HomeDialog: StateDialog {
|
||||
object ScanFailsDialog: HomeDialog()
|
||||
}
|
||||
|
|
@ -3,8 +3,10 @@ package com.tangem.tap.features.send.redux
|
|||
import com.tangem.Message
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.tap.common.redux.ErrorAction
|
||||
import com.tangem.tap.common.redux.ToastNotificationAction
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.features.send.redux.states.FeeType
|
||||
|
|
@ -25,6 +27,7 @@ object ReleaseSendState : Action
|
|||
data class PrepareSendScreen(
|
||||
val coinAmount: Amount?,
|
||||
val coinRate: BigDecimal?,
|
||||
val walletManager: WalletManager?,
|
||||
val tokenAmount: Amount? = null,
|
||||
val tokenRate: BigDecimal? = null
|
||||
) : SendScreenAction
|
||||
|
|
@ -140,14 +143,19 @@ sealed class SendAction : SendScreenAction {
|
|||
|
||||
data class SendError(override val error: TapError) : SendAction(), ErrorAction
|
||||
|
||||
sealed class Dialog : SendAction() {
|
||||
sealed class Dialog : SendAction(), StateDialog {
|
||||
data class TezosWarningDialog(
|
||||
val reduceCallback: () -> Unit,
|
||||
val sendAllCallback: () -> Unit,
|
||||
val reduceAmount: BigDecimal,
|
||||
) : Dialog()
|
||||
data class SendTransactionFails(val errorMessage: String): Dialog()
|
||||
|
||||
data class SendTransactionFails(val errorMessage: String) : Dialog()
|
||||
object Hide : Dialog()
|
||||
}
|
||||
data class SetWarnings(val warningList: List<WarningMessage>) : SendAction()
|
||||
|
||||
sealed class Warnings : SendAction() {
|
||||
object Update : SendAction()
|
||||
data class Set(val warningList: List<WarningMessage>) : SendAction()
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.TapWorkarounds
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.extensions.minimalAmount
|
||||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.send.redux.FeeAction.RequestFee
|
||||
|
|
@ -46,6 +47,7 @@ val sendMiddleware: Middleware<AppState> = { dispatch, appState ->
|
|||
is SendActionUi.SendAmountToRecipient ->
|
||||
verifyAndSendTransaction(action, appState(), dispatch)
|
||||
is PrepareSendScreen -> setIfSendingToPayIdEnabled(appState(), dispatch)
|
||||
is SendAction.Warnings.Update -> updateWarnings(dispatch)
|
||||
}
|
||||
nextDispatch(action)
|
||||
}
|
||||
|
|
@ -56,8 +58,8 @@ private fun verifyAndSendTransaction(
|
|||
action: SendActionUi.SendAmountToRecipient, appState: AppState?, dispatch: (Action) -> Unit,
|
||||
) {
|
||||
val sendState = appState?.sendState ?: return
|
||||
val walletManager = appState.globalState.scanNoteResponse?.walletManager ?: return
|
||||
val card = appState.globalState.scanNoteResponse.card
|
||||
val walletManager = sendState.walletManager ?: return
|
||||
val card = appState.globalState.scanNoteResponse?.card ?: return
|
||||
val destinationAddress = sendState.addressPayIdState.destinationWalletAddress ?: return
|
||||
val typedAmount = sendState.amountState.amountToExtract ?: return
|
||||
val feeAmount = sendState.feeState.currentFee ?: return
|
||||
|
|
@ -120,6 +122,9 @@ private fun sendTransaction(
|
|||
dispatch(GlobalAction.UpdateWalletSignedHashes(result.data.walletSignedHashes))
|
||||
dispatch(NavigationAction.PopBackTo())
|
||||
scope.launch(Dispatchers.IO) {
|
||||
withContext(Dispatchers.Main) {
|
||||
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain.currency))
|
||||
}
|
||||
delay(10000)
|
||||
withContext(Dispatchers.Main) {
|
||||
dispatch(WalletAction.UpdateWallet(walletManager.wallet.blockchain.currency))
|
||||
|
|
@ -142,10 +147,11 @@ private fun sendTransaction(
|
|||
is Throwable -> {
|
||||
val throwable = result.error as Throwable
|
||||
val message = throwable.message
|
||||
val infoHolder = store.state.globalState.feedbackManager?.infoHolder
|
||||
when {
|
||||
message == null -> {
|
||||
dispatch(SendAction.SendError(TapError.UnknownError))
|
||||
updateFeedbackManager(walletManager, amountToSend, feeAmount, destinationAddress, card)
|
||||
infoHolder?.updateOnSendError(walletManager.wallet, amountToSend, feeAmount, destinationAddress)
|
||||
dispatch(SendAction.Dialog.SendTransactionFails("unknown error"))
|
||||
}
|
||||
message.contains("50002") -> {
|
||||
|
|
@ -160,7 +166,7 @@ private fun sendTransaction(
|
|||
Timber.e(throwable)
|
||||
FirebaseCrashlytics.getInstance().recordException(throwable)
|
||||
dispatch(SendAction.SendError(TapError.CustomError(message)))
|
||||
updateFeedbackManager(walletManager, amountToSend, feeAmount, destinationAddress, card)
|
||||
infoHolder?.updateOnSendError(walletManager.wallet, amountToSend, feeAmount, destinationAddress)
|
||||
dispatch(SendAction.Dialog.SendTransactionFails(message))
|
||||
}
|
||||
}
|
||||
|
|
@ -173,29 +179,6 @@ private fun sendTransaction(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateFeedbackManager(
|
||||
walletManager: WalletManager,
|
||||
amountToSend: Amount,
|
||||
feeAmount: Amount,
|
||||
destinationAddress: String,
|
||||
card: Card,
|
||||
) {
|
||||
val infoHolder = store.state.globalState.feedbackManager?.infoHolder ?: return
|
||||
val amountState = store.state.sendState.amountState
|
||||
|
||||
infoHolder.cardId = card.cardId
|
||||
infoHolder.blockchain = walletManager.wallet.blockchain
|
||||
infoHolder.sourceAddress = walletManager.wallet.address
|
||||
infoHolder.destinationAddress = destinationAddress
|
||||
infoHolder.amount = amountToSend.value?.stripZeroPlainString() ?: "0"
|
||||
infoHolder.fee = feeAmount.value?.stripZeroPlainString() ?: "0"
|
||||
infoHolder.cardFirmwareVersion = card.firmwareVersion.version
|
||||
if (amountState.typeOfAmount is AmountType.Token) {
|
||||
infoHolder.token = amountState.amountToExtract?.currencySymbol ?: ""
|
||||
}
|
||||
// infoHolder.transactionHex = ""
|
||||
}
|
||||
|
||||
fun extractErrorsForAmountField(errors: EnumSet<TransactionError>): EnumSet<TransactionError> {
|
||||
val showIntoAmountField = EnumSet.noneOf(TransactionError::class.java)
|
||||
errors.forEach {
|
||||
|
|
@ -243,3 +226,11 @@ private fun setIfSendingToPayIdEnabled(appState: AppState?, dispatch: (Action) -
|
|||
dispatch(AddressPayIdActionUi.ChangePayIdState(isSendingToPayIdEnabled))
|
||||
}
|
||||
|
||||
private fun updateWarnings(dispatch: (Action) -> Unit) {
|
||||
val warningsManager = store.state.globalState.warningManager ?: return
|
||||
val blockchain = store.state.sendState.walletManager?.wallet?.blockchain ?: return
|
||||
|
||||
val warnings = warningsManager.getWarnings(WarningMessage.Location.SendScreen, listOf(blockchain))
|
||||
dispatch(SendAction.Warnings.Set(warnings))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ private class SendReducer : SendInternalReducer {
|
|||
is SendAction.Dialog.TezosWarningDialog -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.SendTransactionFails -> sendState.copy(dialog = action)
|
||||
is SendAction.Dialog.Hide -> sendState.copy(dialog = null)
|
||||
is SendAction.SetWarnings -> sendState.copy(sendWarningsList = action.warningList)
|
||||
is SendAction.Warnings.Set -> sendState.copy(sendWarningsList = action.warningList)
|
||||
else -> return sendState
|
||||
}
|
||||
|
||||
|
|
@ -60,14 +60,15 @@ private class EmptyReducer : SendInternalReducer {
|
|||
private class PrepareSendScreenStatesReducer : SendInternalReducer {
|
||||
override fun handle(action: SendScreenAction, sendState: SendState): SendState {
|
||||
val prepareAction = action as PrepareSendScreen
|
||||
val walletManager = store.state.globalState.scanNoteResponse!!.walletManager!!
|
||||
val walletManager = action.walletManager
|
||||
?: store.state.globalState.scanNoteResponse!!.walletManager!!
|
||||
val amountToExtract = prepareAction.tokenAmount ?: prepareAction.coinAmount!!
|
||||
val decimals = amountToExtract.decimals
|
||||
|
||||
return sendState.copy(
|
||||
walletManager = walletManager,
|
||||
coinConverter = action.coinRate?.let { CurrencyConverter(it, decimals) },
|
||||
tokenConverter = action.tokenRate?. let { CurrencyConverter(it, decimals) },
|
||||
tokenConverter = action.tokenRate?.let { CurrencyConverter(it, decimals) },
|
||||
amountState = sendState.amountState.copy(
|
||||
amountToExtract = amountToExtract,
|
||||
typeOfAmount = amountToExtract.type,
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import com.tangem.blockchain.common.WalletManager
|
|||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.CurrencyConverter
|
||||
import com.tangem.tap.common.entities.TapCurrency
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.common.text.DecimalDigitsInputFilter
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.features.send.redux.SendAction
|
||||
import com.tangem.tap.store
|
||||
import org.rekotlin.StateType
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -40,7 +40,7 @@ data class SendState(
|
|||
val receiptState: ReceiptState = ReceiptState(),
|
||||
val sendWarningsList: List<WarningMessage> = listOf(),
|
||||
val sendButtonState: SendButtonState = SendButtonState.DISABLED,
|
||||
val dialog: SendAction.Dialog? = null
|
||||
val dialog: StateDialog? = null
|
||||
) : SendScreenState {
|
||||
|
||||
override val stateId: StateId = StateId.SEND_SCREEN
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity
|
|||
import com.tangem.tap.common.snackBar.MaxAmountSnackbar
|
||||
import com.tangem.tap.common.text.truncateMiddleWith
|
||||
import com.tangem.tap.common.toggleWidget.*
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.features.send.BaseStoreFragment
|
||||
import com.tangem.tap.features.send.redux.*
|
||||
import com.tangem.tap.features.send.redux.AddressPayIdActionUi.*
|
||||
|
|
@ -235,8 +234,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
rv_warning_messages.addItemDecoration(SpacesItemDecoration(rv_warning_messages.dpToPx(16f).toInt()))
|
||||
rv_warning_messages.adapter = warningsAdapter
|
||||
|
||||
val warnings = store.state.globalState.warningManager?.getWarnings(WarningMessage.Location.SendScreen) ?: listOf()
|
||||
store.dispatch(SendAction.SetWarnings(warnings))
|
||||
store.dispatch(SendAction.Warnings.Update)
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.redux
|
||||
|
||||
import android.content.Context
|
||||
import com.tangem.TangemError
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.commands.common.card.Card
|
||||
|
|
@ -10,6 +9,7 @@ import com.tangem.tap.common.redux.NotificationAction
|
|||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.tokens.CardCurrencies
|
||||
import com.tangem.tap.domain.twins.TwinCardNumber
|
||||
import com.tangem.wallet.R
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -33,29 +33,18 @@ sealed class WalletAction : Action {
|
|||
data class SetArtworkId(val artworkId: String?) : WalletAction()
|
||||
|
||||
|
||||
// sealed class ProcessWallet : WalletAction() {
|
||||
// data class LoadWallet(val artworkId: String?, val allowTopUp: Boolean
|
||||
// ) : ProcessWallet() {
|
||||
// data class Success(val wallet: Wallet) : ProcessWallet()
|
||||
// data class NoAccount(val wallet: Wallet, val amountToCreateAccount: String) : ProcessWallet()
|
||||
// data class Failure(val wallet: Wallet, val errorMessage: String? = null) : ProcessWallet()
|
||||
// }
|
||||
//
|
||||
// data class UpdateWallet(val currency: CryptoCurrencyName? = null) : ProcessWallet() {
|
||||
// object ScheduleUpdatingWallet : ProcessWallet()
|
||||
// data class Success(val wallet: Wallet) : ProcessWallet()
|
||||
// data class Failure(val errorMessage: String? = null) : ProcessWallet()
|
||||
// }
|
||||
// }
|
||||
|
||||
sealed class MultiWallet : WalletAction() {
|
||||
data class SetIsMultiwalletAllowed(val isMultiwalletAllowed: Boolean) : MultiWallet()
|
||||
data class AddWalletManagers(val walletManagers: List<WalletManager>) : MultiWallet()
|
||||
data class AddWalletManagers(val walletManagers: List<WalletManager>) : MultiWallet() {
|
||||
constructor(walletManager: WalletManager) : this(listOf(walletManager))
|
||||
}
|
||||
data class AddBlockchain(val blockchain: Blockchain) : MultiWallet()
|
||||
data class AddBlockchains(val blockchains: List<Blockchain>) : MultiWallet()
|
||||
data class AddTokens(val tokens: List<Token>) : MultiWallet()
|
||||
data class AddToken(val token: Token) : MultiWallet()
|
||||
data class SaveCurrencies(val cardCurrencies: CardCurrencies) : MultiWallet()
|
||||
object FindTokensInUse : MultiWallet()
|
||||
data class FindBlockchainsInUse(val card: Card, val factory: WalletManagerFactory) : MultiWallet()
|
||||
data class TokenLoaded(val amount: Amount) : MultiWallet()
|
||||
data class SelectWallet(val walletData: WalletData?) : MultiWallet()
|
||||
data class RemoveWallet(val walletData: WalletData) : MultiWallet()
|
||||
|
|
@ -72,7 +61,8 @@ sealed class WalletAction : Action {
|
|||
}
|
||||
|
||||
object CheckIfNeeded : Warnings()
|
||||
data class SetWarnings(val warningList: List<WarningMessage>) : Warnings()
|
||||
object Update : Warnings()
|
||||
data class Set(val warningList: List<WarningMessage>) : Warnings()
|
||||
|
||||
object AppRating : Warnings() {
|
||||
object SetNeverToShow : Warnings()
|
||||
|
|
@ -99,7 +89,6 @@ sealed class WalletAction : Action {
|
|||
}
|
||||
|
||||
object Scan : WalletAction()
|
||||
class ScanCardFinished(val scanError: TangemError? = null) : WalletAction()
|
||||
|
||||
data class Send(val amount: Amount? = null) : WalletAction() {
|
||||
data class ChooseCurrency(val amounts: List<Amount>?) : WalletAction()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.common.address.AddressType
|
|||
import com.tangem.blockchain.extensions.isAboveZero
|
||||
import com.tangem.tap.common.entities.Button
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.domain.extensions.toSendableAmounts
|
||||
import com.tangem.tap.domain.twins.TwinCardNumber
|
||||
|
|
@ -22,10 +23,9 @@ data class WalletState(
|
|||
val error: ErrorType? = null,
|
||||
val cardImage: Artwork? = null,
|
||||
val hashesCountVerified: Boolean? = null,
|
||||
val walletDialog: WalletDialog? = null,
|
||||
val walletDialog: StateDialog? = null,
|
||||
val twinCardsState: TwinCardsState? = null,
|
||||
val mainWarningsList: List<WarningMessage> = mutableListOf(),
|
||||
val scanCardFailsCounter: Int = 0,
|
||||
val wallets: List<WalletData> = emptyList(),
|
||||
val walletManagers: List<WalletManager> = emptyList(),
|
||||
val isMultiwalletAllowed: Boolean = false,
|
||||
|
|
@ -42,16 +42,26 @@ data class WalletState(
|
|||
primaryWallet?.currencyData?.status != com.tangem.tap.features.wallet.ui.BalanceStatus.EmptyCard &&
|
||||
primaryWallet?.currencyData?.status != com.tangem.tap.features.wallet.ui.BalanceStatus.UnknownBlockchain
|
||||
|
||||
val blockchains: List<Blockchain>
|
||||
get() = walletManagers.map { it.wallet.blockchain }
|
||||
|
||||
fun getWalletManager(currencyName: CryptoCurrencyName?): WalletManager? {
|
||||
if (currencyName == null) return null
|
||||
val walletManager = walletManagers.find { it.wallet.blockchain.currency == currencyName }
|
||||
if (walletManager != null) return walletManager
|
||||
return walletManager ?: getWalletManagerForToken(currencyName)
|
||||
}
|
||||
|
||||
fun getWalletManagerForToken(currencyName: CryptoCurrencyName?): WalletManager? {
|
||||
val ethereumWalletManager = walletManagers.find { it.wallet.blockchain == Blockchain.Ethereum }
|
||||
return if (ethereumWalletManager?.presetTokens?.find { it.symbol == currencyName } != null) {
|
||||
ethereumWalletManager
|
||||
} else {
|
||||
null
|
||||
val primaryWalletManager = walletManagers.find { it.wallet.blockchain == primaryBlockchain }
|
||||
if (primaryWalletManager?.presetTokens?.find { it.symbol == currencyName } != null) {
|
||||
primaryWalletManager
|
||||
} else {
|
||||
ethereumWalletManager
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +106,7 @@ data class WalletState(
|
|||
|
||||
}
|
||||
|
||||
sealed class WalletDialog {
|
||||
sealed class WalletDialog: StateDialog {
|
||||
data class QrDialog(
|
||||
val qrCode: Bitmap?, val shareUrl: String?, val currencyName: CryptoCurrencyName?
|
||||
) : WalletDialog()
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
package com.tangem.tap.features.wallet.redux.middlewares
|
||||
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.TokenFinder
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -14,14 +15,19 @@ import com.tangem.tap.features.wallet.redux.WalletState
|
|||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class MultiWalletMiddleware {
|
||||
fun handle(
|
||||
action: WalletAction.MultiWallet, walletState: WalletState?, globalState: GlobalState?
|
||||
action: WalletAction.MultiWallet, walletState: WalletState?, globalState: GlobalState?,
|
||||
) {
|
||||
when (action) {
|
||||
is WalletAction.MultiWallet.AddWalletManagers -> {
|
||||
val wallets = action.walletManagers.map { it.wallet }
|
||||
store.state.globalState.feedbackManager?.infoHolder?.setWalletsInfo(wallets)
|
||||
}
|
||||
is WalletAction.MultiWallet.SelectWallet -> {
|
||||
if (action.walletData != null) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletDetails))
|
||||
|
|
@ -37,10 +43,19 @@ class MultiWalletMiddleware {
|
|||
action.tokens.map { addToken(it, walletState) }
|
||||
}
|
||||
is WalletAction.MultiWallet.AddBlockchain -> {
|
||||
globalState?.scanNoteResponse?.card?.cardId?.let {
|
||||
currenciesRepository.saveAddedBlockchain(it, action.blockchain)
|
||||
globalState?.scanNoteResponse?.card?.let { card ->
|
||||
currenciesRepository.saveAddedBlockchain(card.cardId, action.blockchain)
|
||||
globalState.tapWalletManager.walletManagerFactory
|
||||
.makeWalletManager(card, action.blockchain)?.let {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(it))
|
||||
}
|
||||
}
|
||||
store.dispatch(WalletAction.LoadFiatRate(currency = action.blockchain.currency))
|
||||
store.dispatch(WalletAction.LoadWallet(currency = action.blockchain.currency))
|
||||
}
|
||||
is WalletAction.MultiWallet.SaveCurrencies -> {
|
||||
val cardId = globalState?.scanNoteResponse?.card?.cardId
|
||||
cardId?.let { currenciesRepository.saveCardCurrencies(it, action.cardCurrencies) }
|
||||
}
|
||||
is WalletAction.MultiWallet.RemoveWallet -> {
|
||||
val cardId = globalState?.scanNoteResponse?.card?.cardId
|
||||
|
|
@ -50,10 +65,39 @@ class MultiWalletMiddleware {
|
|||
cardId?.let { currenciesRepository.removeBlockchain(it, action.walletData.blockchain) }
|
||||
}
|
||||
}
|
||||
is WalletAction.MultiWallet.FindBlockchainsInUse -> {
|
||||
val blockchains = currenciesRepository.getBlockchains()
|
||||
.filterNot { walletState?.blockchains?.contains(it) == true }
|
||||
val walletManagers = action.factory.makeWalletManagers(action.card, blockchains)
|
||||
|
||||
scope.launch {
|
||||
walletManagers.map { walletManager ->
|
||||
async(Dispatchers.IO) {
|
||||
try {
|
||||
walletManager.update()
|
||||
val wallet = walletManager.wallet
|
||||
val coinAmount = wallet.amounts[AmountType.Coin]?.value
|
||||
if (coinAmount != null && !coinAmount.isZero()) {
|
||||
if (walletState?.getWalletData(wallet.blockchain.currency) == null) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
store.dispatch(WalletAction.MultiWallet.AddWalletManagers(
|
||||
listOfNotNull(walletManager)))
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchain(
|
||||
wallet.blockchain
|
||||
))
|
||||
store.dispatch(WalletAction.LoadWallet.Success(wallet))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is WalletAction.MultiWallet.FindTokensInUse -> {
|
||||
val walletManager = walletState?.getWalletManager(Blockchain.Ethereum.currency)
|
||||
?: return
|
||||
val alreadyAddedTokens = walletManager.presetTokens
|
||||
val tokenFinder = walletManager as TokenFinder
|
||||
scope.launch {
|
||||
val result = tokenFinder.findTokens()
|
||||
|
|
@ -62,9 +106,7 @@ class MultiWalletMiddleware {
|
|||
is Result.Success -> {
|
||||
if (result.data.isNotEmpty()) {
|
||||
store.dispatch(WalletAction.MultiWallet.AddTokens(
|
||||
walletManager.presetTokens
|
||||
.filterNot { presetToken -> alreadyAddedTokens.any { it.symbol == presetToken.symbol } }
|
||||
.toList()
|
||||
walletManager.presetTokens.toList()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -76,8 +118,7 @@ class MultiWalletMiddleware {
|
|||
}
|
||||
|
||||
private fun addToken(token: Token, walletState: WalletState?) {
|
||||
val walletManager =
|
||||
(walletState?.getWalletManager(Blockchain.Ethereum.currency) as? EthereumWalletManager)
|
||||
val walletManager = walletState?.getWalletManager(token.symbol)
|
||||
scope.launch {
|
||||
val result = walletManager?.addToken(token)
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@ package com.tangem.tap.features.wallet.redux.middlewares
|
|||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tangem.TangemSdkError
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.common.extensions.copyToClipboard
|
||||
import com.tangem.tap.common.extensions.shareText
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.extensions.toSendableAmounts
|
||||
|
|
@ -59,6 +60,13 @@ class WalletMiddleware {
|
|||
}
|
||||
}
|
||||
is WalletAction.LoadWallet.Success -> {
|
||||
val coinAmount = action.wallet.amounts[AmountType.Coin]?.value
|
||||
if (coinAmount != null && !coinAmount.isZero()) {
|
||||
if (walletState?.getWalletData(action.wallet.blockchain.currency) == null) {
|
||||
store.dispatch(WalletAction.MultiWallet.AddBlockchain(action.wallet.blockchain))
|
||||
store.dispatch(WalletAction.LoadWallet.Success(action.wallet))
|
||||
}
|
||||
}
|
||||
store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline)
|
||||
warningsMiddleware.tryToShowAppRatingWarning(action.wallet)
|
||||
}
|
||||
|
|
@ -126,27 +134,12 @@ class WalletMiddleware {
|
|||
is WalletAction.Scan -> {
|
||||
scope.launch {
|
||||
val result = tangemSdkManager.scanNote(FirebaseAnalyticsHandler)
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card)
|
||||
globalState?.tapWalletManager
|
||||
?.onCardScanned(result.data, true)
|
||||
if (walletState?.twinCardsState != null) {
|
||||
val showOnboarding = !preferencesStorage.wasTwinsOnboardingShown()
|
||||
if (showOnboarding) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
}
|
||||
}
|
||||
store.dispatch(WalletAction.ScanCardFinished())
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
if (result.error !is TangemSdkError.UserCancelled) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
store.dispatch(WalletAction.ScanCardFinished(result.error))
|
||||
if (store.state.walletState.scanCardFailsCounter >= 2) {
|
||||
store.dispatch(WalletAction.ShowDialog.ScanFails)
|
||||
}
|
||||
}
|
||||
scope.launch(Dispatchers.Main) {
|
||||
store.dispatch(GlobalAction.ScanFailsCounter.ChooseBehavior(result))
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data.card)
|
||||
globalState?.tapWalletManager?.onCardScanned(result.data, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -199,13 +192,14 @@ class WalletMiddleware {
|
|||
private fun prepareSendAction(amount: Amount?, state: WalletState?): Action {
|
||||
val selectedWalletData = state?.getSelectedWalletData()
|
||||
val currency = selectedWalletData?.currencyData?.currencySymbol
|
||||
val wallet = currency?.let { state.getWalletManager(currency)?.wallet }
|
||||
val walletManager = state?.getWalletManager(currency)
|
||||
val wallet = walletManager?.wallet
|
||||
|
||||
return if (amount != null) {
|
||||
if (amount.type is AmountType.Token) {
|
||||
prepareSendActionForToken(amount, state, selectedWalletData, wallet)
|
||||
prepareSendActionForToken(amount, state, selectedWalletData, wallet, walletManager)
|
||||
} else {
|
||||
PrepareSendScreen(amount, selectedWalletData?.fiatRate)
|
||||
PrepareSendScreen(amount, selectedWalletData?.fiatRate, walletManager)
|
||||
}
|
||||
} else {
|
||||
val amounts = wallet?.amounts?.toSendableAmounts()
|
||||
|
|
@ -213,23 +207,24 @@ class WalletMiddleware {
|
|||
val amountToSend = amounts?.find { it.currencySymbol == currency }
|
||||
?: return WalletAction.Send.ChooseCurrency(amounts)
|
||||
if (amountToSend.type is AmountType.Token) {
|
||||
prepareSendActionForToken(amount, state, selectedWalletData, wallet)
|
||||
prepareSendActionForToken(amountToSend, state, selectedWalletData, wallet, walletManager)
|
||||
} else {
|
||||
PrepareSendScreen(amountToSend, selectedWalletData.fiatRate)
|
||||
PrepareSendScreen(amountToSend, selectedWalletData.fiatRate, walletManager)
|
||||
}
|
||||
} else {
|
||||
if (amounts?.size ?: 0 > 1) {
|
||||
WalletAction.Send.ChooseCurrency(amounts)
|
||||
} else {
|
||||
val amountToSend = amounts?.first()
|
||||
PrepareSendScreen(amountToSend, selectedWalletData?.fiatRate)
|
||||
PrepareSendScreen(amountToSend, selectedWalletData?.fiatRate, walletManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareSendActionForToken(
|
||||
amount: Amount?, state: WalletState?, selectedWalletData: WalletData?, wallet: Wallet?
|
||||
amount: Amount, state: WalletState?, selectedWalletData: WalletData?, wallet: Wallet?,
|
||||
walletManager: WalletManager?
|
||||
): PrepareSendScreen {
|
||||
val coinRate = state?.getWalletData(wallet?.blockchain?.currency)?.fiatRate
|
||||
val tokenRate = if (state?.isMultiwalletAllowed == true) {
|
||||
|
|
@ -238,7 +233,7 @@ class WalletMiddleware {
|
|||
selectedWalletData?.currencyData?.token?.fiatRate
|
||||
}
|
||||
return PrepareSendScreen(
|
||||
wallet?.amounts?.get(AmountType.Coin), coinRate,
|
||||
wallet?.amounts?.get(AmountType.Coin), coinRate, walletManager,
|
||||
amount, tokenRate)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.commands.common.card.Card
|
||||
import com.tangem.commands.common.card.CardType
|
||||
import com.tangem.commands.verifycard.VerifyCardState
|
||||
import com.tangem.common.extensions.getType
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.FirebaseAnalyticsHandler
|
||||
|
|
@ -28,16 +29,9 @@ import java.math.BigDecimal
|
|||
class WarningsMiddleware {
|
||||
fun handle(action: WalletAction.Warnings, globalState: GlobalState?) {
|
||||
when (action) {
|
||||
WalletAction.Warnings.Update -> setWarningMessages()
|
||||
is WalletAction.Warnings.CheckIfNeeded -> {
|
||||
val validator = globalState?.scanNoteResponse?.walletManager as? SignatureCountValidator
|
||||
globalState?.scanNoteResponse?.card?.let { card ->
|
||||
globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local)
|
||||
if (card.getType() != CardType.Release) addWarningMessage(WarningMessagesManager.devCardWarning())
|
||||
if (!preferencesStorage.wasCardScannedBefore(card.cardId)) {
|
||||
checkIfWarningNeeded(card, validator)?.let { addWarningMessage(it) }
|
||||
}
|
||||
updateWarningMessages()
|
||||
}
|
||||
showCardWarningsIfNeeded(globalState)
|
||||
val readyToShow = preferencesStorage.appRatingLaunchObserver.isReadyToShow()
|
||||
if (readyToShow) addWarningMessage(WarningMessagesManager.appRatingWarning(), true)
|
||||
}
|
||||
|
|
@ -68,6 +62,25 @@ class WarningsMiddleware {
|
|||
}
|
||||
}
|
||||
|
||||
private fun showCardWarningsIfNeeded(globalState: GlobalState?) {
|
||||
val validator = globalState?.scanNoteResponse?.walletManager as? SignatureCountValidator
|
||||
globalState?.scanNoteResponse?.card?.let { card ->
|
||||
globalState.warningManager?.removeWarnings(WarningMessage.Origin.Local)
|
||||
if (card.getType() != CardType.Release) {
|
||||
addWarningMessage(WarningMessagesManager.devCardWarning())
|
||||
} else if (!preferencesStorage.wasCardScannedBefore(card.cardId)) {
|
||||
checkIfWarningNeeded(card, validator)?.let { addWarningMessage(it) }
|
||||
}
|
||||
if (card.getType() == CardType.Release) {
|
||||
if (globalState.scanNoteResponse.verifyResponse?.verificationState ==
|
||||
VerifyCardState.VerifiedOffline) {
|
||||
addWarningMessage(WarningMessagesManager.onlineVerificationFailed())
|
||||
}
|
||||
}
|
||||
setWarningMessages()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIfWarningNeeded(
|
||||
card: Card, signatureCountValidator: SignatureCountValidator? = null,
|
||||
): WarningMessage? {
|
||||
|
|
@ -118,11 +131,15 @@ class WarningsMiddleware {
|
|||
|
||||
private fun addWarningMessage(warning: WarningMessage, autoUpdate: Boolean = false) {
|
||||
store.state.globalState.warningManager?.addWarning(warning)
|
||||
if (autoUpdate) updateWarningMessages()
|
||||
if (autoUpdate) setWarningMessages()
|
||||
}
|
||||
|
||||
private fun updateWarningMessages() {
|
||||
val warningManager = store.state.globalState.warningManager ?: return
|
||||
store.dispatch(WalletAction.Warnings.SetWarnings(warningManager.getWarnings(WarningMessage.Location.MainScreen)))
|
||||
private fun setWarningMessages() {
|
||||
store.dispatch(WalletAction.Warnings.Set(getWarnings()))
|
||||
}
|
||||
|
||||
private fun getWarnings(): List<WarningMessage> {
|
||||
val warningManager = store.state.globalState.warningManager ?: return emptyList()
|
||||
return warningManager.getWarnings(WarningMessage.Location.MainScreen, store.state.walletState.blockchains)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.redux.reducers
|
||||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.extensions.toFiatString
|
||||
import com.tangem.tap.common.extensions.toFormattedCurrencyString
|
||||
|
|
@ -19,7 +18,7 @@ class MultiWalletReducer {
|
|||
return when (action) {
|
||||
is WalletAction.MultiWallet.AddWalletManagers -> {
|
||||
state.copy(
|
||||
walletManagers = action.walletManagers
|
||||
walletManagers = state.walletManagers + action.walletManagers
|
||||
)
|
||||
}
|
||||
is WalletAction.MultiWallet.AddBlockchains -> {
|
||||
|
|
@ -76,7 +75,6 @@ class MultiWalletReducer {
|
|||
}
|
||||
is WalletAction.MultiWallet.AddTokens -> {
|
||||
if (!state.isMultiwalletAllowed) return state
|
||||
val walletAddresses = createAddressList(state.getWalletManager(Blockchain.Ethereum.currency)?.wallet)
|
||||
val wallets = action.tokens.map { token ->
|
||||
WalletData(
|
||||
currencyData = BalanceWidgetData(
|
||||
|
|
@ -84,17 +82,23 @@ class MultiWalletReducer {
|
|||
currency = token.name,
|
||||
currencySymbol = token.symbol
|
||||
),
|
||||
walletAddresses = walletAddresses,
|
||||
walletAddresses = createAddressList(
|
||||
state.getWalletManagerForToken(token.symbol)?.wallet
|
||||
),
|
||||
mainButton = WalletMainButton.SendButton(false),
|
||||
topUpState = TopUpState(allowed = false),
|
||||
token = token
|
||||
)
|
||||
}
|
||||
state.copy(wallets = state.wallets + wallets)
|
||||
state.copy(wallets = state.replaceSomeWallets(wallets))
|
||||
}
|
||||
is WalletAction.MultiWallet.AddToken -> {
|
||||
if (!state.isMultiwalletAllowed) return state
|
||||
val walletAddresses = createAddressList(state.getWalletManager(Blockchain.Ethereum.currency)?.wallet)
|
||||
|
||||
val walletAddresses = createAddressList(
|
||||
state.getWalletManagerForToken(action.token.symbol)?.wallet
|
||||
|
||||
)
|
||||
val wallet = WalletData(
|
||||
currencyData = BalanceWidgetData(
|
||||
BalanceStatus.Loading,
|
||||
|
|
@ -110,21 +114,23 @@ class MultiWalletReducer {
|
|||
state.copy(wallets = wallets)
|
||||
}
|
||||
is WalletAction.MultiWallet.TokenLoaded -> {
|
||||
val pendingTransactions = state.getWalletManager(Blockchain.Ethereum.currency)
|
||||
val pendingTransactions = state.getWalletManagerForToken(action.amount.currencySymbol)
|
||||
?.wallet?.let { wallet ->
|
||||
wallet.recentTransactions.toPendingTransactions(wallet.address)
|
||||
} ?: emptyList()
|
||||
|
||||
val sendButtonEnabled = action.amount.value?.isZero() == false && pendingTransactions.isEmpty()
|
||||
val balanceStatus = if (pendingTransactions.isNotEmpty()) {
|
||||
BalanceStatus.TransactionInProgress
|
||||
} else {
|
||||
BalanceStatus.VerifiedOnline
|
||||
val tokenPendingTransactions = pendingTransactions
|
||||
.filter { it.currency == action.amount.currencySymbol }
|
||||
val tokenBalanceStatus = when {
|
||||
tokenPendingTransactions.isNotEmpty() -> BalanceStatus.TransactionInProgress
|
||||
pendingTransactions.isNotEmpty() -> BalanceStatus.SameCurrencyTransactionInProgress
|
||||
else -> BalanceStatus.VerifiedOnline
|
||||
}
|
||||
val tokenWalletData = state.getWalletData(action.amount.currencySymbol)
|
||||
val newTokenWalletData = tokenWalletData?.copy(
|
||||
currencyData = tokenWalletData.currencyData.copy(
|
||||
status = balanceStatus,
|
||||
status = tokenBalanceStatus,
|
||||
amount = action.amount.value?.toFormattedCurrencyString(
|
||||
action.amount.decimals, action.amount.currencySymbol
|
||||
),
|
||||
|
|
@ -156,6 +162,8 @@ class MultiWalletReducer {
|
|||
is WalletAction.MultiWallet.SetPrimaryToken ->
|
||||
state.copy(primaryToken = action.token)
|
||||
is WalletAction.MultiWallet.FindTokensInUse -> state
|
||||
is WalletAction.MultiWallet.FindBlockchainsInUse -> state
|
||||
is WalletAction.MultiWallet.SaveCurrencies -> state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.redux.reducers
|
||||
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.tap.common.extensions.toFiatString
|
||||
|
|
@ -21,112 +20,86 @@ import com.tangem.tap.store
|
|||
import java.math.RoundingMode
|
||||
|
||||
class OnWalletLoadedReducer {
|
||||
|
||||
fun reduce(wallet: Wallet, walletState: WalletState, topUpAllowed: Boolean? = null): WalletState {
|
||||
if (!walletState.isMultiwalletAllowed) {
|
||||
return onSingleWalletLoaded(wallet, walletState, topUpAllowed)
|
||||
return if (!walletState.isMultiwalletAllowed) {
|
||||
onSingleWalletLoaded(wallet, walletState, topUpAllowed)
|
||||
} else {
|
||||
val fiatCurrencySymbol = store.state.globalState.appCurrency
|
||||
val amount = wallet.amounts[AmountType.Coin]?.value
|
||||
if (walletState.getWalletData(wallet.blockchain.currency) == null && amount?.isZero() != false) {
|
||||
return walletState
|
||||
}
|
||||
if (wallet.blockchain != Blockchain.Ethereum) {
|
||||
val formattedAmount = amount?.toFormattedCurrencyString(
|
||||
wallet.blockchain.decimals(),
|
||||
wallet.blockchain.currency)
|
||||
|
||||
val pendingTransactions = wallet.recentTransactions
|
||||
.toPendingTransactions(wallet.address)
|
||||
|
||||
val sendButtonEnabled = amount?.isZero() == false && pendingTransactions.isEmpty()
|
||||
val balanceStatus = if (pendingTransactions.isNotEmpty()) {
|
||||
BalanceStatus.TransactionInProgress
|
||||
} else {
|
||||
BalanceStatus.VerifiedOnline
|
||||
}
|
||||
val walletData = walletState.getWalletData(wallet.blockchain.currency)
|
||||
?: WalletData()
|
||||
val newWalletData = walletData.copy(
|
||||
currencyData = walletData.currencyData.copy(
|
||||
status = balanceStatus, currency = wallet.blockchain.fullName,
|
||||
currencySymbol = wallet.blockchain.currency,
|
||||
amount = formattedAmount,
|
||||
fiatAmount = walletData.fiatRate?.let { amount?.toFiatString(it, fiatCurrencySymbol) }
|
||||
),
|
||||
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
|
||||
)
|
||||
val wallets = walletState.replaceWalletInWallets(newWalletData)
|
||||
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
ProgressState.Loading
|
||||
} else {
|
||||
ProgressState.Done
|
||||
}
|
||||
return walletState.copy(
|
||||
state = state, wallets = wallets
|
||||
)
|
||||
} else {
|
||||
val formattedAmount = amount?.toFormattedCurrencyString(
|
||||
wallet.blockchain.decimals(),
|
||||
wallet.blockchain.currency)
|
||||
|
||||
val pendingTransactions = wallet.recentTransactions
|
||||
.toPendingTransactions(wallet.address)
|
||||
|
||||
val sendButtonEnabled = amount?.isZero() == false && pendingTransactions.isEmpty()
|
||||
val balanceStatus = if (pendingTransactions.isNotEmpty()) {
|
||||
BalanceStatus.TransactionInProgress
|
||||
} else {
|
||||
BalanceStatus.VerifiedOnline
|
||||
}
|
||||
|
||||
val ethereumWalletData = walletState.getWalletData(wallet.blockchain.currency)
|
||||
?: WalletData()
|
||||
val newEthereumWalletData = ethereumWalletData.copy(
|
||||
currencyData = ethereumWalletData.currencyData.copy(
|
||||
status = balanceStatus,
|
||||
amount = formattedAmount,
|
||||
currency = wallet.blockchain.fullName,
|
||||
currencySymbol = wallet.blockchain.currency,
|
||||
fiatAmount = ethereumWalletData.fiatRate?.let {
|
||||
amount?.toFiatString(it, fiatCurrencySymbol)
|
||||
}
|
||||
),
|
||||
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
|
||||
)
|
||||
|
||||
val tokens = wallet.getTokens().mapNotNull { token ->
|
||||
val tokenWalletData = walletState.getWalletData(token.symbol)
|
||||
tokenWalletData?.copy(
|
||||
currencyData = tokenWalletData.currencyData.copy(
|
||||
status = balanceStatus,
|
||||
amount = wallet.getTokenAmount(token)?.value?.toFormattedCurrencyString(
|
||||
token.decimals, token.symbol
|
||||
),
|
||||
fiatAmount = tokenWalletData.fiatRate?.let {
|
||||
wallet.getTokenAmount(token)?.value
|
||||
?.toFiatString(it, fiatCurrencySymbol)
|
||||
}
|
||||
),
|
||||
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
|
||||
)
|
||||
}
|
||||
val wallets = walletState.replaceSomeWallets((tokens + newEthereumWalletData).filterNotNull())
|
||||
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
ProgressState.Loading
|
||||
} else {
|
||||
ProgressState.Done
|
||||
}
|
||||
return walletState.copy(
|
||||
state = state, wallets = wallets
|
||||
)
|
||||
}
|
||||
onMultiWalletLoaded(wallet, walletState, topUpAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSingleWalletLoaded(wallet: Wallet, walletState: WalletState, topUpAllowed: Boolean? = null
|
||||
private fun onMultiWalletLoaded(
|
||||
wallet: Wallet, walletState: WalletState, topUpAllowed: Boolean? = null
|
||||
): WalletState {
|
||||
val fiatCurrencySymbol = store.state.globalState.appCurrency
|
||||
val amount = wallet.amounts[AmountType.Coin]?.value
|
||||
if (walletState.getWalletData(wallet.blockchain.currency) == null) {
|
||||
return walletState
|
||||
}
|
||||
val formattedAmount = amount?.toFormattedCurrencyString(
|
||||
wallet.blockchain.decimals(),
|
||||
wallet.blockchain.currency)
|
||||
|
||||
val pendingTransactions = wallet.recentTransactions
|
||||
.toPendingTransactions(wallet.address)
|
||||
|
||||
val sendButtonEnabled = amount?.isZero() == false && pendingTransactions.isEmpty()
|
||||
val balanceStatus = if (pendingTransactions.isNotEmpty()) {
|
||||
BalanceStatus.TransactionInProgress
|
||||
} else {
|
||||
BalanceStatus.VerifiedOnline
|
||||
}
|
||||
val walletData = walletState.getWalletData(wallet.blockchain.currency)
|
||||
?: WalletData()
|
||||
val newWalletData = walletData.copy(
|
||||
currencyData = walletData.currencyData.copy(
|
||||
status = balanceStatus, currency = wallet.blockchain.fullName,
|
||||
currencySymbol = wallet.blockchain.currency,
|
||||
amount = formattedAmount,
|
||||
fiatAmount = walletData.fiatRate?.let { amount?.toFiatString(it, fiatCurrencySymbol) }
|
||||
),
|
||||
pendingTransactions = pendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
|
||||
)
|
||||
|
||||
val tokens = wallet.getTokens().mapNotNull { token ->
|
||||
val tokenWalletData = walletState.getWalletData(token.symbol)
|
||||
val tokenPendingTransactions = pendingTransactions.filter { it.currency == token.symbol }
|
||||
val tokenBalanceStatus = when {
|
||||
tokenPendingTransactions.isNotEmpty() -> BalanceStatus.TransactionInProgress
|
||||
pendingTransactions.isNotEmpty() -> BalanceStatus.SameCurrencyTransactionInProgress
|
||||
else -> BalanceStatus.VerifiedOnline
|
||||
}
|
||||
tokenWalletData?.copy(
|
||||
currencyData = tokenWalletData.currencyData.copy(
|
||||
status = tokenBalanceStatus,
|
||||
amount = wallet.getTokenAmount(token)?.value?.toFormattedCurrencyString(
|
||||
token.decimals, token.symbol
|
||||
),
|
||||
fiatAmount = tokenWalletData.fiatRate?.let {
|
||||
wallet.getTokenAmount(token)?.value
|
||||
?.toFiatString(it, fiatCurrencySymbol)
|
||||
}
|
||||
),
|
||||
pendingTransactions = tokenPendingTransactions.removeUnknownTransactions(),
|
||||
mainButton = WalletMainButton.SendButton(sendButtonEnabled)
|
||||
)
|
||||
}
|
||||
val wallets = walletState.replaceSomeWallets((tokens + newWalletData))
|
||||
|
||||
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
ProgressState.Loading
|
||||
} else {
|
||||
ProgressState.Done
|
||||
}
|
||||
return walletState.copy(
|
||||
state = state, wallets = wallets, error = null
|
||||
)
|
||||
}
|
||||
|
||||
private fun onSingleWalletLoaded(
|
||||
wallet: Wallet, walletState: WalletState, topUpAllowed: Boolean? = null
|
||||
): WalletState {
|
||||
if (wallet.blockchain != walletState.primaryBlockchain) return walletState
|
||||
|
||||
|
|
@ -176,7 +149,7 @@ class OnWalletLoadedReducer {
|
|||
)
|
||||
val wallets = walletData?.let { listOf(walletData) } ?: emptyList()
|
||||
return walletState.copy(
|
||||
state = ProgressState.Done, wallets = wallets
|
||||
state = ProgressState.Done, wallets = wallets, error = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -57,9 +57,16 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
is WalletAction.LoadData.Failure -> {
|
||||
when (action.error) {
|
||||
is TapError.NoInternetConnection -> {
|
||||
val wallets = newState.wallets
|
||||
.map {
|
||||
it.copy(currencyData = it.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable
|
||||
))
|
||||
}
|
||||
newState = newState.copy(
|
||||
state = ProgressState.Error,
|
||||
error = ErrorType.NoInternetConnection,
|
||||
wallets = wallets
|
||||
)
|
||||
}
|
||||
is TapError.UnknownBlockchain -> {
|
||||
|
|
@ -100,7 +107,7 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
)
|
||||
} else {
|
||||
val walletManager = newState.getWalletManager(action.currency) ?: return newState
|
||||
val currencies = listOf(walletManager.wallet.blockchain.currency + walletManager.presetTokens.map { it.symbol })
|
||||
val currencies = listOf(walletManager.wallet.blockchain.currency) + walletManager.presetTokens.map { it.symbol }
|
||||
val newWallets = newState.wallets.filter { currencies.contains(it.currencyData.currencySymbol) }
|
||||
.map { wallet ->
|
||||
wallet.copy(
|
||||
|
|
@ -118,14 +125,11 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
val wallets = newState.replaceSomeWallets(newWallets)
|
||||
newState = newState.copy(wallets = wallets)
|
||||
}
|
||||
|
||||
}
|
||||
is WalletAction.LoadWallet.Success -> newState = onWalletLoadedReducer.reduce(action.wallet, newState)
|
||||
is WalletAction.UpdateWallet.Success -> {
|
||||
newState = onWalletLoadedReducer.reduce(action.wallet, newState)
|
||||
// newState = newState.copy(updatingWallet = newState.pendingTransactions.isNotEmpty())
|
||||
}
|
||||
|
||||
is WalletAction.LoadWallet.NoAccount -> {
|
||||
val walletData = newState.getWalletData(action.wallet.blockchain.currency)?.copy(
|
||||
currencyData = BalanceWidgetData(
|
||||
|
|
@ -135,34 +139,46 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
)
|
||||
)
|
||||
val wallets = newState.replaceWalletInWallets(walletData)
|
||||
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
val progressState = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
ProgressState.Loading
|
||||
} else {
|
||||
ProgressState.Done
|
||||
}
|
||||
newState = newState.copy(
|
||||
state = state,
|
||||
state = progressState,
|
||||
wallets = wallets
|
||||
|
||||
)
|
||||
}
|
||||
is WalletAction.LoadWallet.Failure -> {
|
||||
val message = if (newState.error == ErrorType.NoInternetConnection) {
|
||||
null
|
||||
} else {
|
||||
action.errorMessage
|
||||
}
|
||||
val walletData = newState.getWalletData(action.wallet.blockchain.currency)
|
||||
val newWalletData = walletData?.copy(
|
||||
currencyData = walletData.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable,
|
||||
errorMessage = action.errorMessage
|
||||
errorMessage = message
|
||||
),
|
||||
topUpState = TopUpState(false)
|
||||
)
|
||||
val wallets = newState.replaceWalletInWallets(newWalletData)
|
||||
val state = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
val tokenWallets = action.wallet.getTokens()
|
||||
.mapNotNull { newState.getWalletData(it.symbol) }
|
||||
.map {
|
||||
it.copy(currencyData = it.currencyData.copy(
|
||||
status = BalanceStatus.Unreachable, errorMessage = message
|
||||
))
|
||||
}
|
||||
val wallets = newState.replaceSomeWallets(listOfNotNull(newWalletData) + tokenWallets)
|
||||
|
||||
val progressState = if (wallets.any { it.currencyData.status == BalanceStatus.Loading }) {
|
||||
ProgressState.Loading
|
||||
} else {
|
||||
ProgressState.Done
|
||||
}
|
||||
newState = newState.copy(
|
||||
state = state, wallets = wallets
|
||||
state = progressState, wallets = wallets
|
||||
)
|
||||
}
|
||||
is WalletAction.SetArtworkId -> {
|
||||
|
|
@ -174,21 +190,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
newState = newState.copy(cardImage = cardImage)
|
||||
}
|
||||
|
||||
// is WalletAction.UpdateWallet -> {
|
||||
// if (store.state.walletState.state == ProgressState.Done) {
|
||||
// newState = newState.copy(updatingWallet = true)
|
||||
// }
|
||||
// }
|
||||
// is WalletAction.UpdateWallet.ScheduleUpdatingWallet ->
|
||||
// newState = newState.copy(updatingWallet = true)
|
||||
|
||||
// is WalletAction.UpdateWallet.Failure -> newState = newState.copy(updatingWallet = false)
|
||||
// is WalletAction.LoadFiatRate -> {
|
||||
// newState.copy(currencyData = newState.currencyData.copy(
|
||||
// fiatAmount = null,
|
||||
// token = newState.currencyData.token?.copy(fiatAmount = null))
|
||||
// )
|
||||
// }
|
||||
is WalletAction.LoadFiatRate.Success ->
|
||||
newState = setNewFiatRate(action.fiatRate, state.globalState.appCurrency, newState)
|
||||
is WalletAction.LoadArtwork -> {
|
||||
|
|
@ -246,13 +247,6 @@ private fun internalReduce(action: Action, state: AppState): WalletState {
|
|||
)
|
||||
newState = newState.copy(wallets = wallets)
|
||||
}
|
||||
is WalletAction.ScanCardFinished -> {
|
||||
newState = if (action.scanError == null) {
|
||||
newState.copy(scanCardFailsCounter = 0)
|
||||
} else {
|
||||
newState.copy(scanCardFailsCounter = newState.scanCardFailsCounter + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return newState
|
||||
}
|
||||
|
|
@ -282,16 +276,10 @@ fun createAddressList(wallet: Wallet?, walletAddresses: WalletAddresses? = null)
|
|||
|
||||
private fun handleCheckSignedHashesActions(action: WalletAction.Warnings, state: WalletState): WalletState {
|
||||
return when (action) {
|
||||
WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline -> state
|
||||
WalletAction.Warnings.CheckHashesCount.ConfirmHashesCount -> state.copy(hashesCountVerified = true)
|
||||
WalletAction.Warnings.CheckHashesCount.NeedToCheckHashesCountOnline -> state.copy(hashesCountVerified = false)
|
||||
WalletAction.Warnings.CheckHashesCount.SaveCardId -> state
|
||||
is WalletAction.Warnings.SetWarnings -> state.copy(mainWarningsList = action.warningList)
|
||||
WalletAction.Warnings.CheckIfNeeded -> state
|
||||
WalletAction.Warnings.AppRating -> state
|
||||
WalletAction.Warnings.CheckHashesCount -> state
|
||||
WalletAction.Warnings.AppRating.RemindLater -> state
|
||||
WalletAction.Warnings.AppRating.SetNeverToShow -> state
|
||||
is WalletAction.Warnings.Set -> state.copy(mainWarningsList = action.warningList)
|
||||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import java.math.BigDecimal
|
|||
enum class BalanceStatus {
|
||||
VerifiedOnline,
|
||||
TransactionInProgress,
|
||||
SameCurrencyTransactionInProgress,
|
||||
Unreachable,
|
||||
Loading,
|
||||
NoAccount,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import com.tangem.blockchain.blockchains.bitcoin.BitcoinAddressType
|
|||
import com.tangem.blockchain.blockchains.cardano.CardanoAddressType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.tap.common.redux.global.CryptoCurrencyName
|
||||
import com.tangem.wallet.R
|
||||
|
||||
class MultipleAddressUiHelper {
|
||||
|
|
@ -20,13 +19,6 @@ class MultipleAddressUiHelper {
|
|||
}
|
||||
}
|
||||
|
||||
fun idToType(id: Int, currencyName: CryptoCurrencyName?): AddressType? {
|
||||
val blockchain = currencyName?.let { currency ->
|
||||
Blockchain.fromCurrency(currency)
|
||||
}
|
||||
return idToType(id, blockchain)
|
||||
}
|
||||
|
||||
fun idToType(id: Int, blockchain: Blockchain?): AddressType? {
|
||||
return when (id) {
|
||||
R.id.chip_default -> {
|
||||
|
|
|
|||
|
|
@ -10,21 +10,18 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.MainActivity
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletData
|
||||
import com.tangem.tap.features.wallet.redux.WalletDialog
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.redux.*
|
||||
import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_details_twin_cards.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.rv_pending_transaction
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.toolbar
|
||||
import kotlinx.android.synthetic.main.item_currency_wallet.view.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_error.*
|
||||
|
|
@ -104,6 +101,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
|
||||
showPendingTransactionsIfPresent(selectedWallet.pendingTransactions)
|
||||
setupAddressCard(selectedWallet)
|
||||
setupNoInternetHandling(state)
|
||||
setupBalanceData(selectedWallet.currencyData)
|
||||
|
||||
btn_confirm.isEnabled = selectedWallet.mainButton.enabled
|
||||
|
|
@ -156,7 +154,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
|
||||
private fun setupAddressCard(state: WalletData) {
|
||||
if (state.walletAddresses != null) {
|
||||
if (state.shouldShowMultipleAddress()) {
|
||||
if (state.shouldShowMultipleAddress() && state.blockchain != null) {
|
||||
(card_balance as? ViewGroup)?.beginDelayedTransition()
|
||||
chip_group_address_type.show()
|
||||
chip_group_address_type.fitChipsByGroupWidth()
|
||||
|
|
@ -166,7 +164,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
|
||||
chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
|
||||
if (checkedId == -1) return@setOnCheckedChangeListener
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.currencyData.currencySymbol)
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.blockchain)
|
||||
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
|
||||
}
|
||||
} else {
|
||||
|
|
@ -178,7 +176,21 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
state.walletAddresses.selectedAddress.exploreUrl,
|
||||
requireContext()))
|
||||
}
|
||||
iv_qr_code.setImageBitmap(state.walletAddresses.selectedAddress.address.toQrCode())
|
||||
iv_qr_code.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode())
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNoInternetHandling(state: WalletState) {
|
||||
if (state.state == ProgressState.Error) {
|
||||
if (state.error == ErrorType.NoInternetConnection) {
|
||||
srl_wallet_details?.isRefreshing = false
|
||||
(activity as? MainActivity)?.showSnackbar(
|
||||
text = R.string.wallet_notification_no_internet,
|
||||
buttonTitle = R.string.common_retry
|
||||
) { store.dispatch(WalletAction.LoadData) }
|
||||
}
|
||||
} else {
|
||||
(activity as? MainActivity)?.dismissSnackbar()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,10 +205,12 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
showStatus(R.id.tv_status_loading)
|
||||
showBalanceWithoutToken(data, false)
|
||||
}
|
||||
BalanceStatus.VerifiedOnline, BalanceStatus.TransactionInProgress -> {
|
||||
BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress,
|
||||
BalanceStatus.TransactionInProgress -> {
|
||||
l_balance.show()
|
||||
l_balance_error.hide()
|
||||
val statusView = if (data.status == BalanceStatus.VerifiedOnline) {
|
||||
val statusView = if (data.status == BalanceStatus.VerifiedOnline ||
|
||||
data.status == BalanceStatus.SameCurrencyTransactionInProgress) {
|
||||
R.id.tv_status_verified
|
||||
} else {
|
||||
tv_status_error.text =
|
||||
|
|
@ -233,6 +247,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
)
|
||||
}
|
||||
}
|
||||
card_pending_transaction_warning.show(data.status == BalanceStatus.SameCurrencyTransactionInProgress)
|
||||
}
|
||||
|
||||
private fun showStatus(@IdRes viewRes: Int) {
|
||||
|
|
@ -249,7 +264,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: WalletDialog?) {
|
||||
private fun handleDialogs(walletDialog: StateDialog?) {
|
||||
when (walletDialog) {
|
||||
is WalletDialog.SelectAmountToSendDialog -> {
|
||||
if (dialog == null) dialog = AmountToSendDialog(requireContext()).apply {
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.squareup.picasso.Picasso
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tap.MainActivity
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -30,13 +30,13 @@ import com.tangem.tap.features.wallet.ui.wallet.WalletView
|
|||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.toolbar
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
|
||||
class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<WalletState> {
|
||||
|
||||
private var snackbar: Snackbar? = null
|
||||
|
||||
private lateinit var warningsAdapter: WarningMessagesAdapter
|
||||
|
||||
private var walletView: WalletView = SingleWalletView()
|
||||
|
|
@ -133,15 +133,14 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
private fun setupNoInternetHandling(state: WalletState) {
|
||||
if (state.state == ProgressState.Error) {
|
||||
if (state.error == ErrorType.NoInternetConnection) {
|
||||
srl_wallet?.isRefreshing = false
|
||||
snackbar = Snackbar.make(
|
||||
coordinator_wallet, getString(R.string.wallet_notification_no_internet),
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
).setAction(getString(R.string.common_retry)) { store.dispatch(WalletAction.LoadData) }
|
||||
snackbar?.show()
|
||||
srl_wallet_details?.isRefreshing = false
|
||||
(activity as? MainActivity)?.showSnackbar(
|
||||
text = R.string.wallet_notification_no_internet,
|
||||
buttonTitle = R.string.common_retry
|
||||
) { store.dispatch(WalletAction.LoadData) }
|
||||
}
|
||||
} else {
|
||||
snackbar?.dismiss()
|
||||
(activity as? MainActivity)?.dismissSnackbar()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import androidx.recyclerview.widget.ListAdapter
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.extensions.getColor
|
||||
import com.tangem.tap.common.extensions.getIconRes
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletData
|
||||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
|
|
@ -80,11 +82,8 @@ class WalletAdapter
|
|||
|
||||
fun bind(wallet: WalletData) {
|
||||
view.tv_currency.text = wallet.currencyData.currency
|
||||
view.tv_amount.text = wallet.currencyData.amount
|
||||
if (view.tv_amount.isEllipsized()) {
|
||||
val allowedSize = view.tv_amount.text.length - 4
|
||||
view.tv_amount.text = wallet.currencyData.amount?.ellipsizeBeforeSpace(allowedSize)
|
||||
}
|
||||
view.tv_amount.text = wallet.currencyData.amount?.takeWhile { !it.isWhitespace() }
|
||||
view.tv_currency_symbol.text = wallet.currencyData.amount?.takeLastWhile { !it.isWhitespace() }
|
||||
view.tv_amount_fiat.text = wallet.currencyData.fiatAmount
|
||||
view.tv_exchange_rate.text = wallet.fiatRateString
|
||||
view.card_wallet.setOnClickListener {
|
||||
|
|
@ -101,7 +100,7 @@ class WalletAdapter
|
|||
view.iv_currency.setImageResource(R.drawable.shape_circle)
|
||||
}
|
||||
when (wallet.currencyData.status) {
|
||||
BalanceStatus.VerifiedOnline -> hideWarning()
|
||||
BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress -> hideWarning()
|
||||
BalanceStatus.Loading -> {
|
||||
hideWarning()
|
||||
if (wallet.currencyData.amount == null) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.feedback.ScanFailsEmail
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -22,7 +23,10 @@ class ScanFailsDialog {
|
|||
store.dispatch(GlobalAction.SendFeedback(ScanFailsEmail()))
|
||||
}
|
||||
setNegativeButton(R.string.common_cancel) { _, _ -> }
|
||||
setOnDismissListener { store.dispatch(WalletAction.HideDialog) }
|
||||
setOnDismissListener {
|
||||
store.dispatch(HomeAction.HideDialog)
|
||||
store.dispatch(WalletAction.HideDialog)
|
||||
}
|
||||
}.create()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.app.Dialog
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
|
|
@ -112,7 +113,7 @@ class MultiWalletView : WalletView {
|
|||
}
|
||||
|
||||
private fun showErrorState(
|
||||
fragment: WalletFragment, errorTitle: CharSequence, errorDescription: CharSequence
|
||||
fragment: WalletFragment, errorTitle: CharSequence, errorDescription: CharSequence,
|
||||
) {
|
||||
fragment.l_card_balance.show()
|
||||
fragment.l_balance.hide()
|
||||
|
|
@ -131,14 +132,12 @@ class MultiWalletView : WalletView {
|
|||
fragment.btn_confirm_long.text = fragment.getText(R.string.wallet_button_create_wallet)
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: WalletDialog?) {
|
||||
private fun handleDialogs(walletDialog: StateDialog?) {
|
||||
val fragment = fragment ?: return
|
||||
val context = fragment.context ?: return
|
||||
when (walletDialog) {
|
||||
is WalletDialog.ScanFailsDialog -> {
|
||||
if (dialog == null) dialog = ScanFailsDialog.create(context).apply {
|
||||
this.show()
|
||||
}
|
||||
if (dialog == null) dialog = ScanFailsDialog.create(context).apply { show() }
|
||||
}
|
||||
else -> {
|
||||
dialog?.dismiss()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import android.view.ViewGroup
|
|||
import android.widget.Button
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.global.StateDialog
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.twins.TwinCardNumber
|
||||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.redux.*
|
||||
|
|
@ -105,6 +108,9 @@ class SingleWalletView : WalletView {
|
|||
this.tv_twin_card_number.hide()
|
||||
this.iv_twin_card.hide()
|
||||
}
|
||||
if (twinCardsState?.showTwinOnboarding == true) {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.TwinsOnboarding))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -156,7 +162,7 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
|
||||
private fun setupConfirmButton(
|
||||
state: WalletData, btnConfirm: Button, fragment: WalletFragment, isTwinsWallet: Boolean
|
||||
state: WalletData, btnConfirm: Button, fragment: WalletFragment, isTwinsWallet: Boolean,
|
||||
) {
|
||||
val buttonTitle = when (state.mainButton) {
|
||||
is WalletMainButton.SendButton -> R.string.wallet_button_send
|
||||
|
|
@ -181,7 +187,7 @@ class SingleWalletView : WalletView {
|
|||
|
||||
private fun setupAddressCard(state: WalletData) {
|
||||
val fragment = fragment ?: return
|
||||
if (state.walletAddresses != null) {
|
||||
if (state.walletAddresses != null && state.blockchain != null) {
|
||||
fragment.l_address?.show()
|
||||
if (state.shouldShowMultipleAddress()) {
|
||||
(fragment.l_address as? ViewGroup)?.beginDelayedTransition()
|
||||
|
|
@ -193,7 +199,7 @@ class SingleWalletView : WalletView {
|
|||
|
||||
fragment.chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
|
||||
if (checkedId == -1) return@setOnCheckedChangeListener
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.currencyData.currencySymbol)
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.blockchain)
|
||||
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
|
||||
}
|
||||
} else {
|
||||
|
|
@ -210,7 +216,7 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: WalletDialog?) {
|
||||
private fun handleDialogs(walletDialog: StateDialog?) {
|
||||
val fragment = fragment ?: return
|
||||
val context = fragment.context ?: return
|
||||
when (walletDialog) {
|
||||
|
|
@ -229,9 +235,7 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
}
|
||||
is WalletDialog.ScanFailsDialog -> {
|
||||
if (dialog == null) dialog = ScanFailsDialog.create(context).apply {
|
||||
this.show()
|
||||
}
|
||||
if (dialog == null) dialog = ScanFailsDialog.create(context).apply { show() }
|
||||
}
|
||||
null -> {
|
||||
dialog?.dismiss()
|
||||
|
|
|
|||
|
|
@ -122,7 +122,10 @@ class AppRatingLaunchObserver(
|
|||
if (fundsFoundDate != null) return
|
||||
|
||||
fundsFoundDate = Calendar.getInstance()
|
||||
preferences.edit().putLong(K_FUNDS_FOUND_DATE, fundsFoundDate!!.timeInMillis).apply()
|
||||
preferences.edit(true) {
|
||||
putLong(K_FUNDS_FOUND_DATE, fundsFoundDate!!.timeInMillis).apply()
|
||||
putInt(K_SHOW_RATING_AT_LAUNCH_COUNT, launchCounts + firstShowing)
|
||||
}
|
||||
}
|
||||
|
||||
fun isReadyToShow(): Boolean {
|
||||
|
|
@ -130,8 +133,8 @@ class AppRatingLaunchObserver(
|
|||
|
||||
if (!userWasInteractWithRating()) {
|
||||
val diff = Calendar.getInstance().timeInMillis - fundsDate.timeInMillis
|
||||
val diffInDays = diff / (100 * 60 * 60 * 24)
|
||||
if (diffInDays >= firstShowing) return true
|
||||
val diffInDays = diff / (1000 * 60 * 60 * 24)
|
||||
return launchCounts >= getCounterOfNextShowing() && diffInDays >= firstShowing
|
||||
}
|
||||
|
||||
val nextShowing = getCounterOfNextShowing()
|
||||
|
|
|
|||
BIN
app/src/main/res/drawable/ic_ducatus.png
Normal file
BIN
app/src/main/res/drawable/ic_ducatus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
|
|
@ -258,48 +258,6 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_security_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_blockchain_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="22dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:text="@string/details_section_title_blockchain"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/colorSecondary"
|
||||
android:textSize="13sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_erase_wallet" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_separator_blockchain"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/separatorGrey2"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_blockchain_title" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_manage_tokens"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="15dp"
|
||||
android:paddingTop="7dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:text="@string/details_row_title_manage_tokens"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="16sp"
|
||||
app:drawableEndCompat="@drawable/ic_angle_bracket_right"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_blockchain_title" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_blockchain"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="tv_blockchain_title, v_separator_blockchain, tv_manage_tokens" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
|
|||
|
|
@ -171,6 +171,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_marginTop="30dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/l_address"
|
||||
app:layout_constraintVertical_bias="1"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<include
|
||||
|
|
@ -179,6 +182,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_marginTop="30dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/l_address"
|
||||
app:layout_constraintVertical_bias="1"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
|
|
|||
|
|
@ -79,6 +79,36 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/rv_pending_transaction" />
|
||||
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_pending_transaction_warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:cardBackgroundColor="@color/darkGray1"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/l_wallet_details">
|
||||
|
||||
<TextView
|
||||
android:padding="16dp"
|
||||
android:id="@+id/tv_pending_transaction_warning"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:text="@string/wallet_pending_transaction_warning"
|
||||
android:textColor="@android:color/white" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="l_wallet_details,card_pending_transaction_warning" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_top_up"
|
||||
style="@style/TapButtonWithIcon"
|
||||
|
|
@ -86,11 +116,12 @@
|
|||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginBottom="33dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="@string/wallet_button_topup"
|
||||
app:icon="@drawable/ic_arrow_up"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintVertical_bias="1" />
|
||||
|
|
@ -107,12 +138,13 @@
|
|||
android:id="@+id/btn_confirm"
|
||||
style="@style/TapButtonWithIcon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="33dp"
|
||||
android:text="@string/wallet_button_send"
|
||||
app:icon="@drawable/ic_send"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="76dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_currency"
|
||||
|
|
@ -49,44 +49,48 @@
|
|||
<TextView
|
||||
android:id="@+id/tv_currency"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_currency"
|
||||
app:layout_constraintTop_toTopOf="@id/iv_currency"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Bitcoin" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_exchange_rate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textColor="@color/darkGray2"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_currency"
|
||||
tools:text="USD 3 588" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_status_error_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textColor="@color/warning"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_currency" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_status_loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:drawablePadding="5dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
|
|
@ -94,37 +98,56 @@
|
|||
android:textColor="@color/darkGray6"
|
||||
android:textSize="13sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/iv_currency"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_amount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="end"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/tv_currency_symbol"
|
||||
app:layout_constraintHorizontal_weight="1"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_currency"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="3 588" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_currency_symbol"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:gravity="end"
|
||||
android:maxLines="1"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textColor="@color/darkGray6"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="1"
|
||||
app:layout_constraintStart_toEndOf="@id/tv_currency"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_currency"
|
||||
tools:text="3 588 BTC" />
|
||||
app:layout_constraintStart_toEndOf="@id/tv_amount"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="BTC" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_amount_fiat"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:textColor="@color/darkGray2"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/tv_exchange_rate"
|
||||
tools:text="0.43 USD" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
app:layout_constraintEnd_toEndOf="@id/guideline"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/chip_group_address_type"
|
||||
app:layout_constraintBottom_toBottomOf="@id/btn_copy"
|
||||
app:layout_constraintBottom_toBottomOf="@id/v_qr_lower_end"
|
||||
tools:src="@drawable/ic_qr_code_show" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
|
|
@ -98,7 +98,7 @@
|
|||
android:id="@+id/tv_address"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:ellipsize="middle"
|
||||
android:maxLines="2"
|
||||
|
|
@ -148,6 +148,15 @@
|
|||
app:layout_constraintEnd_toStartOf="@id/btn_share"
|
||||
app:layout_constraintStart_toEndOf="@id/iv_qr_code" />
|
||||
|
||||
<View
|
||||
android:id="@+id/v_qr_lower_end"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_copy"
|
||||
app:layout_constraintStart_toStartOf="@id/btn_copy"
|
||||
android:layout_marginTop="5dp"
|
||||
/>
|
||||
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/btn_share"
|
||||
|
|
|
|||
|
|
@ -97,8 +97,10 @@ this wallet.
|
|||
<string name="wallet_address_button_copy" translatable="false">Copy</string>
|
||||
<string name="wallet_address_button_share" translatable="false">Share</string>
|
||||
<string name="wallet_button_add_tokens" translatable="false">+ Add tokens</string>
|
||||
<string name="wallet_pending_transaction_warning" translatable="false">Please wait for the transaction to complete to be able to send funds</string>
|
||||
|
||||
|
||||
<string name="warning_failed_to_verify_card_title" translatable="false">Authenticity check failed</string>
|
||||
<string name="warning_failed_to_verify_card_message" translatable="false">This card might be a production sample or counterfeit</string>
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue