public void breakEdited(SnookerBreak oldBreak, SnookerBreak newBreak)
        {
            // to make it simple, lets remove ALL the balls that were in the break
            // BEFORE it was edited,
            // then add all new balls AFTER it was edited
            List <int> ballScoreList = new List <int>();

            ballScoreList = oldBreak.Balls;
            int numBalls = ballScoreList.Count();

            for (int ballIdx = numBalls - 1; ballIdx >= 0; ballIdx--)
            {
                int prevBall = 0;
                int curBall  = ballScoreList.ElementAt(ballIdx);
                if (ballIdx > 0)
                {
                    prevBall = ballScoreList.ElementAt(ballIdx - 1);
                }
                localBallsOnTable.ballRemovedFromBreak(curBall, prevBall);
            }

            ballScoreList.Clear();
            ballScoreList = newBreak.Balls;
            numBalls      = ballScoreList.Count();
            for (int ballIdx = 0; ballIdx < numBalls; ballIdx++)
            {
                int curBall = ballScoreList.ElementAt(ballIdx);
                localBallsOnTable.ballPocketed(curBall);
            }

            updateBallsOnTable_ballsChanged();
            updatePointsDiff();
        }
Exemple #2
0
        public SnookerMatchMetadata FromBreak(SnookerBreak snookerBreak)
        {
            var me = App.Repository.GetMyAthlete();

            SnookerMatchMetadata metadata = new SnookerMatchMetadata()
            {
                Date                  = snookerBreak.Date,
                PrimaryAthleteID      = me.AthleteID,
                PrimaryAthleteName    = me.Name,
                PrimaryAthletePicture = me.Picture,
                OpponentAthleteID     = snookerBreak.OpponentAthleteID,
                OpponentAthleteName   = snookerBreak.OpponentName,
                OpponentPicture       = null,
                TableSize             = snookerBreak.TableSize,
                VenueID               = snookerBreak.VenueID,
                VenueName             = snookerBreak.VenueName,
            };

            if (metadata.OpponentAthleteID > 0)
            {
                var person = App.Cache.People.Get(metadata.OpponentAthleteID);
                if (person != null)
                {
                    metadata.OpponentAthleteName = person.Name;
                    metadata.OpponentPicture     = person.Picture;
                }
            }

            return(metadata);
        }
Exemple #3
0
        public async Task Fill()
        {
            this.labelTop.Text = "loading...";

            int venueID = FVOConfig.LoadFromKeyChain(App.KeyChain).VenueID;

            var resultsWeb = await App.WebService.GetResultsAtVenue(venueID);

            var results = resultsWeb.Select(r => r.ToResult()).ToList();
            var scores  = await App.WebService.GetScoresAtVenue(venueID);

            bool failedToLoadFromWeb = results == null || scores == null;

            if (failedToLoadFromWeb)
            {
                scores  = App.Repository.GetScores(true);
                results = App.Repository.GetResults(true).ToList();
            }

            var matches = (from score in scores
                           select SnookerMatchScore.FromScore(score.AthleteAID, score)).ToList();
            var breaks = (from result in results
                          select SnookerBreak.FromResult(result)).ToList();

            await new CacheHelper().LoadFromWebserviceIfNecessary_People(App.Cache, results, scores);
            new CacheHelper().LoadNamesFromCache(App.Cache, breaks);
            new CacheHelper().LoadNamesFromCache(App.Cache, matches);

            listOfMatchesControl.Fill(matches);
            listOfBreaksControl.Fill(breaks);

            this.labelTop.Text = failedToLoadFromWeb ? "Failed to load. Internet issues?" : "History";
        }
