Last active
September 23, 2017 14:58
-
-
Save Kikimora/57ceac2f3dc681febb82087efc7d57fb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public enum Network { Bitcoin, Ethereum } | |
//This interface hides ethereum/bitcoin inconsistencies and provides unified interface to view model. | |
//This make sense only until ETH/BTC has very similar UI and workflow. | |
//This interface is private to SendViewModel since it is designed with it specific tasks in mind. | |
interface ISendRequest | |
{ | |
decimal AvailableFunds { get; } | |
string Recipient { get; set; } | |
decimal Fee { get; set; } | |
void ValidateRecipeint(Ivalidator validator); | |
void Send(); | |
} | |
//This view model holds all data required to send cryptocurrency to some recipient | |
public class SendViewModel : DataContext, IWeakListener | |
{ | |
//_sendRequest actually holds all data | |
//View model delegates most properties to send request and | |
//User fills it by changing properties of this view model | |
ISendRequest _sendRequest; | |
public SendViewModel() | |
{ | |
SendCommand = new AsyncCommand(Send, _ => !_.IsRunning); | |
PropertyChanged += ValidateCalculatedProperties; | |
//JavvyContext holds all global services. | |
//Subscribe to events which comes not from UI but from our model. | |
//Subscriptions are implemented as weak references to avoid memory leaks. | |
JavvyContext.MessageHub.Subscribe("Bitcoin.AvailableFunds", this); | |
JavvyContext.MessageHub.Subscribe("Ethereum.AvailableFunds", this); | |
//Init _sendRequest | |
Network = Network.Bitcoin; | |
} | |
//Change AvailableFunds property when we read corresponding msesage from blockhain network | |
void IWeakListener.OnMessage(Notification notification) | |
{ | |
RaisePropertyChanged(nameof(AvailableFunds)); | |
} | |
public decimal Amount | |
{ | |
get => this._sendRequest.Amount; | |
set | |
{ | |
this.Validator.CheckProperty(value).MoreOrEqThan(0); | |
if (value != this._sendRequest.Amount) | |
{ | |
this._sendRequest.Amount = value; | |
RaisePropertyChanged(nameof(Amount)); | |
OnTotalTransactionAmountChanged(); | |
} | |
} | |
} | |
//Only valid for bitcoin | |
public decimal Fee | |
{ | |
get => this._sendRequest.Fee; | |
set | |
{ | |
//Fee cannot be less than 0 | |
this.Validator.CheckProperty(value).MoreOrEqThan(0).LessThan(); | |
if (value != this._sendRequest.Fee) | |
{ | |
this._sendRequest.Fee = value; | |
RaisePropertyChanged(nameof(Fee)); | |
OnTotalTransactionAmountChanged(); | |
} | |
} | |
} | |
public decimal TotalTransactionAmount | |
{ | |
get | |
{ | |
return Amount + Fee; | |
} | |
} | |
string _recipient; | |
public string Recipient | |
{ | |
get => this._sendRequest.Recipient; | |
set | |
{ | |
var checker = this.Validator.CheckProperty(value).NotEmpty(); | |
this._sendRequest.ValidateRecipient(Validator); | |
if (value != this._sendRequest.Recipient) | |
{ | |
this._sendRequest.Recipient = value; | |
RaisePropertyChanged(nameof(Recipient)); | |
} | |
} | |
} | |
Network _network; | |
public Network Network | |
{ | |
get => _network; | |
set | |
{ | |
if (value != _network) | |
{ | |
_network = value; | |
var request = _network == Network.Bitcoin ? new BitcoinSendRequest() : EthereumSendRequest(); | |
//Copy data from model to request to preserve it over Netwrok property changes | |
//Mapper is an instance of AutoMapper configured to map between SendViewModel and ISendRequest | |
JavvyContext.Mapper.Map(this, request); | |
this._sendRequest = request; | |
RaisePropertyChanged(nameof(Network)); | |
RaisePropertyChanged(nameof(Fee)); | |
OnAvailableFundsChanged(); | |
Validate(); | |
} | |
} | |
} | |
public decimal AvailableFunds | |
{ | |
get | |
{ | |
return this._sendRequest.AvailableFunds; | |
} | |
} | |
private void OnTotalTransactionAmountChanged() | |
{ | |
ValidateTotalAmount(); | |
RaisePropertyChanged(nameof(TotalTransactionAmount)); | |
} | |
private void ValidateTotalAmount() | |
{ | |
this.Validator.Check(TotalTransactionAmount, nameof(TotalTransactionAmount)) | |
.LessThan(AvailableFunds); | |
} | |
private void OnAvailableFundsChanged() | |
{ | |
RaisePropertyChanged(nameof(AvailableFunds)); | |
//TotalTransactionAmount depends on AvailableFunds; | |
OnTotalTransactionAmountChanged(); | |
} | |
private async Task Send(object arg, CancellationToken token) | |
{ | |
_sendStrategy.Send(Recipient, Amount, Fee); | |
} | |
} | |
abstract class BaseSendRequest : ISendRequest | |
{ | |
protected readonly TransactionDto _dto = new TrdansactionDto(); | |
public string Recipient { get => _dto.Recipient; set => _dto.Recipient = value; } | |
public decimal Amount { get => _dto.Amount; set => _dto.Amount = value; } | |
public abstract void ValidateRecipient(IValidator validator); | |
public void Send() | |
{ | |
JavvyContext.TransactionService.Send(_dto); | |
} | |
} | |
class BitcoinSendRequest : BaseSendRequest | |
{ | |
public decimal Fee { get => _dto.Fee; set => _dto.Fee = value; } | |
public decimal AvailableFunds => JavvyContext.User.Bitcoin.AvailableFunds; | |
public Error ValidateRecipient(Ivalidator validator) | |
{ | |
this.validator.Check(nameof(Recipient), recipient).NotEmpty().Convert(BitcoinAddress.Parse).NotNull(); | |
} | |
} | |
class EthereumSendRequest : BaseSendRequest | |
{ | |
public decimal Fee { get => 0; set => {} } | |
public decimal AvailableFunds => JavvyContext.User.Ethereum.AvailableFunds; | |
public void ValidateRecipient(Check<string> recipient) | |
{ | |
this.validator.Check(nameof(Recipient), recipient).NotEmpty().Convert(EthereumAddress.Parse).NotNull(); | |
} | |
} | |
public interface IWeakListener | |
{ | |
void OnMessage(Notification notification); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment