StockTakeCompletionPage.xaml.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. using Comal.Classes;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using Plugin.Media;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using Xamarin.Forms;
  13. using Xamarin.Forms.Xaml;
  14. using XF.Material.Forms.UI.Dialogs;
  15. namespace comal.timesheets
  16. {
  17. [XamlCompilation(XamlCompilationOptions.Compile)]
  18. public partial class StockTakeCompletionPage : ContentPage
  19. {
  20. public delegate void StockTakeCompleted();
  21. public event StockTakeCompleted OnStockTakeCompleted;
  22. List<string> favourites = new List<string>
  23. { "Stocktake complete" };
  24. List<StockMovement> _movements = new List<StockMovement>();
  25. Dictionary<Image, Document> imagesDocuments = new Dictionary<Image, Document>();
  26. public StockTakeCompletionPage(List<StockMovement> movements)
  27. {
  28. InitializeComponent();
  29. _movements = movements;
  30. AddFavButtons();
  31. }
  32. private void AddFavButtons()
  33. {
  34. foreach (string s in favourites)
  35. {
  36. Button button = new Button
  37. {
  38. Text = s,
  39. TextColor = Color.White,
  40. BackgroundColor = Color.FromHex("#15C7C1"),
  41. CornerRadius = 10,
  42. Margin = 2,
  43. FontAttributes = FontAttributes.Bold,
  44. VerticalOptions = LayoutOptions.Center,
  45. HorizontalOptions = LayoutOptions.Center,
  46. Padding = new Thickness(6, 3, 6, 3)
  47. };
  48. button.Clicked += FavButton_Clicked;
  49. optionsFlexLayout.Children.Add(button);
  50. }
  51. }
  52. private void FavButton_Clicked(object sender, EventArgs e)
  53. {
  54. Button button = sender as Button;
  55. if (string.IsNullOrWhiteSpace(notesEdt.Text))
  56. {
  57. notesEdt.Text = button.Text;
  58. }
  59. else
  60. {
  61. notesEdt.Text = notesEdt.Text + " " + button.Text;
  62. }
  63. }
  64. private async void SaveBatch_Clicked(object sender, EventArgs e)
  65. {
  66. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Saving"))
  67. {
  68. StockMovementBatch batch = new StockMovementBatch() { Notes = notesEdt.Text };
  69. batch.Type = StockMovementBatchType.Stocktake;
  70. new Client<StockMovementBatch>().Save(batch, "Created on mobile");
  71. SavePhotos(batch.ID);
  72. foreach (StockMovement movement in _movements)
  73. {
  74. movement.Batch.ID = batch.ID;
  75. movement.Date = batch.Created;
  76. }
  77. Task.Run(() =>
  78. {
  79. new Client<StockMovement>().Save(_movements, "Created on mobile device");
  80. });
  81. Device.BeginInvokeOnMainThread(async () =>
  82. {
  83. saveBatchBtn.IsVisible = false;
  84. await DisplayAlert("Success", "Batch Saved", "OK");
  85. OnStockTakeCompleted?.Invoke();
  86. Navigation.PopAsync();
  87. });
  88. }
  89. }
  90. #region Photos
  91. private async void SavePhotos(Guid batchID)
  92. {
  93. await Task.Run(() =>
  94. {
  95. new Client<Document>().Save(imagesDocuments.Values, "Photo taken on mobile device for stocktake");
  96. // Link the photos to the batch
  97. List<StockMovementBatchDocument> stockMovementBatchDocuments = new List<StockMovementBatchDocument>();
  98. foreach (var doc in imagesDocuments.Values)
  99. {
  100. var smd = new StockMovementBatchDocument();
  101. smd.EntityLink.ID = batchID;
  102. smd.DocumentLink.ID = doc.ID;
  103. smd.DocumentLink.FileName = doc.FileName;
  104. stockMovementBatchDocuments.Add(smd);
  105. }
  106. new Client<StockMovementBatchDocument>().Save(stockMovementBatchDocuments, "Photo taken on mobile device for stocktake");
  107. });
  108. }
  109. async void TakePhoto_Clicked(object sender, EventArgs e)
  110. {
  111. TakeAPhoto();
  112. }
  113. async void ChooseImage_Clicked(object sender, EventArgs e)
  114. {
  115. ChooseAPhoto();
  116. }
  117. private async void TakeAPhoto()
  118. {
  119. await CrossMedia.Current.Initialize();
  120. if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
  121. {
  122. await DisplayAlert("No Camera", ":( No camera available.", "OK");
  123. return;
  124. }
  125. String filename = String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}.png", DateTime.Now);
  126. var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
  127. {
  128. Name = filename,
  129. CompressionQuality = 10,
  130. PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full
  131. });
  132. if (file == null)
  133. return;
  134. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo"))
  135. {
  136. Image img = null;
  137. var memoryStream = new MemoryStream();
  138. file.GetStream().CopyTo(memoryStream);
  139. var data = memoryStream.ToArray();
  140. Document doc = new Document()
  141. {
  142. FileName = filename,
  143. Data = data,
  144. CRC = CoreUtils.CalculateCRC(data),
  145. TimeStamp = DateTime.Now
  146. };
  147. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  148. img = new Image();
  149. img.HeightRequest = 150;
  150. img.WidthRequest = 150;
  151. img.Aspect = Aspect.AspectFit;
  152. img.Source = src;
  153. img.GestureRecognizers.Add(new TapGestureRecognizer
  154. {
  155. Command = new Command(OnTap),
  156. CommandParameter = src,
  157. NumberOfTapsRequired = 1
  158. });
  159. imagesDocuments.Add(img, doc);
  160. file.Dispose();
  161. if (img != null)
  162. {
  163. Device.BeginInvokeOnMainThread(() =>
  164. {
  165. ImageScroller.IsVisible = true;
  166. images.Children.Add(img);
  167. UpdateColours();
  168. });
  169. }
  170. }
  171. }
  172. private async void ChooseAPhoto()
  173. {
  174. await CrossMedia.Current.Initialize();
  175. if (!CrossMedia.Current.IsPickPhotoSupported)
  176. {
  177. await DisplayAlert("No Library", ":( No Photo Library available.", "OK");
  178. return;
  179. }
  180. var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions()
  181. {
  182. CompressionQuality = 10,
  183. PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full
  184. });
  185. if (file == null)
  186. return;
  187. using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo"))
  188. {
  189. Image img = null;
  190. var memoryStream = new MemoryStream();
  191. file.GetStream().CopyTo(memoryStream);
  192. var data = memoryStream.ToArray();
  193. Document doc = new Document()
  194. {
  195. FileName = Path.GetFileName(file.Path),
  196. Data = data,
  197. CRC = CoreUtils.CalculateCRC(data),
  198. TimeStamp = DateTime.Now
  199. };
  200. ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
  201. img = new Image();
  202. img.HeightRequest = 150;
  203. img.WidthRequest = 150;
  204. img.Aspect = Aspect.AspectFit;
  205. img.Source = src;
  206. img.GestureRecognizers.Add(new TapGestureRecognizer
  207. {
  208. Command = new Command(OnTap),
  209. CommandParameter = src,
  210. NumberOfTapsRequired = 1
  211. });
  212. imagesDocuments.Add(img, doc);
  213. file.Dispose();
  214. if (img != null)
  215. {
  216. Device.BeginInvokeOnMainThread(() =>
  217. {
  218. ImageScroller.IsVisible = true;
  219. images.Children.Add(img);
  220. UpdateColours();
  221. });
  222. }
  223. }
  224. }
  225. private void OnTap(object obj)
  226. {
  227. ImageViewer viewer = new ImageViewer(obj as ImageSource);
  228. Navigation.PushAsync(viewer);
  229. viewer.ChooseDelete();
  230. viewer.OnDeleteSelected += () =>
  231. {
  232. Image img = imagesDocuments.Keys.First(x => x.Source.Equals(obj as ImageSource));
  233. imagesDocuments.Remove(img);
  234. Device.BeginInvokeOnMainThread(() =>
  235. {
  236. images.Children.Clear();
  237. if (imagesDocuments.Count > 0)
  238. {
  239. foreach (Image image in imagesDocuments.Keys)
  240. {
  241. images.Children.Add(image);
  242. }
  243. }
  244. UpdateColours();
  245. });
  246. };
  247. }
  248. #endregion
  249. #region Updating Screen
  250. private void NotesEdt_Changed(object sender, EventArgs e)
  251. {
  252. UpdateColours();
  253. }
  254. private void UpdateColours()
  255. {
  256. if (imagesDocuments.Values.Count > 0)
  257. {
  258. photosFrame.BorderColor = Color.Gray;
  259. }
  260. else
  261. {
  262. photosFrame.BorderColor = Color.Red;
  263. }
  264. if (!string.IsNullOrWhiteSpace(notesEdt.Text))
  265. {
  266. if (notesFrame.BorderColor == Color.Red)
  267. {
  268. notesFrame.BorderColor = Color.Gray;
  269. }
  270. }
  271. else
  272. {
  273. notesFrame.BorderColor = Color.Red;
  274. }
  275. ShowSave();
  276. }
  277. private void ShowSave()
  278. {
  279. if (notesFrame.BorderColor == Color.Gray && photosFrame.BorderColor == Color.Gray)
  280. {
  281. saveBatchBtn.IsVisible = true;
  282. }
  283. else
  284. {
  285. saveBatchBtn.IsVisible = false;
  286. }
  287. }
  288. #endregion
  289. }
  290. }