Exemple #4
0
        public async Task <FullSnookerVenueData> Load(int venueID)
        {
            FullSnookerVenueData data = new FullSnookerVenueData();

            data.VenueID = venueID;

            VenueWebModel venue = await App.WebService.GetVenue(venueID);

            if (venue == null)
            {
                return(null);
            }
            data.Venue = venue;

            App.Cache.Venues.Put(venue);

            var webResults = await App.WebService.GetResultsAtVenue(venueID);

            if (webResults != null)
            {
                var results = (from r in webResults
                               select r.ToResult()).ToList();
                data.Breaks = (from i in results
                               select SnookerBreak.FromResult(i)).ToList();
            }

            var scores = await App.WebService.GetScoresAtVenue(venueID);

            if (scores != null)
            {
                data.Matches = (from i in scores
                                select SnookerMatchScore.FromScore(0, i)).ToList();
            }

            var gameHosts = await App.WebService.GetGameHostsAtVenue(venueID, true);

            if (gameHosts != null)
            {
                data.GameHosts = (from i in gameHosts
                                  orderby i.When descending
                                  select i).ToList();
                data.GameHostsInThePast = (from i in gameHosts
                                           where i.When < DateTime.UtcNow
                                           orderby i.When descending
                                           select i).ToList();
                data.GameHostsInTheFuture = (from i in gameHosts
                                             where i.When >= DateTime.UtcNow
                                             orderby i.When ascending
                                             select i).ToList();
            }

            await loadPeople(data);

            this.putPlaceholdersIfInternetIssues(data);
            return(data);
        }
Exemple #5
0
        public RecordBreakPage(SnookerBreak snookerBreak, bool isOpponentsBreak, bool isSingleNotableMode)
        {
            this.IsSingleNotableMode = isSingleNotableMode;
            this.SnookerBreak        = snookerBreak.Clone();
            this.IsOpponentsBreak    = isOpponentsBreak;
            this.metadata            = new MetadataHelper().FromBreak(snookerBreak);

            this.init();
            this.fill();
        }
Exemple #6
0
        public RecordBreakPage(SnookerMatchMetadata metadata, bool isOpponentsBreak, bool isSingleNotableMode)
        {
            this.IsSingleNotableMode = isSingleNotableMode;
            this.SnookerBreak        = new SnookerBreak();
            this.IsOpponentsBreak    = isOpponentsBreak;
            this.metadata            = metadata;

            this.init();
            this.fill();
        }
Exemple #7
0
        // GET: /players/break/id
        public ActionResult Break(int id)
        {
            var result = db.Results.Where(i => i.ResultID == id).Single();
            var person = new PeopleLogic(db).GetBasic(0, result.AthleteID);

            Models.SnookerBreakModel model = new Models.SnookerBreakModel();
            model.Break  = SnookerBreak.FromResult(result);
            model.Player = person;

            return(View("Break", model));
        }
