├── .vs ├── ProjectSettings.json └── slnx.sqlite ├── LICENSE ├── MyContacts.Droid ├── .DS_Store ├── Assets │ └── AboutAssets.txt ├── Effects │ ├── DropShadowEffect.cs │ └── ListViewSortableEffect.cs ├── MainActivity.cs ├── MyContacts.Droid.csproj ├── MyContacts.Droid.csproj.bak ├── Properties │ ├── AndroidManifest.xml │ └── AssemblyInfo.cs ├── Resources │ ├── AboutResources.txt │ ├── Resource.Designer.cs │ ├── drawable-hdpi │ │ └── icon.png │ ├── drawable-xhdpi │ │ └── icon.png │ ├── drawable-xxhdpi │ │ └── icon.png │ ├── drawable │ │ ├── ic_action_search.png │ │ ├── icon.png │ │ └── star.png │ └── values │ │ └── styles.xml └── packages.config ├── MyContacts.UWP ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── MainPage.xaml ├── MainPage.xaml.cs ├── MyContacts.UWP.csproj ├── Package.appxmanifest ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── project.json └── star.png ├── MyContacts.iOS ├── AppDelegate.cs ├── Effects │ └── DropShadowEffect.cs ├── Entitlements.plist ├── Info.plist ├── Main.cs ├── MyContacts.iOS.csproj ├── MyContacts.iOS.csproj.user ├── Properties │ └── AssemblyInfo.cs ├── Resources │ ├── Default-568h@2x.png │ ├── Default-Portrait.png │ ├── Default-Portrait@2x.png │ ├── Default.png │ ├── Default@2x.png │ ├── Icon-60@2x.png │ ├── Icon-60@3x.png │ ├── Icon-76.png │ ├── Icon-76@2x.png │ ├── Icon-Small-40.png │ ├── Icon-Small-40@2x.png │ ├── Icon-Small-40@3x.png │ ├── Icon-Small.png │ ├── Icon-Small@2x.png │ ├── Icon-Small@3x.png │ ├── LaunchScreen.storyboard │ ├── star.png │ └── star@2x.png ├── iTunesArtwork ├── iTunesArtwork@2x └── packages.config ├── MyContacts.sln ├── MyContacts ├── AllContacts.xaml ├── AllContacts.xaml.cs ├── AllContactsViewModel.cs ├── App.cs ├── ContactDetails.xaml ├── ContactDetails.xaml.cs ├── Converters │ ├── BirthdayConverter.cs │ ├── GenderToIndexConverter.cs │ └── ImageResourceConverter.cs ├── Data │ ├── Gender.cs │ ├── Person.cs │ └── PlayerFactory.cs ├── Effects │ └── DropShadowEffect.cs ├── Images │ ├── Apu.gif │ ├── Bart.gif │ ├── ComicBookGuy.gif │ ├── Homer.gif │ ├── Krusty.gif │ ├── Lisa.gif │ ├── Maggie.gif │ ├── Marge.gif │ ├── Milhouse.gif │ ├── MoeSzyslak.gif │ ├── MrBurns.gif │ ├── SideshowBob.gif │ └── WaylonSmithers.gif ├── MyContacts.csproj ├── MyFacade.SecondPart.cs ├── MyFacade.cs ├── ObservableListCollection.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config └── README.md /.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": null 3 | } -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/.vs/slnx.sqlite -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Can Bilgin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MyContacts.Droid/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/.DS_Store -------------------------------------------------------------------------------- /MyContacts.Droid/Assets/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories) and given a Build Action of "AndroidAsset". 3 | 4 | These files will be deployed with you package and will be accessible using Android's 5 | AssetManager, like this: 6 | 7 | public class ReadAsset : Activity 8 | { 9 | protected override void OnCreate (Bundle bundle) 10 | { 11 | base.OnCreate (bundle); 12 | 13 | InputStream input = Assets.Open ("my_asset.txt"); 14 | } 15 | } 16 | 17 | Additionally, some Android functions will automatically load asset files: 18 | 19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); 20 | -------------------------------------------------------------------------------- /MyContacts.Droid/Effects/DropShadowEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using MyContacts.Effects; 4 | using MyContacts.Droid; 5 | using Xamarin.Forms; 6 | using Xamarin.Forms.Platform.Android; 7 | 8 | [assembly: ResolutionGroupName("CubiSoft")] 9 | [assembly: ExportEffect(typeof(DropShadowEffect), "DropShadowEffect")] 10 | namespace MyContacts.Droid 11 | { 12 | public class DropShadowEffect : PlatformEffect 13 | { 14 | protected override void OnAttached() 15 | { 16 | try 17 | { 18 | var control = Control??Container as Android.Views.View; 19 | 20 | var effect = (ViewShadowEffect)Element.Effects.FirstOrDefault(e => e is ViewShadowEffect); 21 | 22 | if (effect != null) 23 | { 24 | float radius = effect.Radius; 25 | Android.Graphics.Color color = effect.Color.ToAndroid(); 26 | //control.SetShadowLayer(radius, distanceX, distanceY, color); 27 | 28 | control.Elevation = radius; 29 | control.TranslationZ = (effect.DistanceX + effect.DistanceY) / 2; 30 | } 31 | } 32 | catch (Exception ex) 33 | { 34 | Console.WriteLine("Cannot set property on attached control. Error: {0}", ex.Message); 35 | } 36 | } 37 | 38 | protected override void OnDetached() 39 | { 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MyContacts.Droid/Effects/ListViewSortableEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Android.Animation; 5 | using Android.Content; 6 | using Android.Database; 7 | using Android.Graphics; 8 | using Android.OS; 9 | using Android.Views; 10 | using Java.Lang; 11 | using MyContacts.Droid.Effects; 12 | using MyContacts.Effects; 13 | using Xamarin.Forms; 14 | using Xamarin.Forms.Platform.Android; 15 | using AViews = Android.Views; 16 | using AWidget = Android.Widget; 17 | 18 | [assembly: ExportEffect(typeof(ListViewSortableEffect), "ListViewSortableEffect")] 19 | namespace MyContacts.Droid.Effects 20 | { 21 | public class ListViewSortableEffect : PlatformEffect 22 | { 23 | private DragListAdapter _dragListAdapter = null; 24 | 25 | protected override void OnAttached() 26 | { 27 | var element = Element as ListView; 28 | 29 | if(Control is AWidget.ListView listView) 30 | { 31 | _dragListAdapter = new DragListAdapter(listView, element); 32 | listView.Adapter = _dragListAdapter; 33 | listView.SetOnDragListener(_dragListAdapter); 34 | listView.OnItemLongClickListener = _dragListAdapter; 35 | } 36 | } 37 | 38 | protected override void OnDetached() 39 | { 40 | if (Control is AWidget.ListView listView) 41 | { 42 | listView.Adapter = _dragListAdapter.WrappedAdapter; 43 | 44 | // TODO: Remove the attached listeners 45 | } 46 | } 47 | 48 | protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args) 49 | { 50 | if (args.PropertyName == Sorting.IsSortableProperty.PropertyName) 51 | { 52 | _dragListAdapter.DragDropEnabled = Sorting.GetIsSortable(Element); 53 | } 54 | } 55 | } 56 | 57 | public class DragItem : Java.Lang.Object 58 | { 59 | /// 60 | /// Initializes a new instance of the class. 61 | /// 62 | /// 63 | /// The initial index for the data item. 64 | /// 65 | /// 66 | /// The view element that is being dragged. 67 | /// 68 | /// 69 | /// The data item that is bound to the view. 70 | /// 71 | public DragItem(int index, AViews.View view, object dataItem) 72 | { 73 | OriginalIndex = Index = index; 74 | View = view; 75 | Item = dataItem; 76 | } 77 | 78 | /// 79 | /// Gets or sets the current index for the data item. 80 | /// 81 | public int Index { get; set; } 82 | 83 | /// 84 | /// Gets the original index for the data item 85 | /// 86 | public int OriginalIndex { get; } 87 | 88 | /// 89 | /// Gets the data item that is being dragged 90 | /// 91 | public object Item { get; } 92 | 93 | /// 94 | /// Gets the view that is being dragged 95 | /// 96 | public AViews.View View { get; } 97 | } 98 | 99 | public class DragListAdapter : 100 | AWidget.BaseAdapter, 101 | AWidget.IWrapperListAdapter, 102 | AViews.View.IOnDragListener, 103 | AWidget.AdapterView.IOnItemLongClickListener 104 | { 105 | private AWidget.IListAdapter _listAdapter; 106 | 107 | private AWidget.ListView _listView; 108 | 109 | private ListView _element; 110 | 111 | private List _translatedItems = new List(); 112 | 113 | /// 114 | /// Initializes a new instance of the class. 115 | /// 116 | /// 117 | /// The list adapter. 118 | /// 119 | /// 120 | /// The list view. 121 | /// 122 | /// 123 | /// The element. 124 | /// 125 | public DragListAdapter(AWidget.ListView listView, ListView element) 126 | { 127 | _listView = listView; 128 | _listAdapter = ((AWidget.IWrapperListAdapter)_listView.Adapter).WrappedAdapter; 129 | _element = element; 130 | } 131 | 132 | public bool DragDropEnabled { get; set; } = false; 133 | 134 | #region IWrapperListAdapter Members 135 | 136 | public AWidget.IListAdapter WrappedAdapter => _listAdapter; 137 | 138 | public override int Count => WrappedAdapter.Count; 139 | 140 | public override bool HasStableIds => WrappedAdapter.HasStableIds; 141 | 142 | public override bool IsEmpty => WrappedAdapter.IsEmpty; 143 | 144 | public override int ViewTypeCount => WrappedAdapter.ViewTypeCount; 145 | 146 | public override bool AreAllItemsEnabled() => WrappedAdapter.AreAllItemsEnabled(); 147 | 148 | public override Java.Lang.Object GetItem(int position) 149 | { 150 | return WrappedAdapter.GetItem(position); 151 | } 152 | 153 | public override long GetItemId(int position) 154 | { 155 | return WrappedAdapter.GetItemId(position); 156 | } 157 | 158 | public override int GetItemViewType(int position) 159 | { 160 | return WrappedAdapter.GetItemViewType(position); 161 | } 162 | 163 | public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent) 164 | { 165 | var view = WrappedAdapter.GetView(position, convertView, parent); 166 | view.SetOnDragListener(this); 167 | return view; 168 | } 169 | 170 | public override bool IsEnabled(int position) 171 | { 172 | return WrappedAdapter.IsEnabled(position); 173 | } 174 | 175 | private DataSetObserver _observer; 176 | 177 | public override void RegisterDataSetObserver(DataSetObserver observer) 178 | { 179 | _observer = observer; 180 | base.RegisterDataSetObserver(observer); 181 | WrappedAdapter.RegisterDataSetObserver(observer); 182 | } 183 | 184 | public override void UnregisterDataSetObserver(DataSetObserver observer) 185 | { 186 | base.UnregisterDataSetObserver(observer); 187 | WrappedAdapter.UnregisterDataSetObserver(observer); 188 | } 189 | 190 | #endregion 191 | 192 | public bool OnDrag(AViews.View v, DragEvent e) 193 | { 194 | switch (e.Action) 195 | { 196 | case DragAction.Started: 197 | break; 198 | case DragAction.Entered: 199 | System.Diagnostics.Debug.WriteLine($"DragAction.Entered from {v.GetType()}"); 200 | 201 | if(!(v is AWidget.ListView)) 202 | { 203 | var dragItem = (DragItem)e.LocalState; 204 | 205 | var targetPosition = InsertOntoView(v, dragItem); 206 | 207 | dragItem.Index = targetPosition; 208 | 209 | // Keep a list of items that has translation so we can reset 210 | // them once the drag'n'drop is finished. 211 | _translatedItems.Add(v); 212 | _listView.Invalidate(); 213 | } 214 | break; 215 | case DragAction.Location: 216 | //_currentPosition = (int)e.GetY(); 217 | //System.Diagnostics.Debug.WriteLine($"DragAction.Location from {v.GetType()} => {_currentPosition}"); 218 | break; 219 | case DragAction.Exited: 220 | System.Diagnostics.Debug.WriteLine($"DragAction.Entered from {v.GetType()}"); 221 | 222 | if (!(v is AWidget.ListView)) 223 | { 224 | var positionEntered = GetListPositionForView(v); 225 | var item1 = _listAdapter.GetItem(positionEntered); 226 | 227 | System.Diagnostics.Debug.WriteLine($"DragAction.Exited index {positionEntered}"); 228 | } 229 | break; 230 | case DragAction.Drop: 231 | 232 | 233 | System.Diagnostics.Debug.WriteLine($"DragAction.Drop from {v.GetType()}"); 234 | 235 | //} 236 | 237 | break; 238 | case DragAction.Ended: 239 | if (!(v is AWidget.ListView)) 240 | { 241 | return false; 242 | } 243 | 244 | System.Diagnostics.Debug.WriteLine($"DragAction.Ended from {v.GetType()}"); 245 | 246 | var mobileItem = (DragItem)e.LocalState; 247 | 248 | mobileItem.View.Visibility = ViewStates.Visible; 249 | 250 | foreach (var view in _translatedItems) 251 | { 252 | view.TranslationY = 0; 253 | } 254 | 255 | _translatedItems.Clear(); 256 | 257 | if (_element.ItemsSource is IOrderable orderable) 258 | { 259 | orderable.ChangeOrdinal(mobileItem.OriginalIndex, mobileItem.Index); 260 | } 261 | 262 | break; 263 | } 264 | 265 | return true; 266 | } 267 | 268 | /// 269 | /// Handler for Long Click event from 270 | /// 271 | /// 272 | /// The parent list view . 273 | /// 274 | /// 275 | /// The view that triggered the long click event 276 | /// 277 | /// 278 | /// The position of the view in the list (has to be normalized, includes headers). 279 | /// 280 | /// 281 | /// The id of the item that triggered the event (must be bigger than 0 under normal circumstances). 282 | /// 283 | /// 284 | /// The flag that identifies whether the event is handled. 285 | /// 286 | public bool OnItemLongClick(AWidget.AdapterView parent, AViews.View view, int position, long id) 287 | { 288 | var selectedItem = ((IList)_element.ItemsSource)[(int)id]; 289 | 290 | DragItem dragItem = new DragItem(NormalizeListPosition(position), view, selectedItem); 291 | 292 | var data = ClipData.NewPlainText(string.Empty, string.Empty); 293 | 294 | AViews.View.DragShadowBuilder shadowBuilder = new AViews.View.DragShadowBuilder(view); 295 | 296 | view.Visibility = ViewStates.Invisible; 297 | 298 | if (Build.VERSION.SdkInt >= BuildVersionCodes.N) 299 | { 300 | view.StartDragAndDrop(data, shadowBuilder, dragItem, 0); 301 | } 302 | else 303 | { 304 | view.StartDrag(data, shadowBuilder, id, 0); 305 | } 306 | 307 | return true; 308 | } 309 | 310 | private int InsertOntoView(AViews.View view, DragItem item) 311 | { 312 | var positionEntered = GetListPositionForView(view); 313 | var correctedPosition = positionEntered; 314 | 315 | // If the view already has a translation, we need to adjust the position 316 | // If the view has a positive translation, that means that the current position 317 | // is actually one index down then where it started. 318 | // If the view has a negative translation, that means it actually moved 319 | // up previous now we will need to move it down. 320 | if (view.TranslationY > 0) 321 | { 322 | correctedPosition += 1; 323 | } 324 | else if (view.TranslationY < 0) 325 | { 326 | correctedPosition -= 1; 327 | } 328 | 329 | // If the current index of the dragging item is bigger than the target 330 | // That means the dragging item is moving up, and the target view should 331 | // move down, and vice-versa 332 | var translationCoef = item.Index > correctedPosition ? 1 : -1; 333 | 334 | // We translate the item as much as the height of the drag item (up or down) 335 | var translationTarget = view.TranslationY + (translationCoef * item.View.Height); 336 | 337 | ObjectAnimator anim = ObjectAnimator.OfFloat(view, "TranslationY", view.TranslationY, translationTarget); 338 | anim.SetDuration(100); 339 | anim.Start(); 340 | 341 | return correctedPosition; 342 | } 343 | 344 | private int GetListPositionForView(AViews.View view) 345 | { 346 | return NormalizeListPosition(_listView.GetPositionForView(view)); 347 | } 348 | 349 | private int NormalizeListPosition(int position) 350 | { 351 | return position - _listView.HeaderViewsCount; 352 | } 353 | 354 | } 355 | } 356 | 357 | /* 358 | public class LongClickListener : Java.Lang.Object, AWidget.AdapterView.IOnItemLongClickListener 359 | { 360 | public bool OnItemLongClick(AWidget.AdapterView parent, Android.Views.View view, int position, long id) 361 | { 362 | System.Diagnostics.Debug.WriteLine("EVENT: On Item Long Click Handler"); 363 | var data = ClipData.NewPlainText(string.Empty, string.Empty); 364 | 365 | DragShadowBuilder shadowBuilder = new global::Android.Views.View.DragShadowBuilder(view); 366 | 367 | view.Visibility = ViewStates.Invisible; 368 | 369 | long itemId = id; 370 | 371 | if (Build.VERSION.SdkInt >= BuildVersionCodes.N) 372 | { 373 | var itemPosition = position - parent.FirstVisiblePosition; 374 | itemId = parent.GetItemIdAtPosition(itemPosition); 375 | view.StartDragAndDrop(data, shadowBuilder, itemId, 0); 376 | System.Diagnostics.Debug.WriteLine($"Item being dragged with {view.Id} and parameters position {position} and id {itemId}"); 377 | } 378 | else 379 | { 380 | view.StartDrag(data, shadowBuilder, itemId, 0); 381 | } 382 | 383 | //view.StartDrag(data, shadowBuilder, tmpObj, 0); 384 | 385 | return true; 386 | } 387 | 388 | public bool OnLongClick(Android.Views.View v) 389 | { 390 | throw new NotImplementedException(); 391 | } 392 | } 393 | 394 | public class DragListener : Java.Lang.Object, Android.Views.View.IOnDragListener, Android.Views.View.IOnTouchListener 395 | { 396 | private AWidget.ListView _listView; 397 | 398 | private ListView _element; 399 | 400 | private static int _lastPosition = 0; 401 | 402 | private static float _currentPointerPosition = -1; 403 | 404 | public DragListener(AWidget.ListView listView, ListView element) 405 | { 406 | _listView = listView; 407 | _element = element; 408 | 409 | if (_listView != null) 410 | { 411 | } 412 | } 413 | 414 | /// 415 | /// This Method handles the animation of the cells switching as also switches the underlying data set 416 | /// 417 | void HandleCellSwitch(Android.Views.View switchView, float diff) 418 | { 419 | try 420 | { 421 | //int deltaY = mLastEventY - mDownY; // total distance moved since the last movement 422 | //int deltaYTotal = mHoverCellOriginalBounds.Top + mTotalOffset + deltaY; // total distance moved from original long press position 423 | 424 | //View belowView = GetViewForID(mBelowItemId); // the view currently below the mobile item 425 | //View mobileView = GetViewForID(mMobileItemId); // the current mobile item view (this is NOT what you see moving around, thats just a dummy, this is the "invisible" cell on the list) 426 | //View aboveView = GetViewForID(mAboveItemId); // the view currently above the mobile item 427 | 428 | //// Detect if we have moved the drawable enough to justify a cell swap 429 | //bool isBelow = (belowView != null) && (deltaYTotal > belowView.Top); 430 | //bool isAbove = (aboveView != null) && (deltaYTotal < aboveView.Top); 431 | 432 | //if (isBelow || isAbove) 433 | //{ 434 | 435 | //View switchView = isBelow ? belowView : aboveView; // get the view we need to animate 436 | 437 | //var diff = GetViewForID(mMobileItemId).Top - switchView.Top; // the difference between the top of the mobile view and top of the view we are about to switch with 438 | 439 | //// Lets animate the view sliding into its new position. Remember: the listview cell corresponding the mobile item is invisible so it looks like 440 | //// the switch view is just sliding into position 441 | ObjectAnimator anim = ObjectAnimator.OfFloat(switchView, "TranslationY", switchView.TranslationY, switchView.TranslationY + diff); 442 | anim.SetDuration(100); 443 | anim.Start(); 444 | 445 | 446 | //// Swap out the mobile item id 447 | //mMobileItemId = GetPositionForView(switchView); 448 | 449 | //// Since the mobile item id has been updated, we also need to make sure and update the above and below item ids 450 | //UpdateNeighborViewsForID(mMobileItemId); 451 | 452 | //// One the animation ends, we want to adjust out visiblity 453 | //anim.AnimationEnd += (sender, e) => 454 | //{ 455 | // // Swap the visbility of the views corresponding to the data items being swapped - since the "switchView" will become the "mobileView" 456 | // // mobileView.Visibility = ViewStates.Visible; 457 | // // switchView.Visibility = ViewStates.Invisible; 458 | 459 | // // Swap the items in the data source and then NotifyDataSetChanged() 460 | // ((IDraggableListAdapter)Adapter).SwapItems(GetPositionForView(mobileView), GetPositionForView(switchView)); 461 | //}; 462 | //} 463 | } 464 | catch (System.Exception ex) 465 | { 466 | Console.WriteLine("Error Switching Cells in DynamicListView.cs - Message: {0}", ex.Message); 467 | Console.WriteLine("Error Switching Cells in DynamicListView.cs - Stacktrace: {0}", ex.StackTrace); 468 | 469 | } 470 | } 471 | 472 | public bool OnDrag(Android.Views.View v, DragEvent e) 473 | { 474 | switch (e.Action) 475 | { 476 | case Android.Views.DragAction.Started: 477 | break; 478 | case Android.Views.DragAction.Entered: 479 | if (!(v is AWidget.ListView)) 480 | { 481 | v.SetBackgroundColor(Android.Graphics.Color.Blue); 482 | var position = (int)_listView?.GetPositionForView(v); 483 | 484 | System.Diagnostics.Debug.WriteLine($"The item is currently on position {position}"); 485 | } 486 | break; 487 | case Android.Views.DragAction.Location: 488 | if((v is AWidget.ListView)) 489 | { 490 | _currentPointerPosition = e.GetY(); 491 | System.Diagnostics.Debug.WriteLine($"The drag.location: {e.GetY()}"); 492 | } 493 | return false; 494 | case Android.Views.DragAction.Exited: 495 | if (!(v is AWidget.ListView)) 496 | { 497 | v.SetBackgroundColor(Android.Graphics.Color.Transparent); 498 | var position = _listView.GetPositionForView(v); 499 | 500 | var dragListAdapter = (_listView.Adapter as AWidget.IWrapperListAdapter).WrappedAdapter as DragListAdapter; 501 | var id = (int)e.LocalState; 502 | 503 | var mobileView = dragListAdapter.GetViewForId(id); 504 | 505 | var diff = (_currentPointerPosition- v.Top) > 0? 1 : -1; 506 | 507 | System.Diagnostics.Debug.WriteLine($"The item is exiting position {v.Top} - cursor position is {mobileView.Top}"); 508 | 509 | HandleCellSwitch(v, (float)(120 * diff)); 510 | 511 | _lastPosition = position; 512 | 513 | System.Diagnostics.Debug.WriteLine($"The item is exiting position {position} - and moving id is {id} with diff {diff}"); 514 | } 515 | break; 516 | case Android.Views.DragAction.Drop: 517 | 518 | v.SetBackgroundColor(Android.Graphics.Color.Transparent); 519 | var dragListAdapter2 = (_listView.Adapter as AWidget.IWrapperListAdapter).WrappedAdapter as DragListAdapter; 520 | var id2 = (long)e.LocalState; 521 | //var actualId = _listView.GetItemIdAtPosition(id2); 522 | var mobileItem = dragListAdapter2.GetViewForId(id2); 523 | mobileItem.Visibility = ViewStates.Visible; 524 | var position2 = _listView.GetPositionForView(mobileItem); 525 | 526 | if (_element.ItemsSource is IOrderable orderableList) 527 | { 528 | var deleteAt = position2 - 2; 529 | var insertAt = _lastPosition - 2; 530 | 531 | orderableList.ChangeOrdinal(deleteAt, insertAt); 532 | 533 | } 534 | dragListAdapter2.NotifyCollectionChanged(); 535 | for (var i = 0; i < _listView.ChildCount; i++) 536 | { 537 | _listView.GetChildAt(i).TranslationY = 0; 538 | } 539 | //_listView.Invalidate(); 540 | 541 | break; 542 | case Android.Views.DragAction.Ended: 543 | break; 544 | } 545 | 546 | return true; 547 | } 548 | 549 | public bool OnHover(Android.Views.View v, MotionEvent e) 550 | { 551 | if(v is AWidget.ListView) 552 | { 553 | System.Diagnostics.Debug.WriteLine($"Hover event with Y: {e.GetY()}"); 554 | } 555 | 556 | return false; 557 | } 558 | 559 | public bool OnTouch(Android.Views.View v, MotionEvent e) 560 | { 561 | if (e.Action == MotionEventActions.Move) 562 | { 563 | System.Diagnostics.Debug.WriteLine($"Hover event with Y: {e.GetY()}"); 564 | } 565 | return false; 566 | } 567 | } 568 | 569 | 570 | */ 571 | 572 | 573 | 574 | //private Android.Views.View GetChild(int xCoordinate, int yCoordinate, out int position) 575 | //{ 576 | // position = -1; 577 | 578 | // Rect rect = new Rect(); 579 | // int[] listViewCoords = new int[2]; 580 | 581 | // _listView.GetLocationOnScreen(listViewCoords); 582 | 583 | // int x = xCoordinate - listViewCoords[0]; 584 | // int y = yCoordinate - listViewCoords[1]; 585 | 586 | // Android.Views.View child; 587 | 588 | // for (int i = 0; i < _listView.ChildCount; i++) 589 | // { 590 | // child = _listView.GetChildAt(i); 591 | // child.GetHitRect(rect); 592 | // if (rect.Contains(x, y)) 593 | // { 594 | // position = i; 595 | 596 | // return child; 597 | // } 598 | // } 599 | 600 | // return null; 601 | //} -------------------------------------------------------------------------------- /MyContacts.Droid/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Android.App; 4 | using Android.Content.PM; 5 | using Android.Runtime; 6 | using Android.Views; 7 | using Android.Widget; 8 | using Android.OS; 9 | 10 | namespace MyContacts.Droid 11 | { 12 | [Activity(Label = "Fenerbahce", Theme = "@android:style/Theme.Material.Light", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] 13 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity 14 | { 15 | protected override void OnCreate(Bundle bundle) 16 | { 17 | base.OnCreate(bundle); 18 | global::Xamarin.Forms.Forms.Init(this, bundle); 19 | LoadApplication(new App()); 20 | 21 | ActionBar.SetIcon(Android.Resource.Color.Transparent); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /MyContacts.Droid/MyContacts.Droid.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40} 8 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 9 | Library 10 | Properties 11 | MyContacts.Droid 12 | MyContacts.Droid 13 | 512 14 | true 15 | Resources\Resource.Designer.cs 16 | Off 17 | Properties\AndroidManifest.xml 18 | True 19 | armeabi,armeabi-v7a,x86 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | v8.0 28 | false 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | None 39 | x86 40 | false 41 | true 42 | x86 43 | 44 | 45 | pdbonly 46 | true 47 | bin\Release\ 48 | TRACE 49 | prompt 50 | 4 51 | 52 | 53 | 54 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\FormsViewGroup.dll 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | ..\packages\Xamarin.Android.Support.Annotations.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Annotations.dll 64 | 65 | 66 | ..\packages\Xamarin.Android.Support.Compat.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Compat.dll 67 | 68 | 69 | ..\packages\Xamarin.Android.Support.Core.UI.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Core.UI.dll 70 | 71 | 72 | ..\packages\Xamarin.Android.Support.Core.Utils.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Core.Utils.dll 73 | 74 | 75 | ..\packages\Xamarin.Android.Support.Media.Compat.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Media.Compat.dll 76 | 77 | 78 | ..\packages\Xamarin.Android.Support.Fragment.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Fragment.dll 79 | 80 | 81 | ..\packages\Xamarin.Android.Support.Transition.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Transition.dll 82 | 83 | 84 | ..\packages\Xamarin.Android.Support.v4.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v4.dll 85 | 86 | 87 | ..\packages\Xamarin.Android.Support.v7.CardView.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.CardView.dll 88 | 89 | 90 | ..\packages\Xamarin.Android.Support.v7.Palette.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.Palette.dll 91 | 92 | 93 | ..\packages\Xamarin.Android.Support.v7.RecyclerView.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.dll 94 | 95 | 96 | ..\packages\Xamarin.Android.Support.Vector.Drawable.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.dll 97 | 98 | 99 | ..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.dll 100 | 101 | 102 | ..\packages\Xamarin.Android.Support.v7.AppCompat.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.dll 103 | 104 | 105 | ..\packages\Xamarin.Android.Support.Design.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Design.dll 106 | 107 | 108 | ..\packages\Xamarin.Android.Support.v7.MediaRouter.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.dll 109 | 110 | 111 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Core.dll 112 | 113 | 114 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.dll 115 | 116 | 117 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll 118 | 119 | 120 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | MyContacts 149 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE} 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /MyContacts.Droid/MyContacts.Droid.csproj.bak: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40} 8 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 9 | Library 10 | Properties 11 | MyContacts.Droid 12 | MyContacts.Droid 13 | 512 14 | true 15 | Resources\Resource.Designer.cs 16 | Off 17 | Properties\AndroidManifest.xml 18 | True 19 | armeabi,armeabi-v7a,x86 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | v8.0 28 | false 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | None 39 | armeabi-v7a 40 | true 41 | 42 | 43 | pdbonly 44 | true 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | ..\packages\Xamarin.Android.Support.Annotations.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Annotations.dll 59 | 60 | 61 | ..\packages\Xamarin.Android.Support.Compat.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Compat.dll 62 | 63 | 64 | ..\packages\Xamarin.Android.Support.Core.UI.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Core.UI.dll 65 | 66 | 67 | ..\packages\Xamarin.Android.Support.Core.Utils.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Core.Utils.dll 68 | 69 | 70 | ..\packages\Xamarin.Android.Support.Media.Compat.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Media.Compat.dll 71 | 72 | 73 | ..\packages\Xamarin.Android.Support.Fragment.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Fragment.dll 74 | 75 | 76 | ..\packages\Xamarin.Android.Support.Transition.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Transition.dll 77 | 78 | 79 | ..\packages\Xamarin.Android.Support.v4.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v4.dll 80 | 81 | 82 | ..\packages\Xamarin.Android.Support.v7.CardView.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.CardView.dll 83 | 84 | 85 | ..\packages\Xamarin.Android.Support.v7.Palette.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.Palette.dll 86 | 87 | 88 | ..\packages\Xamarin.Android.Support.v7.RecyclerView.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.RecyclerView.dll 89 | 90 | 91 | ..\packages\Xamarin.Android.Support.Vector.Drawable.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Vector.Drawable.dll 92 | 93 | 94 | ..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.dll 95 | 96 | 97 | ..\packages\Xamarin.Android.Support.v7.AppCompat.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.AppCompat.dll 98 | 99 | 100 | ..\packages\Xamarin.Android.Support.Design.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.Design.dll 101 | 102 | 103 | ..\packages\Xamarin.Android.Support.v7.MediaRouter.25.3.1\lib\MonoAndroid70\Xamarin.Android.Support.v7.MediaRouter.dll 104 | 105 | 106 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\FormsViewGroup.dll 107 | 108 | 109 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Core.dll 110 | 111 | 112 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll 113 | 114 | 115 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.dll 116 | 117 | 118 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | MyContacts 147 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE} 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /MyContacts.Droid/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /MyContacts.Droid/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("MyContacts.Droid")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("MyContacts.Droid")] 14 | [assembly: AssemblyCopyright("Copyright © 2014")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | 32 | // Add some common permissions, these can be removed if not needed 33 | [assembly: UsesPermission(Android.Manifest.Permission.Internet)] 34 | [assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)] 35 | -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/AboutResources.txt: -------------------------------------------------------------------------------- 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 2 | in your application as resource files. Various Android APIs are designed to 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 4 | directly. 5 | 6 | For example, a sample Android app that contains a user interface layout (main.xml), 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 8 | would keep its resources in the "Resources" directory of the application: 9 | 10 | Resources/ 11 | drawable-hdpi/ 12 | icon.png 13 | 14 | drawable-ldpi/ 15 | icon.png 16 | 17 | drawable-mdpi/ 18 | icon.png 19 | 20 | layout/ 21 | main.xml 22 | 23 | values/ 24 | strings.xml 25 | 26 | In order to get the build system to recognize Android resources, set the build action to 27 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 28 | instead operate on resource IDs. When you compile an Android application that uses resources, 29 | the build system will package the resources for distribution and generate a class called 30 | "Resource" that contains the tokens for each one of the resources included. For example, 31 | for the above Resources layout, this is what the Resource class would expose: 32 | 33 | public class Resource { 34 | public class drawable { 35 | public const int icon = 0x123; 36 | } 37 | 38 | public class layout { 39 | public const int main = 0x456; 40 | } 41 | 42 | public class strings { 43 | public const int first_string = 0xabc; 44 | public const int second_string = 0xbcd; 45 | } 46 | } 47 | 48 | You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main 49 | to reference the layout/main.xml file, or Resource.strings.first_string to reference the first 50 | string in the dictionary file values/strings.xml. 51 | -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/Resources/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/Resources/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/Resources/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/drawable/ic_action_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/Resources/drawable/ic_action_search.png -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/Resources/drawable/icon.png -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/drawable/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.Droid/Resources/drawable/star.png -------------------------------------------------------------------------------- /MyContacts.Droid/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | -------------------------------------------------------------------------------- /MyContacts.Droid/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /MyContacts.UWP/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | -------------------------------------------------------------------------------- /MyContacts.UWP/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | using Windows.UI.Xaml.Controls.Primitives; 13 | using Windows.UI.Xaml.Data; 14 | using Windows.UI.Xaml.Input; 15 | using Windows.UI.Xaml.Media; 16 | using Windows.UI.Xaml.Navigation; 17 | 18 | namespace MyContacts.UWP 19 | { 20 | /// 21 | /// Provides application-specific behavior to supplement the default Application class. 22 | /// 23 | sealed partial class App : Application 24 | { 25 | /// 26 | /// Initializes the singleton application object. This is the first line of authored code 27 | /// executed, and as such is the logical equivalent of main() or WinMain(). 28 | /// 29 | public App() 30 | { 31 | this.InitializeComponent(); 32 | this.Suspending += OnSuspending; 33 | } 34 | 35 | /// 36 | /// Invoked when the application is launched normally by the end user. Other entry points 37 | /// will be used such as when the application is launched to open a specific file. 38 | /// 39 | /// Details about the launch request and process. 40 | protected override void OnLaunched(LaunchActivatedEventArgs e) 41 | { 42 | 43 | #if DEBUG 44 | if (System.Diagnostics.Debugger.IsAttached) 45 | { 46 | this.DebugSettings.EnableFrameRateCounter = true; 47 | } 48 | #endif 49 | 50 | Frame rootFrame = Window.Current.Content as Frame; 51 | 52 | // Do not repeat app initialization when the Window already has content, 53 | // just ensure that the window is active 54 | if (rootFrame == null) 55 | { 56 | // Create a Frame to act as the navigation context and navigate to the first page 57 | rootFrame = new Frame(); 58 | 59 | rootFrame.NavigationFailed += OnNavigationFailed; 60 | 61 | Xamarin.Forms.Forms.Init(e); 62 | 63 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 64 | { 65 | //TODO: Load state from previously suspended application 66 | } 67 | 68 | // Place the frame in the current Window 69 | Window.Current.Content = rootFrame; 70 | } 71 | 72 | if (rootFrame.Content == null) 73 | { 74 | // When the navigation stack isn't restored navigate to the first page, 75 | // configuring the new page by passing required information as a navigation 76 | // parameter 77 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 78 | } 79 | // Ensure the current window is active 80 | Window.Current.Activate(); 81 | } 82 | 83 | /// 84 | /// Invoked when Navigation to a certain page fails 85 | /// 86 | /// The Frame which failed navigation 87 | /// Details about the navigation failure 88 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 89 | { 90 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 91 | } 92 | 93 | /// 94 | /// Invoked when application execution is being suspended. Application state is saved 95 | /// without knowing whether the application will be terminated or resumed with the contents 96 | /// of memory still intact. 97 | /// 98 | /// The source of the suspend request. 99 | /// Details about the suspend request. 100 | private void OnSuspending(object sender, SuspendingEventArgs e) 101 | { 102 | var deferral = e.SuspendingOperation.GetDeferral(); 103 | //TODO: Save application state and stop any background activity 104 | deferral.Complete(); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/StoreLogo.png -------------------------------------------------------------------------------- /MyContacts.UWP/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /MyContacts.UWP/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | -------------------------------------------------------------------------------- /MyContacts.UWP/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Controls.Primitives; 11 | using Windows.UI.Xaml.Data; 12 | using Windows.UI.Xaml.Input; 13 | using Windows.UI.Xaml.Media; 14 | using Windows.UI.Xaml.Navigation; 15 | 16 | // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 17 | 18 | namespace MyContacts.UWP 19 | { 20 | /// 21 | /// An empty page that can be used on its own or navigated to within a Frame. 22 | /// 23 | public sealed partial class MainPage 24 | { 25 | public MainPage() 26 | { 27 | this.InitializeComponent(); 28 | 29 | LoadApplication(new MyContacts.App()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /MyContacts.UWP/MyContacts.UWP.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C} 8 | AppContainerExe 9 | Properties 10 | MyContacts.UWP 11 | MyContacts.UWP 12 | en-US 13 | UAP 14 | 10.0.14393.0 15 | 10.0.10240.0 16 | 14 17 | true 18 | 512 19 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 20 | 21 | 22 | 23 | 24 | true 25 | bin\ARM\Debug\ 26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 27 | ;2008 28 | full 29 | ARM 30 | false 31 | prompt 32 | true 33 | 34 | 35 | bin\ARM\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | true 38 | ;2008 39 | pdbonly 40 | ARM 41 | false 42 | prompt 43 | true 44 | true 45 | 46 | 47 | true 48 | bin\x64\Debug\ 49 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 50 | ;2008 51 | full 52 | x64 53 | false 54 | prompt 55 | true 56 | 57 | 58 | bin\x64\Release\ 59 | TRACE;NETFX_CORE;WINDOWS_UWP 60 | true 61 | ;2008 62 | pdbonly 63 | x64 64 | false 65 | prompt 66 | true 67 | true 68 | 69 | 70 | true 71 | bin\x86\Debug\ 72 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 73 | ;2008 74 | full 75 | x86 76 | false 77 | prompt 78 | true 79 | 80 | 81 | bin\x86\Release\ 82 | TRACE;NETFX_CORE;WINDOWS_UWP 83 | true 84 | ;2008 85 | pdbonly 86 | x86 87 | false 88 | prompt 89 | true 90 | true 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | App.xaml 99 | 100 | 101 | MainPage.xaml 102 | 103 | 104 | 105 | 106 | 107 | Designer 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | MSBuild:Compile 124 | Designer 125 | 126 | 127 | MSBuild:Compile 128 | Designer 129 | 130 | 131 | 132 | 133 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE} 134 | MyContacts 135 | 136 | 137 | 138 | 14.0 139 | 140 | 141 | 148 | -------------------------------------------------------------------------------- /MyContacts.UWP/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | MyContacts.UWP 18 | Xamarin 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /MyContacts.UWP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyContacts.UWP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyContacts.UWP")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /MyContacts.UWP/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 |  17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /MyContacts.UWP/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.UniversalWindowsPlatform": " 5.2.2", 4 | "Xamarin.Forms": "2.3.3.180" 5 | }, 6 | "frameworks": { 7 | "uap10.0": {} 8 | }, 9 | "runtimes": { 10 | "win10-arm": {}, 11 | "win10-arm-aot": {}, 12 | "win10-x86": {}, 13 | "win10-x86-aot": {}, 14 | "win10-x64": {}, 15 | "win10-x64-aot": {} 16 | } 17 | } -------------------------------------------------------------------------------- /MyContacts.UWP/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.UWP/star.png -------------------------------------------------------------------------------- /MyContacts.iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace MyContacts.iOS 9 | { 10 | // The UIApplicationDelegate for the application. This class is responsible for launching the 11 | // User Interface of the application, as well as listening (and optionally responding) to 12 | // application events from iOS. 13 | [Register("AppDelegate")] 14 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate 15 | { 16 | // 17 | // This method is invoked when the application has loaded and is ready to run. In this 18 | // method you should instantiate the window, load the UI into it and then make the window 19 | // visible. 20 | // 21 | // You have 17 seconds to return from this method, or iOS will terminate your application. 22 | // 23 | public override bool FinishedLaunching(UIApplication app, NSDictionary options) 24 | { 25 | global::Xamarin.Forms.Forms.Init(); 26 | LoadApplication(new App()); 27 | 28 | return base.FinishedLaunching(app, options); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MyContacts.iOS/Effects/DropShadowEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using CoreGraphics; 4 | using Foundation; 5 | using MyContacts.Effects; 6 | using MyContacts.iOS; 7 | using UIKit; 8 | using Xamarin.Forms; 9 | using Xamarin.Forms.Platform.iOS; 10 | 11 | [assembly: ResolutionGroupName("CubiSoft")] 12 | [assembly: ExportEffect(typeof(DropShadowEffect), "DropShadowEffect")] 13 | [assembly: ExportEffect(typeof(ListViewSortableEffect), "ListViewSortableEffect")] 14 | namespace MyContacts.iOS 15 | { 16 | public class ListViewSortableEffect : PlatformEffect 17 | { 18 | internal UITableView TableView 19 | { 20 | get 21 | { 22 | return Control as UITableView; 23 | } 24 | } 25 | 26 | protected override void OnAttached() 27 | { 28 | if (TableView == null) 29 | { 30 | return; 31 | } 32 | var isSortable = Sorting.GetIsSortable(Element); 33 | 34 | TableView.Source = new ListSortableTableSource(TableView.Source, Element as ListView); 35 | TableView.SetEditing(isSortable, true); 36 | } 37 | 38 | protected override void OnDetached() 39 | { 40 | TableView.Source = (TableView.Source as ListSortableTableSource).OriginalSource; 41 | TableView.SetEditing(false, true); 42 | } 43 | 44 | protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args) 45 | { 46 | if (args.PropertyName == Sorting.IsSortableProperty.PropertyName) 47 | { 48 | TableView.SetEditing(Sorting.GetIsSortable(Element), true); 49 | } 50 | } 51 | } 52 | 53 | public class ListSortableTableSource : UITableViewSource 54 | { 55 | private UITableViewSource _originalSource; 56 | 57 | private ListView _formsElement; 58 | 59 | public ListSortableTableSource(UITableViewSource source, ListView element) 60 | { 61 | _originalSource = source; 62 | _formsElement = element; 63 | } 64 | 65 | public UITableViewSource OriginalSource 66 | { 67 | get 68 | { 69 | return _originalSource; 70 | } 71 | } 72 | 73 | public override UITableViewCellEditingStyle EditingStyleForRow(UITableView tableView, NSIndexPath indexPath) 74 | { 75 | // We do not want the "-" icon near each row (or the "+" icon) 76 | return UITableViewCellEditingStyle.None; 77 | } 78 | 79 | public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath) 80 | { 81 | // We still want the row to be editable 82 | return true; 83 | } 84 | 85 | public override bool CanMoveRow(UITableView tableView, NSIndexPath indexPath) 86 | { 87 | // We do want each row to be movable 88 | return true; 89 | } 90 | 91 | public override bool ShouldIndentWhileEditing(UITableView tableView, NSIndexPath indexPath) 92 | { 93 | // We do not want the "weird" indent for the rows when they are in editable mode. 94 | return false; 95 | } 96 | 97 | public override void MoveRow(UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath) 98 | { 99 | if (_formsElement.ItemsSource is IOrderable orderableList) 100 | { 101 | var deleteAt = sourceIndexPath.Row; 102 | var insertAt = destinationIndexPath.Row; 103 | 104 | orderableList.ChangeOrdinal(deleteAt, insertAt); 105 | } 106 | } 107 | 108 | 109 | 110 | //public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, Foundation.NSIndexPath indexPath) 111 | //{ 112 | // switch (editingStyle) 113 | // { 114 | // case UITableViewCellEditingStyle.Delete: 115 | // break; 116 | // case UITableViewCellEditingStyle.None: 117 | // break; 118 | // } 119 | //} 120 | 121 | //public override NSIndexPath CustomizeMoveTarget(UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath proposedIndexPath) 122 | //{ 123 | // var numRows = tableView.NumberOfRowsInSection(0); 124 | // if (proposedIndexPath.Row >= numRows) 125 | // return NSIndexPath.FromRowSection(numRows, 0); 126 | // else 127 | // return proposedIndexPath; 128 | //} 129 | 130 | //public override void DraggingEnded(UIScrollView scrollView, bool willDecelerate) 131 | //{ 132 | // _originalSource.DraggingEnded(scrollView, willDecelerate); 133 | //} 134 | 135 | //public override void DraggingStarted(UIScrollView scrollView) 136 | //{ 137 | // _originalSource.DraggingStarted(scrollView); 138 | //} 139 | 140 | public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) 141 | { 142 | return OriginalSource.GetCell(tableView, indexPath); 143 | } 144 | 145 | public override nfloat GetHeightForHeader(UITableView tableView, nint section) 146 | { 147 | return OriginalSource.GetHeightForHeader(tableView, section); 148 | } 149 | 150 | public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath) 151 | { 152 | return OriginalSource.GetHeightForRow(tableView, indexPath); 153 | } 154 | 155 | public override UIView GetViewForHeader(UITableView tableView, nint section) 156 | { 157 | return OriginalSource.GetViewForHeader(tableView, section); 158 | } 159 | 160 | public override void HeaderViewDisplayingEnded(UITableView tableView, UIView headerView, nint section) 161 | { 162 | OriginalSource.HeaderViewDisplayingEnded(tableView, headerView, section); 163 | } 164 | 165 | public override nint NumberOfSections(UITableView tableView) 166 | { 167 | return OriginalSource.NumberOfSections(tableView); 168 | } 169 | 170 | public override void RowDeselected(UITableView tableView, NSIndexPath indexPath) 171 | { 172 | OriginalSource.RowDeselected(tableView, indexPath); 173 | } 174 | 175 | public override void RowSelected(UITableView tableView, NSIndexPath indexPath) 176 | { 177 | OriginalSource.RowSelected(tableView, indexPath); 178 | } 179 | 180 | public override nint RowsInSection(UITableView tableview, nint section) 181 | { 182 | return OriginalSource.RowsInSection(tableview, section); 183 | } 184 | 185 | public override void Scrolled(UIScrollView scrollView) 186 | { 187 | OriginalSource.Scrolled(scrollView); 188 | } 189 | 190 | public override string[] SectionIndexTitles(UITableView tableView) 191 | { 192 | return OriginalSource.SectionIndexTitles(tableView); 193 | } 194 | } 195 | 196 | public class DropShadowEffect : PlatformEffect 197 | { 198 | protected override void OnAttached() 199 | { 200 | try 201 | { 202 | var effect = (ViewShadowEffect)Element.Effects.FirstOrDefault(e => e is ViewShadowEffect); 203 | 204 | if (effect != null) 205 | { 206 | Container.Layer.CornerRadius = effect.Radius; 207 | Container.Layer.ShadowColor = effect.Color.ToCGColor(); 208 | Container.Layer.ShadowOffset = new CGSize(effect.DistanceX, effect.DistanceY); 209 | Container.Layer.ShadowOpacity = 0.5f; 210 | 211 | var color = GetColor(); 212 | Container.Layer.BackgroundColor = new CGColor((nfloat)color.R, (nfloat)color.G, (nfloat)color.B, (nfloat)0.2); 213 | } 214 | } 215 | catch (Exception ex) 216 | { 217 | Console.WriteLine("Cannot set property on attached control. Error: {0}", ex.Message); 218 | } 219 | } 220 | 221 | protected override void OnDetached() 222 | { 223 | } 224 | 225 | private Color GetColor() 226 | { 227 | var currentSpan = (int)DateTime.Now.Second / 10; 228 | 229 | switch(currentSpan) 230 | { 231 | case 0: 232 | return Color.Blue; 233 | case 1: 234 | return Color.Red; 235 | case 2: 236 | return Color.Brown; 237 | case 3: 238 | return Color.Aqua; 239 | case 4: 240 | return Color.Green; 241 | default: 242 | case 5: 243 | return Color.Yellow; 244 | 245 | } 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /MyContacts.iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /MyContacts.iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDeviceFamily 6 | 7 | 1 8 | 2 9 | 10 | UISupportedInterfaceOrientations 11 | 12 | UIInterfaceOrientationPortrait 13 | UIInterfaceOrientationLandscapeLeft 14 | UIInterfaceOrientationLandscapeRight 15 | 16 | UISupportedInterfaceOrientations~ipad 17 | 18 | UIInterfaceOrientationPortrait 19 | UIInterfaceOrientationPortraitUpsideDown 20 | UIInterfaceOrientationLandscapeLeft 21 | UIInterfaceOrientationLandscapeRight 22 | 23 | MinimumOSVersion 24 | 11.2 25 | CFBundleDisplayName 26 | MyContacts 27 | CFBundleIdentifier 28 | com.yourcompany.MyContacts 29 | CFBundleVersion 30 | 1.0 31 | CFBundleIconFiles 32 | 33 | Icon-60@2x 34 | Icon-60@3x 35 | Icon-76 36 | Icon-76@2x 37 | Default 38 | Default@2x 39 | Default-568h@2x 40 | Default-Portrait 41 | Default-Portrait@2x 42 | Icon-Small-40 43 | Icon-Small-40@2x 44 | Icon-Small-40@3x 45 | Icon-Small 46 | Icon-Small@2x 47 | Icon-Small@3x 48 | 49 | UILaunchStoryboardName 50 | LaunchScreen 51 | CFBundleName 52 | MyContacts 53 | 54 | 55 | -------------------------------------------------------------------------------- /MyContacts.iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace MyContacts.iOS 9 | { 10 | public class Application 11 | { 12 | // This is the main entry point of the application. 13 | static void Main(string[] args) 14 | { 15 | // if you want to use a different Application Delegate class from "AppDelegate" 16 | // you can specify it here. 17 | UIApplication.Main(args, null, "AppDelegate"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MyContacts.iOS/MyContacts.iOS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | iPhoneSimulator 6 | {035E6526-E284-4E7C-8AC8-9A309BD1688A} 7 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | Exe 9 | MyContacts.iOS 10 | Resources 11 | MyContactsiOS 12 | 13 | 14 | 15 | true 16 | full 17 | false 18 | bin\iPhoneSimulator\Debug 19 | DEBUG;ENABLE_TEST_CLOUD; 20 | prompt 21 | 4 22 | false 23 | x86_64 24 | None 25 | true 26 | false 27 | iPhone Developer 28 | 29 | 30 | full 31 | true 32 | bin\iPhoneSimulator\Release 33 | prompt 34 | 4 35 | i386, x86_64 36 | false 37 | None 38 | 39 | 40 | true 41 | full 42 | false 43 | bin\iPhone\Debug 44 | DEBUG;ENABLE_TEST_CLOUD; 45 | prompt 46 | 4 47 | false 48 | ARMv7, ARM64 49 | Entitlements.plist 50 | true 51 | iPhone Developer 52 | true 53 | 11.2 54 | 55 | 56 | full 57 | true 58 | bin\iPhone\Release 59 | prompt 60 | 4 61 | Entitlements.plist 62 | ARMv7, ARM64 63 | false 64 | iPhone Developer 65 | 66 | 67 | none 68 | True 69 | bin\iPhone\Ad-Hoc 70 | prompt 71 | 4 72 | False 73 | ARMv7, ARM64 74 | True 75 | Automatic:AdHoc 76 | iPhone Developer 77 | 78 | 79 | none 80 | True 81 | bin\iPhone\AppStore 82 | prompt 83 | 4 84 | False 85 | ARMv7, ARM64 86 | Automatic:AppStore 87 | iPhone Distribution 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | MyContacts 103 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE} 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll 131 | 132 | 133 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll 134 | 135 | 136 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll 137 | 138 | 139 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /MyContacts.iOS/MyContacts.iOS.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Simulator 5 | iPhone 7 iOS 11.2 6 | 7 | -------------------------------------------------------------------------------- /MyContacts.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyContacts.iOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyContacts.iOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Default-Portrait.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Default-Portrait@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Default.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Default@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-60@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-60@3x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-76.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-76@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-Small-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-Small-40.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-Small.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-Small@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/Icon-Small@3x.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/star.png -------------------------------------------------------------------------------- /MyContacts.iOS/Resources/star@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/Resources/star@2x.png -------------------------------------------------------------------------------- /MyContacts.iOS/iTunesArtwork: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/iTunesArtwork -------------------------------------------------------------------------------- /MyContacts.iOS/iTunesArtwork@2x: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts.iOS/iTunesArtwork@2x -------------------------------------------------------------------------------- /MyContacts.iOS/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /MyContacts.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26228.4 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyContacts", "MyContacts\MyContacts.csproj", "{F7E62AA7-D013-43ED-A5DE-16792269C3BE}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyContacts.iOS", "MyContacts.iOS\MyContacts.iOS.csproj", "{035E6526-E284-4E7C-8AC8-9A309BD1688A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyContacts.Droid", "MyContacts.Droid\MyContacts.Droid.csproj", "{AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyContacts.UWP", "MyContacts.UWP\MyContacts.UWP.csproj", "{5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|ARM = Debug|ARM 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|ARM = Release|ARM 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Debug|ARM.ActiveCfg = Debug|Any CPU 27 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Debug|ARM.Build.0 = Debug|Any CPU 28 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Debug|x86.ActiveCfg = Debug|Any CPU 29 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Debug|x86.Build.0 = Debug|Any CPU 30 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Release|ARM.ActiveCfg = Release|Any CPU 33 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Release|ARM.Build.0 = Release|Any CPU 34 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Release|x86.ActiveCfg = Release|Any CPU 35 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE}.Release|x86.Build.0 = Release|Any CPU 36 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator 37 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator 38 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Debug|ARM.ActiveCfg = Debug|iPhone 39 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Debug|ARM.Build.0 = Debug|iPhone 40 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator 41 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Debug|x86.Build.0 = Debug|iPhoneSimulator 42 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator 43 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Release|Any CPU.Build.0 = Release|iPhoneSimulator 44 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Release|ARM.ActiveCfg = Release|iPhone 45 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Release|ARM.Build.0 = Release|iPhone 46 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Release|x86.ActiveCfg = Release|iPhoneSimulator 47 | {035E6526-E284-4E7C-8AC8-9A309BD1688A}.Release|x86.Build.0 = Release|iPhoneSimulator 48 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 51 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|ARM.ActiveCfg = Debug|Any CPU 52 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|ARM.Build.0 = Debug|Any CPU 53 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|ARM.Deploy.0 = Debug|Any CPU 54 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|x86.ActiveCfg = Debug|Any CPU 55 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|x86.Build.0 = Debug|Any CPU 56 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Debug|x86.Deploy.0 = Debug|Any CPU 57 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|Any CPU.Deploy.0 = Release|Any CPU 60 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|ARM.ActiveCfg = Release|Any CPU 61 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|ARM.Build.0 = Release|Any CPU 62 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|ARM.Deploy.0 = Release|Any CPU 63 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|x86.ActiveCfg = Release|Any CPU 64 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|x86.Build.0 = Release|Any CPU 65 | {AE4ADBDC-F8FD-47EC-935C-6EAD95335A40}.Release|x86.Deploy.0 = Release|Any CPU 66 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|Any CPU.ActiveCfg = Debug|x86 67 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|Any CPU.Build.0 = Debug|x86 68 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|Any CPU.Deploy.0 = Debug|x86 69 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|ARM.ActiveCfg = Debug|ARM 70 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|ARM.Build.0 = Debug|ARM 71 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|ARM.Deploy.0 = Debug|ARM 72 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|x86.ActiveCfg = Debug|x86 73 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|x86.Build.0 = Debug|x86 74 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Debug|x86.Deploy.0 = Debug|x86 75 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|Any CPU.ActiveCfg = Release|x86 76 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|Any CPU.Build.0 = Release|x86 77 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|Any CPU.Deploy.0 = Release|x86 78 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|ARM.ActiveCfg = Release|ARM 79 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|ARM.Build.0 = Release|ARM 80 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|ARM.Deploy.0 = Release|ARM 81 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|x86.ActiveCfg = Release|x86 82 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|x86.Build.0 = Release|x86 83 | {5DD83C16-1132-4ACD-B9C4-93D9D33A4E0C}.Release|x86.Deploy.0 = Release|x86 84 | EndGlobalSection 85 | GlobalSection(SolutionProperties) = preSolution 86 | HideSolutionNode = FALSE 87 | EndGlobalSection 88 | EndGlobal 89 | -------------------------------------------------------------------------------- /MyContacts/AllContacts.xaml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /MyContacts/AllContacts.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using Xamarin.Forms; 8 | using System.Threading; 9 | using System.Windows.Input; 10 | using System.ComponentModel; 11 | using System.Collections.ObjectModel; 12 | 13 | namespace MyContacts 14 | { 15 | public partial class AllContacts : ContentPage 16 | { 17 | public AllContacts() 18 | { 19 | InitializeComponent(); 20 | 21 | BindingContext = new AllContactsViewModel(); 22 | 23 | allContacts.BindingContextChanged += (sender, e) => { 24 | var change = e; 25 | }; 26 | 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /MyContacts/AllContactsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | using System.Collections.Generic; 5 | using System.Collections.Specialized; 6 | using System.Windows.Input; 7 | using Xamarin.Forms; 8 | using System.Linq; 9 | using System.Collections.ObjectModel; 10 | using System.Threading.Tasks; 11 | 12 | namespace MyContacts 13 | { 14 | public interface IPlayerService 15 | { 16 | Task> GetPlayersAsync(); 17 | } 18 | 19 | public class PlayersService : IPlayerService 20 | { 21 | private List _contacts = new List(); 22 | 23 | int callCount = 0; 24 | 25 | public Task> GetPlayersAsync() 26 | { 27 | if (!_contacts.Any()) 28 | { 29 | _contacts = new List(PlayerFactory.Players); 30 | } 31 | else 32 | { 33 | AddPlayer(); 34 | } 35 | 36 | //_contacts[callCount++].Position += "-Updated"; 37 | 38 | return Task.FromResult(new List(_contacts.Select(item=>item.Clone())) as IEnumerable); 39 | } 40 | 41 | IEnumerator _enumerator = null; 42 | 43 | private void AddPlayer() 44 | { 45 | if (_enumerator == null) 46 | { 47 | _enumerator = PlayerFactory.GetPlayer().GetEnumerator(); 48 | _enumerator.MoveNext(); 49 | } 50 | 51 | _contacts.Add(_enumerator.Current); 52 | 53 | //SetProperty(ref _allContacts, new List(AllContacts), nameof(AllContacts)); 54 | 55 | _enumerator.MoveNext(); 56 | } 57 | } 58 | 59 | public class AllContactsViewModel: ObservableObject 60 | { 61 | private ObservableListCollection _allContacts = new ObservableListCollection(); 62 | 63 | private IEnumerable> _groupedContacts = null; 64 | 65 | private ObservableListGroupCollection _grouppedCollection = null; 66 | 67 | private PlayersService _service = new PlayersService(); 68 | 69 | private Command _editCommand; 70 | 71 | private Command _updateCommand; 72 | 73 | private bool _allowOrdering; 74 | 75 | public IEnumerable> GroupedContacts { 76 | get 77 | { 78 | return _groupedContacts; 79 | } 80 | set 81 | { 82 | SetProperty(ref _groupedContacts, value); 83 | } 84 | } 85 | 86 | public ObservableListGroupCollection GroupedCollection 87 | { 88 | get 89 | { 90 | return _grouppedCollection; 91 | } 92 | set 93 | { 94 | SetProperty(ref _grouppedCollection, value); 95 | } 96 | } 97 | 98 | public ObservableListCollection AllContacts 99 | { 100 | get 101 | { 102 | return _allContacts; 103 | } 104 | set 105 | { 106 | SetProperty(ref _allContacts, value); 107 | } 108 | } 109 | 110 | public bool AllowOrdering 111 | { 112 | get 113 | { 114 | return _allowOrdering; 115 | } 116 | set 117 | { 118 | SetProperty(ref _allowOrdering, value); 119 | } 120 | } 121 | 122 | public ICommand EditCommand 123 | { 124 | get 125 | { 126 | return _editCommand; 127 | } 128 | } 129 | 130 | public ICommand UpdateCommand 131 | { 132 | get 133 | { 134 | return _updateCommand; 135 | } 136 | } 137 | 138 | public AllContactsViewModel() 139 | { 140 | _editCommand = new Command(() => { AllowOrdering = !AllowOrdering; }); 141 | _updateCommand = new Command(async () => await UpdatePlayers()); 142 | 143 | _allContacts = new ObservableListCollection(Enumerable.Empty(), new PersonNameComparer(), (person, update) => 144 | { 145 | person.LoadData(update); 146 | return true; 147 | }); 148 | 149 | _allContacts.OrderChanged += (sender, e) => { 150 | int jersey = 1; 151 | foreach(var item in _allContacts) 152 | { 153 | item.Jersey = jersey++; 154 | } 155 | }; 156 | 157 | _grouppedCollection = new ObservableListGroupCollection( 158 | Enumerable.Empty(), 159 | item => item.Position, 160 | new PersonNameComparer(), 161 | (person, update) => 162 | { 163 | person.LoadData(update); 164 | return true; 165 | }); 166 | 167 | UpdatePlayers().ConfigureAwait(false); 168 | } 169 | 170 | private async Task UpdatePlayers() 171 | { 172 | IEnumerable serviceResult = Enumerable.Empty(); 173 | 174 | try 175 | { 176 | serviceResult = await _service.GetPlayersAsync(); 177 | } 178 | catch(Exception ex) 179 | { 180 | // TODO: 181 | } 182 | 183 | if(serviceResult?.Any()??false) 184 | { 185 | _allContacts.UpdateRange(serviceResult); 186 | 187 | GroupedContacts = serviceResult.GroupBy(item => item.Position); 188 | GroupedCollection.UpdateItems(serviceResult); 189 | //var newItems = serviceResult.Where(item => !AllContacts.Any(contact => item.Name == contact.Name)); 190 | 191 | //var updatedItems = serviceResult.Where(item => AllContacts.Any(contact => item.Name == contact.Name)); 192 | 193 | //foreach (var updateItem in updatedItems) 194 | //{ 195 | // var existingItem = AllContacts.FirstOrDefault(contact => contact.Name == updateItem.Name); 196 | // existingItem.LoadData(updateItem); 197 | //} 198 | 199 | //foreach(var item in newItems) 200 | //{ 201 | // AllContacts.Add(item); 202 | //} 203 | } 204 | } 205 | 206 | int updateCount = 0; 207 | 208 | private void UpdatePlayer() 209 | { 210 | AllContacts[updateCount].Position = AllContacts[updateCount].Position + "(Updated)"; 211 | 212 | if (updateCount++ > 10) 213 | { 214 | updateCount = 0; 215 | } 216 | } 217 | } 218 | 219 | /// 220 | /// Observable object with INotifyPropertyChanged implemented 221 | /// 222 | public class ObservableObject : INotifyPropertyChanged 223 | { 224 | 225 | /// 226 | /// Occurs when property changed. 227 | /// 228 | public event PropertyChangedEventHandler PropertyChanged; 229 | 230 | /// 231 | /// Sets the property. 232 | /// 233 | /// true, if property was set, false otherwise. 234 | /// Backing store. 235 | /// Incoming new value. 236 | /// Property name. 237 | /// On changed. 238 | /// The 1st type parameter. 239 | protected bool SetProperty( 240 | ref T backingStore, 241 | T value, 242 | [CallerMemberName]string propertyName = "", 243 | Action onChanged = null) 244 | { 245 | if (EqualityComparer.Default.Equals(backingStore, value)) 246 | { 247 | return false; 248 | } 249 | 250 | backingStore = value; 251 | onChanged?.Invoke(); 252 | OnPropertyChanged(propertyName); 253 | return true; 254 | } 255 | 256 | /// 257 | /// Raises the property changed event. 258 | /// 259 | /// Property name. 260 | protected void OnPropertyChanged([CallerMemberName]string propertyName = "") 261 | { 262 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /MyContacts/App.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | using System.Linq; 3 | 4 | namespace MyContacts 5 | { 6 | public class App : Application 7 | { 8 | public App() 9 | { 10 | MainPage = new NavigationPage(new AllContacts()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MyContacts/ContactDetails.xaml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 45 | 46 | -------------------------------------------------------------------------------- /MyContacts/ContactDetails.xaml.cs: -------------------------------------------------------------------------------- 1 | using Xamarin.Forms; 2 | 3 | namespace MyContacts 4 | { 5 | public partial class ContactDetails : ContentPage 6 | { 7 | public ContactDetails(Person person) 8 | { 9 | BindingContext = person; 10 | InitializeComponent(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MyContacts/Converters/BirthdayConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | 4 | namespace MyContacts 5 | { 6 | /// 7 | /// Simple converter to take a DateTime and calculate how many years old it represents. 8 | /// 9 | public class BirthdayConverter : IValueConverter 10 | { 11 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 12 | { 13 | DateTime bday = (DateTime)value; 14 | DateTime today = DateTime.Today; 15 | int age = today.Year - bday.Year; 16 | return (bday > today.AddYears(-age)) ? age-1 : age; 17 | } 18 | 19 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /MyContacts/Converters/GenderToIndexConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | using System.Globalization; 4 | 5 | namespace MyContacts 6 | { 7 | public class GenderToIndexConverter : IValueConverter 8 | { 9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 10 | { 11 | Gender gender = (Gender)value; 12 | if (targetType != typeof(int)) 13 | throw new Exception("GenderConverter.Convert expected integer targetType."); 14 | return (int)gender; 15 | } 16 | 17 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | int index = (int)value; 20 | if (targetType != typeof(Gender)) 21 | throw new Exception("GenderConverter.ConvertBack expected Gender targetType"); 22 | return (Gender)index; 23 | } 24 | } 25 | 26 | /// 27 | /// Simple converter to take a DateTime and calculate how many years old it represents. 28 | /// 29 | public class BirthdayConverter : IValueConverter 30 | { 31 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 32 | { 33 | DateTime bday = (DateTime)value; 34 | DateTime today = DateTime.Today; 35 | int age = today.Year - bday.Year; 36 | return (bday > today.AddYears(-age)) ? age - 1 : age; 37 | } 38 | 39 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 40 | { 41 | throw new NotImplementedException(); 42 | } } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /MyContacts/Converters/ImageResourceConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | 4 | namespace MyContacts 5 | { 6 | public class ImageResourceConverter : IValueConverter 7 | { 8 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 9 | { 10 | return ImageSource.FromUri(new Uri("https://tmssl.akamaized.net//images/portrait/header/" + (value ?? ""))); 11 | } 12 | 13 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 14 | { 15 | throw new NotSupportedException(); 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /MyContacts/Data/Gender.cs: -------------------------------------------------------------------------------- 1 | namespace MyContacts 2 | { 3 | public enum Gender { Male, Female }; 4 | 5 | } 6 | -------------------------------------------------------------------------------- /MyContacts/Data/Person.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace MyContacts 7 | { 8 | public class PersonNameComparer : IEqualityComparer 9 | { 10 | public bool Equals(Person x, Person y) 11 | { 12 | return x.Name == y.Name; 13 | } 14 | 15 | public int GetHashCode(Person obj) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | } 20 | 21 | public class Person : INotifyPropertyChanged 22 | { 23 | private string name; 24 | 25 | private string position; 26 | 27 | private DateTime dob; 28 | 29 | private Gender gender; 30 | 31 | private bool isFavorite; 32 | 33 | private int _jersey; 34 | 35 | public event PropertyChangedEventHandler PropertyChanged = delegate {}; 36 | 37 | public string HeadshotUrl { get; set; } 38 | 39 | public string Name { 40 | get { return name; } 41 | set { SetProperty(ref name, value); } 42 | } 43 | 44 | public string Position 45 | { 46 | get { return position; } 47 | set { SetProperty(ref position, value); } 48 | } 49 | 50 | public DateTime Dob { 51 | get { return dob; } 52 | set { SetProperty(ref dob, value); } 53 | } 54 | 55 | public Gender Gender { 56 | get { return gender; } 57 | set { SetProperty(ref gender, value); } 58 | } 59 | 60 | public bool IsFavorite { 61 | get { return isFavorite; } 62 | set { SetProperty(ref isFavorite, value); } 63 | } 64 | 65 | public int Jersey 66 | { 67 | get { return _jersey; } 68 | set { SetProperty(ref _jersey, value); } 69 | } 70 | 71 | /// 72 | /// Method to compare and replace a field's value and raise a 73 | /// PropertyChanged notification if it was altered. 74 | /// 75 | /// true, if field was set, false otherwise. 76 | /// Field. 77 | /// Value. 78 | /// Property name. 79 | /// Field type. 80 | bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = "") 81 | { 82 | if (!object.Equals(field, value)) { 83 | field = value; 84 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 85 | return true; 86 | } 87 | return false; 88 | } 89 | 90 | public override string ToString() 91 | { 92 | return this.Name; 93 | } 94 | 95 | internal void LoadData(Person item) 96 | { 97 | Position = item.Position; 98 | Dob = item.Dob; 99 | Gender = item.Gender; 100 | Jersey = item.Jersey; 101 | IsFavorite = item.IsFavorite; 102 | HeadshotUrl = item.HeadshotUrl; 103 | } 104 | 105 | internal Person Clone() 106 | { 107 | var target = new Person(); 108 | target.Name = Name; 109 | target.LoadData(this); 110 | 111 | return target; 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /MyContacts/Data/PlayerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | 5 | namespace MyContacts 6 | { 7 | public static class PlayerFactory 8 | { 9 | public static IList Players { get; private set; } 10 | 11 | public static IEnumerable GetPlayer() 12 | { 13 | yield return new Person 14 | { 15 | Name = "Souza", 16 | HeadshotUrl = "73741-1473554668.jpg?lm=1473554751", 17 | Position = "Midfield", 18 | Dob = new DateTime(1989, 2, 11), 19 | IsFavorite = false, 20 | Jersey = 7 21 | }; 22 | yield return new Person 23 | { 24 | Name = "Jermaine Lens", 25 | HeadshotUrl = "38497-1473555279.jpg?lm=1473555301", 26 | Position = "Midfield", 27 | Dob = new DateTime(1987, 10, 24), 28 | IsFavorite = false, 29 | Jersey = 8 30 | }; 31 | yield return new Person 32 | { 33 | Name = "Miroslav Stoch", 34 | HeadshotUrl = "45559-1473555016.jpg?lm=1473555042", 35 | Position = "Midfield", 36 | Dob = new DateTime(1989, 10, 19), 37 | IsFavorite = false, 38 | Jersey = 9 39 | }; 40 | yield return new Person 41 | { 42 | Name = "Moussa Sow", 43 | HeadshotUrl = "22382-1473555184.jpg?lm=1473555202", 44 | Position = "Forward", 45 | Dob = new DateTime(1986, 01, 19), 46 | IsFavorite = false, 47 | Jersey = 10 48 | }; 49 | yield return new Person 50 | { 51 | Name = "Robin van Persie", 52 | HeadshotUrl = "4380-1473555404.jpg?lm=1473555436", 53 | Position = "Forward", 54 | Dob = new DateTime(1983, 9, 6), 55 | IsFavorite = false, 56 | Jersey = 11 57 | }; 58 | } 59 | 60 | static PlayerFactory() 61 | { 62 | Players = new List 63 | { 64 | new Person 65 | { 66 | Name = "Volkan Demirel", 67 | HeadshotUrl = "7079-1473554155.jpg?lm=1473554223", 68 | Position = "Keeper", 69 | Dob = new DateTime(1981, 11, 27), 70 | IsFavorite = false, 71 | Jersey = 1 72 | }, 73 | new Person 74 | { 75 | Name = "Simon Kjaer", 76 | HeadshotUrl = "48859-1473554328.jpg?lm=1473554361", 77 | Position = "Defender", 78 | Dob = new DateTime(1989, 3, 26), 79 | IsFavorite = true, 80 | Jersey = 2 81 | }, 82 | new Person 83 | { 84 | Name = "Martin Skrtel", 85 | HeadshotUrl = "24180-1473554340.jpg?lm=1473554385", 86 | Position = "Defender", 87 | Dob = new DateTime(1984, 12, 15), 88 | IsFavorite = true, 89 | Jersey = 3 90 | }, 91 | new Person 92 | { 93 | Name = "Hasan Ali Kaldirim", 94 | HeadshotUrl = "55605-1473554474.jpg?lm=1473554515", 95 | Position = "Defender", 96 | Dob = new DateTime(1989, 12, 9), 97 | IsFavorite = true, 98 | Jersey = 4 99 | }, 100 | 101 | new Person 102 | { 103 | Name = "Sezer Ozbayrakli", 104 | HeadshotUrl = "169873-1473554503.jpg?lm=1473554574", 105 | Position = "Defender", 106 | Dob = new DateTime(1990, 01, 23), 107 | IsFavorite = false, 108 | Jersey = 5 109 | }, 110 | 111 | new Person 112 | { 113 | Name = "Mehmet Topal", 114 | HeadshotUrl = "44402-1473554660.jpg?lm=1473554723", 115 | Position = "Defensive Midfield", 116 | Dob = new DateTime(1986, 3, 3), 117 | IsFavorite = false, 118 | Jersey = 6 119 | } 120 | }; 121 | } 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /MyContacts/Effects/DropShadowEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Xamarin.Forms; 4 | 5 | namespace MyContacts.Effects 6 | { 7 | public class ViewShadowEffect : RoutingEffect 8 | { 9 | public float Radius { get; set; } 10 | 11 | public Color Color { get; set; } 12 | 13 | public float DistanceX { get; set; } 14 | 15 | public float DistanceY { get; set; } 16 | 17 | public ViewShadowEffect() : base("CubiSoft.DropShadowEffect") 18 | { 19 | } 20 | } 21 | 22 | public static class Sorting 23 | { 24 | public static readonly BindableProperty IsSortableProperty = 25 | BindableProperty.CreateAttached("IsSortable", typeof(bool), typeof(ListViewSortableEffect), false, 26 | propertyChanged: OnIsSortableChanged); 27 | 28 | public static bool GetIsSortable(BindableObject view) 29 | { 30 | return (bool)view.GetValue(IsSortableProperty); 31 | } 32 | 33 | public static void SetIsSortable(BindableObject view, bool value) 34 | { 35 | view.SetValue(IsSortableProperty, value); 36 | } 37 | 38 | static void OnIsSortableChanged(BindableObject bindable, object oldValue, object newValue) 39 | { 40 | var view = bindable as ListView; 41 | if (view == null) 42 | { 43 | return; 44 | } 45 | 46 | if (!view.Effects.Any(item => item is ListViewSortableEffect)) 47 | { 48 | view.Effects.Add(new ListViewSortableEffect()); 49 | } 50 | } 51 | 52 | class ListViewSortableEffect : RoutingEffect 53 | { 54 | public ListViewSortableEffect() : base("CubiSoft.ListViewSortableEffect") 55 | { 56 | 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MyContacts/Images/Apu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Apu.gif -------------------------------------------------------------------------------- /MyContacts/Images/Bart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Bart.gif -------------------------------------------------------------------------------- /MyContacts/Images/ComicBookGuy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/ComicBookGuy.gif -------------------------------------------------------------------------------- /MyContacts/Images/Homer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Homer.gif -------------------------------------------------------------------------------- /MyContacts/Images/Krusty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Krusty.gif -------------------------------------------------------------------------------- /MyContacts/Images/Lisa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Lisa.gif -------------------------------------------------------------------------------- /MyContacts/Images/Maggie.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Maggie.gif -------------------------------------------------------------------------------- /MyContacts/Images/Marge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Marge.gif -------------------------------------------------------------------------------- /MyContacts/Images/Milhouse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/Milhouse.gif -------------------------------------------------------------------------------- /MyContacts/Images/MoeSzyslak.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/MoeSzyslak.gif -------------------------------------------------------------------------------- /MyContacts/Images/MrBurns.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/MrBurns.gif -------------------------------------------------------------------------------- /MyContacts/Images/SideshowBob.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/SideshowBob.gif -------------------------------------------------------------------------------- /MyContacts/Images/WaylonSmithers.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canbilgin/DragAndDropSort/96652a7c21730f5b34f6773c7b5294b9b3adf95c/MyContacts/Images/WaylonSmithers.gif -------------------------------------------------------------------------------- /MyContacts/MyContacts.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10.0 6 | Debug 7 | AnyCPU 8 | {F7E62AA7-D013-43ED-A5DE-16792269C3BE} 9 | Library 10 | Properties 11 | MyContacts 12 | MyContacts 13 | v4.5 14 | Profile259 15 | 512 16 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 18 | 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | AllContacts.xaml 40 | 41 | 42 | 43 | ContactDetails.xaml 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Designer 58 | MSBuild:UpdateDesignTimeXaml 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | MSBuild:UpdateDesignTimeXaml 79 | Designer 80 | 81 | 82 | 83 | 84 | 85 | ..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll 86 | 87 | 88 | ..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll 89 | 90 | 91 | ..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /MyContacts/MyFacade.SecondPart.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MyContacts 8 | { 9 | public partial class MyFacade : IFacade 10 | { 11 | public void Method4() 12 | { 13 | throw new NotImplementedException(); 14 | } 15 | 16 | public void Method5() 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | public void Method6() 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MyContacts/MyFacade.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MyContacts 8 | { 9 | public interface IFacade 10 | { 11 | void Method1(); 12 | void Method2(); 13 | void Method3(); 14 | void Method4(); 15 | void Method5(); 16 | void Method6(); 17 | } 18 | 19 | public partial class MyFacade : IFacade 20 | { 21 | public void Method1() 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | 26 | public void Method2() 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | 31 | public void Method3() 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /MyContacts/ObservableListCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Collections.Specialized; 5 | using System.ComponentModel; 6 | using System.Linq; 7 | 8 | namespace MyContacts 9 | { 10 | public class ObservableListGroupCollection : ObservableListCollection> 11 | { 12 | private Func _groupKeySelector; 13 | 14 | private IEqualityComparer _equivalenceComparer; 15 | 16 | private Func _updateFunction; 17 | 18 | public ObservableListGroupCollection( 19 | IEnumerable collection, 20 | Func keySelector, 21 | IEqualityComparer equivalence = null, 22 | Func updateCallback = null) 23 | { 24 | _groupKeySelector = keySelector; 25 | _equivalenceComparer = equivalence; 26 | _updateFunction = updateCallback; 27 | 28 | UpdateItems(collection); 29 | } 30 | 31 | public void UpdateItems(IEnumerable items) 32 | { 33 | var grouppedItems = items.GroupBy(_groupKeySelector); 34 | 35 | var startIndex = Count; 36 | 37 | var newItems = new List>(); 38 | 39 | foreach (var group in grouppedItems) 40 | { 41 | var section = Items.FirstOrDefault(item => item.Key.Equals(group.Key)); 42 | 43 | if (section == null) 44 | { 45 | var newGroup = new ObservableListGroup(group.Key, group, _equivalenceComparer, _updateFunction); 46 | newItems.Add(newGroup); 47 | Items.Add(newGroup); 48 | } 49 | else 50 | { 51 | section.UpdateRange(group); 52 | } 53 | } 54 | 55 | if (newItems.Any()) 56 | { 57 | OnPropertyChanged(new PropertyChangedEventArgs("Count")); 58 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems, startIndex)); 59 | } 60 | } 61 | } 62 | 63 | /// 64 | /// Grouping of items 65 | /// 66 | public class ObservableListGroup : ObservableListCollection 67 | { 68 | public TKey Key { get; } 69 | 70 | public ObservableListGroup(TKey key, IEnumerable items, IEqualityComparer equivalence = null, Func updateCallback = null) 71 | : base(Enumerable.Empty(), equivalence, updateCallback) 72 | { 73 | Key = key; 74 | UpdateRange(items); 75 | } 76 | } 77 | 78 | /// 79 | /// Used by bound collections to expose ordering methods/events 80 | /// 81 | public interface IOrderable 82 | { 83 | /// 84 | /// Event fired when the items in the collection are re-ordered. 85 | /// 86 | event EventHandler OrderChanged; 87 | 88 | /// 89 | /// Used to change the item orders in an enumerable 90 | /// 91 | /// 92 | /// The old index of the item. 93 | /// 94 | /// 95 | /// The new index of the item. 96 | /// 97 | void ChangeOrdinal(int oldIndex, int newIndex); 98 | } 99 | 100 | /// 101 | /// ObservableCollection implementation for updating and adding items 102 | /// 103 | /// Entity type 104 | public class ObservableListCollection : ObservableCollection, IOrderable 105 | { 106 | private IEqualityComparer _equivalenceComparer; 107 | 108 | private Func _updateFunction; 109 | 110 | /// 111 | /// Initializes a new instance of the class. 112 | /// 113 | public ObservableListCollection() : base() 114 | { 115 | } 116 | public event EventHandler OrderChanged; 117 | 118 | public void ChangeOrdinal(int oldIndex, int newIndex) 119 | { 120 | var priorIndex = oldIndex; 121 | var latterIndex = newIndex; 122 | 123 | var changedItem = Items[oldIndex]; 124 | if (newIndex < oldIndex) 125 | { 126 | // add one to where we delete, because we're increasing the index by inserting 127 | priorIndex += 1; 128 | } 129 | else 130 | { 131 | // add one to where we insert, because we haven't deleted the original yet 132 | latterIndex += 1; 133 | } 134 | 135 | Items.Insert(latterIndex, changedItem); 136 | Items.RemoveAt(priorIndex); 137 | 138 | OrderChanged?.Invoke(this, EventArgs.Empty); 139 | 140 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, changedItem, newIndex, oldIndex)); 141 | } 142 | 143 | /// 144 | /// Initializes a new instance of the class. 145 | /// 146 | /// collection: The collection from which the elements are copied. 147 | /// The collection parameter cannot be null. 148 | public ObservableListCollection(IEnumerable collection, IEqualityComparer equivalence = null, Func updateCallback = null) 149 | : base(collection) 150 | { 151 | _equivalenceComparer = equivalence ?? EqualityComparer.Default; 152 | _updateFunction = updateCallback; 153 | } 154 | 155 | /// 156 | /// Updates or adds the elements of the specified collection to the end of the ObservableCollection(Of T). 157 | /// 158 | /// 159 | /// The collection to be added. 160 | /// 161 | public void UpdateRange(IEnumerable collection) 162 | { 163 | if (collection == null) 164 | { 165 | throw new ArgumentNullException(nameof(collection)); 166 | } 167 | 168 | CheckReentrancy(); 169 | 170 | int startIndex = Count; 171 | 172 | var updatedItems = collection.Where(item => Items.Any(contact => _equivalenceComparer.Equals(contact, item))).ToList(); 173 | 174 | bool anyItemUpdated = false; 175 | 176 | foreach (var updateItem in updatedItems) 177 | { 178 | var existingItem = Items.FirstOrDefault(contact => _equivalenceComparer.Equals(contact, updateItem)); 179 | 180 | // TODO: We can fire NotifyCollectionChanged.Update if needed depending on anyItemUpdated. 181 | anyItemUpdated = anyItemUpdated | _updateFunction?.Invoke(existingItem, updateItem) ?? false; 182 | } 183 | 184 | var newItems = collection.Where(item => !Items.Any(contact => _equivalenceComparer.Equals(contact, item))).ToList(); 185 | 186 | if (!newItems.Any()) 187 | { 188 | return; 189 | } 190 | 191 | foreach (var item in newItems) 192 | { 193 | Items.Add(item); 194 | } 195 | 196 | OnPropertyChanged(new PropertyChangedEventArgs("Count")); 197 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems, startIndex)); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /MyContacts/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("MyContacts")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("MyContacts")] 14 | [assembly: AssemblyCopyright("Copyright © 2014")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | -------------------------------------------------------------------------------- /MyContacts/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DragAndDropSort 2 | Sortable Drag and Drop Sample 3 | 4 | Drag’n’Drop is just another way the user can interact with the data in a mobile application (quite a powerful one I might add). It can be used to move items in a list from one category to another or simply to adjust the priority of list items. In this context, ListView ordering with drag and drop can be treated as a user input and in the world of MVVM and Xamarin.Forms these changes should be reflected on the ViewModel. 5 | 6 | Android | iOS 7 | --- | --- 8 | ![alt text](https://canbilgin.files.wordpress.com/2018/03/androiddragdropwithanimation.gif?w=450&zoom=2 "Android Sample") | ![alt text](https://canbilgin.files.wordpress.com/2018/03/sorting2.gif?w=668&zoom=2 "iOS Sample") 9 | 10 | In this sample, we have a drag and drop reordering functionality for iOS and Android platforms on Xamarin.Forms. 11 | 12 | More information about the implementation can be found at: 13 | 14 | * Android: [Re-Order List View Items with Drag'n'Drop - II](https://canbilgin.wordpress.com/2018/03/17/re-order-listview-items-with-drag-drop-ii/) 15 | * iOS: [Re-Order List View Items with Drag'n'Drop - I](https://canbilgin.wordpress.com/2018/03/04/re-order-listview-items-with-drag-drop-i/) 16 | --------------------------------------------------------------------------------