void ReleaseDesignerOutlets()
        {
            if (AmountText != null)
            {
                AmountText.Dispose();
                AmountText = null;
            }

            if (DeleteButton != null)
            {
                DeleteButton.Dispose();
                DeleteButton = null;
            }

            if (SaveButton != null)
            {
                SaveButton.Dispose();
                SaveButton = null;
            }

            if (SpeciesText != null)
            {
                SpeciesText.Dispose();
                SpeciesText = null;
            }
        }
Exemple #2
0
        //Enter the new liability information
        internal void AddLiabilityDetails()
        {
            ExcelLib.PopulateInCollection(Base.ExcelPath, "Add Tenant");
            SelectElement select        = new SelectElement(LiabilityNameDropdown);
            String        liabilityName = ExcelLib.ReadData(2, "Liability Name");

            switch (liabilityName)
            {
            case "Bond":
                select.SelectByValue("1");
                break;

            case "Insurance":
                select.SelectByValue("2");
                break;

            case "Letting Fee":
                select.SelectByValue("3");
                break;

            case "Body Corp":
                select.SelectByValue("4");
                break;
            }

            AmountText.SendKeys(ExcelLib.ReadData(2, "Amount"));
        }
        void ReleaseDesignerOutlets()
        {
            if (AddToCartButton != null)
            {
                AddToCartButton.Dispose();
                AddToCartButton = null;
            }

            if (AmountText != null)
            {
                AmountText.Dispose();
                AmountText = null;
            }

            if (bView != null)
            {
                bView.Dispose();
                bView = null;
            }

            if (CancelButton != null)
            {
                CancelButton.Dispose();
                CancelButton = null;
            }

            if (imgView != null)
            {
                imgView.Dispose();
                imgView = null;
            }

            if (LongDescriptionText != null)
            {
                LongDescriptionText.Dispose();
                LongDescriptionText = null;
            }

            if (NameLabel != null)
            {
                NameLabel.Dispose();
                NameLabel = null;
            }

            if (PriceLabel != null)
            {
                PriceLabel.Dispose();
                PriceLabel = null;
            }

            if (ShortDescriptionLabel != null)
            {
                ShortDescriptionLabel.Dispose();
                ShortDescriptionLabel = null;
            }
        }
        void ReleaseDesignerOutlets()
        {
            if (AddToCartButton != null)
            {
                AddToCartButton.Dispose();
                AddToCartButton = null;
            }

            if (AmountText != null)
            {
                AmountText.Dispose();
                AmountText = null;
            }

            if (CancelButton != null)
            {
                CancelButton.Dispose();
                CancelButton = null;
            }

            if (DescriptionText != null)
            {
                DescriptionText.Dispose();
                DescriptionText = null;
            }

            if (HotDogImageView != null)
            {
                HotDogImageView.Dispose();
                HotDogImageView = null;
            }

            if (NameLabel != null)
            {
                NameLabel.Dispose();
                NameLabel = null;
            }

            if (PriceLabel != null)
            {
                PriceLabel.Dispose();
                PriceLabel = null;
            }

            if (ShortDescriptionLabel != null)
            {
                ShortDescriptionLabel.Dispose();
                ShortDescriptionLabel = null;
            }
        }
        void ReleaseDesignerOutlets()
        {
            if (AmountText != null)
            {
                AmountText.Dispose();
                AmountText = null;
            }

            if (GenerositySlider != null)
            {
                GenerositySlider.Dispose();
                GenerositySlider = null;
            }

            if (TipLabel != null)
            {
                TipLabel.Dispose();
                TipLabel = null;
            }
        }
        void ReleaseDesignerOutlets()
        {
            if (AmountLabel != null)
            {
                AmountLabel.Dispose();
                AmountLabel = null;
            }

            if (AmountText != null)
            {
                AmountText.Dispose();
                AmountText = null;
            }

            if (ExcellentLabel != null)
            {
                ExcellentLabel.Dispose();
                ExcellentLabel = null;
            }

            if (PercentageLabel != null)
            {
                PercentageLabel.Dispose();
                PercentageLabel = null;
            }

            if (PoorLabel != null)
            {
                PoorLabel.Dispose();
                PoorLabel = null;
            }

            if (RestaurantImageView != null)
            {
                RestaurantImageView.Dispose();
                RestaurantImageView = null;
            }

            if (ServiceLabel != null)
            {
                ServiceLabel.Dispose();
                ServiceLabel = null;
            }

            if (ServiceSlider != null)
            {
                ServiceSlider.Dispose();
                ServiceSlider = null;
            }

            if (TaxAmountText != null)
            {
                TaxAmountText.Dispose();
                TaxAmountText = null;
            }

            if (TaxLabel != null)
            {
                TaxLabel.Dispose();
                TaxLabel = null;
            }

            if (TaxPercentageText != null)
            {
                TaxPercentageText.Dispose();
                TaxPercentageText = null;
            }

            if (TaxSwitch != null)
            {
                TaxSwitch.Dispose();
                TaxSwitch = null;
            }

            if (TipAmountText != null)
            {
                TipAmountText.Dispose();
                TipAmountText = null;
            }

            if (TipCalcLabel != null)
            {
                TipCalcLabel.Dispose();
                TipCalcLabel = null;
            }

            if (TipLabel != null)
            {
                TipLabel.Dispose();
                TipLabel = null;
            }

            if (TipPercentageText != null)
            {
                TipPercentageText.Dispose();
                TipPercentageText = null;
            }

            if (TotalLabel != null)
            {
                TotalLabel.Dispose();
                TotalLabel = null;
            }

            if (TotalText != null)
            {
                TotalText.Dispose();
                TotalText = null;
            }
        }
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.

            CheckChanges();
            ServiceSlider.ValueChanged += (object sender, EventArgs e) =>
            {
                CheckChanges();
            };

            AmountText.EditingDidEnd += (object sender, EventArgs e) =>
            {
                AmountText.ResignFirstResponder();
                CheckChanges();
            };

            TaxPercentageText.EditingDidEnd += (object sender, EventArgs e) =>
            {
                TaxPercentageText.ResignFirstResponder();
                CheckChanges();
            };
            TaxSwitch.ValueChanged += (object sender, EventArgs e) =>
            {
                UIActionSheet actionSheet;

                string taxMessage = "off";

                //When user tries to turn on
                if (TaxSwitch.On)
                {
                    taxMessage = "on";
                }
                else
                {
                    taxMessage = "off";
                }
                //Display Action Sheet
                actionSheet = new UIActionSheet("Would you like to turn " + taxMessage + "?");

                actionSheet.AddButton("Yes");
                actionSheet.AddButton("No");

                //When user finishes to select an answer
                actionSheet.Clicked += delegate(object a, UIButtonEventArgs b)
                {
                    if (b.ButtonIndex == 1)
                    {
                        TaxSwitch.On = !TaxSwitch.On;
                    }
                    if (!TaxSwitch.On)
                    {
                        TaxPercentageText.Enabled = false;
                    }
                    else
                    {
                        TaxPercentageText.Enabled = true;
                    }
                    CheckChanges();
                };
                actionSheet.ShowInView(View);
            };
        }
        protected SendControlViewModel(Wallet wallet, string title)
            : base(title)
        {
            Global = Locator.Current.GetService <Global>();
            Wallet = wallet;

            LabelSuggestion            = new SuggestLabelViewModel();
            BuildTransactionButtonText = DoButtonText;

            this.ValidateProperty(x => x.Address, ValidateAddress);
            this.ValidateProperty(x => x.CustomChangeAddress, ValidateCustomChangeAddress);
            this.ValidateProperty(x => x.Password, ValidatePassword);
            this.ValidateProperty(x => x.UserFeeText, ValidateUserFeeText);

            ResetUi();

            CoinList = new CoinListViewModel(Wallet, displayCommonOwnershipWarning: true);

            Observable.FromEventPattern(CoinList, nameof(CoinList.SelectionChanged))
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ => SetFeesAndTexts());

            _minMaxFeeTargetsEqual = this.WhenAnyValue(x => x.MinimumFeeTarget, x => x.MaximumFeeTarget, (x, y) => x == y)
                                     .ToProperty(this, x => x.MinMaxFeeTargetsEqual, scheduler: RxApp.MainThreadScheduler);

            SetFeeTargetLimits();
            FeeTarget        = Global.UiConfig.FeeTarget;
            FeeDisplayFormat = (FeeDisplayFormat)(Enum.ToObject(typeof(FeeDisplayFormat), Global.UiConfig.FeeDisplayFormat) ?? FeeDisplayFormat.SatoshiPerByte);
            SetFeesAndTexts();

            this.WhenAnyValue(x => x.AmountText).Select(_ => Unit.Default)
            .Merge(Wallet.Synchronizer.WhenAnyValue(x => x.UsdExchangeRate).Select(_ => Unit.Default))
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
                if (Money.TryParse(AmountText.TrimStart('~', ' '), out Money amountBtc))
                {
                    AmountTip = amountBtc.ToUsdString(Wallet.Synchronizer.UsdExchangeRate, lurkingWifeMode: false);
                }
                else
                {
                    AmountTip = "0 USD";
                }

                SetFees();
            });

            AmountKeyUpCommand = ReactiveCommand.Create((KeyEventArgs key) =>
            {
                var amount = AmountText;
                if (IsMax)
                {
                    SetFeesAndTexts();
                }
                else
                {
                    // Correct amount
                    Regex digitsOnly    = new Regex(@"[^\d,.]");
                    string betterAmount = digitsOnly.Replace(amount, "");                     // Make it digits , and . only.

                    betterAmount          = betterAmount.Replace(',', '.');
                    int countBetterAmount = betterAmount.Count(x => x == '.');
                    if (countBetterAmount > 1)                     // Do not enable typing two dots.
                    {
                        var index = betterAmount.IndexOf('.', betterAmount.IndexOf('.') + 1);
                        if (index > 0)
                        {
                            betterAmount = betterAmount.Substring(0, index);
                        }
                    }
                    var dotIndex = betterAmount.IndexOf('.');
                    if (dotIndex != -1 && betterAmount.Length - dotIndex > 8)                     // Enable max 8 decimals.
                    {
                        betterAmount = betterAmount.Substring(0, dotIndex + 1 + 8);
                    }

                    if (betterAmount != amount)
                    {
                        AmountText = betterAmount;
                    }
                }
            });

            this.WhenAnyValue(x => x.IsBusy, x => x.IsHardwareBusy)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ => BuildTransactionButtonText = IsHardwareBusy
                                                ? WaitingForHardwareWalletButtonTextString
                                                : IsBusy
                                                        ? DoingButtonText
                                                        : DoButtonText);

            this.WhenAnyValue(x => x.FeeTarget)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
                IsSliderFeeUsed = true;
                SetFeesAndTexts();
            });

            this.WhenAnyValue(x => x.IsSliderFeeUsed)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(enabled => FeeControlOpacity = enabled ? 1 : 0.5);                     // Give the control the disabled feeling. Real Disable it not a solution as we have to detect if the slider is moved.

            MaxCommand = ReactiveCommand.Create(() => IsMax = !IsMax, outputScheduler: RxApp.MainThreadScheduler);

            this.WhenAnyValue(x => x.IsMax)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
                if (IsMax)
                {
                    SetFeesAndTexts();

                    LabelToolTip = "Spending whole coins does not generate change, thus labeling is unnecessary.";
                }
                else
                {
                    AmountText = "0.0";

                    LabelToolTip = "Who can link this transaction to you? E.g.: \"Max, BitPay\"";
                }
            });

            // Triggering the detection of same address values.
            this.WhenAnyValue(x => x.Address)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ => this.RaisePropertyChanged(nameof(CustomChangeAddress)));

            this.WhenAnyValue(x => x.CustomChangeAddress)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ => this.RaisePropertyChanged(nameof(Address)));

            this.WhenAnyValue(x => x.IsCustomChangeAddressVisible)
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ =>
            {
                this.RaisePropertyChanged(nameof(Address));
                this.RaisePropertyChanged(nameof(CustomChangeAddress));
            });

            FeeRateCommand = ReactiveCommand.Create(ChangeFeeRateDisplay, outputScheduler: RxApp.MainThreadScheduler);

            OnAddressPasteCommand = ReactiveCommand.Create((BitcoinUrlBuilder url) => OnAddressPaste(url));

            BuildTransactionCommand = ReactiveCommand.CreateFromTask(async() =>
            {
                try
                {
                    IsBusy = true;
                    MainWindowViewModel.Instance.StatusBar.TryAddStatus(StatusType.BuildingTransaction);

                    var label             = new SmartLabel(LabelSuggestion.Label);
                    LabelSuggestion.Label = label;
                    if (!IsMax && label.IsEmpty)
                    {
                        NotificationHelpers.Warning("Known By is required.", "");
                        return;
                    }

                    var selectedCoinViewModels = CoinList.Coins.Where(cvm => cvm.IsSelected);
                    var selectedCoinReferences = selectedCoinViewModels.Select(cvm => cvm.Model.OutPoint).ToList();

                    if (!selectedCoinReferences.Any())
                    {
                        NotificationHelpers.Warning("No coins are selected to spend.", "");
                        return;
                    }

                    BitcoinAddress address;
                    try
                    {
                        address = BitcoinAddress.Create(Address, Global.Network);
                    }
                    catch (FormatException)
                    {
                        NotificationHelpers.Warning("Invalid address.", "");
                        return;
                    }

                    var requests = new List <DestinationRequest>();

                    if (IsCustomChangeAddressVisible && !string.IsNullOrWhiteSpace(CustomChangeAddress))
                    {
                        try
                        {
                            var customChangeAddress = BitcoinAddress.Create(CustomChangeAddress, Global.Network);

                            if (customChangeAddress == address)
                            {
                                NotificationHelpers.Warning("The active address and the change address cannot be the same.", "");
                                return;
                            }

                            requests.Add(new DestinationRequest(customChangeAddress, MoneyRequest.CreateChange(subtractFee: true), label));
                        }
                        catch (FormatException)
                        {
                            NotificationHelpers.Warning("Invalid custom change address.", "");
                            return;
                        }
                    }

                    MoneyRequest moneyRequest;
                    if (IsMax)
                    {
                        moneyRequest = MoneyRequest.CreateAllRemaining(subtractFee: true);
                    }
                    else
                    {
                        if (!Money.TryParse(AmountText, out Money amount) || amount == Money.Zero)
                        {
                            NotificationHelpers.Warning("Invalid amount.");
                            return;
                        }

                        if (amount == selectedCoinViewModels.Sum(x => x.Amount))
                        {
                            NotificationHelpers.Warning("Looks like you want to spend whole coins. Try Max button instead.", "");
                            return;
                        }
                        moneyRequest = MoneyRequest.Create(amount, subtractFee: false);
                    }

                    if (FeeRate is null || FeeRate.SatoshiPerByte < 1)
                    {
                        NotificationHelpers.Warning("Invalid fee rate.", "");
                        return;
                    }

                    var feeStrategy = FeeStrategy.CreateFromFeeRate(FeeRate);

                    var activeDestinationRequest = new DestinationRequest(address, moneyRequest, label);
                    requests.Add(activeDestinationRequest);

                    var intent = new PaymentIntent(requests);
                    try
                    {
                        MainWindowViewModel.Instance.StatusBar.TryAddStatus(StatusType.DequeuingSelectedCoins);
                        OutPoint[] toDequeue = selectedCoinViewModels.Where(x => x.CoinJoinInProgress).Select(x => x.Model.OutPoint).ToArray();
                        if (toDequeue != null && toDequeue.Any())
                        {
                            await Wallet.ChaumianClient.DequeueCoinsFromMixAsync(toDequeue, DequeueReason.TransactionBuilding);
                        }
                    }
                    catch
                    {
                        NotificationHelpers.Error("Cannot spend mixing coins.", "");
                        return;
                    }
                    finally
                    {
                        MainWindowViewModel.Instance.StatusBar.TryRemoveStatus(StatusType.DequeuingSelectedCoins);
                    }

                    if (!Wallet.KeyManager.IsWatchOnly)
                    {
                        try
                        {
                            PasswordHelper.GetMasterExtKey(Wallet.KeyManager, Password, out string compatiblityPasswordUsed);                             // We could use TryPassword but we need the exception.
                            if (compatiblityPasswordUsed != null)
                            {
                                Password = compatiblityPasswordUsed;                                 // Overwrite the password for BuildTransaction function.
                                NotificationHelpers.Warning(PasswordHelper.CompatibilityPasswordWarnMessage);
                            }
                        }
                        catch (SecurityException ex)
                        {
                            NotificationHelpers.Error(ex.Message, "");
                            return;
                        }
                        catch (Exception ex)
                        {
                            Logger.LogError(ex);
                            NotificationHelpers.Error(ex.ToUserFriendlyString());
                            return;
                        }
                    }

                    await BuildTransaction(Password, intent, feeStrategy, allowUnconfirmed: true, allowedInputs: selectedCoinReferences);
                }
                catch (InsufficientBalanceException ex)
                {
                    Money needed = ex.Minimum - ex.Actual;
                    NotificationHelpers.Error($"Not enough coins selected. You need an estimated {needed.ToString(false, true)} BTC more to make this transaction.", "");
                }
                catch (HttpRequestException ex)
                {
                    NotificationHelpers.Error(ex.ToUserFriendlyString());
                    Logger.LogError(ex);
                }
                catch (Exception ex)
                {
                    NotificationHelpers.Error(ex.ToUserFriendlyString(), sender: Wallet);
                    Logger.LogError(ex);
                }
                finally
                {
                    MainWindowViewModel.Instance.StatusBar.TryRemoveStatus(StatusType.BuildingTransaction, StatusType.SigningTransaction, StatusType.BroadcastingTransaction);
                    IsBusy = false;
                }
            },
                                                                     this.WhenAny(x => x.IsMax, x => x.AmountText, x => x.Address, x => x.IsBusy,
                                                                                  (isMax, amount, address, busy) => (isMax.Value || !string.IsNullOrWhiteSpace(amount.Value)) && !string.IsNullOrWhiteSpace(Address) && !IsBusy)
                                                                     .ObserveOn(RxApp.MainThreadScheduler));

            UserFeeTextKeyUpCommand = ReactiveCommand.Create((KeyEventArgs key) =>
            {
                IsSliderFeeUsed = !IsCustomFee;
                SetFeesAndTexts();
            });

            FeeSliderClickedCommand = ReactiveCommand.Create((PointerPressedEventArgs mouse) => IsSliderFeeUsed = true);

            HighLightFeeSliderCommand = ReactiveCommand.Create((bool entered) =>
            {
                if (IsSliderFeeUsed)
                {
                    return;
                }

                FeeControlOpacity = entered ? 0.8 : 0.5;
            });

            Observable
            .Merge(MaxCommand.ThrownExceptions)
            .Merge(FeeRateCommand.ThrownExceptions)
            .Merge(OnAddressPasteCommand.ThrownExceptions)
            .Merge(BuildTransactionCommand.ThrownExceptions)
            .Merge(UserFeeTextKeyUpCommand.ThrownExceptions)
            .Merge(FeeSliderClickedCommand.ThrownExceptions)
            .Merge(HighLightFeeSliderCommand.ThrownExceptions)
            .Merge(AmountKeyUpCommand.ThrownExceptions)
            .ObserveOn(RxApp.TaskpoolScheduler)
            .Subscribe(ex =>
            {
                NotificationHelpers.Error(ex.ToUserFriendlyString());
                Logger.LogError(ex);
            });
        }