Exemple #8
0
        private void buttonNewBreak_Clicked(object sender, EventArgs e)
        {
            if (App.Navigator.GetOpenedPage(typeof(RecordBreakPage)) != null)
            {
                return;
            }

            var page = new RecordBreakPage(this.metadata, false, true);

            App.Navigator.NavPage.Navigation.PushModalAsync(page);
            page.Done += async(s1, e1) =>
            {
                SnookerBreak snookerBreak = e1;
                this.metadataControl.Fill(this.metadata);
                if (snookerBreak == null)
                {
                    return;
                }

                if (page.IsOpponentsBreak == false)
                {
                    // save this as a notable break
                    Result result = new Result();
                    snookerBreak.PostToResult(result);
                    result.AthleteID    = App.Repository.GetMyAthleteID();
                    result.TimeModified = DateTimeHelper.GetUtcNow();
                    App.Repository.AddResult(result);

                    await App.Navigator.GoToMyProfile(ProfilePersonStateEnum.Breaks, true);

                    App.Navigator.StartSyncAndCheckForNotifications();
                }
                else
                {
                    // save this as opponent's break
                    Result result = new Result();
                    snookerBreak.PostToResult(result);
                    result.AthleteID                 = metadata.OpponentAthleteID;
                    result.OpponentAthleteID         = App.Repository.GetMyAthleteID();
                    result.TimeModified              = DateTimeHelper.GetUtcNow();
                    result.IsNotAcceptedByAthleteYet = true;
                    App.Repository.AddResult(result);

                    App.Navigator.StartSyncAndCheckForNotifications();
                    App.Navigator.DisplayAlertRegular("The break was recorded as a notable break for '" + metadata.OpponentAthleteName + "'. Once the data is synced with snookerbyb.com, '" + metadata.OpponentAthleteName + "' will be able to accept it.");
                }
            };
        }
        public async Task <FullSnookerPlayerData> LoadForPlayer(int athleteID)
        {
            FullSnookerPlayerData data = new FullSnookerPlayerData();

            data.AthleteID = athleteID;

            var webResults = await App.WebService.GetResults(data.AthleteID);

            if (webResults != null)
            {
                var results = (from r in webResults
                               select r.ToResult()).ToList();
                data.Breaks = (from i in results
                               select SnookerBreak.FromResult(i)).ToList();
            }
            else
            {
                data.InternetIssues = true;
            }

            var scores = await App.WebService.GetScores(data.AthleteID);

            if (scores != null)
            {
                data.Matches = (from i in scores
                                select SnookerMatchScore.FromScore(data.AthleteID, i)).ToList();
            }
            else
            {
                data.InternetIssues = true;
            }

            await loadOpponents(data);
            await loadVenues(data);

            data.Person = await App.WebService.GetPersonByID(data.AthleteID);

            if (data.Person == null)
            {
                data.InternetIssues = true;
            }

            this.putPlaceholdersIfInternetIssues(data);
            return(data);
        }
        public async Task <FullSnookerPlayerData> LoadForMe()
        {
            DateTime timeBegin = DateTime.Now;

            FullSnookerPlayerData data = new FullSnookerPlayerData();

            data.AthleteID = App.Repository.GetMyAthleteID();

            var results = App.Repository.GetResults(data.AthleteID, false);

            data.Breaks = (from i in results
                           select SnookerBreak.FromResult(i)).ToList();

            var scores = App.Repository.GetScores(false);

            data.Matches = (from i in scores
                            select SnookerMatchScore.FromScore(data.AthleteID, i)).ToList();

            await loadOpponents(data);
            await loadVenues(data);

            data.Person = await App.WebService.GetPersonByID(data.AthleteID);

            if (data.Person == null)
            {
                data.InternetIssues = true;

                var athlete = App.Repository.GetAthlete(data.AthleteID);
                data.Person = new PersonFullWebModel();
                data.Person.CopyFrom(athlete);
            }

            this.putPlaceholdersIfInternetIssues(data);

            if (data.InternetIssues == false && data.Person != null)
            {
                await App.Cache.LoadFromWebserviceIfNecessary_Metro(data.Person.MetroID);
            }

            TraceHelper.TraceTimeSpan(timeBegin, DateTime.Now, "FullSnookerPlayerDataHelper.LoadForMe");
            return(data);
        }
Exemple #11
0
        async void ctrl_UserWantsToDeleteBreak(object sender, SnookerEventArgs e)
        {
            if (this.IsMyAthlete == false)
            {
                return;
            }

            SnookerBreak snookerBreak = e.SnookerBreak;

            bool ok = await App.Navigator.NavPage.DisplayAlert("Byb", "Delete break " + snookerBreak.ToString() + " ?", "Yes, delete", "Cancel");

            if (ok == false)
            {
                return;
            }

            App.Repository.SetIsDeletedOnResult(snookerBreak.ID, true);
            App.Navigator.StartSyncAndCheckForNotifications();

            this.loadDataAsyncAndFill(false);
        }
        public void breakDeleted(SnookerBreak deletedBreak)
        {
            // Remove ALL the balls that were in the break
            List <int> ballScoreList = new List <int>();

            ballScoreList = deletedBreak.Balls;
            int numBalls = ballScoreList.Count();

            for (int ballIdx = numBalls - 1; ballIdx >= 0; ballIdx--)
            {
                int prevBall = 0;
                int curBall  = ballScoreList.ElementAt(ballIdx);
                if (ballIdx > 0)
                {
                    prevBall = ballScoreList.ElementAt(ballIdx - 1);
                }
                localBallsOnTable.ballRemovedFromBreak(curBall, prevBall);
            }

            updateBallsOnTable_ballsChanged();
            updatePointsDiff();
        }
