Commit 363d5a57 by Javier Piris

Creados y añadido modelo nuevo de datos + CustomCells nuevas, un selector…

Creados y añadido modelo nuevo de datos + CustomCells nuevas, un selector template y la adaptación para la vista de nueva consulta + Adaptación delos viewmodels de preguntas al nuevo modelo
parent 88f1509e
using MvvmHelpers;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
namespace inutralia.Models.Questions
{
[JsonObject(MemberSerialization.OptIn)]
[DataPath("messages")]
public class Message : ObservableEntityData
{
public enum Estatus
{
Pending,
Answered_for_client,
Answered_for_nutricionist,
Closed
}
public string StatusImg => imgStatus[StateId];
[JsonProperty("text", Required = Required.Always)]
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value); }
}
string _text;
[JsonProperty("datetime", Required = Required.Always)]
public DateTime MessageDateTime
{
get { return _messageDateTime; }
set { SetProperty(ref _messageDateTime, value); }
}
DateTime _messageDateTime;
public string TimeDisplay => MessageDateTime.ToLocalTime().ToString();
[JsonProperty("isText", Required = Required.Always)]
public bool IsTextIn
{
get { return _isTextIn; }
set { SetProperty(ref _isTextIn, value); }
}
bool _isTextIn;
[JsonProperty("state_id", Required = Required.Always)]
public int StateId { get; set; }
[JsonProperty("status", Required = Required.Always)]
[JsonConverter(typeof(StringEnumConverter))]
public Estatus State { get; set; }
[JsonProperty("subject", Required = Required.Always)]
public string Subject
{
get { return _subject; }
set { SetProperty(ref _subject, value); }
}
string _subject;
string[] imgStatus = new string[2]
{
"pendiente.png", // 1 - Pendiente de responder
//"respondida_por_cliente.png", // 2 - Respondida por cliente
//"respondida_por_nutricionista", // 3- Respondida por nutricionista
"cerrada" // 4 - Conversación cerrada
};
}
}
\ No newline at end of file
......@@ -29,6 +29,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="Questions\Message.cs" />
<Compile Include="Utils\BoolConverter.cs" />
<Compile Include="Menu\LocalMenu.cs" />
<Compile Include="Menu\MenuBase.cs" />
......@@ -37,8 +38,6 @@
<Compile Include="Profile\Profile.cs" />
<Compile Include="Menu\Ingredient.cs" />
<Compile Include="Menu\Menu.cs" />
<Compile Include="Questions\QuestionMessage.cs" />
<Compile Include="Questions\QuestionSpecialist.cs" />
<Compile Include="Recipe\Recipe.cs" />
<Compile Include="Recipe\RecipeOption.cs" />
<Compile Include="Recipe\RecipeOptionGroup.cs" />
......
using inutralia.CustomCells;
using inutralia.Models.Questions;
using Xamarin.Forms;
namespace inutralia
{
public class SelectorDataTemplate : DataTemplateSelector
{
private readonly DataTemplate textInDataTemplate;
private readonly DataTemplate textOutDataTemplate;
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var messageVm = item as Message;
if (messageVm == null)
return null;
return messageVm.IsTextIn ? this.textInDataTemplate : this.textOutDataTemplate;
}
public SelectorDataTemplate()
{
this.textInDataTemplate = new DataTemplate(typeof(TextInViewCell));
this.textOutDataTemplate = new DataTemplate(typeof(TextOutViewCell));
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="inutralia.CustomCells.TextInViewCell">
<Grid ColumnSpacing="2" Padding="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Frame Grid.Row="0" Grid.Column="1" BackgroundColor="#0535f0" CornerRadius="15">
<Frame.HasShadow>
<OnPlatform x:TypeArguments="x:Boolean" iOS="false" Android="true"/>
</Frame.HasShadow>
<StackLayout>
<Label TextColor="White" Text="{Binding Text}" />
</StackLayout>
</Frame>
<Label FontSize="Micro" Grid.Row="1" Grid.Column="1" Text="{Binding MessageDateTime, StringFormat='{0:MM/dd/yyyy hh:mm tt}'}" TextColor="Gray"></Label>
</Grid>
</ViewCell>
\ No newline at end of file
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace inutralia.CustomCells
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TextInViewCell : ViewCell
{
public TextInViewCell()
{
InitializeComponent();
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="inutralia.CustomCells.TextOutViewCell">
<Grid ColumnSpacing="2" Padding="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="2"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Frame Grid.Row="0" Grid.Column="1" CornerRadius="15">
<Frame.HasShadow>
<OnPlatform x:TypeArguments="x:Boolean" Android="true" iOS="True"/>
</Frame.HasShadow>
<Frame.BackgroundColor>
<OnPlatform x:TypeArguments="Color" Android="White" iOS="#F5F5F5"/>
</Frame.BackgroundColor>
<StackLayout>
<Label TextColor="Black" Text="{Binding Text}" />
</StackLayout>
</Frame>
<Label Grid.Row="1" FontSize="Micro" Grid.Column="1" HorizontalTextAlignment="End" Text="{Binding MessageDateTime, StringFormat='{0:MM/dd/yyyy hh:mm tt}'}" TextColor="Gray"></Label>
</Grid>
</ViewCell>
\ No newline at end of file
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace inutralia.CustomCells
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TextOutViewCell : ViewCell
{
public TextOutViewCell()
{
InitializeComponent();
}
}
}
\ No newline at end of file
using inutralia.Models;
using inutralia.Models.Questions;
using MvvmHelpers;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System;
using System.Windows.Input;
using Xamarin.Forms;
namespace inutralia.ViewModels
{
public class NewQuestionViewModel : BaseNavigationViewModel
public class NewQuestionViewModel : BaseViewModel
{
public enum Estatus
{
Pending,
Answered_for_client,
Answered_for_nutricionist,
Closed
}
public QuestionSpecialist QuestionSpecialist { private set; get; }
public Estatus State => (Estatus)QuestionSpecialist?.Id;
public ObservableRangeCollection<QuestionMessage> _NewQuestion;
// Comando de update del listado
Command _RefreshNewQuestionCommand;
// Comando de borrado de elemento
Command _DeleteNewQuestionCommand;
public NewQuestionViewModel(QuestionSpecialist quest)
{
QuestionSpecialist = quest;
Title = QuestionSpecialist.Subject;
if (quest.Messages.Count() > 0)
{
NewQuestion = new ObservableRangeCollection<QuestionMessage>(quest.Messages);
}
else
{
NewQuestion = new ObservableRangeCollection<QuestionMessage>();
}
}
// Acceso a la lista de PREGUNTAS
public ObservableRangeCollection<QuestionMessage> NewQuestion
{
// Getter (lazy load), crea la lista si no existe
get { return _NewQuestion ?? (_NewQuestion = new ObservableRangeCollection<QuestionMessage>()); }
// Setter. Cambia el valor y notifica a la vista de dicho cambio
set
{
_NewQuestion = value;
OnPropertyChanged("NewQuestion");
}
}
public async Task RefreshData()
{
if (QuestionSpecialist == null || (QuestionSpecialist.Id < 0))
return;
IsBusy = true;
if (await App.API.RefreshItemAsync(QuestionSpecialist))
{
Title = QuestionSpecialist.StatusImg;
OnPropertyChanged("State");
}
IsBusy = false;
await FetchQuestions();
}
///<summary>
/// Método que realiza la carga inicial del listado
///</summary>
public async Task ExecuteLoadNewQuestionCommand()
{
///Realiza el procesp de actualización si hay menos
///de un elemento en el listado
if (QuestionSpecialist.Messages.Count() < 1)
await FetchQuestions();
}
/// <summary>
/// Acceso al comando de actualización del listado
/// </summary>
public Command RefreshNewQuestionCommand
{
// Getter (lazy load), crea el comando si no existe
get { return _RefreshNewQuestionCommand ?? (_RefreshNewQuestionCommand = new Command(async () => await ExecuteRefreshQuestionMessagesCommand())); }
}
/// <summary>
/// Proceso de ejecución del comando de actualización del listado
/// </summary>
public async Task ExecuteRefreshQuestionMessagesCommand()
{
try
{
// Hace que el comando no se pueda ejecutar de nuevo
RefreshNewQuestionCommand.ChangeCanExecute();
// Realiza el proceso de actualización
await FetchQuestions();
// Hace que el comando pueda volver a ejecutarse
RefreshNewQuestionCommand.ChangeCanExecute();
}
catch (System.Exception e)
{
string err = e.Message;
}
}
public ObservableRangeCollection<Message> ListMessages { get; }
public ICommand SendCommand { get; set; }
///<summary>
///Proceso de actualización del listado
///</summary>
async Task FetchQuestions()
{
// Indicamos que estámos ocupados (provoca que aparezca el indicador de carga)
IsBusy = true;
// Llamada al API para coger el listado (provoca que se actualize la vista del listado)
try
{
if (await App.API.RefreshItemAsync(QuestionSpecialist) == true)
public NewQuestionViewModel()
{
Title = QuestionSpecialist.Subject;
NewQuestion = new ObservableRangeCollection<QuestionMessage>(QuestionSpecialist.Messages);
}
}
catch (System.Exception e)
{
string err = e.Message;
NewQuestion.Clear();
}
ListMessages = new ObservableRangeCollection<Message>();
// Indicamos que ya no estámos ocupados (provoca que desaparezca el indicador de carga)
IsBusy = false;
}
///<summary>
///Acceso al comando de borrado de pregunta
///</summary>
public Command DeleteQuestionCommand
{
// Getter (lazy load), crea el comando si no existe. Nótese que, a diferencia del comando
// de Refresh, éste recibe una notificación como parámetro
get
SendCommand = new Command(() =>
{
return _DeleteNewQuestionCommand ?? (_DeleteNewQuestionCommand = new Command(async (parameter) => await ExecuteDeleteQuestionCommand(parameter as QuestionMessage)));
}
}
///<summary>
///Proceso de ejecución de comando de borrado
///</summary>
///<param name="messag"></param>
///<returns></returns>
async Task ExecuteDeleteQuestionCommand(QuestionMessage messag)
if (!String.IsNullOrWhiteSpace(OutText))
{
// Verificar parámetro
if (messag != null)
var message = new Message
{
// Indicamos que estámos ocupados (provoca que aparezca el indicador de carga)
IsBusy = true;
// Llamamos al API para borrar el mensaje
await App.API.DeleteItemAsync(messag);
//Actualizamos la lista
await FetchQuestions();
//Indicamos que no estámos ocupados (provoca que desarparezca el indicador de carga)
IsBusy = false;
}
}
///<summary>
///Guarda un mensaje perteneciente a QuestionSpecialist ya sea una pregunta nueva, nuevo mensaje o edición
///</summary>
///<param name="text"></param>
///<returns></returns>
public async Task SaveQuestion(string text)
{
var q = QuestionSpecialist;
HttpMethod method = HttpMethod.Post;
IsBusy = true;
if (q.Id < 0)
{
var data = new Dictionary<string, string>()
{
{"subject", q.Subject }, {"message", text}
Text = OutText,
IsTextIn = false,
MessageDateTime = DateTime.Now
};
// New Question
await App.API.RawMessage(method, string.Format("questions"), data, q);
}
else
{
QuestionMessage msg;
if (q.State == QuestionSpecialist.Estatus.Closed)
{
//Edit last Message
msg = q.Messages.Last();
method = HttpMethod.Put;
}
else
{
//Add new Message
msg = new QuestionMessage();
} //endif
msg.Text = text;
await App.API.RawMessage(method, string.Format("questions/{0}", q.Id), msg, q);
} // endif
IsBusy = false;
NewQuestion = new ObservableRangeCollection<QuestionMessage>(QuestionSpecialist.Messages);
ListMessages.Add(message);
OutText = "";
}
///<summary>
///Actualiza una pregunta
///</summary>
///<returns></returns>
public async Task SaveQuestion()
{
var q = QuestionSpecialist;
HttpMethod method = HttpMethod.Post;
IsBusy = true;
});
}
await App.API.UpdateItemAsync(q);
if (await App.API.RefreshItemAsync(QuestionSpecialist))
public string OutText
{
Title = QuestionSpecialist.StatusImg;
OnPropertyChanged("State");
}
IsBusy = false;
get { return _outText; }
set { SetProperty(ref _outText, value); }
}
public bool IsCloseOrPending => (State == Estatus.Answered_for_client || State == Estatus.Answered_for_nutricionist || State == Estatus.Pending || State == Estatus.Closed) && QuestionSpecialist.Messages.Count() > 0 || State == Estatus.Answered_for_nutricionist;
public bool MayBeClosed => !IsCloseOrPending;
string _outText = string.Empty;
}
}
using System.Threading.Tasks;
using inutralia.Models;
using inutralia.Models.Questions;
namespace inutralia.ViewModels
{
......@@ -13,31 +14,31 @@ namespace inutralia.ViewModels
Cerrado = 4
}
public PendingReadViewModel(QuestionSpecialist questionSpecialist)
public PendingReadViewModel(Message message)
{
QuestionSpecialist = questionSpecialist;
Message = message;
Title = QuestionSpecialist?.StatusImg;
Title = message?.StatusImg;
}
public PendingReadViewModel() { }
public QuestionSpecialist QuestionSpecialist { private set; get; }
public Message Message { private set; get; }
public int StateId => QuestionSpecialist.StateId;
public int StateId => Message.StateId;
public Estatus estatus => (Estatus)QuestionSpecialist?.StateId;
public Estatus estatus => (Estatus)Message?.StateId;
public async Task RefresData()
{
if (QuestionSpecialist == null)
if (Message == null)
return;
IsBusy = true;
if (await App.API.RefreshItemAsync(QuestionSpecialist))
if (await App.API.RefreshItemAsync(Message))
{
Title = QuestionSpecialist.StatusImg;
Title = Message.StatusImg;
OnPropertyChanged("");
}
......
using inutralia.Models;
using inutralia.Models.Questions;
using MvvmHelpers; // Este namespace está en el paquete Refractored.MvvmHelpers
using System;
using System.Threading.Tasks;
......@@ -14,7 +15,7 @@ namespace inutralia.ViewModels
public QuestionListViewModel() { }
// Datos del histórico
ObservableRangeCollection<QuestionSpecialist> _QuestionList;
ObservableRangeCollection<Message> _QuestionList;
// Comando de loading del listado
Command _LoadQuestionListCommand;
......@@ -23,10 +24,10 @@ namespace inutralia.ViewModels
Command _RefreshQuestionListCommand;
// Acceso a la lista preguntas
public ObservableRangeCollection<QuestionSpecialist> QuestionList
public ObservableRangeCollection<Message> QuestionList
{
// Getter (lazy load), crea la lista si no exite
get => _QuestionList ?? (_QuestionList = new ObservableRangeCollection<QuestionSpecialist>());
get => _QuestionList ?? (_QuestionList = new ObservableRangeCollection<Message>());
// Setter. Cambia el valor y notifica a la vista de dicho cambio
set
......@@ -97,7 +98,7 @@ namespace inutralia.ViewModels
// la notificación (campo Body)
try
{
QuestionList = new ObservableRangeCollection<QuestionSpecialist>(await App.API.RefreshListAsync<QuestionSpecialist>());
QuestionList = new ObservableRangeCollection<Message>(await App.API.RefreshListAsync<Message>());
}
catch (Exception e)
{
......
using inutralia.Models;
using inutralia.Models.Questions;
using inutralia.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
......@@ -18,7 +19,7 @@ namespace inutralia.Views.Question
protected async void ItemTapped(object sender, ItemTappedEventArgs e)
{
var respon = e.Item as QuestionSpecialist;
var respon = e.Item as Message;
if (respon.StatusImg == "Respondida")
{
await DisplayAlert("ERROR", "La pregunta ya está respondida", "Entendido");
......@@ -28,7 +29,7 @@ namespace inutralia.Views.Question
await Navigation.PushAsync(
new PendingReadView()
{
BindingContext = new PendingReadViewModel((QuestionSpecialist)e.Item)
BindingContext = new PendingReadViewModel((Message)e.Item)
}
);
((ListView)sender).SelectedItem = null;
......
......@@ -10,15 +10,26 @@ namespace inutralia.Views.Question
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NewConsultationView : ContentPage
{
protected NewQuestionViewModel ViewModel => BindingContext as NewQuestionViewModel;
//protected NewQuestionViewModel ViewModel => BindingContext as NewQuestionViewModel;
NewQuestionViewModel vm;
public NewConsultationView()
{
InitializeComponent();
newQuest.IsEnabled = true;
buttonNewQuestion.IsEnabled = false;
buttonNewQuestion.Clicked += ButtonNewQuestion_Clicked;
BindingContext = vm = new NewQuestionViewModel();
vm.ListMessages.CollectionChanged += (sender, e) =>
{
var target = vm.ListMessages[vm.ListMessages.Count - 1];
MessagesListView.ScrollTo(target, ScrollToPosition.End, true);
};
//newQuest.IsEnabled = true;
//buttonNewQuestion.IsEnabled = false;
//buttonNewQuestion.Clicked += ButtonNewQuestion_Clicked;
}
//protected override void OnBindingContextChanged()
......@@ -32,28 +43,28 @@ namespace inutralia.Views.Question
// OnDataRefreshed();
//}
private async void ButtonNewQuestion_Clicked(object sender, EventArgs e)
{
if (String.IsNullOrWhiteSpace(newQuest.Text))
{
newQuest.Text = "";
return;
}
//private async void ButtonNewQuestion_Clicked(object sender, EventArgs e)
//{
// if (String.IsNullOrWhiteSpace(newQuest.Text))
// {
// newQuest.Text = "";
// return;
// }
await ViewModel.SaveQuestion(newQuest.Text);
listNewConsultation.SelectedItem = null;
//OnDataRefreshed();
}
// await ViewModel.SaveQuestion(newQuest.Text);
// listNewConsultation.SelectedItem = null;
// //OnDataRefreshed();
//}
///// <summary>
///// Método llamado cada vez que una página pasa a ser visible
///// </summary>
protected override async void OnAppearing()
{
base.OnAppearing();
//await ViewModel.RefreshData();
//OnDataRefreshed();
}
//protected override async void OnAppearing()
//{
// base.OnAppearing();
// await ViewModel.RefreshData();
// OnDataRefreshed();
//}
///// <summary>
///// Método llamado al hacer tap en un elemento de la lista. Navega a la página de detalle
......@@ -61,22 +72,22 @@ namespace inutralia.Views.Question
///// </summary>
///// <param name="sender">La ListiView</param>
///// <param name="e">Argumentos del evento</param>
void ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e == null) return; // has been set to null, do not 'process' tapped event
//void ItemTapped(object sender, ItemTappedEventArgs e)
//{
// if (e == null) return; // has been set to null, do not 'process' tapped event
QuestionMessage item = (QuestionMessage)e.Item;
if (ViewModel.NewQuestion.Last() == item && item.FromUser)
{
buttonNewQuestion.IsEnabled = true;
newQuest.IsEnabled = true;
newQuest.Text = item.Text;
}
else
{
((ListView)sender).SelectedItem = null; // de-select the row
}
}
// QuestionMessage item = (QuestionMessage)e.Item;
// if (ViewModel.NewQuestion.Last() == item && item.FromUser)
// {
// buttonNewQuestion.IsEnabled = true;
// newQuest.IsEnabled = true;
// newQuest.Text = item.Text;
// }
// else
// {
// ((ListView)sender).SelectedItem = null; // de-select the row
// }
//}
//private void OnDataRefreshed()
//{
......
using inutralia.Models;
using inutralia.Models.Questions;
using inutralia.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
......@@ -10,7 +11,7 @@ namespace inutralia.Views.Question
{
protected PendingReadViewModel ViewModel => BindingContext as PendingReadViewModel;
public QuestionSpecialist QuestionSpecialist { private set; get; }
public Message Message { private set; get; }
public PendingReadView()
{
......
......@@ -37,6 +37,13 @@
<Compile Include="API\LocalDataService.cs" />
<Compile Include="Converters\ImageTransformator.cs" />
<Compile Include="Converters\AlternatingBackgroundColorConverter.cs" />
<Compile Include="CustomCells\SelectorDataTemplate.cs" />
<Compile Include="CustomCells\TextInViewCell.xaml.cs">
<DependentUpon>TextInViewCell.xaml</DependentUpon>
</Compile>
<Compile Include="CustomCells\TextOutViewCell.xaml.cs">
<DependentUpon>TextOutViewCell.xaml</DependentUpon>
</Compile>
<Compile Include="Helpers\Settings.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="App.xaml.cs">
......@@ -275,7 +282,6 @@
<SubType>Designer</SubType>
</None>
<None Include="SampleData.json" />
<None Include="Gorilla.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Views\Recipe\ItemList\RecipeItemTemplate.xaml">
......@@ -480,6 +486,18 @@
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="CustomCells\TextInViewCell.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="CustomCells\TextOutViewCell.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment