public ComposeBubble(long time, BubbleDirection direction, Service service, VisualBubble bubbleToSend, Contact.ID[] ids) : base(time, direction, service) { Ids = ids; BubbleToSend = bubbleToSend; }
public static void UpdateLastBubbleOrAndLastModifiedIndex(string bubbleGroupId, VisualBubble lastBubble = null, long lastModifiedIndex = -1) { lock (_dbLock) { if (lastBubble == null && lastModifiedIndex == -1) return; using (var db = new SqlDatabase<Entry>(Location, false)) { if (!db.Failed) { foreach (var item in db.Store.Where(x => !x.Unified && x.Guid == bubbleGroupId)) { if (lastBubble != null) { item.LastBubble = SerializeBubble(lastBubble); item.LastBubbleGuid = lastBubble.ID; } if (lastModifiedIndex != -1) { item.LastModifiedIndex = lastModifiedIndex; } db.Update(item); } } } } }
public static string GetMediaFilePathIfPossible(VisualBubble bubble) { var imageBubble = bubble as ImageBubble; if (imageBubble != null) { return imageBubble.ImagePath; } var videoBubble = bubble as VideoBubble; if (videoBubble != null) { return videoBubble.VideoPath; } var audioBubble = bubble as AudioBubble; if (audioBubble != null) { return audioBubble.AudioPath; } var fileBubble = bubble as FileBubble; if (fileBubble != null) { return fileBubble.Path; } return null; }
public static Task JustQueue(VisualBubble visualBubble) { return Task.Factory.StartNew(() => { var entry = Add(visualBubble); }); }
public bool LoadBubblesComparer(VisualBubble localBubble, VisualBubble agentBubble) { if (localBubble.IdService == agentBubble.IdService) { return true; } return false; }
public static BubbleGroup AddNewIfNotExist(VisualBubble bubble, bool updateUi = false) { var group = BubbleGroupManager.FindWithAddress(bubble.Service, bubble.Address); if (@group != null) return null; return AddNewInternal(bubble, updateUi); }
public UnifiedBubbleGroup(List<BubbleGroup> groups, BubbleGroup primaryGroup, VisualBubble initialBubble, string id = null) : base(initialBubble, id, false) { _unifiedService = initialBubble.Service; Groups = groups; PrimaryGroup = primaryGroup; SendingGroup = primaryGroup; }
public bool LoadBubblesComparer(VisualBubble localBubble, VisualBubble agentBubble) { DebugPrint("###### Local bubble id service " + localBubble.IdService); DebugPrint("###### agent bubble id service " + agentBubble.IdService); if (localBubble.IdService == agentBubble.IdService) { return true; } return false; }
protected internal void OnBubbleUpdated(VisualBubble bubble, BubbleGroup group) { if (Bubbles.Count > BubblesCapSize) { Bubbles.RemoveAt(0); } var addedToEnd = false; for (int i = Bubbles.Count - 1; i >= 0; i--) { var nBubble = Bubbles[i]; if (nBubble.Time <= bubble.Time) { // adding it to the end, we can do a simple contract if (i == Bubbles.Count - 1) { addedToEnd = true; Bubbles.Add(bubble); if (bubble.Direction == Bubble.BubbleDirection.Incoming) { BubbleGroupSettingsManager.SetUnread(this, true); } } // inserting, do a full contract else { Bubbles.Insert(i + 1, bubble); } break; } // could not find a valid place to insert, then skip insertion. if (i == 0) { return; } } if (SendingGroup != group && addedToEnd) { SendingGroup = group; BubbleGroupEvents.RaiseSendingServiceChange(this); } RaiseBubbleInserted(bubble); }
public static void AddBubble(BubbleGroup group, VisualBubble b) { lock (OperationLock) { using (var ms = new MemoryStream()) { Serializer.Serialize(ms, b); var bubbleData = ms.ToArray(); var bubbleHeader = b.GetType().Name + ":" + b.ID + ":" + b.Time; var file = GetLocation(@group); using (var stream = File.Open(file, FileMode.Append, FileAccess.Write)) { BubbleGroupDatabasePrimitives.WriteBubbleData(stream, bubbleData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, bubbleHeader); } } } }
public static void ForwardCopyToMediaDirectoryIfNeeded(VisualBubble vb) { if (vb is TextBubble) return; if (vb is LocationBubble) return; var videoBubble = vb as VideoBubble; if (videoBubble != null) { if (IsInMediaLocation(videoBubble.VideoPath)) return; var path = CopyVideoToDisaVideoLocation(videoBubble.VideoPath); if (path == null) return; videoBubble.VideoPath = path; } var audioBubble = vb as AudioBubble; if (audioBubble != null) { if (IsInMediaLocation(audioBubble.AudioPath)) return; var path = CopyAudioToDisaAudioLocation(audioBubble.AudioPath); audioBubble.AudioPath = path; } var imageBubble = vb as ImageBubble; if (imageBubble != null) { if (IsInMediaLocation(imageBubble.ImagePath)) return; var path = CopyPhotoToDisaPictureLocation(imageBubble.ImagePath); if (path == null) return; imageBubble.ImagePath = path; } }
public static bool UpdateBubble(BubbleGroup group, VisualBubble bubble, int searchDepth = 100) { return UpdateBubble(@group, new[] { bubble }, searchDepth); }
public static bool InsertBubbleByTime(BubbleGroup group, VisualBubble bubble, int maxDepth = 1000) { return InsertBubblesByTime(@group, new [] { bubble }, maxDepth); }
public static void UpdateStatus(VisualBubble b, Bubble.BubbleStatus status, BubbleGroup group, bool updateBubbleGroupBubbles = true) { b.Status = status; BubbleGroupDatabase.UpdateBubble(@group, b); if (updateBubbleGroupBubbles) BubbleGroupEvents.RaiseBubblesUpdated(@group); BubbleGroupEvents.RaiseRefreshed(@group); }
public static bool Update(BubbleGroup group, VisualBubble[] bubbles, int bubbleDepth = 100) { return BubbleGroupDatabase.UpdateBubble(@group, bubbles, bubbleDepth); }
public void AddVisualBubbleIdServices(VisualBubble bubble) { bubble.IdService2 = NextMessageId; }
public static void UpdateStatus(VisualBubble[] bubbles, Bubble.BubbleStatus status, BubbleGroup group, bool updateBubbleGroupBubbles = true) { foreach (var bubble in bubbles) { bubble.Status = status; } BubbleGroupDatabase.UpdateBubble(@group, bubbles); if (updateBubbleGroupBubbles) BubbleGroupEvents.RaiseBubblesUpdated(@group); BubbleGroupEvents.RaiseRefreshed(@group); }
private static void FailBubbleIfPathDoesntExist(VisualBubble bubble) { var path = GetMediaFilePathIfPossible(bubble); if (String.IsNullOrWhiteSpace(path)) return; if (!File.Exists(path)) { throw new ServiceBubbleSendFailedException("Visual bubble media file path doesn't exist."); } }
private void AddQuotedMessageToBubble(Message replyMessage, VisualBubble bubble) { if (replyMessage == null) { return; } if(!string.IsNullOrEmpty(replyMessage.MessageProperty)) { bubble.QuotedType = VisualBubble.MediaType.Text; bubble.QuotedContext = replyMessage.MessageProperty; } else { var messageMedia = replyMessage.Media; var messageMediaPhoto = messageMedia as MessageMediaPhoto; var messageMediaDocument = messageMedia as MessageMediaDocument; var messageMediaGeo = messageMedia as MessageMediaGeo; var messageMediaVenue = messageMedia as MessageMediaVenue; var messageMediaContact = messageMedia as MessageMediaContact; if (messageMediaPhoto != null) { bubble.QuotedType = VisualBubble.MediaType.Image; bubble.HasQuotedThumbnail = true; bubble.QuotedThumbnail = GetCachedPhotoBytes(messageMediaPhoto.Photo); } if(messageMediaDocument != null) { var document = messageMediaDocument.Document as Document; if(document!=null) { if (document.MimeType.Contains("audio")) { bubble.QuotedType = VisualBubble.MediaType.Audio; bubble.QuotedSeconds = GetAudioTime(document); } else if (document.MimeType.Contains("video")) { bubble.QuotedType = VisualBubble.MediaType.File; bubble.QuotedContext = "Video"; } else { bubble.QuotedType = VisualBubble.MediaType.File; bubble.QuotedContext = GetDocumentFileName(document); } } } if(messageMediaGeo != null) { var geoPoint = messageMediaGeo.Geo as GeoPoint; if (geoPoint != null) { bubble.QuotedType = VisualBubble.MediaType.Location; bubble.QuotedContext = (int)geoPoint.Lat + "," + (int)geoPoint.Long; bubble.QuotedLocationLatitude = geoPoint.Lat; bubble.QuotedLocationLongitude = geoPoint.Long; bubble.HasQuotedThumbnail = true; } } if(messageMediaVenue != null) { var geoPoint = messageMediaVenue.Geo as GeoPoint; if (geoPoint != null) { bubble.QuotedType = VisualBubble.MediaType.Location; bubble.QuotedContext = messageMediaVenue.Title; bubble.QuotedLocationLatitude = geoPoint.Lat; bubble.QuotedLocationLongitude = geoPoint.Long; bubble.HasQuotedThumbnail = true; } } if(messageMediaContact != null) { bubble.QuotedType = VisualBubble.MediaType.Contact; bubble.QuotedContext = messageMediaContact.FirstName + " " + messageMediaContact.LastName; } } bubble.QuotedAddress = replyMessage.FromId.ToString(CultureInfo.InvariantCulture); bubble.QuotedIdService = replyMessage.Id.ToString(CultureInfo.InvariantCulture); }
public static bool Update(BubbleGroup group, VisualBubble visualBubble, int bubbleDepth = 100) { if (visualBubble.BubbleGroupReference != null) { BubbleGroupDatabase.UpdateBubble(visualBubble.BubbleGroupReference, visualBubble, bubbleDepth); return true; } var unifiedGroup = @group as UnifiedBubbleGroup; if (unifiedGroup == null) { BubbleGroupDatabase.UpdateBubble(@group, visualBubble, bubbleDepth); return true; } foreach (var innerGroup in unifiedGroup.Groups) { foreach (var bubble in innerGroup.Bubbles) { if (bubble.ID != visualBubble.ID) continue; BubbleGroupDatabase.UpdateBubble(innerGroup, visualBubble, bubbleDepth); return true; } } return false; }
private static bool IsBubbleSending(VisualBubble bubble) { if (bubble is NewBubble) { return false; } if (bubble.Status == Bubble.BubbleStatus.Waiting && bubble.Direction == Bubble.BubbleDirection.Outgoing) { return true; } return false; }
private static bool IsBubbleDownloading(VisualBubble bubble) { var imageBubble = bubble as ImageBubble; if (imageBubble != null) { return imageBubble.Transfer != null; } var videoBubble = bubble as VideoBubble; if (videoBubble != null) { return videoBubble.Transfer != null; } var audioBubble = bubble as AudioBubble; if (audioBubble != null) { return audioBubble.Transfer != null; } var fileBubble = bubble as FileBubble; if (fileBubble != null) { return fileBubble.Transfer != null; } return false; }
public DeliveredBubbleReceipt(long time, BubbleDirection direction, Service service, VisualBubble bubbleUpdated) : base(time, direction, service) { BubbleUpdated = bubbleUpdated; }
internal static BubbleGroup Group(VisualBubble vb, bool resend = false, bool insertAtBottom = false) { lock (BubbleGroupDatabase.OperationLock) { Utils.DebugPrint("Grouping an " + vb.Direction + " bubble on service " + vb.Service.Information.ServiceName); var theGroup = BubbleGroupManager.FindWithAddress(vb.Service, vb.Address); BubbleGroupFactory.LoadFullyIfNeeded(theGroup); var duplicate = false; var newGroup = false; if (theGroup == null) { Utils.DebugPrint(vb.Service.Information.ServiceName + " unable to find suitable group. Creating a new one."); theGroup = new BubbleGroup(vb, null, false); newGroup = true; Utils.DebugPrint("GUID of new group: " + theGroup.ID); vb.Service.NewBubbleGroupCreated(theGroup).ContinueWith(x => { // force the UI to refetch the photo theGroup.IsPhotoSetFromService = false; SendSubscribe(theGroup, true); BubbleGroupUpdater.Update(theGroup); }); BubbleGroupManager.BubbleGroupsAdd(theGroup); } else { if (resend) { if (vb.Status == Bubble.BubbleStatus.Failed) { UpdateStatus(vb, Bubble.BubbleStatus.Waiting, theGroup); } return theGroup; } var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId; if (visualBubbleServiceId != null && visualBubbleServiceId.DisctinctIncomingVisualBubbleIdServices()) { if (vb.IdService != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => x.GetType() == vb.GetType() && x.IdService == vb.IdService) != null; } if (!duplicate && vb.IdService2 != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => x.GetType() == vb.GetType() && x.IdService2 == vb.IdService2) != null; } } if (!duplicate) { Utils.DebugPrint(vb.Service.Information.ServiceName + " found a group. Adding."); if (insertAtBottom) { var lastBubble = theGroup.LastBubbleSafe(); if (lastBubble.Time > vb.Time) { vb.Time = lastBubble.Time; } } theGroup.InsertByTime(vb); } else { Utils.DebugPrint("Yuck. It's a duplicate bubble. No need to readd: " + vb.IdService + ", " + vb.IdService2); } } try { if (theGroup.IsParty && !string.IsNullOrWhiteSpace(vb.ParticipantAddressNickname)) { var participantAddressNicknamesArray = theGroup.ParticipantNicknames; if (participantAddressNicknamesArray == null) { participantAddressNicknamesArray = new DisaParticipantNickname[0]; } var participantAddressNicknames = participantAddressNicknamesArray.ToList(); var changed = false; var adding = true; foreach (var participantAddressNickname in participantAddressNicknames) { if (theGroup.Service.BubbleGroupComparer(participantAddressNickname.Address, vb.ParticipantAddress)) { if (participantAddressNickname.Nickname != vb.ParticipantAddressNickname) { participantAddressNickname.Nickname = vb.ParticipantAddressNickname; changed = true; } adding = false; break; } } if (adding) { participantAddressNicknames.Add(new DisaParticipantNickname { Address = vb.ParticipantAddress, Nickname = vb.ParticipantAddressNickname, }); } if (changed || adding) { theGroup.ParticipantNicknames = participantAddressNicknames.ToArray(); } } } catch (Exception ex) { Utils.DebugPrint("Failed to insert/update participant nickname into cache: " + ex); } if (!duplicate) { Utils.DebugPrint("Inserting bubble into database group!"); try { if (newGroup) { BubbleGroupDatabase.AddBubble(theGroup, vb); } else { BubbleGroupDatabase.InsertBubbleByTime(theGroup, vb); } } catch (Exception ex) { Utils.DebugPrint("Bubble failed to be inserting/added into the group " + theGroup.ID + ": " + ex); } try { BubbleGroupEvents.RaiseBubbleInserted(vb, theGroup); } catch (Exception ex) { Utils.DebugPrint( "Error in notifying the interface that the bubble group has been updated (" + vb.Service.Information.ServiceName + "): " + ex.Message); } } return theGroup; } }
public static void AddBubbles(BubbleGroup group, VisualBubble[] bubbles) { lock (OperationLock) { var file = GetLocation(@group); using (var stream = File.Open(file, FileMode.Append, FileAccess.Write)) { BubbleGroupIndex.UpdateLastBubbleOrAndLastModifiedIndex(group.ID, bubbles.Last(), stream.Position); foreach (var b in bubbles) { using (var ms = new MemoryStream()) { Serializer.Serialize(ms, b); var bubbleData = ms.ToArray(); var bubbleHeader = b.GetType().Name + ":" + b.ID + ":" + b.Time; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, bubbleData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, bubbleHeader); } } } } }
public void AddVisualBubbleIdServices(VisualBubble bubble) { bubble.IdService = _deviceId + ++_bubbleSendCount; }
public static bool InsertBubblesByTime(BubbleGroup group, VisualBubble[] bubbles, int maxDepth = 1000, bool guidCheck = false, bool insertAtTop = false) { //we can't operate if a thread/worker is concurrently processing a new bubble lock (OperationLock) { var groupDatabaseLocation = GetLocation(@group); var bubbleTuples = bubbles.Select(x => new Tuple<long, VisualBubble>(x.Time, x)).ToList(); VisualBubble lastBubble = null; long insertPosition = -1; using (var stream = File.Open(groupDatabaseLocation, FileMode.Open, FileAccess.ReadWrite)) { stream.Seek(stream.Length, SeekOrigin.Begin); for (var i = 0; i < (maxDepth != -1 ? maxDepth : Int32.MaxValue); i++) { if (stream.Position == 0) { if (insertAtTop) { insertPosition = 0; var cut = new byte[(int)stream.Length]; stream.Read(cut, 0, (int)stream.Length); stream.Position = 0; var bubblesToInsert = bubbleTuples.Select(x => x.Item2).ToList(); bubblesToInsert.TimSort((x, y) => x.Time.CompareTo(y.Time)); foreach (var bubbleToInsert in bubblesToInsert) { using (var ms = new MemoryStream()) { Serializer.Serialize(ms, bubbleToInsert); var bubbleToInsertData = ms.ToArray(); var bubbleToInsertHeader = bubbleToInsert.GetType().Name + ":" + bubbleToInsert.ID + ":" + bubbleToInsert.Time; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, bubbleToInsertData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, bubbleToInsertHeader); } } stream.Write(cut, 0, cut.Length); stream.SetLength(stream.Position); break; } else { break; } } byte[] headerBytes; int headerBytesLength; int endPosition; BubbleGroupDatabasePrimitives.ReadBubbleHeader(stream, out headerBytes, out headerBytesLength); BubbleGroupDatabasePrimitives.FindBubbleHeaderDelimiter(headerBytes, headerBytesLength, 0, out endPosition); var bubbleDataLength = BubbleGroupDatabasePrimitives.JumpBubbleData(stream); //we need to seek over the data. var guid = BubbleGroupDatabasePrimitives.ReadBubbleHeaderStruct(headerBytes, headerBytesLength, endPosition + 1, out endPosition); var time = BubbleGroupDatabasePrimitives.AsciiBytesToString(headerBytes, endPosition + 1, headerBytesLength); long longTime; Int64.TryParse(time, out longTime); { var bubblesToInsert = bubbleTuples.Where(x => { if (guidCheck && guid == x.Item2.ID) return false; if (longTime <= x.Item1) return true; return false; }).ToList(); if (!bubblesToInsert.Any()) { continue; } var bubbleSize = headerBytesLength + bubbleDataLength + 8; var insertLocation = stream.Position + bubbleSize; stream.Seek(insertLocation, SeekOrigin.Begin); var cutLength = stream.Length - insertLocation; var cut = new byte[cutLength]; stream.Read(cut, 0, (int)cutLength); //should always work as long as the count ain't crazy high stream.Seek(insertLocation, SeekOrigin.Begin); insertPosition = stream.Position; foreach (var bubbleToInsert in bubblesToInsert.Select(x => x.Item2)) { using (var ms = new MemoryStream()) { Serializer.Serialize(ms, bubbleToInsert); var bubbleToInsertData = ms.ToArray(); var bubbleToInsertHeader = bubbleToInsert.GetType().Name + ":" + bubbleToInsert.ID + ":" + bubbleToInsert.Time; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, bubbleToInsertData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, bubbleToInsertHeader); } } stream.Write(cut, 0, cut.Length); stream.SetLength(stream.Position); // adding to end if (cut.Length == 0) { lastBubble = bubblesToInsert.Last().Item2; } foreach (var bubbleToInsert in bubblesToInsert) { bubbleTuples.Remove(bubbleToInsert); } if (!bubbleTuples.Any()) { break; } } } BubbleGroupIndex.UpdateLastBubbleOrAndLastModifiedIndex(group.ID, lastBubble, insertPosition); } if (!bubbleTuples.Any()) { return true; } return false; } }
public static string PatchPath(VisualBubble bubble) { string path = null; string newBase = null; var imageBubble = bubble as ImageBubble; var videoBubble = bubble as VideoBubble; var audioBubble = bubble as AudioBubble; var fileBubble = bubble as FileBubble; if (imageBubble != null) { path = imageBubble.ImagePathNative; newBase = Platform.GetPicturesPath(); } else if (videoBubble != null) { path = videoBubble.VideoPathNative; newBase = Platform.GetVideosPath(); } else if (audioBubble != null) { path = audioBubble.AudioPathNative; newBase = Platform.GetAudioPath(); } else if (fileBubble != null) { path = fileBubble.PathNative; newBase = Platform.GetFilesPath(); } if (path == null || newBase == null) throw new Exception("Uknown bubble"); var indexes = FindIndexesFromRear(path, Path.DirectorySeparatorChar); var seperators = indexes.Take(2).ToList(); if (seperators.Count < 2) return path; var end = path.Substring(seperators[1] + 1); return Path.Combine(newBase, end); }
public static bool UpdateBubble(BubbleGroup group, VisualBubble[] bubbles, int searchDepth = 100) { //we can't operate if a thread/worker is concurrently processing a new bubble lock (OperationLock) { var groupDatabaseLocation = GetLocation(@group); var bubbleTuples = bubbles.Select(x => new Tuple<string, VisualBubble>(x.ID, x)).ToList(); VisualBubble lastBubble = null; long insertPosition = -1; using (var stream = File.Open(groupDatabaseLocation, FileMode.Open, FileAccess.ReadWrite)) { stream.Seek(stream.Length, SeekOrigin.Begin); for (var i = 0; i < (searchDepth != -1 ? searchDepth : Int32.MaxValue); i++) { if (stream.Position == 0) { break; } byte[] headerBytes; int headerBytesLength; int endPosition; BubbleGroupDatabasePrimitives.ReadBubbleHeader(stream, out headerBytes, out headerBytesLength); BubbleGroupDatabasePrimitives.FindBubbleHeaderDelimiter(headerBytes, headerBytesLength, 0, out endPosition); var bubbleDataLength = BubbleGroupDatabasePrimitives.JumpBubbleData(stream); //we need to seek over the data. var guid = BubbleGroupDatabasePrimitives.ReadBubbleHeaderStruct(headerBytes, headerBytesLength, endPosition + 1, out endPosition); Tuple<string, VisualBubble> bubbleTuple; if ((bubbleTuple = bubbleTuples.FirstOrDefault(x => x.Item1 == guid)) == null) { continue; } var b = bubbleTuple.Item2; var bubbleSize = headerBytesLength + bubbleDataLength + 8; var cutStart = stream.Position + bubbleSize; var cutLength = stream.Length - cutStart; insertPosition = stream.Position; using (var ms = new MemoryStream()) { Serializer.Serialize(ms, b); var updatedBubbleData = ms.ToArray(); var updatedBubbleHeader = b.GetType().Name + ":" + b.ID + ":" + b.Time; var updatedBubbleSize = updatedBubbleHeader.Length + updatedBubbleData.Length + 8; var bubbleInjectDelta = bubbleSize - updatedBubbleSize; //enough room if (bubbleInjectDelta != 0) { var injectPosition = stream.Position; stream.Position = cutStart; //higher var cut = new byte[cutLength]; stream.Read(cut, 0, (int)cutLength);//should always work as long as the count ain't crazy high //var bw = new BinaryWriter(stream, Encoding.ASCII); stream.Position = injectPosition; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, updatedBubbleData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, updatedBubbleHeader); stream.Write(cut, 0, cut.Length); stream.SetLength(stream.Position); } //they're the same! else if (bubbleInjectDelta == 0) { //var bw = new BinaryWriter(stream, Encoding.ASCII); BubbleGroupDatabasePrimitives.WriteBubbleData(stream, updatedBubbleData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, updatedBubbleHeader); } } if (cutLength == 0) { lastBubble = b; } bubbleTuples.Remove(bubbleTuple); if (!bubbleTuples.Any()) { break; } } BubbleGroupIndex.UpdateLastBubbleOrAndLastModifiedIndex(group.ID, lastBubble, insertPosition); } if (!bubbleTuples.Any()) { return true; } return false; } }
public Task<bool> DeleteBubble(BubbleGroup @group, VisualBubble bubble) { //just basic true, since we plan on not implementing this stuff return Task<bool>.Factory.StartNew(() => true); }