Exemple #13
0
        void ctrl_UserWantsToEditBreak(object sender, SnookerEventArgs e)
        {
            if (this.IsMyAthlete == false)
            {
                return;
            }

            SnookerBreak snookerBreak = e.SnookerBreak;

            if (snookerBreak.OpponentConfirmation == OpponentConfirmationEnum.Confirmed)
            {
                App.Navigator.DisplayAlertRegular("Cannot edit a confirmed break.");
                return;
            }

            var page = new RecordBreakPage(snookerBreak, false, true);

            App.Navigator.NavPage.Navigation.PushModalAsync(page);
            page.Done += async(s1, e1) =>
            {
                snookerBreak = e1;
                if (snookerBreak == null)
                {
                    return;
                }

                // update
                Result result = App.Repository.GetResult(snookerBreak.ID);
                result.TimeModified         = DateTimeHelper.GetUtcNow();
                result.OpponentConfirmation = (int)OpponentConfirmationEnum.NotYet;
                snookerBreak.PostToResult(result);
                App.Repository.UpdateResult(result);

                await App.Navigator.GoToMyProfile(ProfilePersonStateEnum.Breaks, true);

                App.Navigator.StartSyncAndCheckForNotifications();
            };
        }
        private async void listOfBreaksInMatchControl_UserTappedOnBreak(object sender, SnookerBreak snookerBreak)
        {
            if (Config.IsTablet == false && this.isPastBreaksExpanded == false)
            {
                this.panelPastBreaksTapped();
                return;
            }

            string strPoints      = snookerBreak.Points.ToString();
            string strOtherPlayer = ((snookerBreak.AthleteID == MatchScore.YourAthleteID) ? (MatchScore.OpponentName ?? "Opponent") : MatchScore.YourName);

            string strEdit     = "Edit";
            string strDelete   = "Delete";
            string strReassign = "Assign to " + strOtherPlayer;

            string strResult1 = await this.DisplayActionSheet(snookerBreak.Points.ToString() + " point break", "Cancel", null, strDelete, strReassign, strEdit);

            if (string.IsNullOrEmpty(strResult1) || strResult1 == "Cancel")
            {
                return;
            }

            if (strResult1 == strEdit)
            {
                RecordBreakPage page = new RecordBreakPage(snookerBreak, false, false);
                await this.Navigation.PushModalAsync(page);

                page.Done += (s1, updatedBreak) =>
                {
                    if (updatedBreak == null || updatedBreak.Points == 0)
                    {
                        return;
                    }

                    // update balls on table
                    this.snookerBreakControl.breakEdited(snookerBreak, updatedBreak);

                    int diff = updatedBreak.Points - snookerBreak.Points;
                    if (snookerBreak.OpponentAthleteID != this.MatchScore.YourAthleteID)
                    {
                        this.CurrentFrameScore.A = System.Math.Max(0, this.CurrentFrameScore.A + diff);
                    }
                    else
                    {
                        this.CurrentFrameScore.B = System.Math.Max(0, this.CurrentFrameScore.B + diff);
                    }
                    snookerBreak.Points        = updatedBreak.Points;
                    snookerBreak.NumberOfBalls = updatedBreak.NumberOfBalls;
                    snookerBreak.Balls         = updatedBreak.Balls.ToList();
                    snookerBreak.IsFoul        = updatedBreak.IsFoul;

                    this.listOfBreaksInMatchControl.Fill(this.MatchScore, this.MatchScore.FrameScores.IndexOf(this.CurrentFrameScore) + 1);

                    updateFrameScoreInSnookerBreakControl();

                    this.snookerBreakControl.updateFrameScoreOnBreakEdit((int)this.entryCurrentFrameA.Number, (int)this.entryCurrentFrameB.Number);
                };

                return;
            }
            else if (strResult1 == strDelete)
            {
                string strSubtractScore = "Remove " + strPoints + " from the score?";
                string strKeepScore     = "Keep the score";
                string strResult2       = await this.DisplayActionSheet("Frame score", "Cancel", null, strSubtractScore, strKeepScore);

                if (string.IsNullOrEmpty(strResult2) || strResult2 == "Cancel")
                {
                    return;
                }

                if (strResult2 == strSubtractScore)
                {
                    // update ballsOnTable
                    this.snookerBreakControl.breakDeleted(snookerBreak);

                    if (snookerBreak.OpponentAthleteID != this.MatchScore.YourAthleteID)
                    {
                        this.CurrentFrameScore.A = System.Math.Max(0, this.CurrentFrameScore.A - snookerBreak.Points);
                    }
                    else if (snookerBreak.OpponentAthleteID == this.MatchScore.YourAthleteID)
                    {
                        this.CurrentFrameScore.B = System.Math.Max(0, this.CurrentFrameScore.B - snookerBreak.Points);
                    }
                    this.MatchScore.YourBreaks.Remove(snookerBreak);
                    this.MatchScore.OpponentBreaks.Remove(snookerBreak);
                }
                else if (strResult2 == strKeepScore)
                {
                    this.MatchScore.YourBreaks.Remove(snookerBreak);
                    this.MatchScore.OpponentBreaks.Remove(snookerBreak);
                }

                this.listOfBreaksInMatchControl.Fill(this.MatchScore, this.MatchScore.FrameScores.IndexOf(this.CurrentFrameScore) + 1);

                updateFrameScoreInSnookerBreakControl();

                return;
            }
            else if (strResult1 == strReassign)
            {
                string strMoveScore;
                if (snookerBreak.OpponentAthleteID != this.MatchScore.YourAthleteID)
                {
                    strMoveScore = MatchScore.YourName + " -" + snookerBreak.Points.ToString() + ", " + MatchScore.OpponentName + " +" + snookerBreak.Points.ToString();
                }
                else
                {
                    strMoveScore = MatchScore.YourName + " +" + snookerBreak.Points.ToString() + ", " + MatchScore.OpponentName + " -" + snookerBreak.Points.ToString();
                }

                string strKeepScore = "Do NOT change the frame scores";
                string strResult2   = await this.DisplayActionSheet("Re-assign the break and...", "Cancel", null, strMoveScore, strKeepScore);

                if (string.IsNullOrEmpty(strResult2) || strResult2 == "Cancel")
                {
                    return;
                }
                if (strResult2 == strMoveScore)
                {
                    if (snookerBreak.OpponentAthleteID != this.MatchScore.YourAthleteID)
                    {
                        this.CurrentFrameScore.A  = System.Math.Max(0, this.CurrentFrameScore.A - snookerBreak.Points);
                        this.CurrentFrameScore.B += snookerBreak.Points;
                    }
                    else if (snookerBreak.OpponentAthleteID == this.MatchScore.YourAthleteID)
                    {
                        this.CurrentFrameScore.B  = System.Math.Max(0, this.CurrentFrameScore.B - snookerBreak.Points);
                        this.CurrentFrameScore.A += snookerBreak.Points;
                    }
                }
                if (strResult2 == strMoveScore || strResult2 == strKeepScore)
                {
                    this.MatchScore.YourBreaks.Remove(snookerBreak);
                    this.MatchScore.OpponentBreaks.Remove(snookerBreak);

                    int a = snookerBreak.AthleteID;
                    snookerBreak.AthleteID         = snookerBreak.OpponentAthleteID;
                    snookerBreak.OpponentAthleteID = a;
                    string n = snookerBreak.AthleteName;
                    snookerBreak.AthleteName          = snookerBreak.OpponentName;
                    snookerBreak.OpponentName         = snookerBreak.AthleteName;
                    snookerBreak.OpponentConfirmation = OpponentConfirmationEnum.NotYet;
                    if (snookerBreak.AthleteID == this.MatchScore.YourAthleteID)
                    {
                        this.MatchScore.YourBreaks.Add(snookerBreak);
                    }
                    else
                    {
                        this.MatchScore.OpponentBreaks.Add(snookerBreak);
                    }
                }

                this.listOfBreaksInMatchControl.Fill(this.MatchScore, this.MatchScore.FrameScores.IndexOf(this.CurrentFrameScore) + 1);

                updateFrameScoreInSnookerBreakControl();

                return;
            }
        }
        void snookerBreakControl_Done(bool isOpponent)
        {
            var balls = snookerBreakControl.EnteredBalls;

            if (balls.Count == 0)
            {
                snookerBreakControl.ClearBalls();
                return;
            }

            //this.labelTapToEditFrameScore.Opacity = 1.0;
            //this.labelTapToEditFrameScore.Text = "(edit any time)";
            this.changeOpacityOnControls(false);



            SnookerBreak snookerBreak = new SnookerBreak();

            snookerBreak.AthleteID         = !isOpponent ? MatchScore.YourAthleteID : MatchScore.OpponentAthleteID;
            snookerBreak.OpponentAthleteID = !isOpponent ? MatchScore.OpponentAthleteID : MatchScore.YourAthleteID;
            snookerBreak.Date        = DateTime.Now;
            snookerBreak.IsFoul      = snookerBreakControl.isFoul;
            snookerBreak.FrameNumber = this.MatchScore.FrameScores.IndexOf(this.CurrentFrameScore) + 1;
            snookerBreak.Balls       = balls;
            snookerBreak.CalcFromBalls();
            if (this.MatchScore.YourBreaks == null)
            {
                this.MatchScore.YourBreaks = new List <SnookerBreak>();
            }
            if (this.MatchScore.OpponentBreaks == null)
            {
                this.MatchScore.OpponentBreaks = new List <SnookerBreak>();
            }
            if (!isOpponent)
            {
                this.MatchScore.YourBreaks.Add(snookerBreak);
            }
            else
            {
                this.MatchScore.OpponentBreaks.Add(snookerBreak);
            }

            snookerBreakControl.ClearBalls();

            if (!isOpponent)
            {
                this.CurrentFrameScore.A += snookerBreak.Points;
            }
            else
            {
                this.CurrentFrameScore.B += snookerBreak.Points;
            }

            // Fill list of breaks AFTER the currentFrameScore has been updated
            this.listOfBreaksInMatchControl.Fill(this.MatchScore, snookerBreak.FrameNumber);

            updateFrameScoreInSnookerBreakControl();

            if (App.UserPreferences.IsVoiceOn)
            {
                // Announce break points and name
                string name = isOpponent ? MatchScore.OpponentName : MatchScore.YourName;

                string textToPronounce = snookerBreak.Points.ToString();
                if (string.IsNullOrEmpty(name) == false)
                {
                    textToPronounce += ". " + name;
                }

                // Also say the new frame score
                if (Config.IsIOS == false)
                {
                    textToPronounce += ". " + CurrentFrameScore.A.ToString() + ". " + CurrentFrameScore.B.ToString();
                }

                App.ScorePronouncer.Pronounce(textToPronounce, App.UserPreferences.Voice, App.UserPreferences.VoiceRate, App.UserPreferences.VoicePitch);
            }

            //if (this.isMatchEditMode == false)
            new TempSavedMatchHelper(App.KeyChain).Save(MatchScore);
        }
