using System; using System.ComponentModel; using ShareeBike.Model.Connector; using ShareeBike.Model.Device; using ShareeBike.Model.User; using ShareeBike.View; using ShareeBike.ViewModel.Bikes.Bike.BC.RequestHandler; using BikeInfoMutable = ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable; namespace ShareeBike.ViewModel.Bikes.Bike.BC { /// /// View model for a BC bike. /// Provides functionality for views /// - MyBikes /// - BikesAtStation /// public class BikeViewModel : BikeViewModelBase, INotifyPropertyChanged { /// /// Notifies GUI about changes. /// public override event PropertyChangedEventHandler PropertyChanged; /// Holds object which manages requests. private IRequestHandler RequestHandler { get; set; } /// Raises events in order to update GUI. public override void RaisePropertyChanged(object sender, PropertyChangedEventArgs eventArgs) => PropertyChanged?.Invoke(sender, eventArgs); /// /// Constructs a bike view model object. /// /// Provides info about the smart device (phone, tablet, ...). /// Bike to be displayed. /// Object holding logged in user or an empty user object. /// Provides in use state information. /// View model to be used for progress report and unlocking/ locking view. /// Delegate to open browser. public BikeViewModel( Func isConnectedDelegate, Func connectorFactory, Action bikeRemoveDelegate, Func viewUpdateManager, ISmartDevice smartDevice, IViewService viewService, BikeInfoMutable selectedBike, IUser activeUser, IInUseStateInfoProvider stateInfoProvider, IBikesViewModel bikesViewModel, Action openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, activeUser, new ViewContext(PageContext.BikesAtStation), stateInfoProvider, bikesViewModel, openUrlInBrowser) { RequestHandler = activeUser.IsLoggedIn ? RequestHandlerFactory.Create( selectedBike, isConnectedDelegate, connectorFactory, viewUpdateManager, smartDevice, viewService, bikesViewModel, ActiveUser) : new NotLoggedIn( selectedBike.State.Value, viewService, bikesViewModel, ActiveUser); selectedBike.PropertyChanged += (sender, ev) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible))); } /// /// Handles BikeInfoMutable events. /// Helper member to raise events. Maps model event change notification to view model events. /// Todo: Check which events are received here and filter, to avoid event storm. /// /// public override void OnSelectedBikeStateChanged() { RequestHandler = RequestHandlerFactory.Create( Bike, IsConnectedDelegate, ConnectorFactory, ViewUpdateManager, SmartDevice, ViewService, BikesViewModel, ActiveUser); var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(nameof(ButtonText))); handler(this, new PropertyChangedEventArgs(nameof(IsButtonVisible))); } } /// Gets visibility of the copri command button. public bool IsButtonVisible => RequestHandler.IsButtonVisible && Bike.DataSource == Model.Bikes.BikeInfoNS.BC.DataSource.Copri /* do not show button if data is from cache */ ; /// Gets the text of the copri command button. public string ButtonText => RequestHandler.ButtonText; /// Processes request to perform a copri action (reserve bike and cancel reservation). public System.Windows.Input.ICommand OnButtonClicked => new Xamarin.Forms.Command(async () => { var lastHandler = RequestHandler; var lastState = Bike.State.Value; RequestHandler = await RequestHandler.HandleRequest(); CheckRemoveBike(Id, lastState); if (lastHandler.GetType() == RequestHandler.GetType()) { // No state change occurred. return; } // State changed and instance of request handler was switched. if (lastHandler.ButtonText != ButtonText) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonText))); } if (lastHandler.IsButtonVisible != IsButtonVisible) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible))); } }); } }