mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
Support encrypted transactions
This commit is contained in:
parent
4fd8b81a77
commit
f125c65907
@ -4858,6 +4858,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Wallet.Send.OwnAddressAlertProceed" = "Proceed";
|
||||
"Wallet.Send.TransactionInProgress" = "Please wait until the current transaction is completed.";
|
||||
"Wallet.Send.SyncInProgress" = "Please wait while the wallet finishes syncing with the TON Blockchain.";
|
||||
"Wallet.Send.EncryptComment" = "Encrypt Text";
|
||||
"Wallet.Settings.Title" = "Settings";
|
||||
"Wallet.Settings.Configuration" = "Server Settings";
|
||||
"Wallet.Settings.ConfigurationInfo" = "Advanced Settings";
|
||||
|
@ -765,7 +765,7 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
beginWithController(infoScreen)
|
||||
})
|
||||
} else {
|
||||
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(record.info, nil), walletCreatedPreloadState: nil)
|
||||
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(walletInfo: record.info, words: nil), walletCreatedPreloadState: nil)
|
||||
beginWithController(createdScreen)
|
||||
}
|
||||
} else {
|
||||
|
@ -62,6 +62,7 @@
|
||||
"Wallet.Send.OwnAddressAlertProceed" = "Proceed";
|
||||
"Wallet.Send.TransactionInProgress" = "Please wait until the current transaction is completed.";
|
||||
"Wallet.Send.SyncInProgress" = "Please wait while the wallet finishes syncing with the TON Blockchain.";
|
||||
"Wallet.Send.EncryptComment" = "Encrypt Text";
|
||||
"Wallet.Settings.Title" = "Settings";
|
||||
"Wallet.Settings.Configuration" = "Server Settings";
|
||||
"Wallet.Settings.ConfigurationInfo" = "Advanced Settings";
|
||||
|
@ -1,51 +0,0 @@
|
||||
//
|
||||
// EDSunriseSet.h
|
||||
//
|
||||
// Created by Ernesto García on 20/08/11.
|
||||
// Copyright 2011 Ernesto García. All rights reserved.
|
||||
//
|
||||
|
||||
// C/C++ sun calculations created by Paul Schlyter
|
||||
// sunriset.c
|
||||
// http://stjarnhimlen.se/english.html
|
||||
// SUNRISET.C - computes Sun rise/set times, start/end of twilight, and
|
||||
// the length of the day at any date and latitude
|
||||
// Written as DAYLEN.C, 1989-08-16
|
||||
// Modified to SUNRISET.C, 1992-12-01
|
||||
// (c) Paul Schlyter, 1989, 1992
|
||||
// Released to the public domain by Paul Schlyter, December 1992
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag in this file.
|
||||
#endif
|
||||
|
||||
@interface EDSunriseSet : NSObject
|
||||
|
||||
@property (readonly, strong) NSDate *date;
|
||||
@property (readonly, strong) NSDate *sunset;
|
||||
@property (readonly, strong) NSDate *sunrise;
|
||||
@property (readonly, strong) NSDate *civilTwilightStart;
|
||||
@property (readonly, strong) NSDate *civilTwilightEnd;
|
||||
@property (readonly, strong) NSDate *nauticalTwilightStart;
|
||||
@property (readonly, strong) NSDate *nauticalTwilightEnd;
|
||||
@property (readonly, strong) NSDate *astronomicalTwilightStart;
|
||||
@property (readonly, strong) NSDate *astronomicalTwilightEnd;
|
||||
|
||||
@property (readonly, strong) NSDateComponents* localSunrise;
|
||||
@property (readonly, strong) NSDateComponents* localSunset;
|
||||
@property (readonly, strong) NSDateComponents* localCivilTwilightStart;
|
||||
@property (readonly, strong) NSDateComponents* localCivilTwilightEnd;
|
||||
@property (readonly, strong) NSDateComponents* localNauticalTwilightStart;
|
||||
@property (readonly, strong) NSDateComponents* localNauticalTwilightEnd;
|
||||
@property (readonly, strong) NSDateComponents* localAstronomicalTwilightStart;
|
||||
@property (readonly, strong) NSDateComponents* localAstronomicalTwilightEnd;
|
||||
|
||||
|
||||
-(instancetype)initWithDate:(NSDate*)date timezone:(NSTimeZone*)timezone latitude:(double)latitude longitude:(double)longitude NS_DESIGNATED_INITIALIZER;
|
||||
+(instancetype)sunrisesetWithDate:(NSDate*)date timezone:(NSTimeZone*)timezone latitude:(double)latitude longitude:(double)longitude;
|
||||
-(instancetype) init __attribute__((unavailable("init not available. Use initWithDate:timeZone:latitude:longitude: instead")));
|
||||
|
||||
@end
|
@ -1,447 +0,0 @@
|
||||
//
|
||||
// EDSunriseSet.m
|
||||
//
|
||||
// Created by Ernesto García on 20/08/11.
|
||||
// Copyright 2011 Ernesto García. All rights reserved.
|
||||
//
|
||||
|
||||
// C/C++ sun calculations created by Paul Schlyter
|
||||
// sunriset.c
|
||||
// http://stjarnhimlen.se/english.html
|
||||
// SUNRISET.C - computes Sun rise/set times, start/end of twilight, and
|
||||
// the length of the day at any date and latitude
|
||||
// Written as DAYLEN.C, 1989-08-16
|
||||
// Modified to SUNRISET.C, 1992-12-01
|
||||
// (c) Paul Schlyter, 1989, 1992
|
||||
// Released to the public domain by Paul Schlyter, December 1992
|
||||
//
|
||||
|
||||
#import "EDSunriseSet.h"
|
||||
|
||||
//
|
||||
// Defines from sunriset.c
|
||||
//
|
||||
#define INV360 ( 1.0 / 360.0 )
|
||||
|
||||
#define RADEG ( 180.0 / M_PI )
|
||||
#define DEGRAD ( M_PI / 180.0 )
|
||||
|
||||
/* The trigonometric functions in degrees */
|
||||
|
||||
#define sind(x) sin((x)*DEGRAD)
|
||||
#define cosd(x) cos((x)*DEGRAD)
|
||||
#define tand(x) tan((x)*DEGRAD)
|
||||
|
||||
#define atand(x) (RADEG*atan(x))
|
||||
#define asind(x) (RADEG*asin(x))
|
||||
#define acosd(x) (RADEG*acos(x))
|
||||
#define atan2d(y,x) (RADEG*atan2(y,x))
|
||||
|
||||
/* A macro to compute the number of days elapsed since 2000 Jan 0.0 */
|
||||
/* (which is equal to 1999 Dec 31, 0h UT) */
|
||||
#define days_since_2000_Jan_0(y,m,d) \
|
||||
(367L*(y)-((7*((y)+(((m)+9)/12)))/4)+((275*(m))/9)+(d)-730530L)
|
||||
|
||||
|
||||
#if defined(__IPHONE_8_0) || defined (__MAC_10_10)
|
||||
#define EDGregorianCalendar NSCalendarIdentifierGregorian
|
||||
#else
|
||||
#define EDGregorianCalendar NSGregorianCalendar
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark - Readwrite accessors only private
|
||||
@interface EDSunriseSet()
|
||||
|
||||
@property (nonatomic) double latitude;
|
||||
@property (nonatomic) double longitude;
|
||||
@property (nonatomic, strong) NSTimeZone *timezone;
|
||||
@property (nonatomic, strong) NSCalendar *calendar;
|
||||
@property (nonatomic, strong) NSTimeZone *utcTimeZone;
|
||||
|
||||
@property (readwrite, strong) NSDate *date;
|
||||
@property (readwrite, strong) NSDate *sunset;
|
||||
@property (readwrite, strong) NSDate *sunrise;
|
||||
@property (readwrite, strong) NSDate *civilTwilightStart;
|
||||
@property (readwrite, strong) NSDate *civilTwilightEnd;
|
||||
@property (readwrite, strong) NSDate *nauticalTwilightStart;
|
||||
@property (readwrite, strong) NSDate *nauticalTwilightEnd;
|
||||
@property (readwrite, strong) NSDate *astronomicalTwilightStart;
|
||||
@property (readwrite, strong) NSDate *astronomicalTwilightEnd;
|
||||
|
||||
@property (readwrite, strong) NSDateComponents* localSunrise;
|
||||
@property (readwrite, strong) NSDateComponents* localSunset;
|
||||
@property (readwrite, strong) NSDateComponents* localCivilTwilightStart;
|
||||
@property (readwrite, strong) NSDateComponents* localCivilTwilightEnd;
|
||||
@property (readwrite, strong) NSDateComponents* localNauticalTwilightStart;
|
||||
@property (readwrite, strong) NSDateComponents* localNauticalTwilightEnd;
|
||||
@property (readwrite, strong) NSDateComponents* localAstronomicalTwilightStart;
|
||||
@property (readwrite, strong) NSDateComponents* localAstronomicalTwilightEnd;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Calculations from sunriset.c
|
||||
@implementation EDSunriseSet(Calculations)
|
||||
|
||||
/*****************************************/
|
||||
/* Reduce angle to within 0..360 degrees */
|
||||
/*****************************************/
|
||||
-(double) revolution:(double) x
|
||||
{
|
||||
return( x - 360.0 * floor( x * INV360 ) );
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Reduce angle to within -180..+180 degrees */
|
||||
/*********************************************/
|
||||
-(double) rev180:(double) x
|
||||
{
|
||||
return( x - 360.0 * floor( x * INV360 + 0.5 ) );
|
||||
}
|
||||
|
||||
-(double) GMST0:(double) d
|
||||
{
|
||||
double sidtim0;
|
||||
/* Sidtime at 0h UT = L (Sun's mean longitude) + 180.0 degr */
|
||||
/* L = M + w, as defined in sunpos(). Since I'm too lazy to */
|
||||
/* add these numbers, I'll let the C compiler do it for me. */
|
||||
/* Any decent C compiler will add the constants at compile */
|
||||
/* time, imposing no runtime or code overhead. */
|
||||
sidtim0 = [self revolution: ( 180.0 + 356.0470 + 282.9404 ) +
|
||||
( 0.9856002585 + 4.70935E-5 ) * d];
|
||||
return sidtim0;
|
||||
}
|
||||
|
||||
/******************************************************/
|
||||
/* Computes the Sun's ecliptic longitude and distance */
|
||||
/* at an instant given in d, number of days since */
|
||||
/* 2000 Jan 0.0. The Sun's ecliptic latitude is not */
|
||||
/* computed, since it's always very near 0. */
|
||||
/******************************************************/
|
||||
-(void) sunposAtDay:(double)d longitude:(double*)lon r:(double *)r
|
||||
{
|
||||
double M, /* Mean anomaly of the Sun */
|
||||
w, /* Mean longitude of perihelion */
|
||||
/* Note: Sun's mean longitude = M + w */
|
||||
e, /* Eccentricity of Earth's orbit */
|
||||
E, /* Eccentric anomaly */
|
||||
x, y, /* x, y coordinates in orbit */
|
||||
v; /* True anomaly */
|
||||
|
||||
/* Compute mean elements */
|
||||
M = [self revolution:( 356.0470 + 0.9856002585 * d )];
|
||||
w = 282.9404 + 4.70935E-5 * d;
|
||||
e = 0.016709 - 1.151E-9 * d;
|
||||
|
||||
/* Compute true longitude and radius vector */
|
||||
E = M + e * RADEG * sind(M) * ( 1.0 + e * cosd(M) );
|
||||
x = cosd(E) - e;
|
||||
y = sqrt( 1.0 - e*e ) * sind(E);
|
||||
*r = sqrt( x*x + y*y ); /* Solar distance */
|
||||
v = atan2d( y, x ); /* True anomaly */
|
||||
*lon = v + w; /* True solar longitude */
|
||||
if ( *lon >= 360.0 )
|
||||
*lon -= 360.0; /* Make it 0..360 degrees */
|
||||
}
|
||||
|
||||
-(void) sun_RA_decAtDay:(double)d RA:(double*)RA decl:(double *)dec r:(double *)r
|
||||
{
|
||||
double lon, obl_ecl;
|
||||
double xs, ys, zs;
|
||||
double xe, ye, ze;
|
||||
|
||||
/* Compute Sun's ecliptical coordinates */
|
||||
//sunpos( d, &lon, r );
|
||||
[self sunposAtDay:d longitude:&lon r:r];
|
||||
|
||||
/* Compute ecliptic rectangular coordinates */
|
||||
xs = *r * cosd(lon);
|
||||
ys = *r * sind(lon);
|
||||
zs = 0; /* because the Sun is always in the ecliptic plane! */
|
||||
|
||||
/* Compute obliquity of ecliptic (inclination of Earth's axis) */
|
||||
obl_ecl = 23.4393 - 3.563E-7 * d;
|
||||
|
||||
/* Convert to equatorial rectangular coordinates - x is unchanged */
|
||||
xe = xs;
|
||||
ye = ys * cosd(obl_ecl);
|
||||
ze = ys * sind(obl_ecl);
|
||||
|
||||
/* Convert to spherical coordinates */
|
||||
*RA = atan2d( ye, xe );
|
||||
*dec = atan2d( ze, sqrt(xe*xe + ye*ye) );
|
||||
|
||||
} /* sun_RA_dec */
|
||||
|
||||
#define sun_rise_set(year,month,day,lon,lat,rise,set) \
|
||||
__sunriset__( year, month, day, lon, lat, -35.0/60.0, 1, rise, set )
|
||||
|
||||
-(int)sunRiseSetForYear:(int)year month:(int)month day:(int)day longitude:(double)lon latitude:(double)lat
|
||||
trise:(double *)trise tset:(double *)tset
|
||||
{
|
||||
|
||||
return [self sunRiseSetHelperForYear:year month:month day:day longitude:lon latitude:lat altitude:(-35.0/60.0)
|
||||
upper_limb:1 trise:trise tset:tset];
|
||||
|
||||
}
|
||||
/*
|
||||
#define civil_twilight(year,month,day,lon,lat,start,end) \
|
||||
__sunriset__( year, month, day, lon, lat, -6.0, 0, start, end )
|
||||
*/
|
||||
-(int) civilTwilightForYear:(int)year month:(int)month day:(int)day longitude:(double)lon latitude:(double)lat
|
||||
trise:(double *)trise tset:(double *)tset
|
||||
{
|
||||
return [self sunRiseSetHelperForYear:year month:month day:day longitude:lon latitude:lat altitude:-6.0
|
||||
upper_limb:0 trise:trise tset:tset];
|
||||
}
|
||||
/*
|
||||
#define nautical_twilight(year,month,day,lon,lat,start,end) \
|
||||
__sunriset__( year, month, day, lon, lat, -12.0, 0, start, end )
|
||||
*/
|
||||
-(int) nauticalTwilightForYear:(int)year month:(int)month day:(int)day longitude:(double)lon latitude:(double)lat
|
||||
trise:(double *)trise tset:(double *)tset
|
||||
{
|
||||
return [self sunRiseSetHelperForYear:year month:month day:day longitude:lon latitude:lat altitude:-12.0
|
||||
upper_limb:0 trise:trise tset:tset];
|
||||
}
|
||||
/*
|
||||
#define astronomical_twilight(year,month,day,lon,lat,start,end) \
|
||||
__sunriset__( year, month, day, lon, lat, -18.0, 0, start, end )
|
||||
*/
|
||||
-(int) astronomicalTwilightForYear:(int)year month:(int)month day:(int)day longitude:(double)lon latitude:(double)lat
|
||||
trise:(double *)trise tset:(double *)tset
|
||||
{
|
||||
return [self sunRiseSetHelperForYear:year month:month day:day longitude:lon latitude:lat altitude:-18.0
|
||||
upper_limb:0 trise:trise tset:tset];
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* Note: year,month,date = calendar date, 1801-2099 only. */
|
||||
/* Eastern longitude positive, Western longitude negative */
|
||||
/* Northern latitude positive, Southern latitude negative */
|
||||
/* The longitude value IS critical in this function! */
|
||||
/* altit = the altitude which the Sun should cross */
|
||||
/* Set to -35/60 degrees for rise/set, -6 degrees */
|
||||
/* for civil, -12 degrees for nautical and -18 */
|
||||
/* degrees for astronomical twilight. */
|
||||
/* upper_limb: non-zero -> upper limb, zero -> center */
|
||||
/* Set to non-zero (e.g. 1) when computing rise/set */
|
||||
/* times, and to zero when computing start/end of */
|
||||
/* twilight. */
|
||||
/* *rise = where to store the rise time */
|
||||
/* *set = where to store the set time */
|
||||
/* Both times are relative to the specified altitude, */
|
||||
/* and thus this function can be used to comupte */
|
||||
/* various twilight times, as well as rise/set times */
|
||||
/* Return value: 0 = sun rises/sets this day, times stored at */
|
||||
/* *trise and *tset. */
|
||||
/* +1 = sun above the specified "horizon" 24 hours. */
|
||||
/* *trise set to time when the sun is at south, */
|
||||
/* minus 12 hours while *tset is set to the south */
|
||||
/* time plus 12 hours. "Day" length = 24 hours */
|
||||
/* -1 = sun is below the specified "horizon" 24 hours */
|
||||
/* "Day" length = 0 hours, *trise and *tset are */
|
||||
/* both set to the time when the sun is at south. */
|
||||
/* */
|
||||
/**********************************************************************/
|
||||
-(int)sunRiseSetHelperForYear:(int)year month:(int)month day:(int)day longitude:(double)lon latitude:(double)lat
|
||||
altitude:(double)altit upper_limb:(int)upper_limb trise:(double *)trise tset:(double *)tset
|
||||
{
|
||||
double d, /* Days since 2000 Jan 0.0 (negative before) */
|
||||
sr, /* Solar distance, astronomical units */
|
||||
sRA, /* Sun's Right Ascension */
|
||||
sdec, /* Sun's declination */
|
||||
sradius, /* Sun's apparent radius */
|
||||
t, /* Diurnal arc */
|
||||
tsouth, /* Time when Sun is at south */
|
||||
sidtime; /* Local sidereal time */
|
||||
|
||||
int rc = 0; /* Return cde from function - usually 0 */
|
||||
|
||||
/* Compute d of 12h local mean solar time */
|
||||
d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0;
|
||||
|
||||
|
||||
/* Compute local sideral time of this moment */
|
||||
//sidtime = revolution( GMST0(d) + 180.0 + lon );
|
||||
sidtime = [self revolution:[self GMST0:d] + 180.0 + lon];
|
||||
/* Compute Sun's RA + Decl at this moment */
|
||||
//sun_RA_dec( d, &sRA, &sdec, &sr );
|
||||
[self sun_RA_decAtDay:d RA: &sRA decl:&sdec r:&sr];
|
||||
|
||||
/* Compute time when Sun is at south - in hours UT */
|
||||
//tsouth = 12.0 - rev180(sidtime - sRA)/15.0;
|
||||
tsouth = 12.0 - [self rev180:sidtime - sRA] / 15.0;
|
||||
|
||||
/* Compute the Sun's apparent radius, degrees */
|
||||
sradius = 0.2666 / sr;
|
||||
|
||||
/* Do correction to upper limb, if necessary */
|
||||
if ( upper_limb )
|
||||
altit -= sradius;
|
||||
|
||||
/* Compute the diurnal arc that the Sun traverses to reach */
|
||||
/* the specified altitide altit: */
|
||||
{
|
||||
double cost;
|
||||
cost = ( sind(altit) - sind(lat) * sind(sdec) ) /
|
||||
( cosd(lat) * cosd(sdec) );
|
||||
if ( cost >= 1.0 )
|
||||
rc = -1, t = 0.0; /* Sun always below altit */
|
||||
else if ( cost <= -1.0 )
|
||||
rc = +1, t = 12.0; /* Sun always above altit */
|
||||
else
|
||||
t = acosd(cost)/15.0; /* The diurnal arc, hours */
|
||||
}
|
||||
|
||||
/* Store rise and set times - in hours UT */
|
||||
*trise = tsouth - t;
|
||||
*tset = tsouth + t;
|
||||
|
||||
return rc;
|
||||
} /* __sunriset__ */
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - Private Implementation
|
||||
|
||||
@implementation EDSunriseSet(Private)
|
||||
|
||||
static const int kSecondsInHour= 60.0*60.0;
|
||||
|
||||
|
||||
-(NSDate*)utcTime:(NSDateComponents*)dateComponents withOffset:(NSTimeInterval)interval
|
||||
{
|
||||
[self.calendar setTimeZone:self.utcTimeZone];
|
||||
return [[self.calendar dateFromComponents:dateComponents] dateByAddingTimeInterval:(NSTimeInterval)(interval)];
|
||||
}
|
||||
|
||||
-(NSDateComponents*)localTime:(NSDate*)refDate
|
||||
{
|
||||
[self.calendar setTimeZone:self.timezone];
|
||||
// Return only hour, minute, seconds
|
||||
NSDateComponents *dc = [self.calendar components:( NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond) fromDate:refDate] ;
|
||||
|
||||
return dc;
|
||||
}
|
||||
|
||||
- (instancetype) init {
|
||||
[super doesNotRecognizeSelector:_cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:
|
||||
@"Date: %@\nTimeZone: %@\n"
|
||||
@"Local Sunrise: %@\n"
|
||||
@"Local Sunset: %@\n"
|
||||
@"Local Civil Twilight Start: %@\n"
|
||||
@"Local Civil Twilight End: %@\n"
|
||||
@"Local Nautical Twilight Start: %@\n"
|
||||
@"Local Nautical Twilight End: %@\n"
|
||||
@"Local Astronomical Twilight Start: %@\n"
|
||||
@"Local Astronomical Twilight End: %@\n",
|
||||
self.date.description, self.timezone.name,
|
||||
self.localSunrise.description, self.localSunset.description,
|
||||
self.localCivilTwilightStart, self.localCivilTwilightEnd,
|
||||
self.localNauticalTwilightStart, self.localNauticalTwilightEnd,
|
||||
self.localAstronomicalTwilightStart, self.localAstronomicalTwilightEnd
|
||||
];
|
||||
}
|
||||
|
||||
#pragma mark - Calculation methods
|
||||
|
||||
-(void)calculateSunriseSunset
|
||||
{
|
||||
// Get date components
|
||||
[self.calendar setTimeZone:self.timezone];
|
||||
NSDateComponents *dateComponents = [self.calendar components:( NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay ) fromDate:self.date];
|
||||
|
||||
// Calculate sunrise and sunset
|
||||
double rise=0.0, set=0.0;
|
||||
[self sunRiseSetForYear:(int)[dateComponents year] month:(int)[dateComponents month] day:(int)[dateComponents day] longitude:self.longitude latitude:self.latitude
|
||||
trise:&rise tset:&set ];
|
||||
NSTimeInterval secondsRise = rise*kSecondsInHour;
|
||||
NSTimeInterval secondsSet = set*kSecondsInHour;
|
||||
|
||||
self.sunrise = [self utcTime:dateComponents withOffset:(NSTimeInterval)secondsRise];
|
||||
self.sunset = [self utcTime:dateComponents withOffset:(NSTimeInterval)secondsSet];
|
||||
self.localSunrise = [self localTime:self.sunrise];
|
||||
self.localSunset = [self localTime:self.sunset];
|
||||
}
|
||||
|
||||
-(void)calculateTwilight
|
||||
{
|
||||
// Get date components
|
||||
[self.calendar setTimeZone:self.timezone];
|
||||
NSDateComponents *dateComponents = [self.calendar components:( NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay ) fromDate:self.date];
|
||||
double start=0.0, end=0.0;
|
||||
|
||||
// Civil twilight
|
||||
[self civilTwilightForYear:(int)[dateComponents year] month:(int)[dateComponents month] day:(int)[dateComponents day] longitude:self.longitude latitude:self.latitude
|
||||
trise:&start tset:&end ];
|
||||
self.civilTwilightStart = [self utcTime:dateComponents withOffset:(NSTimeInterval)(start*kSecondsInHour)];
|
||||
self.civilTwilightEnd = [self utcTime:dateComponents withOffset:(NSTimeInterval)(end*kSecondsInHour)];
|
||||
self.localCivilTwilightStart = [self localTime:self.civilTwilightStart];
|
||||
self.localCivilTwilightEnd = [self localTime:self.civilTwilightEnd];
|
||||
|
||||
// Nautical twilight
|
||||
[self nauticalTwilightForYear:(int)[dateComponents year] month:(int)[dateComponents month] day:(int)[dateComponents day] longitude:self.longitude latitude:self.latitude
|
||||
trise:&start tset:&end ];
|
||||
self.nauticalTwilightStart = [self utcTime:dateComponents withOffset:(NSTimeInterval)(start*kSecondsInHour)];
|
||||
self.nauticalTwilightEnd = [self utcTime:dateComponents withOffset:(NSTimeInterval)(end*kSecondsInHour)];
|
||||
self.localNauticalTwilightStart = [self localTime:self.nauticalTwilightStart];
|
||||
self.localNauticalTwilightEnd = [self localTime:self.nauticalTwilightEnd];
|
||||
// Astronomical twilight
|
||||
[self astronomicalTwilightForYear:(int)[dateComponents year] month:(int)[dateComponents month] day:(int)[dateComponents day] longitude:self.longitude latitude:self.latitude
|
||||
trise:&start tset:&end ];
|
||||
self.astronomicalTwilightStart = [self utcTime:dateComponents withOffset:(NSTimeInterval)(start*kSecondsInHour)];
|
||||
self.astronomicalTwilightEnd = [self utcTime:dateComponents withOffset:(NSTimeInterval)(end*kSecondsInHour)];
|
||||
self.localAstronomicalTwilightStart = [self localTime:self.astronomicalTwilightStart];
|
||||
self.localAstronomicalTwilightEnd = [self localTime:self.astronomicalTwilightEnd];
|
||||
}
|
||||
|
||||
-(void)calculate
|
||||
{
|
||||
[self calculateSunriseSunset];
|
||||
[self calculateTwilight];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - Public Implementation
|
||||
|
||||
@implementation EDSunriseSet
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
-(EDSunriseSet*)initWithDate:(NSDate*)date timezone:(NSTimeZone*)tz latitude:(double)latitude longitude:(double)longitude {
|
||||
self = [super init];
|
||||
if( self )
|
||||
{
|
||||
self.latitude = latitude;
|
||||
self.longitude = longitude;
|
||||
self.timezone = tz;
|
||||
self.date = date;
|
||||
|
||||
self.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:EDGregorianCalendar];
|
||||
self.utcTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
|
||||
|
||||
[self calculate];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+(EDSunriseSet*)sunrisesetWithDate:(NSDate*)date timezone:(NSTimeZone*)tz latitude:(double)latitude longitude:(double)longitude {
|
||||
return [[EDSunriseSet alloc] initWithDate:date timezone:tz latitude:latitude longitude:longitude];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -159,8 +159,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (SSignal *)createKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword;
|
||||
- (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey initialWalletId:(int64_t)initialWalletId;
|
||||
- (SSignal *)getAccountStateWithAddress:(NSString *)accountAddress;
|
||||
- (SSignal *)generateSendGramsQueryFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId;
|
||||
- (SSignal *)generateFakeSendGramsQueryFromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout;
|
||||
- (SSignal *)generateSendGramsQueryFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount comment:(NSData *)comment encryptComment:(bool)encryptComment forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId;
|
||||
- (SSignal *)generateFakeSendGramsQueryFromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount comment:(NSData *)comment encryptComment:(bool)encryptComment forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout;
|
||||
- (SSignal *)estimateSendGramsQueryFees:(TONPreparedSendGramsQuery *)preparedQuery;
|
||||
- (SSignal *)commitPreparedSendGramsQuery:(TONPreparedSendGramsQuery *)preparedQuery;
|
||||
- (SSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword;
|
||||
@ -168,6 +168,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (SSignal *)deleteKey:(TONKey *)key;
|
||||
- (SSignal *)deleteAllKeys;
|
||||
- (SSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash;
|
||||
- (SSignal *)decryptMessagesWithKey:(TONKey * _Nonnull)key localPassword:(NSData * _Nonnull)localPassword messages:(NSArray<NSData *> * _Nonnull)messages;
|
||||
|
||||
- (NSData *)encrypt:(NSData *)decryptedData secret:(NSData *)data;
|
||||
- (NSData * __nullable)decrypt:(NSData *)encryptedData secret:(NSData *)data;
|
||||
|
@ -699,7 +699,7 @@ typedef enum {
|
||||
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
|
||||
}
|
||||
|
||||
- (SSignal *)generateSendGramsQueryFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId {
|
||||
- (SSignal *)generateSendGramsQueryFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount comment:(NSData *)comment encryptComment:(bool)encryptComment forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId {
|
||||
return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
|
||||
if ([_sendGramRandomIds containsObject:@(randomId)]) {
|
||||
[_sendGramRandomIds addObject:@(randomId)];
|
||||
@ -739,9 +739,16 @@ typedef enum {
|
||||
}
|
||||
}];
|
||||
|
||||
auto inputMessageData = make_object<tonlib_api::msg_dataEncryptedText>(
|
||||
makeString(textMessage)
|
||||
);
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> inputMessageData;
|
||||
if (encryptComment && comment.length != 0) {
|
||||
inputMessageData = make_object<tonlib_api::msg_dataDecryptedText>(
|
||||
makeString(comment)
|
||||
);
|
||||
} else {
|
||||
inputMessageData = make_object<tonlib_api::msg_dataText>(
|
||||
makeString(comment)
|
||||
);
|
||||
}
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message> > inputMessages;
|
||||
inputMessages.push_back(make_object<tonlib_api::msg_message>(
|
||||
make_object<tonlib_api::accountAddress>(address.UTF8String),
|
||||
@ -772,7 +779,7 @@ typedef enum {
|
||||
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
|
||||
}
|
||||
|
||||
- (SSignal *)generateFakeSendGramsQueryFromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout {
|
||||
- (SSignal *)generateFakeSendGramsQueryFromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount comment:(NSData *)comment encryptComment:(bool)encryptComment forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout {
|
||||
return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
|
||||
|
||||
uint64_t requestId = _nextRequestId;
|
||||
@ -792,9 +799,16 @@ typedef enum {
|
||||
}
|
||||
}];
|
||||
|
||||
auto inputMessageData = make_object<tonlib_api::msg_dataEncryptedText>(
|
||||
makeString(textMessage)
|
||||
);
|
||||
tonlib_api::object_ptr<tonlib_api::msg_Data> inputMessageData;
|
||||
if (encryptComment && comment.length != 0) {
|
||||
inputMessageData = make_object<tonlib_api::msg_dataDecryptedText>(
|
||||
makeString(comment)
|
||||
);
|
||||
} else {
|
||||
inputMessageData = make_object<tonlib_api::msg_dataText>(
|
||||
makeString(comment)
|
||||
);
|
||||
}
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_message> > inputMessages;
|
||||
inputMessages.push_back(make_object<tonlib_api::msg_message>(
|
||||
make_object<tonlib_api::accountAddress>(address.UTF8String),
|
||||
@ -1079,4 +1093,74 @@ typedef enum {
|
||||
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
|
||||
}
|
||||
|
||||
- (SSignal *)decryptMessagesWithKey:(TONKey * _Nonnull)key localPassword:(NSData * _Nonnull)localPassword messages:(NSArray<NSData *> * _Nonnull)messages {
|
||||
return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
|
||||
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (publicKeyData == nil) {
|
||||
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in decryptMessagesWithKey"]];
|
||||
return [[SBlockDisposable alloc] initWithBlock:^{}];
|
||||
}
|
||||
|
||||
uint64_t requestId = _nextRequestId;
|
||||
_nextRequestId += 1;
|
||||
|
||||
_requestHandlers[@(requestId)] = [[TONRequestHandler alloc] initWithCompletion:^(tonlib_api::object_ptr<tonlib_api::Object> &object) {
|
||||
if (object->get_id() == tonlib_api::error::ID) {
|
||||
auto error = tonlib_api::move_object_as<tonlib_api::error>(object);
|
||||
[subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]];
|
||||
} else if (object->get_id() == tonlib_api::msg_dataArray::ID) {
|
||||
auto result = tonlib_api::move_object_as<tonlib_api::msg_dataArray>(object);
|
||||
if (result->elements_.size() != messages.count) {
|
||||
[subscriber putError:[[TONError alloc] initWithText:@"API interaction error"]];
|
||||
} else {
|
||||
NSMutableArray<id<TONTransactionMessageContents> > *resultMessages = [[NSMutableArray alloc] init];
|
||||
int index = 0;
|
||||
for (auto &it : result->elements_) {
|
||||
if (it->get_id() == tonlib_api::msg_dataDecryptedText::ID) {
|
||||
auto dataDecryptedText = tonlib_api::move_object_as<tonlib_api::msg_dataDecryptedText>(it);
|
||||
NSString *decryptedString = readString(dataDecryptedText->text_);
|
||||
if (decryptedString != nil) {
|
||||
[resultMessages addObject:[[TONTransactionMessageContentsPlainText alloc] initWithText:decryptedString]];
|
||||
} else {
|
||||
[resultMessages addObject:[[TONTransactionMessageContentsEncryptedText alloc] initWithData:messages[index]]];
|
||||
}
|
||||
} else {
|
||||
[resultMessages addObject:[[TONTransactionMessageContentsEncryptedText alloc] initWithData:messages[index]]];
|
||||
}
|
||||
index++;
|
||||
}
|
||||
[subscriber putNext:resultMessages];
|
||||
[subscriber putCompletion];
|
||||
}
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}];
|
||||
|
||||
std::vector<tonlib_api::object_ptr<tonlib_api::msg_Data>> inputData;
|
||||
for (NSData *message in messages) {
|
||||
inputData.push_back(make_object<tonlib_api::msg_dataEncryptedText>(
|
||||
makeString(message)
|
||||
));
|
||||
}
|
||||
|
||||
auto query = make_object<tonlib_api::msg_decrypt>(
|
||||
make_object<tonlib_api::inputKeyRegular>(
|
||||
make_object<tonlib_api::key>(
|
||||
makeString(publicKeyData),
|
||||
makeSecureString(key.secret)
|
||||
),
|
||||
makeSecureString(localPassword)
|
||||
),
|
||||
make_object<tonlib_api::msg_dataArray>(
|
||||
std::move(inputData)
|
||||
)
|
||||
);
|
||||
_client->send({ requestId, std::move(query) });
|
||||
|
||||
return [[SBlockDisposable alloc] initWithBlock:^{
|
||||
}];
|
||||
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -427,14 +427,45 @@ public final class TonInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func prepareSendGramsFromWalletQuery(decryptedSecret: Data, localPassword: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: Data, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal<TONPreparedSendGramsQuery, SendGramsFromWalletError> {
|
||||
fileprivate func decryptWalletTransactions(decryptionKey: WalletTransactionDecryptionKey, encryptedMessages: [Data]) -> Signal<[WalletTransactionMessageContents], DecryptWalletTransactionsError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
impl.withInstance { ton in
|
||||
let cancel = ton.decryptMessages(with: TONKey(publicKey: decryptionKey.walletInfo.publicKey.rawValue, secret: decryptionKey.decryptedSecret), localPassword: decryptionKey.localPassword, messages: encryptedMessages).start(next: { result in
|
||||
guard let result = result as? [TONTransactionMessageContents] else {
|
||||
subscriber.putError(.generic)
|
||||
return
|
||||
}
|
||||
subscriber.putNext(result.map(WalletTransactionMessageContents.init(tonTransactionMessageContents:)))
|
||||
}, error: { error in
|
||||
if let error = error as? TONError {
|
||||
subscriber.putError(.generic)
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
disposable.set(ActionDisposable {
|
||||
cancel?.dispose()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func prepareSendGramsFromWalletQuery(decryptedSecret: Data, localPassword: Data, walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, comment: Data, encryptComment: Bool, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal<TONPreparedSendGramsQuery, SendGramsFromWalletError> {
|
||||
let key = TONKey(publicKey: walletInfo.publicKey.rawValue, secret: decryptedSecret)
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
impl.withInstance { ton in
|
||||
let cancel = ton.generateSendGramsQuery(from: key, localPassword: localPassword, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId).start(next: { result in
|
||||
let cancel = ton.generateSendGramsQuery(from: key, localPassword: localPassword, fromAddress: fromAddress, toAddress: toAddress, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId).start(next: { result in
|
||||
guard let result = result as? TONPreparedSendGramsQuery else {
|
||||
subscriber.putError(.generic)
|
||||
return
|
||||
@ -472,13 +503,13 @@ public final class TonInstance {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func prepareFakeSendGramsFromWalletQuery(walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, textMessage: Data, timeout: Int32) -> Signal<TONPreparedSendGramsQuery, SendGramsFromWalletError> {
|
||||
fileprivate func prepareFakeSendGramsFromWalletQuery(walletInfo: WalletInfo, fromAddress: String, toAddress: String, amount: Int64, comment: Data, encryptComment: Bool, forceIfDestinationNotInitialized: Bool, timeout: Int32) -> Signal<TONPreparedSendGramsQuery, SendGramsFromWalletError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
impl.withInstance { ton in
|
||||
let cancel = ton.generateFakeSendGramsQuery(fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: true, timeout: timeout).start(next: { result in
|
||||
let cancel = ton.generateFakeSendGramsQuery(fromAddress: fromAddress, toAddress: toAddress, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout).start(next: { result in
|
||||
guard let result = result as? TONPreparedSendGramsQuery else {
|
||||
subscriber.putError(.generic)
|
||||
return
|
||||
@ -699,6 +730,15 @@ public struct CombinedWalletState: Codable, Equatable {
|
||||
public var timestamp: Int64
|
||||
public var topTransactions: [WalletTransaction]
|
||||
public var pendingTransactions: [PendingWalletTransaction]
|
||||
|
||||
public func withTopTransactions(_ topTransactions: [WalletTransaction]) -> CombinedWalletState {
|
||||
return CombinedWalletState(
|
||||
walletState: self.walletState,
|
||||
timestamp: self.timestamp,
|
||||
topTransactions: self.topTransactions,
|
||||
pendingTransactions: self.pendingTransactions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public struct WalletStateRecord: Codable, Equatable {
|
||||
@ -843,7 +883,7 @@ public enum CombinedWalletStateSubject {
|
||||
case address(String)
|
||||
}
|
||||
|
||||
public func getCombinedWalletState(storage: WalletStorageInterface, subject: CombinedWalletStateSubject, tonInstance: TonInstance, onlyCached: Bool = false) -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> {
|
||||
public func getCombinedWalletState(storage: WalletStorageInterface, subject: CombinedWalletStateSubject, transactionDecryptionKey: WalletTransactionDecryptionKey?, tonInstance: TonInstance, onlyCached: Bool) -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> {
|
||||
switch subject {
|
||||
case let .wallet(walletInfo):
|
||||
return storage.getWalletRecords()
|
||||
@ -893,14 +933,21 @@ public func getCombinedWalletState(storage: WalletStorageInterface, subject: Com
|
||||
|> mapToSignal { walletState, syncUtime -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
let topTransactions: Signal<[WalletTransaction], GetCombinedWalletStateError>
|
||||
if walletState.lastTransactionId == cachedState?.walletState.lastTransactionId {
|
||||
topTransactions = .single(cachedState?.topTransactions ?? [])
|
||||
if let topTransactionsValue = cachedState?.topTransactions, let transactionDecryptionKey = transactionDecryptionKey {
|
||||
topTransactions = decryptWalletTransactions(decryptionKey: transactionDecryptionKey, transactions: topTransactionsValue, tonInstance: tonInstance)
|
||||
|> mapError { _ -> GetCombinedWalletStateError in
|
||||
return .generic
|
||||
}
|
||||
} else {
|
||||
topTransactions = .single(cachedState?.topTransactions ?? [])
|
||||
}
|
||||
} else {
|
||||
if cachedState == nil {
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, tonInstance: tonInstance)
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, transactionDecryptionKey: transactionDecryptionKey, tonInstance: tonInstance)
|
||||
|> retry(1.0, maxDelay: 5.0, onQueue: .concurrentDefaultQueue())
|
||||
|> castError(GetCombinedWalletStateError.self)
|
||||
} else {
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, tonInstance: tonInstance)
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, transactionDecryptionKey: transactionDecryptionKey, tonInstance: tonInstance)
|
||||
|> mapError { error -> GetCombinedWalletStateError in
|
||||
if case .network = error {
|
||||
return .network
|
||||
@ -962,7 +1009,7 @@ public func getCombinedWalletState(storage: WalletStorageInterface, subject: Com
|
||||
|> mapToSignal { walletState, syncUtime -> Signal<CombinedWalletStateResult, GetCombinedWalletStateError> in
|
||||
let topTransactions: Signal<[WalletTransaction], GetCombinedWalletStateError>
|
||||
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, tonInstance: tonInstance)
|
||||
topTransactions = getWalletTransactions(address: address, previousId: nil, transactionDecryptionKey: nil, tonInstance: tonInstance)
|
||||
|> mapError { _ -> GetCombinedWalletStateError in
|
||||
return .generic
|
||||
}
|
||||
@ -994,25 +1041,48 @@ public struct EstimatedSendGramsFees {
|
||||
public let fwdFee: Int64
|
||||
}
|
||||
|
||||
public func verifySendGramsRequestAndEstimateFees(tonInstance: TonInstance, walletInfo: WalletInfo, toAddress: String, amount: Int64, textMessage: Data, timeout: Int32) -> Signal<EstimatedSendGramsFees, SendGramsFromWalletError> {
|
||||
public struct SendGramsVerificationResult {
|
||||
public let fees: EstimatedSendGramsFees
|
||||
public let canNotEncryptComment: Bool
|
||||
}
|
||||
|
||||
public func verifySendGramsRequestAndEstimateFees(tonInstance: TonInstance, walletInfo: WalletInfo, toAddress: String, amount: Int64, comment: Data, encryptComment: Bool, timeout: Int32) -> Signal<SendGramsVerificationResult, SendGramsFromWalletError> {
|
||||
return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance)
|
||||
|> castError(SendGramsFromWalletError.self)
|
||||
|> mapToSignal { fromAddress -> Signal<EstimatedSendGramsFees, SendGramsFromWalletError> in
|
||||
return tonInstance.prepareFakeSendGramsFromWalletQuery(walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, timeout: timeout)
|
||||
|> mapToSignal { preparedQuery -> Signal<EstimatedSendGramsFees, SendGramsFromWalletError> in
|
||||
return tonInstance.estimateSendGramsQueryFees(preparedQuery: preparedQuery)
|
||||
|> map { result -> EstimatedSendGramsFees in
|
||||
return EstimatedSendGramsFees(inFwdFee: result.sourceFees.inFwdFee, storageFee: result.sourceFees.storageFee, gasFee: result.sourceFees.gasFee, fwdFee: result.sourceFees.fwdFee)
|
||||
|> mapToSignal { fromAddress -> Signal<SendGramsVerificationResult, SendGramsFromWalletError> in
|
||||
struct QueryWithInfo {
|
||||
let query: TONPreparedSendGramsQuery
|
||||
let canNotEncryptComment: Bool
|
||||
}
|
||||
return tonInstance.prepareFakeSendGramsFromWalletQuery(walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, comment: comment, encryptComment: false, forceIfDestinationNotInitialized: false, timeout: timeout)
|
||||
|> map { query -> QueryWithInfo in
|
||||
return QueryWithInfo(query: query, canNotEncryptComment: false)
|
||||
}
|
||||
|> `catch` { error -> Signal<QueryWithInfo, SendGramsFromWalletError> in
|
||||
switch error {
|
||||
case .destinationIsNotInitialized:
|
||||
return tonInstance.prepareFakeSendGramsFromWalletQuery(walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, comment: comment, encryptComment: false, forceIfDestinationNotInitialized: true, timeout: timeout)
|
||||
|> map { query -> QueryWithInfo in
|
||||
return QueryWithInfo(query: query, canNotEncryptComment: encryptComment)
|
||||
}
|
||||
default:
|
||||
return .fail(error)
|
||||
}
|
||||
}
|
||||
|> mapToSignal { queryWithInfo -> Signal<SendGramsVerificationResult, SendGramsFromWalletError> in
|
||||
return tonInstance.estimateSendGramsQueryFees(preparedQuery: queryWithInfo.query)
|
||||
|> map { result -> SendGramsVerificationResult in
|
||||
return SendGramsVerificationResult(fees: EstimatedSendGramsFees(inFwdFee: result.sourceFees.inFwdFee, storageFee: result.sourceFees.storageFee, gasFee: result.sourceFees.gasFee, fwdFee: result.sourceFees.fwdFee), canNotEncryptComment: queryWithInfo.canNotEncryptComment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func sendGramsFromWallet(storage: WalletStorageInterface, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, localPassword: Data, toAddress: String, amount: Int64, textMessage: Data, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal<PendingWalletTransaction, SendGramsFromWalletError> {
|
||||
public func sendGramsFromWallet(storage: WalletStorageInterface, tonInstance: TonInstance, walletInfo: WalletInfo, decryptedSecret: Data, localPassword: Data, toAddress: String, amount: Int64, comment: Data, encryptComment: Bool, forceIfDestinationNotInitialized: Bool, timeout: Int32, randomId: Int64) -> Signal<PendingWalletTransaction, SendGramsFromWalletError> {
|
||||
return walletAddress(publicKey: walletInfo.publicKey, tonInstance: tonInstance)
|
||||
|> castError(SendGramsFromWalletError.self)
|
||||
|> mapToSignal { fromAddress -> Signal<PendingWalletTransaction, SendGramsFromWalletError> in
|
||||
return tonInstance.prepareSendGramsFromWalletQuery(decryptedSecret: decryptedSecret, localPassword: localPassword, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId)
|
||||
return tonInstance.prepareSendGramsFromWalletQuery(decryptedSecret: decryptedSecret, localPassword: localPassword, walletInfo: walletInfo, fromAddress: fromAddress, toAddress: toAddress, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: timeout, randomId: randomId)
|
||||
|> mapToSignal { preparedQuery -> Signal<PendingWalletTransaction, SendGramsFromWalletError> in
|
||||
return tonInstance.commitPreparedSendGramsQuery(preparedQuery)
|
||||
|> retryTonRequest(isNetworkError: { error in
|
||||
@ -1025,7 +1095,7 @@ public func sendGramsFromWallet(storage: WalletStorageInterface, tonInstance: To
|
||||
|> mapToSignal { _ -> Signal<PendingWalletTransaction, SendGramsFromWalletError> in
|
||||
return .complete()
|
||||
}
|
||||
|> then(.single(PendingWalletTransaction(timestamp: Int64(Date().timeIntervalSince1970), validUntilTimestamp: preparedQuery.validUntil, bodyHash: preparedQuery.bodyHash, address: toAddress, value: amount, comment: textMessage)))
|
||||
|> then(.single(PendingWalletTransaction(timestamp: Int64(Date().timeIntervalSince1970), validUntilTimestamp: preparedQuery.validUntil, bodyHash: preparedQuery.bodyHash, address: toAddress, value: amount, comment: comment)))
|
||||
|> mapToSignal { result in
|
||||
return storage.updateWalletRecords { records in
|
||||
var records = records
|
||||
@ -1122,7 +1192,13 @@ public final class WalletTransactionMessage: Codable, Equatable {
|
||||
public let contents: WalletTransactionMessageContents
|
||||
public let bodyHash: Data
|
||||
|
||||
init(value: Int64, source: String, destination: String, contents: WalletTransactionMessageContents, bodyHash: Data) {
|
||||
init(
|
||||
value: Int64,
|
||||
source: String,
|
||||
destination: String,
|
||||
contents: WalletTransactionMessageContents,
|
||||
bodyHash: Data
|
||||
) {
|
||||
self.value = value
|
||||
self.source = source
|
||||
self.destination = destination
|
||||
@ -1150,6 +1226,18 @@ public final class WalletTransactionMessage: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private extension WalletTransactionMessage {
|
||||
func withContents(_ contents: WalletTransactionMessageContents) -> WalletTransactionMessage {
|
||||
return WalletTransactionMessage(
|
||||
value: self.value,
|
||||
source: self.source,
|
||||
destination: self.destination,
|
||||
contents: contents,
|
||||
bodyHash: self.bodyHash
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private extension WalletTransactionMessage {
|
||||
convenience init(tonTransactionMessage: TONTransactionMessage) {
|
||||
self.init(value: tonTransactionMessage.value, source: tonTransactionMessage.source, destination: tonTransactionMessage.destination, contents: WalletTransactionMessageContents(tonTransactionMessageContents: tonTransactionMessage.contents), bodyHash: tonTransactionMessage.bodyHash)
|
||||
@ -1260,13 +1348,100 @@ public enum GetWalletTransactionsError {
|
||||
case network
|
||||
}
|
||||
|
||||
public func getWalletTransactions(address: String, previousId: WalletTransactionId?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> {
|
||||
return getWalletTransactionsOnce(address: address, previousId: previousId, tonInstance: tonInstance)
|
||||
public final class WalletTransactionDecryptionKey {
|
||||
fileprivate let decryptedSecret: Data
|
||||
fileprivate let localPassword: Data
|
||||
fileprivate let walletInfo: WalletInfo
|
||||
|
||||
fileprivate init(
|
||||
decryptedSecret: Data,
|
||||
localPassword: Data,
|
||||
walletInfo: WalletInfo
|
||||
) {
|
||||
self.decryptedSecret = decryptedSecret
|
||||
self.localPassword = localPassword
|
||||
self.walletInfo = walletInfo
|
||||
}
|
||||
}
|
||||
|
||||
public enum DecryptWalletTransactionsError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func walletTransactionDecryptionKey(keychain: TonKeychain, walletInfo: WalletInfo, localPassword: Data) -> Signal<WalletTransactionDecryptionKey?, NoError> {
|
||||
return keychain.decrypt(walletInfo.encryptedSecret)
|
||||
|> map { decryptedSecret -> WalletTransactionDecryptionKey? in
|
||||
return WalletTransactionDecryptionKey(decryptedSecret: decryptedSecret, localPassword: localPassword, walletInfo: walletInfo)
|
||||
}
|
||||
|> `catch` { _ -> Signal<WalletTransactionDecryptionKey?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
public func decryptWalletTransactions(decryptionKey: WalletTransactionDecryptionKey, transactions: [WalletTransaction], tonInstance: TonInstance) -> Signal<[WalletTransaction], DecryptWalletTransactionsError> {
|
||||
enum EncryptedMessagePath: Equatable {
|
||||
case inMessage
|
||||
case outMessage(Int)
|
||||
}
|
||||
var encryptedMessages: [(Int, EncryptedMessagePath, Data)] = []
|
||||
for i in 0 ..< transactions.count {
|
||||
if let inMessage = transactions[i].inMessage {
|
||||
switch inMessage.contents {
|
||||
case let .encryptedText(data):
|
||||
encryptedMessages.append((i, .inMessage, data))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
for outIndex in 0 ..< transactions[i].outMessages.count {
|
||||
switch transactions[i].outMessages[outIndex].contents {
|
||||
case let .encryptedText(data):
|
||||
encryptedMessages.append((i, .outMessage(outIndex), data))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !encryptedMessages.isEmpty {
|
||||
return tonInstance.decryptWalletTransactions(decryptionKey: decryptionKey, encryptedMessages: encryptedMessages.map { $0.2 })
|
||||
|> map { contentsList -> [WalletTransaction] in
|
||||
var result: [WalletTransaction] = []
|
||||
for transactionIndex in 0 ..< transactions.count {
|
||||
let transaction = transactions[transactionIndex]
|
||||
|
||||
var inMessage = transaction.inMessage
|
||||
var outMessages = transaction.outMessages
|
||||
|
||||
for encryptedIndex in 0 ..< encryptedMessages.count {
|
||||
if encryptedMessages[encryptedIndex].0 == transactionIndex {
|
||||
switch encryptedMessages[encryptedIndex].1 {
|
||||
case .inMessage:
|
||||
inMessage = inMessage?.withContents(contentsList[encryptedIndex])
|
||||
case let .outMessage(outIndex):
|
||||
outMessages[outIndex] = outMessages[outIndex].withContents(contentsList[encryptedIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.append(WalletTransaction(data: transaction.data, transactionId: transaction.transactionId, timestamp: transaction.timestamp, storageFee: transaction.storageFee, otherFee: transaction.otherFee, inMessage: inMessage, outMessages: outMessages))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|> `catch` { _ -> Signal<[WalletTransaction], DecryptWalletTransactionsError> in
|
||||
return .single(transactions)
|
||||
}
|
||||
} else {
|
||||
return .single(transactions)
|
||||
}
|
||||
}
|
||||
|
||||
public func getWalletTransactions(address: String, previousId: WalletTransactionId?, transactionDecryptionKey: WalletTransactionDecryptionKey?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> {
|
||||
return getWalletTransactionsOnce(address: address, previousId: previousId, transactionDecryptionKey: transactionDecryptionKey, tonInstance: tonInstance)
|
||||
|> mapToSignal { transactions in
|
||||
guard let lastTransaction = transactions.last, transactions.count >= 2 else {
|
||||
return .single(transactions)
|
||||
}
|
||||
return getWalletTransactionsOnce(address: address, previousId: lastTransaction.transactionId, tonInstance: tonInstance)
|
||||
return getWalletTransactionsOnce(address: address, previousId: lastTransaction.transactionId, transactionDecryptionKey: transactionDecryptionKey, tonInstance: tonInstance)
|
||||
|> map { additionalTransactions in
|
||||
var result = transactions
|
||||
var existingIds = Set(result.map { $0.transactionId })
|
||||
@ -1293,7 +1468,7 @@ private enum WalletLastTransactionIdError {
|
||||
case network
|
||||
}
|
||||
|
||||
private func getWalletTransactionsOnce(address: String, previousId: WalletTransactionId?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> {
|
||||
private func getWalletTransactionsOnce(address: String, previousId: WalletTransactionId?, transactionDecryptionKey: WalletTransactionDecryptionKey?, tonInstance: TonInstance) -> Signal<[WalletTransaction], GetWalletTransactionsError> {
|
||||
let previousIdValue: Signal<WalletTransactionId?, GetWalletTransactionsError>
|
||||
if let previousId = previousId {
|
||||
previousIdValue = .single(previousId)
|
||||
@ -1325,6 +1500,66 @@ private func getWalletTransactionsOnce(address: String, previousId: WalletTransa
|
||||
return false
|
||||
}
|
||||
})
|
||||
|> mapToSignal { transactions -> Signal<[WalletTransaction], GetWalletTransactionsError> in
|
||||
if let transactionDecryptionKey = transactionDecryptionKey {
|
||||
enum EncryptedMessagePath: Equatable {
|
||||
case inMessage
|
||||
case outMessage(Int)
|
||||
}
|
||||
var encryptedMessages: [(Int, EncryptedMessagePath, Data)] = []
|
||||
for i in 0 ..< transactions.count {
|
||||
if let inMessage = transactions[i].inMessage {
|
||||
switch inMessage.contents {
|
||||
case let .encryptedText(data):
|
||||
encryptedMessages.append((i, .inMessage, data))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
for outIndex in 0 ..< transactions[i].outMessages.count {
|
||||
switch transactions[i].outMessages[outIndex].contents {
|
||||
case let .encryptedText(data):
|
||||
encryptedMessages.append((i, .outMessage(outIndex), data))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !encryptedMessages.isEmpty {
|
||||
return tonInstance.decryptWalletTransactions(decryptionKey: transactionDecryptionKey, encryptedMessages: encryptedMessages.map { $0.2 })
|
||||
|> map { contentsList -> [WalletTransaction] in
|
||||
var result: [WalletTransaction] = []
|
||||
for transactionIndex in 0 ..< transactions.count {
|
||||
let transaction = transactions[transactionIndex]
|
||||
|
||||
var inMessage = transaction.inMessage
|
||||
var outMessages = transaction.outMessages
|
||||
|
||||
for encryptedIndex in 0 ..< encryptedMessages.count {
|
||||
if encryptedMessages[encryptedIndex].0 == transactionIndex {
|
||||
switch encryptedMessages[encryptedIndex].1 {
|
||||
case .inMessage:
|
||||
inMessage = inMessage?.withContents(contentsList[encryptedIndex])
|
||||
case let .outMessage(outIndex):
|
||||
outMessages[outIndex] = outMessages[outIndex].withContents(contentsList[encryptedIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.append(WalletTransaction(data: transaction.data, transactionId: transaction.transactionId, timestamp: transaction.timestamp, storageFee: transaction.storageFee, otherFee: transaction.otherFee, inMessage: inMessage, outMessages: outMessages))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|> `catch` { _ -> Signal<[WalletTransaction], GetWalletTransactionsError> in
|
||||
return .single(transactions)
|
||||
}
|
||||
} else {
|
||||
return .single(transactions)
|
||||
}
|
||||
} else {
|
||||
return .single(transactions)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single([])
|
||||
}
|
||||
|
Binary file not shown.
@ -316,6 +316,7 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
||||
switch neighbors.bottom {
|
||||
case .sameSection(false):
|
||||
bottomStripeInset = leftInset
|
||||
strongSelf.bottomStripeNode.isHidden = false
|
||||
default:
|
||||
bottomStripeInset = 0.0
|
||||
hasBottomCorners = true
|
||||
@ -327,7 +328,7 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||
|
||||
if strongSelf.textNode.attributedPlaceholderText == nil || !strongSelf.textNode.attributedPlaceholderText!.isEqual(to: attributedPlaceholderText) {
|
||||
strongSelf.textNode.attributedPlaceholderText = attributedPlaceholderText
|
||||
@ -393,7 +394,7 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
||||
let textBottomInset: CGFloat = 11.0
|
||||
|
||||
self.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
self.bottomStripeNode.frame = CGRect(origin: CGPoint(x: self.bottomStripeNode.frame.minX, y: contentSize.height), size: CGSize(width: self.bottomStripeNode.frame.size.width, height: separatorHeight))
|
||||
self.bottomStripeNode.frame = CGRect(origin: CGPoint(x: self.bottomStripeNode.frame.minX, y: contentSize.height - separatorHeight), size: CGSize(width: self.bottomStripeNode.frame.size.width, height: separatorHeight))
|
||||
|
||||
self.textClippingNode.frame = CGRect(origin: CGPoint(x: leftInset, y: textTopInset), size: CGSize(width: max(0.0, params.width - leftInset - params.rightInset), height: max(0.0, contentSize.height - textTopInset - textBottomInset)))
|
||||
}
|
||||
|
@ -0,0 +1,412 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
|
||||
enum ItemListSwitchItemNodeType {
|
||||
case regular
|
||||
case icon
|
||||
}
|
||||
|
||||
class ItemListSwitchItem: ListViewItem, ItemListItem {
|
||||
let theme: WalletTheme
|
||||
let title: String
|
||||
let value: Bool
|
||||
let type: ItemListSwitchItemNodeType
|
||||
let enableInteractiveChanges: Bool
|
||||
let enabled: Bool
|
||||
let disableLeadingInset: Bool
|
||||
let maximumNumberOfLines: Int
|
||||
let sectionId: ItemListSectionId
|
||||
let style: ItemListStyle
|
||||
let updated: (Bool) -> Void
|
||||
let activatedWhileDisabled: () -> Void
|
||||
let tag: ItemListItemTag?
|
||||
|
||||
init(theme: WalletTheme, title: String, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, disableLeadingInset: Bool = false, maximumNumberOfLines: Int = 1, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, activatedWhileDisabled: @escaping () -> Void = {}, tag: ItemListItemTag? = nil) {
|
||||
self.theme = theme
|
||||
self.title = title
|
||||
self.value = value
|
||||
self.type = type
|
||||
self.enableInteractiveChanges = enableInteractiveChanges
|
||||
self.enabled = enabled
|
||||
self.disableLeadingInset = disableLeadingInset
|
||||
self.maximumNumberOfLines = maximumNumberOfLines
|
||||
self.sectionId = sectionId
|
||||
self.style = style
|
||||
self.updated = updated
|
||||
self.activatedWhileDisabled = activatedWhileDisabled
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
async {
|
||||
let node = ItemListSwitchItemNode(type: self.type)
|
||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
Queue.mainQueue().async {
|
||||
completion(node, {
|
||||
return (nil, { _ in apply(false) })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
if let nodeValue = node() as? ItemListSwitchItemNode {
|
||||
let makeLayout = nodeValue.asyncLayout()
|
||||
|
||||
async {
|
||||
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||
Queue.mainQueue().async {
|
||||
completion(layout, { _ in
|
||||
var animated = true
|
||||
if case .None = animation {
|
||||
animated = false
|
||||
}
|
||||
apply(animated)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let topStripeNode: ASDisplayNode
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let titleNode: TextNode
|
||||
private var switchNode: SwitchNode
|
||||
private let switchGestureNode: ASDisplayNode
|
||||
private var disabledOverlayNode: ASDisplayNode?
|
||||
|
||||
private let activateArea: AccessibilityAreaNode
|
||||
|
||||
private var item: ItemListSwitchItem?
|
||||
|
||||
var tag: ItemListItemTag? {
|
||||
return self.item?.tag
|
||||
}
|
||||
|
||||
init(type: ItemListSwitchItemNodeType) {
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.backgroundColor = .white
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
|
||||
self.topStripeNode = ASDisplayNode()
|
||||
self.topStripeNode.isLayerBacked = true
|
||||
|
||||
self.bottomStripeNode = ASDisplayNode()
|
||||
self.bottomStripeNode.isLayerBacked = true
|
||||
|
||||
self.titleNode = TextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
self.switchNode = SwitchNode()
|
||||
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isLayerBacked = true
|
||||
|
||||
self.switchGestureNode = ASDisplayNode()
|
||||
|
||||
self.activateArea = AccessibilityAreaNode()
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.switchNode)
|
||||
self.addSubnode(self.switchGestureNode)
|
||||
self.addSubnode(self.activateArea)
|
||||
|
||||
self.activateArea.activate = { [weak self] in
|
||||
guard let strongSelf = self, let item = strongSelf.item, item.enabled else {
|
||||
return false
|
||||
}
|
||||
let value = !strongSelf.switchNode.isOn
|
||||
if item.enableInteractiveChanges {
|
||||
strongSelf.switchNode.setOn(value, animated: true)
|
||||
}
|
||||
item.updated(value)
|
||||
return true
|
||||
}
|
||||
|
||||
self.switchNode.valueUpdated = { [weak self] value in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
item.updated(value)
|
||||
}
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.switchGestureNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ item: ItemListSwitchItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) {
|
||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||
|
||||
let currentItem = self.item
|
||||
var currentDisabledOverlayNode = self.disabledOverlayNode
|
||||
|
||||
return { item, params, neighbors in
|
||||
var contentSize: CGSize
|
||||
var insets: UIEdgeInsets
|
||||
let separatorHeight = UIScreenPixel
|
||||
let itemBackgroundColor: UIColor
|
||||
let itemSeparatorColor: UIColor
|
||||
|
||||
let titleFont = Font.regular(17.0)
|
||||
|
||||
var updatedTheme: WalletTheme?
|
||||
|
||||
if currentItem?.theme !== item.theme {
|
||||
updatedTheme = item.theme
|
||||
}
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
itemBackgroundColor = item.theme.list.plainBackgroundColor
|
||||
itemSeparatorColor = item.theme.list.itemPlainSeparatorColor
|
||||
contentSize = CGSize(width: params.width, height: 44.0)
|
||||
insets = itemListNeighborsPlainInsets(neighbors)
|
||||
case .blocks:
|
||||
itemBackgroundColor = item.theme.list.itemBlocksBackgroundColor
|
||||
itemSeparatorColor = item.theme.list.itemBlocksSeparatorColor
|
||||
contentSize = CGSize(width: params.width, height: 44.0)
|
||||
insets = itemListNeighborsGroupedInsets(neighbors)
|
||||
}
|
||||
|
||||
if item.disableLeadingInset {
|
||||
insets.top = 0.0
|
||||
insets.bottom = 0.0
|
||||
}
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: item.maximumNumberOfLines, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 80.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
contentSize.height = max(contentSize.height, titleLayout.size.height + 22.0)
|
||||
|
||||
if !item.enabled {
|
||||
if currentDisabledOverlayNode == nil {
|
||||
currentDisabledOverlayNode = ASDisplayNode()
|
||||
currentDisabledOverlayNode?.backgroundColor = itemBackgroundColor.withAlphaComponent(0.6)
|
||||
}
|
||||
} else {
|
||||
currentDisabledOverlayNode = nil
|
||||
}
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||
let layoutSize = layout.size
|
||||
|
||||
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] animated in
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = item
|
||||
|
||||
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
|
||||
|
||||
strongSelf.activateArea.accessibilityLabel = item.title
|
||||
strongSelf.activateArea.accessibilityValue = item.value ? "On" : "Off"
|
||||
strongSelf.activateArea.accessibilityHint = "Tap to change"
|
||||
var accessibilityTraits = UIAccessibilityTraits()
|
||||
if item.enabled {
|
||||
} else {
|
||||
accessibilityTraits.insert(.notEnabled)
|
||||
}
|
||||
strongSelf.activateArea.accessibilityTraits = accessibilityTraits
|
||||
|
||||
let transition: ContainedViewLayoutTransition
|
||||
if animated {
|
||||
transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||
} else {
|
||||
transition = .immediate
|
||||
}
|
||||
|
||||
if let currentDisabledOverlayNode = currentDisabledOverlayNode {
|
||||
if currentDisabledOverlayNode != strongSelf.disabledOverlayNode {
|
||||
strongSelf.disabledOverlayNode = currentDisabledOverlayNode
|
||||
strongSelf.insertSubnode(currentDisabledOverlayNode, belowSubnode: strongSelf.switchGestureNode)
|
||||
currentDisabledOverlayNode.alpha = 0.0
|
||||
transition.updateAlpha(node: currentDisabledOverlayNode, alpha: 1.0)
|
||||
currentDisabledOverlayNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height - separatorHeight))
|
||||
} else {
|
||||
transition.updateFrame(node: currentDisabledOverlayNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width, height: layout.contentSize.height - separatorHeight)))
|
||||
}
|
||||
} else if let disabledOverlayNode = strongSelf.disabledOverlayNode {
|
||||
transition.updateAlpha(node: disabledOverlayNode, alpha: 0.0, completion: { [weak disabledOverlayNode] _ in
|
||||
disabledOverlayNode?.removeFromSupernode()
|
||||
})
|
||||
strongSelf.disabledOverlayNode = nil
|
||||
}
|
||||
|
||||
if let _ = updatedTheme {
|
||||
strongSelf.topStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor
|
||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||
|
||||
strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor
|
||||
}
|
||||
|
||||
let _ = titleApply()
|
||||
|
||||
let leftInset = 16.0 + params.leftInset
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
if strongSelf.backgroundNode.supernode != nil {
|
||||
strongSelf.backgroundNode.removeFromSupernode()
|
||||
}
|
||||
if strongSelf.topStripeNode.supernode != nil {
|
||||
strongSelf.topStripeNode.removeFromSupernode()
|
||||
}
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||
}
|
||||
if strongSelf.maskNode.supernode != nil {
|
||||
strongSelf.maskNode.removeFromSupernode()
|
||||
}
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||
case .blocks:
|
||||
if strongSelf.backgroundNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
|
||||
}
|
||||
if strongSelf.topStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||
}
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
}
|
||||
if strongSelf.maskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||
}
|
||||
|
||||
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||
var hasTopCorners = false
|
||||
var hasBottomCorners = false
|
||||
switch neighbors.top {
|
||||
case .sameSection(false):
|
||||
strongSelf.topStripeNode.isHidden = true
|
||||
default:
|
||||
hasTopCorners = true
|
||||
strongSelf.topStripeNode.isHidden = hasCorners
|
||||
}
|
||||
let bottomStripeInset: CGFloat
|
||||
switch neighbors.bottom {
|
||||
case .sameSection(false):
|
||||
bottomStripeInset = 16.0 + params.leftInset
|
||||
default:
|
||||
bottomStripeInset = 0.0
|
||||
hasBottomCorners = true
|
||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: contentSize.height))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||
}
|
||||
|
||||
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floorToScreenPixels((contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size)
|
||||
if let switchView = strongSelf.switchNode.view as? UISwitch {
|
||||
if strongSelf.switchNode.bounds.size.width.isZero {
|
||||
switchView.sizeToFit()
|
||||
}
|
||||
let switchSize = switchView.bounds.size
|
||||
|
||||
strongSelf.switchNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - switchSize.width - 15.0, y: floor((contentSize.height - switchSize.height) / 2.0)), size: switchSize)
|
||||
strongSelf.switchGestureNode.frame = strongSelf.switchNode.frame
|
||||
if switchView.isOn != item.value {
|
||||
switchView.setOn(item.value, animated: animated)
|
||||
}
|
||||
switchView.isUserInteractionEnabled = item.enableInteractiveChanges
|
||||
}
|
||||
strongSelf.switchGestureNode.isHidden = item.enableInteractiveChanges && item.enabled
|
||||
|
||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 44.0 + UIScreenPixel + UIScreenPixel))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override func accessibilityActivate() -> Bool {
|
||||
guard let item = self.item else {
|
||||
return false
|
||||
}
|
||||
if !item.enabled {
|
||||
return false
|
||||
}
|
||||
self.switchNode.isOn = !self.switchNode.isOn
|
||||
item.updated(self.switchNode.isOn)
|
||||
return true
|
||||
}
|
||||
|
||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||
|
||||
if highlighted {
|
||||
self.highlightedBackgroundNode.alpha = 1.0
|
||||
if self.highlightedBackgroundNode.supernode == nil {
|
||||
var anchorNode: ASDisplayNode?
|
||||
if self.bottomStripeNode.supernode != nil {
|
||||
anchorNode = self.bottomStripeNode
|
||||
} else if self.topStripeNode.supernode != nil {
|
||||
anchorNode = self.topStripeNode
|
||||
} else if self.backgroundNode.supernode != nil {
|
||||
anchorNode = self.backgroundNode
|
||||
}
|
||||
if let anchorNode = anchorNode {
|
||||
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
|
||||
} else {
|
||||
self.addSubnode(self.highlightedBackgroundNode)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.highlightedBackgroundNode.supernode != nil {
|
||||
if animated {
|
||||
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
|
||||
if let strongSelf = self {
|
||||
if completed {
|
||||
strongSelf.highlightedBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
})
|
||||
self.highlightedBackgroundNode.alpha = 0.0
|
||||
} else {
|
||||
self.highlightedBackgroundNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||
}
|
||||
|
||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if let item = self.item, let switchView = self.switchNode.view as? UISwitch, case .ended = recognizer.state {
|
||||
if item.enabled {
|
||||
let value = switchView.isOn
|
||||
item.updated(!value)
|
||||
} else {
|
||||
item.activatedWhileDisabled()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -569,6 +569,10 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
|
||||
private let stateDisposable = MetaDisposable()
|
||||
private let transactionListDisposable = MetaDisposable()
|
||||
private let transactionDecryptionKey = Promise<WalletTransactionDecryptionKey?>()
|
||||
private var transactionDecryptionKeyRequested = false
|
||||
private var transactionDecryptionKeyValue: WalletTransactionDecryptionKey?
|
||||
private var transactionDecryptionKeyDisposable: Disposable?
|
||||
|
||||
private var listOffset: CGFloat?
|
||||
private(set) var reloadingState: Bool = false
|
||||
@ -689,21 +693,50 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
if let walletInfo = walletInfo {
|
||||
subject = .wallet(walletInfo)
|
||||
|
||||
self.watchCombinedStateDisposable = (context.storage.watchWalletRecords()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] records in
|
||||
guard let strongSelf = self else {
|
||||
let watchCombinedStateSignal = context.storage.watchWalletRecords()
|
||||
|> map { records -> WalletStateRecord? in
|
||||
for record in records {
|
||||
if record.info.publicKey == walletInfo.publicKey {
|
||||
return record
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { wallet -> Signal<CombinedWalletState?, NoError> in
|
||||
guard let wallet = wallet, let state = wallet.state else {
|
||||
return .single(nil)
|
||||
}
|
||||
return .single(state)
|
||||
}
|
||||
|
||||
let tonInstance = self.context.tonInstance
|
||||
let decryptedWalletState = combineLatest(queue: .mainQueue(),
|
||||
watchCombinedStateSignal,
|
||||
self.transactionDecryptionKey.get()
|
||||
)
|
||||
|> mapToSignal { maybeState, decryptionKey -> Signal<CombinedWalletState?, NoError> in
|
||||
guard let state = maybeState, let decryptionKey = decryptionKey else {
|
||||
return .single(maybeState)
|
||||
}
|
||||
return decryptWalletTransactions(decryptionKey: decryptionKey, transactions: state.topTransactions, tonInstance: tonInstance)
|
||||
|> `catch` { _ -> Signal<[WalletTransaction], NoError> in
|
||||
return .single(state.topTransactions)
|
||||
}
|
||||
|> map { transactions -> CombinedWalletState? in
|
||||
return state.withTopTransactions(transactions)
|
||||
}
|
||||
}
|
||||
|
||||
self.watchCombinedStateDisposable = (decryptedWalletState
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self, let state = state else {
|
||||
return
|
||||
}
|
||||
for wallet in records {
|
||||
if wallet.info.publicKey == walletInfo.publicKey {
|
||||
if let state = wallet.state {
|
||||
if state.pendingTransactions != strongSelf.combinedState?.pendingTransactions || state.timestamp != strongSelf.combinedState?.timestamp {
|
||||
if !strongSelf.reloadingState {
|
||||
strongSelf.updateCombinedState(combinedState: state, isUpdated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
if state.pendingTransactions != strongSelf.combinedState?.pendingTransactions || state.timestamp != strongSelf.combinedState?.timestamp {
|
||||
if !strongSelf.reloadingState {
|
||||
strongSelf.updateCombinedState(combinedState: state, isUpdated: true)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -711,7 +744,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
subject = .address(address)
|
||||
}
|
||||
let pollCombinedState: Signal<Never, NoError> = (
|
||||
getCombinedWalletState(storage: context.storage, subject: subject, tonInstance: context.tonInstance)
|
||||
getCombinedWalletState(storage: context.storage, subject: subject, transactionDecryptionKey: nil, tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> ignoreValues
|
||||
|> `catch` { _ -> Signal<Never, NoError> in
|
||||
return .complete()
|
||||
@ -736,6 +769,81 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
strongSelf.headerNode.refreshNode.update(state: .refreshing)
|
||||
}
|
||||
})
|
||||
|
||||
self.transactionDecryptionKeyDisposable = (self.transactionDecryptionKey.get()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.transactionDecryptionKeyValue = value
|
||||
if let value = value, let currentEntries = strongSelf.currentEntries {
|
||||
var encryptedTransactions: [WalletTransactionId: WalletTransaction] = [:]
|
||||
for entry in currentEntries {
|
||||
switch entry {
|
||||
case .empty:
|
||||
break
|
||||
case let .transaction(_, transaction):
|
||||
switch transaction {
|
||||
case let .completed(transaction):
|
||||
var isEncrypted = false
|
||||
if let inMessage = transaction.inMessage {
|
||||
switch inMessage.contents {
|
||||
case .encryptedText:
|
||||
isEncrypted = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
for outMessage in transaction.outMessages {
|
||||
switch outMessage.contents {
|
||||
case .encryptedText:
|
||||
isEncrypted = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
if isEncrypted {
|
||||
encryptedTransactions[transaction.transactionId] = transaction
|
||||
}
|
||||
case .pending:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !encryptedTransactions.isEmpty {
|
||||
let _ = (decryptWalletTransactions(decryptionKey: value, transactions: Array(encryptedTransactions.values), tonInstance: strongSelf.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { decryptedTransactions in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var decryptedTransactionMap: [WalletTransactionId: WalletTransaction] = [:]
|
||||
for transaction in decryptedTransactions {
|
||||
decryptedTransactionMap[transaction.transactionId] = transaction
|
||||
}
|
||||
var updatedEntries: [WalletInfoListEntry] = []
|
||||
for entry in currentEntries {
|
||||
switch entry {
|
||||
case .empty:
|
||||
updatedEntries.append(entry)
|
||||
case let .transaction(index, transaction):
|
||||
switch transaction {
|
||||
case .pending:
|
||||
updatedEntries.append(entry)
|
||||
case let .completed(transaction):
|
||||
if let decryptedTransaction = decryptedTransactionMap[transaction.transactionId] {
|
||||
updatedEntries.append(.transaction(index, .completed(decryptedTransaction)))
|
||||
} else {
|
||||
updatedEntries.append(entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
strongSelf.replaceEntries(updatedEntries)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -745,6 +853,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
self.pollCombinedStateDisposable?.dispose()
|
||||
self.watchCombinedStateDisposable?.dispose()
|
||||
self.refreshProgressDisposable?.dispose()
|
||||
self.transactionDecryptionKeyDisposable?.dispose()
|
||||
}
|
||||
|
||||
func scrollToHideHeader() {
|
||||
@ -811,7 +920,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
subject = .address(self.address)
|
||||
}
|
||||
|
||||
self.stateDisposable.set((getCombinedWalletState(storage: self.context.storage, subject: subject, tonInstance: self.context.tonInstance)
|
||||
self.stateDisposable.set((getCombinedWalletState(storage: self.context.storage, subject: subject, transactionDecryptionKey: self.transactionDecryptionKeyValue, tonInstance: self.context.tonInstance, onlyCached: false)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -975,7 +1084,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
break
|
||||
}
|
||||
}
|
||||
self.transactionListDisposable.set((getWalletTransactions(address: self.address, previousId: lastTransactionId, tonInstance: self.context.tonInstance)
|
||||
self.transactionListDisposable.set((getWalletTransactions(address: self.address, previousId: lastTransactionId, transactionDecryptionKey: self.transactionDecryptionKeyValue, tonInstance: self.context.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] transactions in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -1041,6 +1150,61 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.replaceEntries(updatedEntries)
|
||||
|
||||
if !self.transactionDecryptionKeyRequested {
|
||||
var encryptedTransactions: [WalletTransactionId: WalletTransaction] = [:]
|
||||
for entry in updatedEntries {
|
||||
switch entry {
|
||||
case .empty:
|
||||
break
|
||||
case let .transaction(_, transaction):
|
||||
switch transaction {
|
||||
case let .completed(transaction):
|
||||
var isEncrypted = false
|
||||
if let inMessage = transaction.inMessage {
|
||||
switch inMessage.contents {
|
||||
case .encryptedText:
|
||||
isEncrypted = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
for outMessage in transaction.outMessages {
|
||||
switch outMessage.contents {
|
||||
case .encryptedText:
|
||||
isEncrypted = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
if isEncrypted {
|
||||
encryptedTransactions[transaction.transactionId] = transaction
|
||||
}
|
||||
case .pending:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !encryptedTransactions.isEmpty, let walletInfo = self.walletInfo {
|
||||
let keychain = self.context.keychain
|
||||
self.transactionDecryptionKeyRequested = true
|
||||
self.transactionDecryptionKey.set(self.context.getServerSalt()
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Data?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { serverSalt -> Signal<WalletTransactionDecryptionKey?, NoError> in
|
||||
guard let serverSalt = serverSalt else {
|
||||
return .single(nil)
|
||||
}
|
||||
return walletTransactionDecryptionKey(keychain: keychain, walletInfo: walletInfo, localPassword: serverSalt)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func replaceEntries(_ updatedEntries: [WalletInfoListEntry]) {
|
||||
let transaction = preparedTransition(from: self.currentEntries ?? [], to: updatedEntries, presentationData: self.presentationData, action: { [weak self] transaction in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
@ -16,16 +16,18 @@ private final class WalletSendScreenArguments {
|
||||
let context: WalletContext
|
||||
let updateState: ((WalletSendScreenState) -> WalletSendScreenState) -> Void
|
||||
let updateText: (WalletSendScreenEntryTag, String) -> Void
|
||||
let updateIsEncrypted: (Bool) -> Void
|
||||
let selectInputItem: (WalletSendScreenEntryTag) -> Void
|
||||
let scrollToBottom: () -> Void
|
||||
let dismissInput: () -> Void
|
||||
let openQrScanner: () -> Void
|
||||
let proceed: () -> Void
|
||||
|
||||
init(context: WalletContext, updateState: @escaping ((WalletSendScreenState) -> WalletSendScreenState) -> Void, updateText: @escaping (WalletSendScreenEntryTag, String) -> Void, selectInputItem: @escaping (WalletSendScreenEntryTag) -> Void, scrollToBottom: @escaping () -> Void, dismissInput: @escaping () -> Void, openQrScanner: @escaping () -> Void, proceed: @escaping () -> Void) {
|
||||
init(context: WalletContext, updateState: @escaping ((WalletSendScreenState) -> WalletSendScreenState) -> Void, updateText: @escaping (WalletSendScreenEntryTag, String) -> Void, updateIsEncrypted: @escaping (Bool) -> Void, selectInputItem: @escaping (WalletSendScreenEntryTag) -> Void, scrollToBottom: @escaping () -> Void, dismissInput: @escaping () -> Void, openQrScanner: @escaping () -> Void, proceed: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.updateState = updateState
|
||||
self.updateText = updateText
|
||||
self.updateIsEncrypted = updateIsEncrypted
|
||||
self.selectInputItem = selectInputItem
|
||||
self.scrollToBottom = scrollToBottom
|
||||
self.dismissInput = dismissInput
|
||||
@ -62,6 +64,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
case addressInfo(WalletTheme, String)
|
||||
case commentHeader(WalletTheme, String)
|
||||
case comment(WalletTheme, String, String, Bool)
|
||||
case commendEncryption(WalletTheme, String, Bool)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
@ -69,7 +72,7 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
return WalletSendScreenSection.amount.rawValue
|
||||
case .addressHeader, .address, .addressInfo:
|
||||
return WalletSendScreenSection.address.rawValue
|
||||
case .commentHeader, .comment:
|
||||
case .commentHeader, .comment, .commendEncryption:
|
||||
return WalletSendScreenSection.comment.rawValue
|
||||
}
|
||||
}
|
||||
@ -90,6 +93,8 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
return 5
|
||||
case .comment:
|
||||
return 6
|
||||
case .commendEncryption:
|
||||
return 7
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +142,12 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .commendEncryption(lhsTheme, lhsText, lhsValue):
|
||||
if case let .commendEncryption(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,6 +268,10 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
||||
arguments.proceed()
|
||||
}
|
||||
})
|
||||
case let .commendEncryption(theme, text, value):
|
||||
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
|
||||
arguments.updateIsEncrypted(value)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,6 +280,7 @@ private struct WalletSendScreenState: Equatable {
|
||||
var address: String
|
||||
var amount: String
|
||||
var comment: String
|
||||
var isCommentEncrypted: Bool
|
||||
}
|
||||
|
||||
private func walletSendScreenEntries(presentationData: WalletPresentationData, balance: Int64?, state: WalletSendScreenState, sendEnabled: Bool) -> [WalletSendScreenEntry] {
|
||||
@ -284,6 +300,8 @@ private func walletSendScreenEntries(presentationData: WalletPresentationData, b
|
||||
|
||||
entries.append(.commentHeader(presentationData.theme, presentationData.strings.Wallet_Receive_CommentHeader))
|
||||
entries.append(.comment(presentationData.theme, presentationData.strings.Wallet_Receive_CommentInfo, state.comment, sendEnabled))
|
||||
entries.append(.commendEncryption(presentationData.theme, presentationData.strings.Wallet_Send_EncryptComment, state.isCommentEncrypted))
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
@ -298,7 +316,7 @@ private final class WalletSendScreenImpl: ItemListController, WalletSendScreen {
|
||||
public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo: WalletInfo, address: String? = nil, amount: Int64? = nil, comment: String? = nil) -> ViewController {
|
||||
let presentationData = context.presentationData
|
||||
|
||||
let initialState = WalletSendScreenState(address: address ?? "", amount: amount.flatMap { formatBalanceText($0, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) } ?? "", comment: comment ?? "")
|
||||
let initialState = WalletSendScreenState(address: address ?? "", amount: amount.flatMap { formatBalanceText($0, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) } ?? "", comment: comment ?? "", isCommentEncrypted: true)
|
||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: initialState)
|
||||
let updateState: ((WalletSendScreenState) -> WalletSendScreenState) -> Void = { f in
|
||||
@ -337,6 +355,12 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
return state
|
||||
}
|
||||
ensureItemVisibleImpl?(tag, false)
|
||||
}, updateIsEncrypted: { value in
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.isCommentEncrypted = value
|
||||
return state
|
||||
}
|
||||
}, selectInputItem: { tag in
|
||||
selectInputItemImpl?(tag)
|
||||
}, scrollToBottom: {
|
||||
@ -393,15 +417,15 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
presentControllerImpl?(controller, nil)
|
||||
|
||||
let _ = (verifySendGramsRequestAndEstimateFees(tonInstance: context.tonInstance, walletInfo: walletInfo, toAddress: destinationAddress, amount: amount, textMessage: commentData ?? Data(), timeout: 0)
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] fees in
|
||||
let _ = (verifySendGramsRequestAndEstimateFees(tonInstance: context.tonInstance, walletInfo: walletInfo, toAddress: destinationAddress, amount: amount, comment: commentData ?? Data(), encryptComment: state.isCommentEncrypted, timeout: 0)
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] verificationResult in
|
||||
controller?.dismiss()
|
||||
|
||||
let presentationData = context.presentationData
|
||||
|
||||
let title = NSAttributedString(string: presentationData.strings.Wallet_Send_Confirmation, font: Font.semibold(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
|
||||
let feeAmount = fees.inFwdFee + fees.storageFee + fees.gasFee + fees.fwdFee
|
||||
let feeAmount = verificationResult.fees.inFwdFee + verificationResult.fees.storageFee + verificationResult.fees.gasFee + verificationResult.fees.fwdFee
|
||||
|
||||
let (text, ranges) = presentationData.strings.Wallet_Send_ConfirmationText(formatBalanceText(amount, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), formattedAddress, "\(formatBalanceText(feeAmount, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))")
|
||||
let bodyAttributes = MarkdownAttributeSet(font: Font.regular(13.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
|
||||
@ -413,6 +437,11 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
}
|
||||
}
|
||||
|
||||
if verificationResult.canNotEncryptComment {
|
||||
//TODO:localize
|
||||
attributedText.append(NSAttributedString(string: "\n\nThe destination wallet is not initialized. The comment will be sent unencrypted.", font: Font.regular(13.0), textColor: presentationData.theme.list.itemDestructiveColor))
|
||||
}
|
||||
|
||||
var dismissAlertImpl: ((Bool) -> Void)?
|
||||
let theme = context.presentationData.theme
|
||||
let controller = richTextAlertController(alertContext: AlertControllerContext(theme: theme.alert, themeSignal: .single(theme.alert)), title: title, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Wallet_Navigation_Cancel, action: {
|
||||
@ -449,7 +478,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
|> deliverOnMainQueue).start(next: { serverSalt in
|
||||
if let serverSalt = serverSalt {
|
||||
if let commentData = state.comment.data(using: .utf8) {
|
||||
pushImpl?(WalletSplashScreen(context: context, mode: .sending(walletInfo, state.address, amount, commentData, randomId, serverSalt), walletCreatedPreloadState: nil))
|
||||
pushImpl?(WalletSplashScreen(context: context, mode: .sending(walletInfo: walletInfo, address: state.address, amount: amount, comment: commentData, encryptComment: state.isCommentEncrypted && !verificationResult.canNotEncryptComment, randomId: randomId, serverSalt: serverSalt), walletCreatedPreloadState: nil))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -515,7 +544,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
})
|
||||
})
|
||||
|
||||
let walletState: Signal<WalletState?, NoError> = getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance, onlyCached: true)
|
||||
let walletState: Signal<WalletState?, NoError> = getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), transactionDecryptionKey: nil, tonInstance: context.tonInstance, onlyCached: true)
|
||||
|> map { combinedState -> WalletState? in
|
||||
var state: WalletState?
|
||||
switch combinedState {
|
||||
@ -529,7 +558,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
||||
|> `catch` { _ -> Signal<WalletState?, NoError> in
|
||||
return .single(nil)
|
||||
|> then(
|
||||
getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance, onlyCached: false)
|
||||
getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), transactionDecryptionKey: nil, tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> map { combinedState -> WalletState? in
|
||||
var state: WalletState?
|
||||
switch combinedState {
|
||||
|
@ -19,11 +19,11 @@ public enum WalletSecureStorageResetReason {
|
||||
|
||||
public enum WalletSplashMode {
|
||||
case intro
|
||||
case created(WalletInfo, [String]?)
|
||||
case success(WalletInfo)
|
||||
case created(walletInfo: WalletInfo, words: [String]?)
|
||||
case success(walletInfo: WalletInfo)
|
||||
case restoreFailed
|
||||
case sending(WalletInfo, String, Int64, Data, Int64, Data)
|
||||
case sent(WalletInfo, Int64)
|
||||
case sending(walletInfo: WalletInfo, address: String, amount: Int64, comment: Data, encryptComment: Bool, randomId: Int64, serverSalt: Data)
|
||||
case sent(walletInfo: WalletInfo, amount: Int64)
|
||||
case secureStorageNotAvailable
|
||||
case secureStorageReset(WalletSecureStorageResetReason)
|
||||
}
|
||||
@ -52,7 +52,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
self.walletCreatedPreloadState = walletCreatedPreloadState
|
||||
} else {
|
||||
self.walletCreatedPreloadState = Promise()
|
||||
self.walletCreatedPreloadState?.set(getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance)
|
||||
self.walletCreatedPreloadState?.set(getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), transactionDecryptionKey: nil, tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<CombinedWalletStateResult?, NoError> in
|
||||
return .single(nil)
|
||||
@ -63,7 +63,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
self.walletCreatedPreloadState = walletCreatedPreloadState
|
||||
} else {
|
||||
self.walletCreatedPreloadState = Promise()
|
||||
self.walletCreatedPreloadState?.set(getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), tonInstance: context.tonInstance)
|
||||
self.walletCreatedPreloadState?.set(getCombinedWalletState(storage: context.storage, subject: .wallet(walletInfo), transactionDecryptionKey: nil, tonInstance: context.tonInstance, onlyCached: false)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<CombinedWalletStateResult?, NoError> in
|
||||
return .single(nil)
|
||||
@ -82,14 +82,14 @@ public final class WalletSplashScreen: ViewController {
|
||||
|
||||
switch self.mode {
|
||||
case let .intro: self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Wallet_Intro_ImportExisting, style: .plain, target: self, action: #selector(self.importPressed)), animated: false)
|
||||
case let .sending(walletInfo, address, amount, textMessage, randomId, serverSalt):
|
||||
case let .sending(walletInfo, address, amount, comment, encryptComment, randomId, serverSalt):
|
||||
self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false)
|
||||
let _ = (self.context.keychain.decrypt(walletInfo.encryptedSecret)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] decryptedSecret in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: true, randomId: randomId, serverSalt: serverSalt)
|
||||
strongSelf.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: true, randomId: randomId, serverSalt: serverSalt)
|
||||
}, error: { [weak self] error in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -133,8 +133,8 @@ public final class WalletSplashScreen: ViewController {
|
||||
self.push(WalletWordCheckScreen(context: self.context, mode: .import, walletCreatedPreloadState: nil))
|
||||
}
|
||||
|
||||
private func sendGrams(walletInfo: WalletInfo, decryptedSecret: Data, address: String, amount: Int64, textMessage: Data, forceIfDestinationNotInitialized: Bool, randomId: Int64, serverSalt: Data) {
|
||||
let _ = (sendGramsFromWallet(storage: self.context.storage, tonInstance: self.context.tonInstance, walletInfo: walletInfo, decryptedSecret: decryptedSecret, localPassword: serverSalt, toAddress: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: 0, randomId: randomId)
|
||||
private func sendGrams(walletInfo: WalletInfo, decryptedSecret: Data, address: String, amount: Int64, comment: Data, encryptComment: Bool, forceIfDestinationNotInitialized: Bool, randomId: Int64, serverSalt: Data) {
|
||||
let _ = (sendGramsFromWallet(storage: self.context.storage, tonInstance: self.context.tonInstance, walletInfo: walletInfo, decryptedSecret: decryptedSecret, localPassword: serverSalt, toAddress: address, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: forceIfDestinationNotInitialized, timeout: 0, randomId: randomId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] sentTransaction in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -142,7 +142,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
|
||||
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Wallet_WordImport_Continue, style: .plain, target: strongSelf, action: #selector(strongSelf.sendGramsContinuePressed)), animated: false)
|
||||
|
||||
let check = getCombinedWalletState(storage: strongSelf.context.storage, subject: .wallet(walletInfo), tonInstance: strongSelf.context.tonInstance)
|
||||
let check = getCombinedWalletState(storage: strongSelf.context.storage, subject: .wallet(walletInfo), transactionDecryptionKey: nil, tonInstance: strongSelf.context.tonInstance, onlyCached: false)
|
||||
|> mapToSignal { state -> Signal<Bool, GetCombinedWalletStateError> in
|
||||
switch state {
|
||||
case .cached:
|
||||
@ -183,7 +183,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
controllers.append(controller)
|
||||
}
|
||||
}
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .sent(walletInfo, amount), walletCreatedPreloadState: nil))
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .sent(walletInfo: walletInfo, amount: amount), walletCreatedPreloadState: nil))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
})
|
||||
@ -208,7 +208,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
controllers.append(controller)
|
||||
}
|
||||
}
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .sent(walletInfo, amount), walletCreatedPreloadState: nil))
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .sent(walletInfo: walletInfo, amount: amount), walletCreatedPreloadState: nil))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
})
|
||||
@ -246,7 +246,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
}
|
||||
}),
|
||||
TextAlertAction(type: .defaultAction, title: "Send Anyway", action: {
|
||||
self?.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, textMessage: textMessage, forceIfDestinationNotInitialized: true, randomId: randomId, serverSalt: serverSalt)
|
||||
self?.sendGrams(walletInfo: walletInfo, decryptedSecret: decryptedSecret, address: address, amount: amount, comment: comment, encryptComment: encryptComment, forceIfDestinationNotInitialized: true, randomId: randomId, serverSalt: serverSalt)
|
||||
})
|
||||
])
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
@ -333,7 +333,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return
|
||||
}
|
||||
controller.dismiss()
|
||||
(strongSelf.navigationController as? NavigationController)?.replaceController(strongSelf, with: WalletSplashScreen(context: strongSelf.context, mode: .created(walletInfo, wordList), walletCreatedPreloadState: nil), animated: true)
|
||||
(strongSelf.navigationController as? NavigationController)?.replaceController(strongSelf, with: WalletSplashScreen(context: strongSelf.context, mode: .created(walletInfo: walletInfo, words: wordList), walletCreatedPreloadState: nil), animated: true)
|
||||
}, error: { _ in
|
||||
displayError()
|
||||
})
|
||||
@ -360,7 +360,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.mode = .created(walletInfo, wordList)
|
||||
strongSelf.mode = .created(walletInfo: walletInfo, words: wordList)
|
||||
strongSelf.push(WalletWordDisplayScreen(context: strongSelf.context, walletInfo: walletInfo, wordList: wordList, mode: .check, walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
}, error: { _ in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -245,215 +245,216 @@ public final class WalletStrings: Equatable {
|
||||
public var Wallet_Intro_ImportExisting: String { return self._s[46]! }
|
||||
public var Wallet_Receive_CommentInfo: String { return self._s[47]! }
|
||||
public var Wallet_WordCheck_Continue: String { return self._s[48]! }
|
||||
public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[49]! }
|
||||
public var Wallet_Completed_Text: String { return self._s[50]! }
|
||||
public var Wallet_WordCheck_IncorrectHeader: String { return self._s[52]! }
|
||||
public var Wallet_Configuration_SourceHeader: String { return self._s[53]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[54]! }
|
||||
public var Wallet_Receive_Title: String { return self._s[55]! }
|
||||
public var Wallet_Info_WalletCreated: String { return self._s[56]! }
|
||||
public var Wallet_Navigation_Cancel: String { return self._s[57]! }
|
||||
public var Wallet_CreateInvoice_Title: String { return self._s[58]! }
|
||||
public var Wallet_Send_EncryptComment: String { return self._s[49]! }
|
||||
public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[50]! }
|
||||
public var Wallet_Completed_Text: String { return self._s[51]! }
|
||||
public var Wallet_WordCheck_IncorrectHeader: String { return self._s[53]! }
|
||||
public var Wallet_Configuration_SourceHeader: String { return self._s[54]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[55]! }
|
||||
public var Wallet_Receive_Title: String { return self._s[56]! }
|
||||
public var Wallet_Info_WalletCreated: String { return self._s[57]! }
|
||||
public var Wallet_Navigation_Cancel: String { return self._s[58]! }
|
||||
public var Wallet_CreateInvoice_Title: String { return self._s[59]! }
|
||||
public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[59]!, self._r[59]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[60]!, self._r[60]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_TransactionInfo_SenderHeader: String { return self._s[60]! }
|
||||
public var Wallet_TransactionInfo_SenderHeader: String { return self._s[61]! }
|
||||
public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[61]!, self._r[61]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[62]!, self._r[62]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_GenAugust: String { return self._s[62]! }
|
||||
public var Wallet_Info_UnknownTransaction: String { return self._s[63]! }
|
||||
public var Wallet_Receive_CreateInvoice: String { return self._s[64]! }
|
||||
public var Wallet_Month_GenSeptember: String { return self._s[65]! }
|
||||
public var Wallet_Month_GenJuly: String { return self._s[66]! }
|
||||
public var Wallet_Receive_AddressHeader: String { return self._s[67]! }
|
||||
public var Wallet_Send_AmountText: String { return self._s[68]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[69]! }
|
||||
public var Wallet_Month_GenAugust: String { return self._s[63]! }
|
||||
public var Wallet_Info_UnknownTransaction: String { return self._s[64]! }
|
||||
public var Wallet_Receive_CreateInvoice: String { return self._s[65]! }
|
||||
public var Wallet_Month_GenSeptember: String { return self._s[66]! }
|
||||
public var Wallet_Month_GenJuly: String { return self._s[67]! }
|
||||
public var Wallet_Receive_AddressHeader: String { return self._s[68]! }
|
||||
public var Wallet_Send_AmountText: String { return self._s[69]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[70]! }
|
||||
public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[70]!, self._r[70]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[71]!, self._r[71]!, [_1, _2, _3])
|
||||
}
|
||||
public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[71]!, self._r[71]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[72]!, self._r[72]!, [_0])
|
||||
}
|
||||
public var Wallet_Configuration_Title: String { return self._s[73]! }
|
||||
public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[74]! }
|
||||
public var Wallet_Words_Title: String { return self._s[75]! }
|
||||
public var Wallet_Month_ShortMay: String { return self._s[76]! }
|
||||
public var Wallet_WordCheck_Title: String { return self._s[77]! }
|
||||
public var Wallet_Words_NotDoneResponse: String { return self._s[78]! }
|
||||
public var Wallet_Configuration_SourceURL: String { return self._s[79]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[80]! }
|
||||
public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[81]! }
|
||||
public var Wallet_Configuration_Title: String { return self._s[74]! }
|
||||
public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[75]! }
|
||||
public var Wallet_Words_Title: String { return self._s[76]! }
|
||||
public var Wallet_Month_ShortMay: String { return self._s[77]! }
|
||||
public var Wallet_WordCheck_Title: String { return self._s[78]! }
|
||||
public var Wallet_Words_NotDoneResponse: String { return self._s[79]! }
|
||||
public var Wallet_Configuration_SourceURL: String { return self._s[80]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[81]! }
|
||||
public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[82]! }
|
||||
public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[82]!, self._r[82]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[83]!, self._r[83]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Info_Address: String { return self._s[83]! }
|
||||
public var Wallet_Intro_CreateWallet: String { return self._s[84]! }
|
||||
public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[85]! }
|
||||
public var Wallet_Info_Address: String { return self._s[84]! }
|
||||
public var Wallet_Intro_CreateWallet: String { return self._s[85]! }
|
||||
public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[86]! }
|
||||
public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[86]!, self._r[86]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[87]!, self._r[87]!, [_0])
|
||||
}
|
||||
public var Wallet_Send_SendAnyway: String { return self._s[87]! }
|
||||
public var Wallet_UnknownError: String { return self._s[88]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[89]! }
|
||||
public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[90]! }
|
||||
public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[92]! }
|
||||
public var Wallet_Configuration_SourceInfo: String { return self._s[93]! }
|
||||
public var Wallet_Words_NotDoneOk: String { return self._s[94]! }
|
||||
public var Wallet_Intro_Title: String { return self._s[95]! }
|
||||
public var Wallet_Info_Receive: String { return self._s[96]! }
|
||||
public var Wallet_Completed_ViewWallet: String { return self._s[97]! }
|
||||
public var Wallet_Month_ShortJuly: String { return self._s[98]! }
|
||||
public var Wallet_Month_ShortApril: String { return self._s[99]! }
|
||||
public var Wallet_Send_SendAnyway: String { return self._s[88]! }
|
||||
public var Wallet_UnknownError: String { return self._s[89]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[90]! }
|
||||
public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[91]! }
|
||||
public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[93]! }
|
||||
public var Wallet_Configuration_SourceInfo: String { return self._s[94]! }
|
||||
public var Wallet_Words_NotDoneOk: String { return self._s[95]! }
|
||||
public var Wallet_Intro_Title: String { return self._s[96]! }
|
||||
public var Wallet_Info_Receive: String { return self._s[97]! }
|
||||
public var Wallet_Completed_ViewWallet: String { return self._s[98]! }
|
||||
public var Wallet_Month_ShortJuly: String { return self._s[99]! }
|
||||
public var Wallet_Month_ShortApril: String { return self._s[100]! }
|
||||
public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[100]!, self._r[100]!, [_1, _2])
|
||||
return formatWithArgumentRanges(self._s[101]!, self._r[101]!, [_1, _2])
|
||||
}
|
||||
public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[101]! }
|
||||
public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[102]! }
|
||||
public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[102]!, self._r[102]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[103]!, self._r[103]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Send_UninitializedText: String { return self._s[104]! }
|
||||
public var Wallet_Send_UninitializedText: String { return self._s[105]! }
|
||||
public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[105]!, self._r[105]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[106]!, self._r[106]!, [_0])
|
||||
}
|
||||
public var Wallet_Month_GenNovember: String { return self._s[106]! }
|
||||
public var Wallet_Month_GenNovember: String { return self._s[107]! }
|
||||
public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[107]!, self._r[107]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[108]!, self._r[108]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_GenApril: String { return self._s[108]! }
|
||||
public var Wallet_Month_ShortMarch: String { return self._s[109]! }
|
||||
public var Wallet_Month_GenFebruary: String { return self._s[110]! }
|
||||
public var Wallet_Qr_ScanCode: String { return self._s[111]! }
|
||||
public var Wallet_Receive_AddressCopied: String { return self._s[112]! }
|
||||
public var Wallet_Send_UninitializedTitle: String { return self._s[113]! }
|
||||
public var Wallet_AccessDenied_Title: String { return self._s[114]! }
|
||||
public var Wallet_AccessDenied_Settings: String { return self._s[115]! }
|
||||
public var Wallet_Send_Send: String { return self._s[116]! }
|
||||
public var Wallet_Info_RefreshErrorTitle: String { return self._s[117]! }
|
||||
public var Wallet_Month_GenJune: String { return self._s[118]! }
|
||||
public var Wallet_Send_AddressHeader: String { return self._s[119]! }
|
||||
public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[120]! }
|
||||
public var Wallet_Send_Confirmation: String { return self._s[121]! }
|
||||
public var Wallet_Completed_Title: String { return self._s[122]! }
|
||||
public var Wallet_Alert_OK: String { return self._s[123]! }
|
||||
public var Wallet_Settings_DeleteWallet: String { return self._s[124]! }
|
||||
public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[125]! }
|
||||
public var Wallet_Month_ShortSeptember: String { return self._s[126]! }
|
||||
public var Wallet_Info_TransactionTo: String { return self._s[127]! }
|
||||
public var Wallet_Send_ConfirmationConfirm: String { return self._s[128]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[129]! }
|
||||
public var Wallet_Receive_AmountText: String { return self._s[130]! }
|
||||
public var Wallet_Receive_CopyAddress: String { return self._s[131]! }
|
||||
public var Wallet_Intro_Text: String { return self._s[133]! }
|
||||
public var Wallet_Configuration_Apply: String { return self._s[134]! }
|
||||
public var Wallet_Month_GenApril: String { return self._s[109]! }
|
||||
public var Wallet_Month_ShortMarch: String { return self._s[110]! }
|
||||
public var Wallet_Month_GenFebruary: String { return self._s[111]! }
|
||||
public var Wallet_Qr_ScanCode: String { return self._s[112]! }
|
||||
public var Wallet_Receive_AddressCopied: String { return self._s[113]! }
|
||||
public var Wallet_Send_UninitializedTitle: String { return self._s[114]! }
|
||||
public var Wallet_AccessDenied_Title: String { return self._s[115]! }
|
||||
public var Wallet_AccessDenied_Settings: String { return self._s[116]! }
|
||||
public var Wallet_Send_Send: String { return self._s[117]! }
|
||||
public var Wallet_Info_RefreshErrorTitle: String { return self._s[118]! }
|
||||
public var Wallet_Month_GenJune: String { return self._s[119]! }
|
||||
public var Wallet_Send_AddressHeader: String { return self._s[120]! }
|
||||
public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[121]! }
|
||||
public var Wallet_Send_Confirmation: String { return self._s[122]! }
|
||||
public var Wallet_Completed_Title: String { return self._s[123]! }
|
||||
public var Wallet_Alert_OK: String { return self._s[124]! }
|
||||
public var Wallet_Settings_DeleteWallet: String { return self._s[125]! }
|
||||
public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[126]! }
|
||||
public var Wallet_Month_ShortSeptember: String { return self._s[127]! }
|
||||
public var Wallet_Info_TransactionTo: String { return self._s[128]! }
|
||||
public var Wallet_Send_ConfirmationConfirm: String { return self._s[129]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[130]! }
|
||||
public var Wallet_Receive_AmountText: String { return self._s[131]! }
|
||||
public var Wallet_Receive_CopyAddress: String { return self._s[132]! }
|
||||
public var Wallet_Intro_Text: String { return self._s[134]! }
|
||||
public var Wallet_Configuration_Apply: String { return self._s[135]! }
|
||||
public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[135]!, self._r[135]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[136]!, self._r[136]!, [_0])
|
||||
}
|
||||
public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[136]!, self._r[136]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[137]!, self._r[137]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_RestoreFailed_CreateWallet: String { return self._s[137]! }
|
||||
public var Wallet_Weekday_Yesterday: String { return self._s[138]! }
|
||||
public var Wallet_Receive_AmountHeader: String { return self._s[139]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[140]! }
|
||||
public var Wallet_Month_ShortFebruary: String { return self._s[141]! }
|
||||
public var Wallet_Configuration_SourceJSON: String { return self._s[142]! }
|
||||
public var Wallet_Alert_Cancel: String { return self._s[143]! }
|
||||
public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[144]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[145]! }
|
||||
public var Wallet_Info_TransactionFrom: String { return self._s[146]! }
|
||||
public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[147]! }
|
||||
public var Wallet_Send_OwnAddressAlertText: String { return self._s[148]! }
|
||||
public var Wallet_Words_NotDoneTitle: String { return self._s[149]! }
|
||||
public var Wallet_Month_ShortOctober: String { return self._s[150]! }
|
||||
public var Wallet_Month_GenMay: String { return self._s[151]! }
|
||||
public var Wallet_Intro_CreateErrorTitle: String { return self._s[152]! }
|
||||
public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[153]! }
|
||||
public var Wallet_Month_ShortJanuary: String { return self._s[154]! }
|
||||
public var Wallet_Month_GenMarch: String { return self._s[155]! }
|
||||
public var Wallet_AccessDenied_Camera: String { return self._s[156]! }
|
||||
public var Wallet_Sending_Text: String { return self._s[157]! }
|
||||
public var Wallet_Month_GenOctober: String { return self._s[158]! }
|
||||
public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[159]! }
|
||||
public var Wallet_ContextMenuCopy: String { return self._s[160]! }
|
||||
public var Wallet_RestoreFailed_CreateWallet: String { return self._s[138]! }
|
||||
public var Wallet_Weekday_Yesterday: String { return self._s[139]! }
|
||||
public var Wallet_Receive_AmountHeader: String { return self._s[140]! }
|
||||
public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[141]! }
|
||||
public var Wallet_Month_ShortFebruary: String { return self._s[142]! }
|
||||
public var Wallet_Configuration_SourceJSON: String { return self._s[143]! }
|
||||
public var Wallet_Alert_Cancel: String { return self._s[144]! }
|
||||
public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[145]! }
|
||||
public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[146]! }
|
||||
public var Wallet_Info_TransactionFrom: String { return self._s[147]! }
|
||||
public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[148]! }
|
||||
public var Wallet_Send_OwnAddressAlertText: String { return self._s[149]! }
|
||||
public var Wallet_Words_NotDoneTitle: String { return self._s[150]! }
|
||||
public var Wallet_Month_ShortOctober: String { return self._s[151]! }
|
||||
public var Wallet_Month_GenMay: String { return self._s[152]! }
|
||||
public var Wallet_Intro_CreateErrorTitle: String { return self._s[153]! }
|
||||
public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[154]! }
|
||||
public var Wallet_Month_ShortJanuary: String { return self._s[155]! }
|
||||
public var Wallet_Month_GenMarch: String { return self._s[156]! }
|
||||
public var Wallet_AccessDenied_Camera: String { return self._s[157]! }
|
||||
public var Wallet_Sending_Text: String { return self._s[158]! }
|
||||
public var Wallet_Month_GenOctober: String { return self._s[159]! }
|
||||
public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[160]! }
|
||||
public var Wallet_ContextMenuCopy: String { return self._s[161]! }
|
||||
public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[161]!, self._r[161]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[162]!, self._r[162]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Info_Updating: String { return self._s[163]! }
|
||||
public var Wallet_Created_ExportErrorTitle: String { return self._s[164]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[165]! }
|
||||
public var Wallet_Sending_Title: String { return self._s[166]! }
|
||||
public var Wallet_Navigation_Done: String { return self._s[167]! }
|
||||
public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[168]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[169]! }
|
||||
public var Wallet_Settings_Title: String { return self._s[170]! }
|
||||
public var Wallet_Info_Updating: String { return self._s[164]! }
|
||||
public var Wallet_Created_ExportErrorTitle: String { return self._s[165]! }
|
||||
public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[166]! }
|
||||
public var Wallet_Sending_Title: String { return self._s[167]! }
|
||||
public var Wallet_Navigation_Done: String { return self._s[168]! }
|
||||
public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[169]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[170]! }
|
||||
public var Wallet_Settings_Title: String { return self._s[171]! }
|
||||
public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[171]!, self._r[171]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[172]!, self._r[172]!, [_0])
|
||||
}
|
||||
public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[172]! }
|
||||
public var Wallet_Weekday_Today: String { return self._s[174]! }
|
||||
public var Wallet_Month_ShortDecember: String { return self._s[175]! }
|
||||
public var Wallet_Words_Text: String { return self._s[176]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[177]! }
|
||||
public var Wallet_WordCheck_ViewWords: String { return self._s[178]! }
|
||||
public var Wallet_Send_AddressInfo: String { return self._s[179]! }
|
||||
public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[173]! }
|
||||
public var Wallet_Weekday_Today: String { return self._s[175]! }
|
||||
public var Wallet_Month_ShortDecember: String { return self._s[176]! }
|
||||
public var Wallet_Words_Text: String { return self._s[177]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[178]! }
|
||||
public var Wallet_WordCheck_ViewWords: String { return self._s[179]! }
|
||||
public var Wallet_Send_AddressInfo: String { return self._s[180]! }
|
||||
public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[180]!, self._r[180]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[181]!, self._r[181]!, [_0])
|
||||
}
|
||||
public var Wallet_Intro_NotNow: String { return self._s[181]! }
|
||||
public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[182]! }
|
||||
public var Wallet_Navigation_Close: String { return self._s[183]! }
|
||||
public var Wallet_Month_GenDecember: String { return self._s[185]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[186]! }
|
||||
public var Wallet_WordImport_IncorrectTitle: String { return self._s[187]! }
|
||||
public var Wallet_Send_AddressText: String { return self._s[188]! }
|
||||
public var Wallet_Receive_AmountInfo: String { return self._s[189]! }
|
||||
public var Wallet_Intro_NotNow: String { return self._s[182]! }
|
||||
public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[183]! }
|
||||
public var Wallet_Navigation_Close: String { return self._s[184]! }
|
||||
public var Wallet_Month_GenDecember: String { return self._s[186]! }
|
||||
public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[187]! }
|
||||
public var Wallet_WordImport_IncorrectTitle: String { return self._s[188]! }
|
||||
public var Wallet_Send_AddressText: String { return self._s[189]! }
|
||||
public var Wallet_Receive_AmountInfo: String { return self._s[190]! }
|
||||
public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[190]!, self._r[190]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[191]!, self._r[191]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Month_ShortAugust: String { return self._s[191]! }
|
||||
public var Wallet_Qr_Title: String { return self._s[192]! }
|
||||
public var Wallet_Settings_Configuration: String { return self._s[193]! }
|
||||
public var Wallet_WordCheck_TryAgain: String { return self._s[194]! }
|
||||
public var Wallet_Info_TransactionPendingHeader: String { return self._s[195]! }
|
||||
public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[196]! }
|
||||
public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[197]! }
|
||||
public var Wallet_Send_TransactionInProgress: String { return self._s[198]! }
|
||||
public var Wallet_Created_Text: String { return self._s[199]! }
|
||||
public var Wallet_Created_Proceed: String { return self._s[200]! }
|
||||
public var Wallet_Words_Done: String { return self._s[201]! }
|
||||
public var Wallet_WordImport_Continue: String { return self._s[202]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[203]! }
|
||||
public var Wallet_WordImport_CanNotRemember: String { return self._s[204]! }
|
||||
public var Wallet_Month_ShortAugust: String { return self._s[192]! }
|
||||
public var Wallet_Qr_Title: String { return self._s[193]! }
|
||||
public var Wallet_Settings_Configuration: String { return self._s[194]! }
|
||||
public var Wallet_WordCheck_TryAgain: String { return self._s[195]! }
|
||||
public var Wallet_Info_TransactionPendingHeader: String { return self._s[196]! }
|
||||
public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[197]! }
|
||||
public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[198]! }
|
||||
public var Wallet_Send_TransactionInProgress: String { return self._s[199]! }
|
||||
public var Wallet_Created_Text: String { return self._s[200]! }
|
||||
public var Wallet_Created_Proceed: String { return self._s[201]! }
|
||||
public var Wallet_Words_Done: String { return self._s[202]! }
|
||||
public var Wallet_WordImport_Continue: String { return self._s[203]! }
|
||||
public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[204]! }
|
||||
public var Wallet_WordImport_CanNotRemember: String { return self._s[205]! }
|
||||
public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[205]!, self._r[205]!, [_1, _2, _3])
|
||||
}
|
||||
public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[206]!, self._r[206]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Created_ExportErrorText: String { return self._s[208]! }
|
||||
public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[207]!, self._r[207]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Created_ExportErrorText: String { return self._s[209]! }
|
||||
public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[209]!, self._r[209]!, [_0])
|
||||
return formatWithArgumentRanges(self._s[210]!, self._r[210]!, [_0])
|
||||
}
|
||||
public var Wallet_Settings_DeleteWalletInfo: String { return self._s[210]! }
|
||||
public var Wallet_Intro_CreateErrorText: String { return self._s[211]! }
|
||||
public var Wallet_Sent_ViewWallet: String { return self._s[212]! }
|
||||
public var Wallet_Send_ErrorInvalidAddress: String { return self._s[213]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[214]! }
|
||||
public var Wallet_Settings_DeleteWalletInfo: String { return self._s[211]! }
|
||||
public var Wallet_Intro_CreateErrorText: String { return self._s[212]! }
|
||||
public var Wallet_Sent_ViewWallet: String { return self._s[213]! }
|
||||
public var Wallet_Send_ErrorInvalidAddress: String { return self._s[214]! }
|
||||
public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[215]! }
|
||||
public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) {
|
||||
return formatWithArgumentRanges(self._s[215]!, self._r[215]!, [_1, _2, _3])
|
||||
return formatWithArgumentRanges(self._s[216]!, self._r[216]!, [_1, _2, _3])
|
||||
}
|
||||
public var Wallet_Send_Title: String { return self._s[216]! }
|
||||
public var Wallet_Info_RefreshErrorText: String { return self._s[217]! }
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[218]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[219]! }
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[220]! }
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
public var Wallet_Send_Title: String { return self._s[217]! }
|
||||
public var Wallet_Info_RefreshErrorText: String { return self._s[218]! }
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[219]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[220]! }
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[221]! }
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
}
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
|
@ -2137,7 +2137,7 @@ public final class WalletWordCheckScreen: ViewController {
|
||||
return true
|
||||
}
|
||||
let _ = confirmWalletExported(storage: strongSelf.context.storage, publicKey: walletInfo.publicKey).start()
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .success(walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .success(walletInfo: walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
@ -2205,7 +2205,7 @@ public final class WalletWordCheckScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .success(walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
controllers.append(WalletSplashScreen(context: strongSelf.context, mode: .success(walletInfo: walletInfo), walletCreatedPreloadState: strongSelf.walletCreatedPreloadState))
|
||||
strongSelf.view.endEditing(true)
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
swift -swift-version 4 tools/GenerateLocalization.swift Telegram-iOS/en.lproj/Localizable.strings submodules/TelegramPresentationData/Sources/PresentationStrings.swift submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping
|
||||
swift -swift-version 4 tools/GenerateLocalization.swift Telegram/Telegram-iOS/en.lproj/Localizable.strings submodules/TelegramPresentationData/Sources/PresentationStrings.swift submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping
|
||||
|
||||
mkdir -p submodules/WalletUI/Resources
|
||||
swift -swift-version 4 tools/GenerateLocalization.swift Telegram-iOS/en.lproj/Localizable.strings submodules/WalletUI/Sources/WalletStrings.swift submodules/WalletUI/Resources/WalletStrings.mapping "Wallet."
|
||||
swift -swift-version 4 tools/GenerateLocalization.swift Telegram/Telegram-iOS/en.lproj/Localizable.strings submodules/WalletUI/Sources/WalletStrings.swift submodules/WalletUI/Resources/WalletStrings.mapping "Wallet."
|
||||
|
||||
wallet_strings_path="Wallet/Strings"
|
||||
strings_name="Localizable.strings"
|
||||
rm -rf "$wallet_strings_path"
|
||||
|
||||
for f in $(basename $(find "Telegram-iOS" -name "*.lproj")); do
|
||||
for f in $(basename $(find "Telegram/Telegram-iOS" -name "*.lproj")); do
|
||||
mkdir -p "$wallet_strings_path/$f"
|
||||
if [ -f "Telegram-iOS/$f/$strings_name" ]; then
|
||||
cat "Telegram-iOS/$f/$strings_name" | grep -E '^"Wallet\..*?$' > "$wallet_strings_path/$f/$strings_name"
|
||||
if [ -f "Telegram/Telegram-iOS/$f/$strings_name" ]; then
|
||||
cat "Telegram/Telegram-iOS/$f/$strings_name" | grep -E '^"Wallet\..*?$' > "$wallet_strings_path/$f/$strings_name"
|
||||
fi
|
||||
done
|
||||
|
Loading…
x
Reference in New Issue
Block a user