Exemple #16
0
        void addSnookerBreakControls(SnookerBreak snookerBreak, bool isOpponentsBreak)
        {
            StackLayout[] horizontalStack = new StackLayout[5];
            int           lineIdx;

            // Determine number of lines needed to display all balls in a break
            int numLines = (int)(snookerBreak.Balls.Count / maxNumberOfBallsPerLine) + 1;

            for (lineIdx = 0; lineIdx < numLines; lineIdx++)
            {
                horizontalStack[lineIdx] = new StackLayout()
                {
                    Orientation       = StackOrientation.Horizontal,
                    Padding           = new Thickness(1, 0, 1, 0),
                    BackgroundColor   = Config.ColorBackground,
                    Spacing           = 2,
                    HorizontalOptions = (!isOpponentsBreak || (lineIdx > 0)) ? LayoutOptions.Start : LayoutOptions.End
                };
            }

            // if more than one line, start adding opponent's balls from the left
            if (snookerBreak.Balls.Count >= maxNumberOfBallsPerLine)
            {
                horizontalStack[0].HorizontalOptions = LayoutOptions.Start;
            }

            double sizeOfPocketedBalls = Config.ExtraSmallBallSize;

            // Fill horizonal stack lines with the balls
            lineIdx = 0;
            if (snookerBreak.HasBalls)
            {
                int ballIdx = 0;
                foreach (var ballScore in snookerBreak.Balls)
                {
                    Color color       = Config.BallColors[ballScore];
                    Color borderColor = color;
                    if (ballScore == 7)
                    {
                        borderColor = Color.Gray;
                    }

                    RoundedBoxView.Forms.Plugin.Abstractions.RoundedBoxView ball = new RoundedBoxView.Forms.Plugin.Abstractions.RoundedBoxView {
                        WidthRequest         = sizeOfPocketedBalls,
                        HeightRequest        = sizeOfPocketedBalls,
                        MinimumWidthRequest  = sizeOfPocketedBalls,
                        MinimumHeightRequest = sizeOfPocketedBalls,
                        Color           = color,
                        BorderColor     = borderColor,
                        BackgroundColor = color,
                        BorderThickness = 1,
                        CornerRadius    = (int)(sizeOfPocketedBalls / 2),
                        VerticalOptions = LayoutOptions.Center
                    };

                    // if 8 balls in each line:
                    //   0/8 - 0, 7/8 - 0, 8/8 - 1, 9/8 - 1 ...
                    //
                    lineIdx = (int)(ballIdx / maxNumberOfBallsPerLine);
                    horizontalStack[lineIdx].Children.Insert(horizontalStack[lineIdx].Children.Count, ball);

                    ballIdx++;
                }
            }

            if (snookerBreak.IsFoul)
            {
                // add "foul":
                //   if on right side "foul xxx 15"
                //   if on left side  "xxx 15 foul"

                string foulLabelString = isOpponentsBreak ?
                                         "foul ": // if on right side "foul xxx 15"
                                         " foul"; // if on left side  "xxx 15 foul"

                BybLabel foulLabel = new BybLabel()
                {
                    Text         = foulLabelString,
                    TextColor    = Config.ColorRed,
                    WidthRequest = Config.IsTablet ? 35 : 27,
                    //VerticalTextAlignment = TextAlignment.Center,
                    HorizontalTextAlignment = TextAlignment.Start
                };

                if (isOpponentsBreak)
                {
                    horizontalStack[0].Children.Insert(0, foulLabel);                     // insert "foul " in the beginning "foul xxx 15"
                }
                else
                {
                    horizontalStack[0].Children.Add(foulLabel);                        // add " foul" to the end "15 xxx foul"
                }
            }

            // This grid hold all the break info
            BybBreakGrid breakGrid = new BybBreakGrid(isOpponentsBreak);

            // Add all the lines of balls to stack
            for (lineIdx = 0; lineIdx < numLines; lineIdx++)
            {
                breakGrid.ballsStack.Children.Add(horizontalStack[lineIdx]);
            }

            // Break score - 3 character string
            string   breakPointsString = String.Format("{0,3}", snookerBreak.Points.ToString());
            BybLabel breakPointsLabel  = new BybLabel()
            {
                Text                    = breakPointsString,
                BackgroundColor         = Config.ColorBackground,
                TextColor               = snookerBreak.IsFoul ? Config.ColorRed : Color.White,
                VerticalTextAlignment   = TextAlignment.Center,
                HorizontalTextAlignment = (isOpponentsBreak) ? TextAlignment.End : TextAlignment.Start
            };

            breakGrid.ballsStack.GestureRecognizers.Add(new TapGestureRecognizer
            {
                Command = new Command(() =>
                {
                    if (this.UserTappedOnBreak != null)
                    {
                        this.UserTappedOnBreak(this, snookerBreak);
                    }
                }),
                NumberOfTapsRequired = 1
            });
            breakPointsLabel.GestureRecognizers.Add(new TapGestureRecognizer
            {
                Command = new Command(() =>
                {
                    if (this.UserTappedOnBreak != null)
                    {
                        this.UserTappedOnBreak(this, snookerBreak);
                    }
                }),
                NumberOfTapsRequired = 1
            });

            // Add to the player who scored,
            // leave the other player's corresponding fields empty:
            //  - balls
            //  - break score field
            if (isOpponentsBreak)
            {
                breakGrid.Children.Add(breakGrid.ballsStack, 3, 0);
                breakGrid.Children.Add(breakPointsLabel, 4, 0);
            }
            else
            {
                breakGrid.Children.Add(breakPointsLabel, 0, 0);
                breakGrid.Children.Add(breakGrid.ballsStack, 1, 0);
            }
            int childIdx = breakGrid.Children.Count();

            // If running frame score is valid, add it in the middle
            if (frameScoreValid)
            {
                Grid frameScoreGrid = new CurrentBreakScoreGrid(frameScoreYou, frameScoreOpponent);
                breakGrid.Children.Add(frameScoreGrid, 2, 0);
            }

            // I think this might not be necessary
            breakGrid.RaiseChild(breakGrid.Children.ElementAt(childIdx - 1));
            breakGrid.RaiseChild(breakGrid.Children.ElementAt(childIdx - 2));

            // add the new break to the list of breaks
            this.Children.Add(breakGrid);
        } // addSnookerBreakControls()